diff --git a/plugins/terminal/frontend/src/com/intellij/terminal/frontend/view/impl/CopyOnSelectionHandler.kt b/plugins/terminal/frontend/src/com/intellij/terminal/frontend/view/impl/CopyOnSelectionHandler.kt index c90e73985dc4..83789ed2d29b 100644 --- a/plugins/terminal/frontend/src/com/intellij/terminal/frontend/view/impl/CopyOnSelectionHandler.kt +++ b/plugins/terminal/frontend/src/com/intellij/terminal/frontend/view/impl/CopyOnSelectionHandler.kt @@ -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) } } diff --git a/plugins/terminal/tests/src/com/intellij/terminal/tests/reworked/frontend/TerminalCopyOnSelectionTest.kt b/plugins/terminal/tests/src/com/intellij/terminal/tests/reworked/frontend/TerminalCopyOnSelectionTest.kt index a4da5120f9b1..eeac95f93e30 100644 --- a/plugins/terminal/tests/src/com/intellij/terminal/tests/reworked/frontend/TerminalCopyOnSelectionTest.kt +++ b/plugins/terminal/tests/src/com/intellij/terminal/tests/reworked/frontend/TerminalCopyOnSelectionTest.kt @@ -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 } }