From 1ce192de162a70016c3a1383c9ffe8b1c8b4d10a Mon Sep 17 00:00:00 2001 From: Patrick Hemmer Date: Wed, 22 Oct 2025 08:14:30 -0400 Subject: [PATCH] feat: add middle-click to remove files from context. (#1148) * add middle-click to remove files from context. Previously when you wanted to remove files which were previously added to the chat context, you had to click the little "x" icon one by one. When you had several files to remove, this got tedious and difficult, especially since the file box varies in width, so the "x" is not in the same space. This change makes this operation easier by allowing you to middle-click anywhere on the file box to remove it. * fix: mouse actions when clicked outside of the tag label --------- Co-authored-by: Carl-Robert Linnupuu --- .../textarea/header/UserInputHeaderPanel.kt | 26 +++++++------------ .../ui/textarea/header/tag/TagPanel.kt | 22 +++++++++++----- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/header/UserInputHeaderPanel.kt b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/header/UserInputHeaderPanel.kt index c999552c..b0172216 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/header/UserInputHeaderPanel.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/header/UserInputHeaderPanel.kt @@ -360,20 +360,21 @@ class UserInputHeaderPanel( } private inner class TagPopupMenu : JBPopupMenu() { + private fun resolveTagPanel(from: Component): TagPanel? = when (from) { + is TagPanel -> from + else -> SwingUtilities.getAncestorOfClass(TagPanel::class.java, from) as? TagPanel + } + private val closeMenuItem = createPopupMenuItem(CodeGPTBundle.get("tagPopupMenuItem.close")) { - val tagPanel = invoker as? TagPanel - tagPanel?.let { - if (it.tagDetails.isRemovable) { - tagManager.remove(it.tagDetails) - } + resolveTagPanel(invoker)?.let { + if (it.tagDetails.isRemovable) tagManager.remove(it.tagDetails) } } private val closeOtherTagsMenuItem = createPopupMenuItem(CodeGPTBundle.get("tagPopupMenuItem.closeOthers")) { - val tagPanel = invoker as? TagPanel - tagPanel?.let { currentPanel -> + resolveTagPanel(invoker)?.let { currentPanel -> val currentTag = currentPanel.tagDetails tagManager.getTags() .filter { it != currentTag && it.isRemovable } @@ -411,8 +412,7 @@ class UserInputHeaderPanel( } private fun closeTagsInRange(rangeSelector: (Array, Int) -> List) { - val tagPanel = invoker as? TagPanel - tagPanel?.let { currentPanel -> + resolveTagPanel(invoker)?.let { currentPanel -> val components = this@UserInputHeaderPanel.components val currentIndex = components.indexOf(currentPanel) @@ -433,13 +433,7 @@ class UserInputHeaderPanel( } override fun show(invoker: Component, x: Int, y: Int) { - val tagPanel = when (invoker) { - is TagPanel -> invoker - else -> SwingUtilities.getAncestorOfClass( - TagPanel::class.java, - invoker - ) as? TagPanel - } ?: return + val tagPanel = resolveTagPanel(invoker) ?: return if (!tagPanel.isEnabled) return val components = this@UserInputHeaderPanel.components.filterIsInstance() val currentIndex = components.indexOf(tagPanel) diff --git a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/header/tag/TagPanel.kt b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/header/tag/TagPanel.kt index 1b75d78a..18e2afce 100644 --- a/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/header/tag/TagPanel.kt +++ b/src/main/kotlin/ee/carlrobert/codegpt/ui/textarea/header/tag/TagPanel.kt @@ -87,14 +87,13 @@ abstract class TagPanel( label.inheritsPopupMenu = true closeButton.inheritsPopupMenu = true - label.addMouseListener(object : MouseAdapter() { + val mouseAdapter = object : MouseAdapter() { override fun mousePressed(e: MouseEvent) { - if (SwingUtilities.isLeftMouseButton(e)) { - this@TagPanel.doClick() - e.consume() - } + handleMousePress(e) } - }) + } + label.addMouseListener(mouseAdapter) + addMouseListener(mouseAdapter) addActionListener { if (isRevertingSelection) return@addActionListener @@ -116,6 +115,17 @@ abstract class TagPanel( repaint() } + private fun handleMousePress(e: MouseEvent) { + if (SwingUtilities.isLeftMouseButton(e)) { + this@TagPanel.doClick() + e.consume() + } + if (SwingUtilities.isMiddleMouseButton(e) && tagDetails.isRemovable) { + onClose() + e.consume() + } + } + private fun toProjectRelative(path: String): String? { val base = project.basePath ?: return path val baseTrim = base.trimEnd('/', '\\')