diff --git a/bin/omarchy-clipboard-paste-text b/bin/omarchy-clipboard-paste-text index 3f3eee65..2927260c 100755 --- a/bin/omarchy-clipboard-paste-text +++ b/bin/omarchy-clipboard-paste-text @@ -2,20 +2,46 @@ # omarchy:summary=Copy text to the clipboard and type or paste it # omarchy:group=clipboard -# omarchy:args=[--shift-insert] +# omarchy:args=[--shift-insert] [--history-index |] # omarchy:examples=omarchy clipboard paste text "hello" | omarchy clipboard paste text --shift-insert "hello" use_shift_insert=false +history_index="" +text="" -if [[ ${1:-} == "--shift-insert" ]]; then +while [[ $# -gt 0 ]]; do + case "$1" in + --shift-insert) + use_shift_insert=true + shift + ;; + --history-index) + history_index="${2:-}" + shift 2 + ;; + *) + break + ;; + esac +done + +copy_history_entry() { + local history_path="$HOME/.local/state/omarchy/clipboard-history.json" + + [[ $history_index =~ ^[0-9]+$ ]] || exit + jq -e --argjson index "$history_index" '.[$index].type == "text" and (.[$index].text | type == "string")' "$history_path" >/dev/null || exit + jq -j --argjson index "$history_index" '.[$index].text' "$history_path" | wl-copy +} + +if [[ -n $history_index ]]; then + copy_history_entry use_shift_insert=true - shift +else + text=${1:-} + [[ -n $text ]] || exit + printf '%s' "$text" | wl-copy fi -text=${1:-} -[[ -n $text ]] || exit - -printf '%s' "$text" | wl-copy sleep 0.15 if [[ $use_shift_insert == "true" ]]; then diff --git a/shell/plugins/clipboard/Clipboard.qml b/shell/plugins/clipboard/Clipboard.qml index e6aafe61..6c3e80ab 100644 --- a/shell/plugins/clipboard/Clipboard.qml +++ b/shell/plugins/clipboard/Clipboard.qml @@ -40,7 +40,7 @@ Item { root.opened = true root.filterText = "" root.selectedIndex = 0 - root.cursorActive = false + root.cursorActive = true root.rebuildDisplay() Qt.callLater(function() { keyCatcher.forceActiveFocus() }) } @@ -140,7 +140,7 @@ Item { if (row.entryType === "image") { Quickshell.execDetached([root.omarchyPath + "/bin/omarchy-clipboard-paste-file", row.mime, row.path]) } else if (row.fullText) { - Quickshell.execDetached([root.omarchyPath + "/bin/omarchy-clipboard-paste-text", "--shift-insert", row.fullText]) + Quickshell.execDetached([root.omarchyPath + "/bin/omarchy-clipboard-paste-text", "--shift-insert", "--history-index", String(row.index)]) } } diff --git a/shell/plugins/clipboard/ClipboardHistory.js b/shell/plugins/clipboard/ClipboardHistory.js index 6fb0d5b2..8e5587bb 100644 --- a/shell/plugins/clipboard/ClipboardHistory.js +++ b/shell/plugins/clipboard/ClipboardHistory.js @@ -1,13 +1,13 @@ function normalizeEntry(value) { if (typeof value === "string") - return value.length > 0 ? { type: "text", text: value } : null + return value.trim().length > 0 ? { type: "text", text: value } : null if (!value || typeof value !== "object") return null var type = String(value.type || value.kind || "") if (type === "text") { var text = String(value.text || "") - return text.length > 0 ? { type: "text", text: text } : null + return text.trim().length > 0 ? { type: "text", text: text } : null } if (type === "image") { @@ -107,7 +107,7 @@ function displayRows(history, query, limit) { previewImage: isImage ? String(entry.path || "") : "", path: isImage ? String(entry.path || "") : "", mime: isImage ? String(entry.mime || "image/png") : "text/plain", - index: rows.length + index: i }) if (rows.length >= max) break } diff --git a/test/shell.d/clipboard-test.sh b/test/shell.d/clipboard-test.sh index 5d05bd54..cf42a2e5 100644 --- a/test/shell.d/clipboard-test.sh +++ b/test/shell.d/clipboard-test.sh @@ -29,6 +29,8 @@ assertDeepEqual( 'clipboard history parser drops invalid entries' ) +assertDeepEqual(clipboard.parseHistory(JSON.stringify([' ', '\n', { type: 'text', text: '\t' }])), [], 'clipboard history parser drops whitespace-only text') + const history = [ { type: 'text', text: 'old' }, { type: 'text', text: 'new' }, @@ -51,6 +53,12 @@ assertDeepEqual( 'clipboard display rows search image metadata' ) +assertDeepEqual( + clipboard.displayRows(history, 'image', 50).map(row => row.index), + [2], + 'clipboard display rows preserve original history indexes' +) + assertDeepEqual( clipboard.displayRows([{ type: 'text', text: 'line one\nline two' }], '', 50)[0].previewText, 'line one line two', @@ -60,3 +68,31 @@ assertDeepEqual( assertDeepEqual(clipboard.displayRows(history, '', 0), [], 'clipboard display rows supports zero result limit') assertDeepEqual(clipboard.addEntry(history, 'next', 0), [], 'clipboard addEntry supports zero history limit') JS + +TMPDIR=$(mktemp -d) +trap 'rm -rf "$TMPDIR"' EXIT + +mkdir -p "$TMPDIR/bin" "$TMPDIR/home/.local/state/omarchy" + +cat >"$TMPDIR/bin/wl-copy" <<'SH' +#!/bin/bash +cat >"$WL_COPY_OUT" +SH + +cat >"$TMPDIR/bin/wtype" <<'SH' +#!/bin/bash +printf '%s\n' "$*" >"$WTYPE_OUT" +SH + +chmod +x "$TMPDIR/bin/wl-copy" "$TMPDIR/bin/wtype" + +jq -n --arg text "$(printf 'large block line 1\nlarge block line 2\n')" '[{type:"text", text:"ignored"}, {type:"text", text:$text}]' >"$TMPDIR/home/.local/state/omarchy/clipboard-history.json" + +WL_COPY_OUT="$TMPDIR/copied" WTYPE_OUT="$TMPDIR/wtype" HOME="$TMPDIR/home" PATH="$TMPDIR/bin:$PATH" \ + "$ROOT/bin/omarchy-clipboard-paste-text" --shift-insert --history-index 1 + +[[ $(<"$TMPDIR/copied") == "$(printf 'large block line 1\nlarge block line 2')" ]] || fail "clipboard paste helper copies history entry text" +pass "clipboard paste helper copies history entry text" + +[[ $(<"$TMPDIR/wtype") == "-M shift -k Insert -m shift" ]] || fail "clipboard paste helper pastes history entries with shift insert" +pass "clipboard paste helper pastes history entries with shift insert"