From ab4f0ef785b5aa9b5e3a2b5bd2b051db6b9a27d1 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Wed, 7 Oct 2026 17:35:10 +0200 Subject: [PATCH] Revert "gui: remove cut/copy/paste from prompt input" This reverts commit eb09a95a64aa7aec6b06b488b291b1c787f1711f. --- kde/gui/ChatPane.qml | 73 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/kde/gui/ChatPane.qml b/kde/gui/ChatPane.qml index ca03725..b23e382 100644 --- a/kde/gui/ChatPane.qml +++ b/kde/gui/ChatPane.qml @@ -406,7 +406,7 @@ Item { if (!ollie.activeSessionId) return "No session" if (!ollie.activeAgentId) return "No agent" if (ollie.activeSessionPaused) return "Session paused" - return "B1=sel B2=exec B3=plumb" + return "B1=sel B2=exec B3=plumb B1+B2=cut B1+B3=paste" } enabled: ollie.daemonConnected && ollie.activeSessionId !== "" && ollie.activeAgentId !== "" && !ollie.activeSessionPaused wrapMode: TextEdit.Wrap @@ -432,10 +432,12 @@ Item { } } - // Acme-style mouse handling overlay + // Acme-style mouse chording overlay // B1 = select (handled by TextArea) // B2 = execute selection // B3 = plumb selection / context menu + // B1+B2 = cut (snarf) + // B1+B3 = paste MouseArea { id: chordArea anchors.fill: parent @@ -443,12 +445,46 @@ Item { propagateComposedEvents: true cursorShape: Qt.IBeamCursor + // Track if B1 (left) is currently held for chord detection + property bool leftHeld: false + + // We can't directly detect B1 here since TextArea handles it, + // but we can check mouse.buttons in the handlers + onPressed: function(mouse) { + // Check if this is a chord (B1 already held) + if (mouse.buttons & Qt.LeftButton) { + leftHeld = true + if (mouse.button === Qt.MiddleButton) { + // B1+B2 = cut + promptInput.cut() + mouse.accepted = true + return + } else if (mouse.button === Qt.RightButton) { + // B1+B3 = paste + promptInput.paste() + mouse.accepted = true + return + } + } + leftHeld = false + mouse.accepted = false // Let it propagate for non-chord + } + onClicked: function(mouse) { + // Only handle non-chord clicks + if (leftHeld) { + leftHeld = false + return + } + if (mouse.button === Qt.MiddleButton) { // B2: Execute selection as prompt var sel = promptInput.selectedText if (sel && sel.trim() !== "") { ollie.submit(sel.trim()) + } else { + // No selection - paste from clipboard and execute? + // Or just ignore. For now, ignore. } } else if (mouse.button === Qt.RightButton) { // B3: Plumb selection or show context menu @@ -460,6 +496,10 @@ Item { } } } + + onReleased: { + leftHeld = false + } } Menu { @@ -481,6 +521,22 @@ Item { } } MenuSeparator {} + MenuItem { + text: "Cut (B1+B2)" + enabled: promptInput.selectedText.length > 0 + onTriggered: promptInput.cut() + } + MenuItem { + text: "Copy" + enabled: promptInput.selectedText.length > 0 + onTriggered: promptInput.copy() + } + MenuItem { + text: "Paste (B1+B3)" + enabled: promptInput.canPaste + onTriggered: promptInput.paste() + } + MenuSeparator {} MenuItem { text: "Select All" onTriggered: promptInput.selectAll() @@ -488,6 +544,19 @@ Item { } } + // Paste button (mouse-first workflow) + ToolButton { + text: "📋" + font.pixelSize: 14 + implicitWidth: 36 + implicitHeight: 36 + Layout.alignment: Qt.AlignBottom + enabled: promptInput.enabled + onClicked: promptInput.paste() + ToolTip.visible: hovered + ToolTip.text: "Paste from clipboard" + } + // Send button (larger touch target) Button { text: "▶"