aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <rahm@google.com>2025-10-29 16:42:17 -0600
committerJosh Rahm <rahm@google.com>2025-10-29 16:47:03 -0600
commit67feeb51a2c3e4fb579c129b15784c65d57c2607 (patch)
tree85c12447419c7feb14e21311d996ef6637187c51
parent00a4a74040b0e75bcd97b35bf979d77d94ba42e3 (diff)
downloadrde-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.
-rwxr-xr-xextras/HOME/.local/bin/quick-clip.sh196
-rw-r--r--src/Main.hs2
-rw-r--r--src/Rahm/Desktop/Keys.hs14
3 files changed, 201 insertions, 11 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"
diff --git a/src/Main.hs b/src/Main.hs
index 4158c6a..09810e2 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -122,6 +122,8 @@ main = do
className =? "Tilda" --> doFloat,
className =? "yakuake" --> doFloat,
className =? "MPlayer" --> doFloat,
+ className =? "zenity" --> doCenterFloat,
+ className =? "Yad" --> doCenterFloat,
className =? "Xfce4-notifyd" --> doIgnore,
className =? "popup-terminal" --> doShift "*" <> updatePopupTerminalHook,
className =? "spotify" --> doShift "s",
diff --git a/src/Rahm/Desktop/Keys.hs b/src/Rahm/Desktop/Keys.hs
index 9ca862a..8ec3aeb 100644
--- a/src/Rahm/Desktop/Keys.hs
+++ b/src/Rahm/Desktop/Keys.hs
@@ -395,7 +395,7 @@ bindings = do
bind xK_b $ do
justMod $ spawnX "bluetooth-select.sh"
- bind xK_u $ do
+ bind xK_i $ do
justMod $ spawnX "notes-select.sh"
bind xK_c $ do
@@ -631,10 +631,6 @@ bindings = do
flip whenJust toggleWindowInSelection =<< withWindowSet (return . W.peek)
bind xK_m $ do
- rawMask
- mod2Mask
- (logs Info "Testing Mod2Mask" :: X ())
-
justMod
$ doc
"Mark the windows described by the window set with a given character.\n\n\t\
@@ -925,12 +921,8 @@ bindings = do
-- Explode
bind xK_c $ do
noMod -|- justMod $
- doc "Toggle explode on the workspace" $ do
- sendMessage
- ( toggleExplodeM
- movePopupToCurrentWorkspace
- movePopupToHiddenWorkspace
- )
+ doc "Run Quick-clip" $
+ spawnX "quick-clip.sh"
bindOtherKeys $ \(_, _, s) ->
logs Info "Unhandled key pressed: %s" s