blob: 49dfe484ffea7025e498b83f8412918c9b2c41ac (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
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"
|