[terminal] IJPL-248564 Do not set empty text into clipboard of selection is removed

Also, edit tests to cover the empty selection case + single/block selection.


(cherry picked from commit 8ab446220b9825b9cb0c6a67818ac4344733fd43)

IJ-CR-211956

GitOrigin-RevId: 9b3474034a868910742ba6e8cc9d40005b7a523a
This commit is contained in:
Konstantin Hudyakov
2026-07-29 18:11:10 +00:00
committed by intellij-monorepo-bot
parent a8663450dc
commit c459b0fade
2 changed files with 41 additions and 9 deletions
@@ -41,9 +41,10 @@ internal class CopyOnSelectionHandler private constructor(private val settings:
private inner class MySelectionListener : SelectionListener {
override fun selectionChanged(e: SelectionEvent) {
// Only perform copying if the editor is focused.
// In most cases it is, but if the selection was updated through the API it may not be the case.
// In most cases it is, but if the selection was updated through the API, it may not be the case.
if (!settings.copyOnSelect() || e.editor?.contentComponent?.isFocusOwner != true) return
val text = e.editor.selectionModel.getSelectedText(true) ?: return
// Take only if not empty. `getSelectedText(allCarets=true)` returns an empty string if there is no selection.
val text = e.editor.selectionModel.getSelectedText(true)?.takeIf { it.isNotEmpty() } ?: return
copy(text)
}
}
@@ -42,7 +42,7 @@ internal class TerminalCopyOnSelectionTest : BasePlatformTestCase() {
}
@Test
fun `copy on selection copies block selection from all selected lines`() {
fun `copy on selection works for single selection and does not clear clipboard when selection becomes empty`() {
val editor = createTerminalEditor()
editor.emitOnTerminal(
"""
@@ -52,11 +52,43 @@ internal class TerminalCopyOnSelectionTest : BasePlatformTestCase() {
""".trimIndent()
)
editor.selectionModel.setBlockSelection(LogicalPosition(0, 1), LogicalPosition(2, 4))
// Select "first"
editor.selectionModel.setSelection(0, 5)
val copied = copiedTransferable()
assertNotNull(copied)
assertEquals("first", copied!!.getTransferData(DataFlavor.stringFlavor))
val transferable = copiedTransferable()
assertNotNull(transferable)
assertEquals("irs\neco\nhir", transferable!!.getTransferData(DataFlavor.stringFlavor))
// Clearing the selection fires a selection change event with an empty selection.
editor.selectionModel.removeSelection()
val afterClear = copiedTransferable()
assertNotNull(afterClear)
assertEquals("first", afterClear!!.getTransferData(DataFlavor.stringFlavor))
}
@Test
fun `copy on selection works for block selection and does not clear clipboard when block selection is cleared`() {
val editor = createTerminalEditor()
editor.emitOnTerminal(
"""
first
second
third
""".trimIndent()
)
// A vertical (block) selection is copied to the clipboard.
editor.selectionModel.setBlockSelection(LogicalPosition(0, 1), LogicalPosition(2, 4))
val copied = copiedTransferable()
assertNotNull(copied)
assertEquals("irs\neco\nhir", copied!!.getTransferData(DataFlavor.stringFlavor))
// Clearing the block selection collapses back to a single caret (as a click does) and fires a
// selection change event with an empty selection. It must not overwrite the clipboard.
editor.caretModel.removeSecondaryCarets()
editor.selectionModel.removeSelection(true)
val afterClear = copiedTransferable()
assertNotNull(afterClear)
assertEquals("irs\neco\nhir", afterClear!!.getTransferData(DataFlavor.stringFlavor))
}
private fun createTerminalEditor(): Editor {
@@ -85,6 +117,5 @@ internal class TerminalCopyOnSelectionTest : BasePlatformTestCase() {
psiFile.charsSequence = this.document.immutableCharSequence
}
private fun copiedTransferable() =
CopyPasteManager.getInstance().let { it.systemSelectionContents ?: it.contents }
private fun copiedTransferable() = CopyPasteManager.getInstance().let { it.systemSelectionContents ?: it.contents }
}