feat: add tooltips for input editor tags (closes #1109)

This commit is contained in:
Carl-Robert Linnupuu 2025-09-24 00:34:10 +01:00
parent 38b9705e74
commit fb449f62e3
6 changed files with 77 additions and 20 deletions

View file

@ -52,7 +52,7 @@ class DiffAcceptedPanel(
LocalFileSystem.getInstance().findFileByPath(filePath)?.let { vFile ->
FileEditorManager.getInstance(project).openFile(vFile, true)
}
}
}.apply { toolTipText = filePath }
private fun createLeftPanel(fileLink: ActionLink, statsPanel: JPanel): JPanel =
JPanel().apply {
@ -114,4 +114,4 @@ class DiffAcceptedPanel(
add(viewDetailsLink)
}
}
}
}

View file

@ -138,6 +138,7 @@ abstract class HeaderPanel(protected val config: HeaderConfig) : BorderLayoutPan
OpenFileAction.openFile(virtualFile, config.project)
}.apply {
setExternalLinkIcon()
toolTipText = virtualFile.path
})
add(statsComponent)
}
@ -176,7 +177,10 @@ abstract class HeaderPanel(protected val config: HeaderConfig) : BorderLayoutPan
ProjectView.getInstance(config.project).select(null, newFile, true)
}
}
}.apply { icon = AllIcons.General.InlineAdd }
}.apply {
icon = AllIcons.General.InlineAdd
toolTipText = filePath
}
return actionLink
}

View file

@ -214,6 +214,7 @@ class UserMessagePanel(
})
actionLink.icon =
if (it.isDirectory) AllIcons.Nodes.Folder else it.fileType.icon
actionLink.toolTipText = it.path
actionLink
}
.toList()
@ -258,4 +259,4 @@ class UserMessagePanel(
})
}
}
}
}

View file

@ -140,9 +140,9 @@ class UserInputHeaderPanel(
private fun createTagPanel(tagDetails: TagDetails) =
(if (tagDetails is EditorSelectionTagDetails) {
SelectionTagPanel(tagDetails, tagManager, promptTextField)
SelectionTagPanel(tagDetails, tagManager, promptTextField, project)
} else {
object : TagPanel(tagDetails, tagManager, false) {
object : TagPanel(tagDetails, tagManager, false, project) {
init {
cursor = if (tagDetails is FileTagDetails)

View file

@ -20,6 +20,8 @@ sealed class TagDetails(
var selected: Boolean = true
abstract fun getTooltipText(): String?
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is TagDetails) return false
@ -36,6 +38,8 @@ class EditorTagDetails(val virtualFile: VirtualFile, isRemovable: Boolean = true
private val type: String = "EditorTagDetails"
override fun getTooltipText(): String = virtualFile.path
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@ -58,6 +62,8 @@ class FileTagDetails(val virtualFile: VirtualFile) :
private val type: String = "FileTagDetails"
override fun getTooltipText(): String = virtualFile.path
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
@ -83,6 +89,8 @@ data class SelectionTagDetails(
) {
var selectedText: String? = selectionModel.selectedText
private set
override fun getTooltipText(): String = virtualFile.path
}
class EditorSelectionTagDetails(
@ -99,6 +107,8 @@ class EditorSelectionTagDetails(
var selectedText: String? = selectionModel.selectedText
private set
override fun getTooltipText(): String = virtualFile.path
override fun equals(other: Any?): Boolean {
if (other === null) return false
return other::class == this::class
@ -110,33 +120,55 @@ class EditorSelectionTagDetails(
}
data class DocumentationTagDetails(var documentationDetails: DocumentationDetails) :
TagDetails(documentationDetails.name, AllIcons.Toolwindows.Documentation)
TagDetails(documentationDetails.name, AllIcons.Toolwindows.Documentation) {
override fun getTooltipText(): String? = documentationDetails.url
}
data class PersonaTagDetails(var personaDetails: PersonaDetails) :
TagDetails(personaDetails.name, AllIcons.General.User)
TagDetails(personaDetails.name, AllIcons.General.User) {
override fun getTooltipText(): String? = null
}
data class GitCommitTagDetails(var gitCommit: GitCommit) :
TagDetails(gitCommit.id.asString().take(6), AllIcons.Vcs.CommitNode)
TagDetails(gitCommit.id.asString().take(6), AllIcons.Vcs.CommitNode) {
override fun getTooltipText(): String? = gitCommit.fullMessage
}
class CurrentGitChangesTagDetails :
TagDetails("Current Git Changes", AllIcons.Vcs.CommitNode)
TagDetails("Current Git Changes", AllIcons.Vcs.CommitNode) {
override fun getTooltipText(): String? = null
}
data class FolderTagDetails(var folder: VirtualFile) :
TagDetails(folder.name, AllIcons.Nodes.Folder)
TagDetails(folder.name, AllIcons.Nodes.Folder) {
override fun getTooltipText(): String = folder.path
}
class WebTagDetails : TagDetails("Web", AllIcons.General.Web)
class WebTagDetails : TagDetails("Web", AllIcons.General.Web) {
override fun getTooltipText(): String? = null
}
data class ImageTagDetails(val imagePath: String) :
TagDetails(imagePath.substringAfterLast('/'), AllIcons.FileTypes.Image)
TagDetails(imagePath.substringAfterLast('/'), AllIcons.FileTypes.Image) {
override fun getTooltipText(): String = imagePath
}
data class HistoryTagDetails(
val conversationId: UUID,
val title: String,
) : TagDetails(title, AllIcons.General.Balloon)
) : TagDetails(title, AllIcons.General.Balloon) {
override fun getTooltipText(): String? = null
}
class EmptyTagDetails : TagDetails("")
class EmptyTagDetails : TagDetails("") {
override fun getTooltipText(): String? = null
}
class CodeAnalyzeTagDetails : TagDetails("Code Analyze", AllIcons.Actions.DependencyAnalyzer)
class CodeAnalyzeTagDetails : TagDetails("Code Analyze", AllIcons.Actions.DependencyAnalyzer) {
override fun getTooltipText(): String? = null
}
data class DiagnosticsTagDetails(val virtualFile: VirtualFile) :
TagDetails("${virtualFile.name} Problems", AllIcons.General.InspectionsEye)
TagDetails("${virtualFile.name} Problems", AllIcons.General.InspectionsEye) {
override fun getTooltipText(): String = virtualFile.path
}

View file

@ -4,6 +4,7 @@ import com.intellij.icons.AllIcons
import com.intellij.icons.AllIcons.Actions.Close
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.colors.EditorColorsManager
import com.intellij.openapi.project.Project
import com.intellij.ui.components.JBLabel
import com.intellij.util.IconUtil
import com.intellij.util.ui.JBUI
@ -23,8 +24,8 @@ abstract class TagPanel(
var tagDetails: TagDetails,
private val tagManager: TagManager,
private val shouldPreventDeselection: Boolean = true,
protected val project: Project,
) : JToggleButton() {
private val label = TagLabel(tagDetails.name, tagDetails.icon, tagDetails.selected)
private val closeButton = CloseButton {
isVisible = isSelected && tagDetails.isRemovable
@ -43,6 +44,11 @@ abstract class TagPanel(
fun update(text: String, icon: Icon? = null) {
closeButton.isVisible = isSelected && tagDetails.isRemovable
label.update(text, icon, isSelected)
tagDetails.getTooltipText()?.let { tooltip ->
val relativeTooltipText = toProjectRelative(tooltip)
this.toolTipText = relativeTooltipText
label.toolTipText = relativeTooltipText
}
revalidate()
repaint()
}
@ -67,6 +73,11 @@ abstract class TagPanel(
cursor = Cursor(Cursor.HAND_CURSOR)
isSelected = tagDetails.selected
closeButton.isVisible = isSelected && tagDetails.isRemovable
tagDetails.getTooltipText()?.let { tooltip ->
val relativeTooltipText = toProjectRelative(tooltip)
this.toolTipText = relativeTooltipText
label.toolTipText = relativeTooltipText
}
val gbc = GridBagConstraints().apply {
gridx = 0
@ -100,6 +111,14 @@ abstract class TagPanel(
repaint()
}
private fun toProjectRelative(path: String): String? {
val base = project.basePath ?: return path
val baseTrim = base.trimEnd('/', '\\')
return if (path.startsWith("$baseTrim/") || path.startsWith("$baseTrim\\")) {
path.substring(baseTrim.length + 1)
} else path
}
private class TagLabel(
name: String,
icon: Icon? = null,
@ -158,7 +177,8 @@ class SelectionTagPanel(
tagDetails: EditorSelectionTagDetails,
tagManager: TagManager,
private val promptTextField: PromptTextField,
) : TagPanel(tagDetails, tagManager, true) {
project: Project,
) : TagPanel(tagDetails, tagManager, true, project) {
init {
cursor = Cursor(Cursor.DEFAULT_CURSOR)
@ -175,4 +195,4 @@ class SelectionTagPanel(
override fun onClose() {
(tagDetails as? EditorSelectionTagDetails)?.selectionModel?.removeSelection()
}
}
}