From 0f551270ac0ac4823f7cd4fa15440673500bfab2 Mon Sep 17 00:00:00 2001 From: Bartek Pacia Date: Wed, 2 Jul 2025 10:22:36 +0200 Subject: [PATCH] [ByteCodeViewer] IDEA-375222 Fully match the "tab name deduplication behavior" of the main editor Previously, the behavior was mostly correct but there were edge cases, for example if 'Show Bytecode' action was triggered for the following files which were open in the main editor: - classes/java/org/example/Main.java - classes/java/main/simple1/Main.java - classes/java/main/simple1/Main.java Then the titles of tabs in the main editor were (correct): - example/Main.java - simple1/Main.java - simple2/Main.java But the titles of tabs in the bytecode viewer tool window were (wrong): - org/example/Main.class - simple1/Main.class - simple2/Main.class But after this commit, the names of tabs in the bytecode viewer tool window are (correct): - example/Main.class - simple1/Main.class - simple2/Main.class GitOrigin-RevId: 2c903dab6fccdf08ded1f09119d46307b587d59e --- .../BytecodeToolWindowService.kt | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/plugins/ByteCodeViewer/src/com/intellij/byteCodeViewer/BytecodeToolWindowService.kt b/plugins/ByteCodeViewer/src/com/intellij/byteCodeViewer/BytecodeToolWindowService.kt index e4275785df75..efcaec80b0c1 100644 --- a/plugins/ByteCodeViewer/src/com/intellij/byteCodeViewer/BytecodeToolWindowService.kt +++ b/plugins/ByteCodeViewer/src/com/intellij/byteCodeViewer/BytecodeToolWindowService.kt @@ -1,13 +1,14 @@ // Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.byteCodeViewer +import com.intellij.filename.UniqueNameBuilder import com.intellij.ide.ui.UISettings import com.intellij.openapi.components.Service import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer +import com.intellij.openapi.util.NlsSafe import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.wm.ToolWindow -import com.intellij.ui.content.Content import com.intellij.ui.content.ContentManagerEvent import com.intellij.ui.content.ContentManagerListener import java.util.concurrent.ConcurrentHashMap @@ -61,31 +62,28 @@ class BytecodeToolWindowService(private val project: Project) { * Updates tab titles to avoid duplicate names by adding path information when necessary. */ fun deduplicateTabNames(toolWindow: ToolWindow) { - val titlesToContents = mutableMapOf>() - for (content in toolWindow.contentManager.contents) { - val classFileName = content.getUserData(JAVA_CLASS_FILE)?.name - ?: throw IllegalStateException("Content entry has no JAVA_CLASS_FILE or it is null. Entry: $content") - titlesToContents.getOrPut(classFileName) { mutableListOf() }.add(content) + val javaClassFiles = toolWindow.contentManager.contents.map { content -> + content.getUserData(JAVA_CLASS_FILE) ?: throw IllegalStateException("Content has no JAVA_CLASS_FILE or it is null. Content: $content") } - for ((classFileName, contents) in titlesToContents) { - if (contents.size == 1) { - contents[0].displayName = classFileName - } - else if (contents.size > 1) { - val paths = contents.map { - it.getUserData(JAVA_CLASS_FILE) ?: throw IllegalStateException("No class file path for content entry $it") - } - val commonAncestor = VfsUtil.getCommonAncestor(paths) ?: continue + if (javaClassFiles.size == 1) { + toolWindow.contentManager.contents[0].displayName = javaClassFiles[0].name + return + } - for (i in contents.indices) { - val content = contents[i] - content.displayName = VfsUtil.getRelativePath( - content.getUserData(JAVA_CLASS_FILE) ?: throw IllegalStateException("No class file path for content entry $content"), - commonAncestor, - ) - } - } + val commonAncestor = VfsUtil.getCommonAncestor(javaClassFiles)?.path ?: return + val uniqueNameBuilder = UniqueNameBuilder(commonAncestor, "/") + + for (javaClassFile in javaClassFiles) { + uniqueNameBuilder.addPath(javaClassFile.path, javaClassFile.path) + } + + for (content in toolWindow.contentManager.contents) { + val javaClassFile = content.getUserData(JAVA_CLASS_FILE) + ?: throw IllegalStateException("Content has no JAVA_CLASS_FILE or it is null. Content: $content") + @NlsSafe val displayName = uniqueNameBuilder.getShortPath(javaClassFile.path) + ?: throw IllegalStateException("Cannot get short path for ${javaClassFile.path}") + content.displayName = displayName } }