Keep the first emoji result selected whenever results exist, including after search filtering, so Enter inserts immediately. Route emoji insertion through a hidden helper that serves a transient sensitive clipboard entry long enough for Shift+Insert, then stops that clipboard owner. Mark transient emoji inserts so clipboard history skips only that event while continuing to record normal terminal copies.
237 lines
9.6 KiB
Bash
237 lines
9.6 KiB
Bash
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
|
|
|
run_node_test <<'JS'
|
|
const clipboard = requireFromRoot('shell/plugins/clipboard/ClipboardHistory.js')
|
|
|
|
assertDeepEqual(
|
|
clipboard.normalizeEntry('hello'),
|
|
{ type: 'text', text: 'hello' },
|
|
'clipboard normalizes string entries'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
clipboard.normalizeEntry({ kind: 'image', path: '/tmp/a.png' }),
|
|
{ type: 'image', path: '/tmp/a.png', mime: 'image/png' },
|
|
'clipboard normalizes image entries with default mime'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
clipboard.normalizeEntry({ type: 'image', path: '/tmp/a.png', mime: 'image/png', capturedAt: 'Friday 14:42' }),
|
|
{ type: 'image', path: '/tmp/a.png', mime: 'image/png', capturedAt: 'Friday 14:42' },
|
|
'clipboard keeps image capture timestamps'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
clipboard.parseHistory(JSON.stringify(['one', '', { type: 'text', text: 'two' }, { type: 'image', path: '/tmp/a.jpg', mime: 'image/jpeg' }])),
|
|
[
|
|
{ type: 'text', text: 'one' },
|
|
{ type: 'text', text: 'two' },
|
|
{ type: 'image', path: '/tmp/a.jpg', mime: 'image/jpeg' }
|
|
],
|
|
'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' },
|
|
{ type: 'image', path: '/tmp/a.png', mime: 'image/png' }
|
|
]
|
|
|
|
assertDeepEqual(
|
|
clipboard.addEntry(history, { type: 'text', text: 'new' }, 100),
|
|
[
|
|
{ type: 'text', text: 'new' },
|
|
{ type: 'text', text: 'old' },
|
|
{ type: 'image', path: '/tmp/a.png', mime: 'image/png' }
|
|
],
|
|
'clipboard addEntry moves duplicate text to front'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
clipboard.removeEntryAt(history, 1),
|
|
[
|
|
{ type: 'text', text: 'old' },
|
|
{ type: 'image', path: '/tmp/a.png', mime: 'image/png' }
|
|
],
|
|
'clipboard removeEntryAt removes the requested entry'
|
|
)
|
|
|
|
assertDeepEqual(clipboard.removeEntryAt(history, 10), history, 'clipboard removeEntryAt ignores invalid indexes')
|
|
assertDeepEqual(clipboard.clearHistory(), [], 'clipboard clearHistory returns an empty history')
|
|
|
|
assertDeepEqual(
|
|
clipboard.displayRows(history, 'image', 50).map(row => ({ type: row.entryType, preview: row.previewText, mime: row.mime })),
|
|
[{ type: 'image', preview: 'Image', mime: 'image/png' }],
|
|
'clipboard display rows search image metadata'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
clipboard.displayRows([{ type: 'image', path: '/tmp/a.png', mime: 'image/png', capturedAt: 'Friday 14:42' }], '', 50)[0].previewText,
|
|
'Screenshot from Friday 14:42',
|
|
'clipboard labels timestamped png image entries as screenshots'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
clipboard.displayRows([{ type: 'image', path: '/tmp/a.jpg', mime: 'image/jpeg', capturedAt: 'Friday 14:42' }], '', 50)[0].previewText,
|
|
'Image from Friday 14:42',
|
|
'clipboard labels timestamped non-png image entries as images'
|
|
)
|
|
|
|
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',
|
|
'clipboard display rows collapse text whitespace'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
clipboard.displayRows([{ type: 'text', text: 'file:///home/dhh/Videos/screenrecording-2026-05-29_13-56-43-720p.gif\n' }], '', 50)[0],
|
|
{
|
|
entryType: 'file',
|
|
fullText: '/home/dhh/Videos/screenrecording-2026-05-29_13-56-43-720p.gif',
|
|
previewText: 'screenrecording-2026-05-29_13-56-43-720p.gif',
|
|
previewImage: '/home/dhh/Videos/screenrecording-2026-05-29_13-56-43-720p.gif',
|
|
path: '/home/dhh/Videos/screenrecording-2026-05-29_13-56-43-720p.gif',
|
|
mime: 'text/plain',
|
|
index: 0
|
|
},
|
|
'clipboard display rows show file uri entries as files'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
clipboard.displayRows([{ type: 'text', text: 'file:///home/dhh/One.txt\nfile:///home/dhh/Two.txt\n' }], '', 50)[0].previewText,
|
|
'2 files',
|
|
'clipboard display rows summarize multiple file uri entries'
|
|
)
|
|
|
|
assertDeepEqual(
|
|
clipboard.displayRows([{ type: 'text', text: 'file:///home/dhh/Videos/demo.mp4\n' }], '', 50)[0].previewImage,
|
|
'',
|
|
'clipboard display rows do not preview video file uri entries inline'
|
|
)
|
|
|
|
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/wl-paste" <<'SH'
|
|
#!/bin/bash
|
|
if [[ $1 == "--list-types" ]]; then
|
|
printf 'text/plain\n'
|
|
elif [[ $1 == "--type" && $2 == "text" ]]; then
|
|
printf '%s' "${WL_PASTE_TEXT:-terminal copy}"
|
|
fi
|
|
SH
|
|
|
|
cat >"$TMPDIR/bin/wtype" <<'SH'
|
|
#!/bin/bash
|
|
printf '%s\n' "$*" >"$WTYPE_OUT"
|
|
SH
|
|
|
|
cat >"$TMPDIR/bin/omarchy-launch-browser" <<'SH'
|
|
#!/bin/bash
|
|
printf '%s\n' "$*" >"$BROWSER_OUT"
|
|
SH
|
|
|
|
cat >"$TMPDIR/bin/omarchy-launch-editor" <<'SH'
|
|
#!/bin/bash
|
|
printf '%s\n' "$1" >"$EDITOR_PATH_OUT"
|
|
cat "$1" >"$EDITOR_TEXT_OUT"
|
|
SH
|
|
|
|
cat >"$TMPDIR/bin/satty" <<'SH'
|
|
#!/bin/bash
|
|
printf '%s\n' "$*" >"$SATTY_OUT"
|
|
SH
|
|
|
|
chmod +x "$TMPDIR/bin/wl-copy" "$TMPDIR/bin/wl-paste" "$TMPDIR/bin/wtype" "$TMPDIR/bin/omarchy-launch-browser" "$TMPDIR/bin/omarchy-launch-editor" "$TMPDIR/bin/satty"
|
|
|
|
capture_output=$(CLIPBOARD_STATE=sensitive XDG_RUNTIME_DIR="$TMPDIR" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh")
|
|
[[ $capture_output == '{"type":"text","text":"terminal copy"}' ]] || fail "clipboard capture records sensitive text events"
|
|
pass "clipboard capture records sensitive text events"
|
|
|
|
printf '😀' >"$TMPDIR/omarchy-emoji-insert-ignore"
|
|
capture_output=$(WL_PASTE_TEXT="😀" XDG_RUNTIME_DIR="$TMPDIR" PATH="$TMPDIR/bin:$PATH" "$ROOT/shell/plugins/clipboard/capture.sh")
|
|
[[ -z $capture_output ]] || fail "clipboard capture ignores transient emoji insert"
|
|
pass "clipboard capture ignores transient emoji insert"
|
|
|
|
[[ ! -e "$TMPDIR/omarchy-emoji-insert-ignore" ]] || fail "clipboard capture consumes transient emoji marker"
|
|
pass "clipboard capture consumes transient emoji marker"
|
|
|
|
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"
|
|
|
|
rm -f "$TMPDIR/wtype"
|
|
WL_COPY_OUT="$TMPDIR/copied" WTYPE_OUT="$TMPDIR/wtype" HOME="$TMPDIR/home" PATH="$TMPDIR/bin:$PATH" \
|
|
"$ROOT/bin/omarchy-clipboard-paste-text" --copy-only --history-index 1
|
|
|
|
[[ $(<"$TMPDIR/copied") == "$(printf 'large block line 1\nlarge block line 2')" ]] || fail "clipboard paste helper copy-only copies history entry text"
|
|
pass "clipboard paste helper copy-only copies history entry text"
|
|
|
|
[[ ! -e "$TMPDIR/wtype" ]] || fail "clipboard paste helper copy-only skips typing"
|
|
pass "clipboard paste helper copy-only skips typing"
|
|
|
|
printf 'image-data' >"$TMPDIR/image.png"
|
|
rm -f "$TMPDIR/wtype"
|
|
WL_COPY_OUT="$TMPDIR/copied" WTYPE_OUT="$TMPDIR/wtype" PATH="$TMPDIR/bin:$PATH" \
|
|
"$ROOT/bin/omarchy-clipboard-paste-file" --copy-only image/png "$TMPDIR/image.png"
|
|
|
|
[[ $(<"$TMPDIR/copied") == "image-data" ]] || fail "clipboard file paste helper copy-only copies file content"
|
|
pass "clipboard file paste helper copy-only copies file content"
|
|
|
|
[[ ! -e "$TMPDIR/wtype" ]] || fail "clipboard file paste helper copy-only skips paste keystroke"
|
|
pass "clipboard file paste helper copy-only skips paste keystroke"
|
|
|
|
jq -n --arg url 'https://example.com/docs' --arg text "$(printf 'plain text\nsecond line')" --arg image "$TMPDIR/image.png" \
|
|
'[{type:"text", text:$url}, {type:"text", text:$text}, {type:"image", mime:"image/png", path:$image}]' >"$TMPDIR/home/.local/state/omarchy/clipboard-history.json"
|
|
|
|
BROWSER_OUT="$TMPDIR/browser" HOME="$TMPDIR/home" PATH="$TMPDIR/bin:$PATH" \
|
|
"$ROOT/bin/omarchy-clipboard-open" --history-index 0
|
|
|
|
[[ $(<"$TMPDIR/browser") == "https://example.com/docs" ]] || fail "clipboard open helper opens URL entries in browser"
|
|
pass "clipboard open helper opens URL entries in browser"
|
|
|
|
EDITOR_PATH_OUT="$TMPDIR/editor-path" EDITOR_TEXT_OUT="$TMPDIR/editor-text" HOME="$TMPDIR/home" XDG_STATE_HOME="$TMPDIR/state" PATH="$TMPDIR/bin:$PATH" \
|
|
"$ROOT/bin/omarchy-clipboard-open" --history-index 1
|
|
|
|
[[ $(<"$TMPDIR/editor-text") == "$(printf 'plain text\nsecond line')" ]] || fail "clipboard open helper opens text entries in editor"
|
|
pass "clipboard open helper opens text entries in editor"
|
|
|
|
[[ $(<"$TMPDIR/editor-path") == "$TMPDIR"/state/omarchy/clipboard-open/clipboard.*.txt ]] || fail "clipboard open helper writes text entries to a temporary file"
|
|
pass "clipboard open helper writes text entries to a temporary file"
|
|
|
|
SATTY_OUT="$TMPDIR/satty" HOME="$TMPDIR/home" PATH="$TMPDIR/bin:$PATH" \
|
|
"$ROOT/bin/omarchy-clipboard-open" --history-index 2
|
|
|
|
[[ $(<"$TMPDIR/satty") == "--filename $TMPDIR/image.png --output-filename $TMPDIR/image.png" ]] || fail "clipboard open helper opens image entries in satty"
|
|
pass "clipboard open helper opens image entries in satty"
|