diff options
| author | Josh Rahm <rahm@google.com> | 2025-10-29 16:42:17 -0600 |
|---|---|---|
| committer | Josh Rahm <rahm@google.com> | 2025-10-29 16:47:03 -0600 |
| commit | 67feeb51a2c3e4fb579c129b15784c65d57c2607 (patch) | |
| tree | 85c12447419c7feb14e21311d996ef6637187c51 /extras/HOME | |
| parent | 00a4a74040b0e75bcd97b35bf979d77d94ba42e3 (diff) | |
| download | rde-67feeb51a2c3e4fb579c129b15784c65d57c2607.tar.gz rde-67feeb51a2c3e4fb579c129b15784c65d57c2607.tar.bz2 rde-67feeb51a2c3e4fb579c129b15784c65d57c2607.zip | |
Add quick-clip and bind it to <M-z>c.
Quick-clip makes it easy to keep text snippets around for quick
copy-paste.
Diffstat (limited to 'extras/HOME')
| -rwxr-xr-x | extras/HOME/.local/bin/quick-clip.sh | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/extras/HOME/.local/bin/quick-clip.sh b/extras/HOME/.local/bin/quick-clip.sh new file mode 100755 index 0000000..49dfe48 --- /dev/null +++ b/extras/HOME/.local/bin/quick-clip.sh @@ -0,0 +1,196 @@ +#!/usr/bin/env bash + +# set -euo pipefail + +# --- Config ----------------------------------------------------------------- +: "${XDG_CONFIG_HOME:=${HOME}/.config}" +SNIPPETS_DIR="${XDG_CONFIG_HOME}/quick-clip" +SNIPPETS_FILE="${SNIPPETS_DIR}/snippets.tsv" +PROMPT="Quick Clip" +SHOW_NOTIFICATIONS="yes" # set to "no" to disable notify-send +ROFI_CMD=(rofi -markup-rows -dmenu -i -p "${PROMPT}" -lines 30 -theme-str '* {theme-color: #ffffdd;}' \ + -kb-custom-1 'Alt+d' \ + -kb-custom-2 'Alt+r' + ) + +# --- Helpers ---------------------------------------------------------------- +copy() { + # Copy stdin to clipboard using best available tool. + if [ -n "${WAYLAND_DISPLAY:-}" ] && command -v wl-copy >/dev/null 2>&1; then + wl-copy --primary && wl-copy # copy to both clipboards on Wayland + elif command -v xclip >/dev/null 2>&1; then + xclip -selection clipboard + printf "%s" "$CLIPBUF" | xclip -selection primary || true + elif command -v xsel >/dev/null 2>&1; then + xsel --clipboard --input + printf "%s" "$CLIPBUF" | xsel --primary --input || true + else + echo "quick-clip: no clipboard tool found (need wl-copy, xclip, or xsel)" >&2 + exit 1 + fi +} + +notify() { + if [ "${SHOW_NOTIFICATIONS}" = "yes" ] && command -v notify-send >/dev/null 2>&1; then + notify-send "${PROMPT}" "$1" + fi +} + +ensure_files() { + mkdir -p "${SNIPPETS_DIR}" + if [ ! -f "${SNIPPETS_FILE}" ]; then + cat >"${SNIPPETS_FILE}" <<'TPL' +# Example snippets (TSV): +# Label Value +Email josh@example.com +GitHub https://github.com/Josh +# Single-field lines copy the whole line: ++1 (555) 867-5309 +TPL + fi +} + +open_editor() { + local editor + editor="${EDITOR:-}" + if [ -z "$editor" ]; then + if command -v vim >/dev/null 2>&1; then editor=vim + elif command -v nano >/dev/null 2>&1; then editor=nano + elif command -v vi >/dev/null 2>&1; then editor=vi + else + printf "quick-clip: set $EDITOR or install nano/vim.\n" >&2 + exit 1 + fi + fi + alacritty --class "floating-terminal" -e "$editor" "${SNIPPETS_FILE}" +} + +add_snippet_via_rofi() { + local label value + label=$(printf '' | rofi -dmenu -i -p "new label" -lines 0 || true) + [ -z "$label" ] && return 0 + value=$(printf '' | rofi -dmenu -i -p "new value" -lines 0 || true) + [ -z "$value" ] && return 0 + printf '%s\t%s\n' "$label" "$value" >>"${SNIPPETS_FILE}" + notify "Added snippet: $label" +} + +add_snippet() { + if ! command -v zenity >/dev/null 2>&1; then + echo "quick-clip: zenity not found (install zenity or change add flow)" >&2 + notify "zenity not found" + return 1 + fi + local label value + label=$(zenity --entry --title="$PROMPT" --text="New snippet label:" 2>/dev/null) || return 0 + value=$(zenity --entry --title="$PROMPT" --text="Value for '$label':" 2>/dev/null) || return 0 + [ -z "$value" ] && return 0 + if [ -z "$label" ] ; then + printf "%s" "$value" + else + printf '%s\t%s\n' "$label" "$value" >>"${SNIPPETS_FILE}" + fi + + notify "Added snippet: $label" +} + +add_snippet_via_yad() { + if ! command -v yad >/dev/null 2>&1; then + echo "quick-clip: yad not found (install yad or change add flow)" >&2 + notify "yad not found" + return 1 + fi + local out label value + out=$(yad --form \ + --title="$PROMPT" \ + --center --on-top \ + --window-icon="accessories-text-editor" \ + --field="Label" \ + --field="Value" \ + --borders=10 \ + --separator=$'🔨' 2>/dev/null) || return 0 + IFS=$'🔨' read -r label value <<<"${out%🔨}" + echo "label: $label, value: $value" + if [ -z "$label" ]; then + printf '%s\n' "$value" >>"${SNIPPETS_FILE}" + notify "Added snippet: $value" + else + printf '%s\t%s\n' "$label" "$value" >>"${SNIPPETS_FILE}" + notify "Added snippet: $label" + fi +} + + + +# Given a chosen line, determine the text to copy. +extract_value() { + # If line contains a TAB, take field 2; else copy entire line. + awk -F "\t" 'NF>=2 {print $2; exit} NF==1 {print $0; exit}' +} + +# --- Main ------------------------------------------------------------------- +ensure_files + +SPEC_ADD="α Add new snippet" +SPEC_EDIT="ε Edit snippets" + +# Build menu: actions then snippets (skip comments/blank lines) +mapfile -t MENU < <( + printf "<b><span foreground='#8888ff'>Snippets</span></b>\t\n" + awk 'BEGIN{FS="\t"} /^[[:space:]]*#/ {next} NF==0 {next} {print $0}' "${SNIPPETS_FILE}" + for f in "$HOME/.local/lib/quick-clip"/*; do + if [ -f "$f" ] && [ -x "$f" ]; then + "$f" + fi + done + printf "\n<b><span foreground='#8888ff'>Actions</span></b>\t\n" + printf '%s\n' "$SPEC_ADD" "$SPEC_EDIT" +) + +# Show menu; allow custom input +SELECTION=$(printf '%s\n' "${MENU[@]}" | "${ROFI_CMD[@]}") + +ec="$?" + +echo "EC: $ec" +if [[ "$ec" -eq 10 ]] ; then # Delete the entry + tfile=/tmp/$(mktemp 'XXXX.tmp') + grep -Fxv "$SELECTION" "$SNIPPETS_FILE" > "$tfile" + if [[ "$?" -ne 0 ]] ; then + notify "Could not delete" + else + mv "$tfile" "$SNIPPETS_FILE" + notify "Deleted Snippet: $SELECTION" + fi + + exit 0 +fi + +if [[ "$ec" -eq 11 ]] ; then # Run the entry + val=$(extract_value <<< "$SELECTION") + sh -c "$val" + exit 0 +fi + +# If empty (Esc), quit +[ -z "${SELECTION}" ] && exit 0 + +case "${SELECTION}" in + $SPEC_ADD) + add_snippet_via_yad + exit 0 + ;; + $SPEC_EDIT) + open_editor + exit 0 + ;; + *) + ;; + esac + +# If the selection equals a menu entry that came from the file and contains a TAB, +# copy field 2; otherwise, treat it as free text. +CLIPBUF=$(printf '%s' "${SELECTION}" | extract_value) + +printf '%s' "${CLIPBUF}" | copy +notify "Copied to clipboard" |