-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplauncher
executable file
·177 lines (153 loc) · 4.29 KB
/
plauncher
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
#!/bin/sh -e
help() {
cat - >&2 <<EOF
plauncher - POSIX launcher script
plauncher [supervisor_command [args...]]
plauncher will query a command from the user and run the command. A
history of commands will be shown to the user to select from, or the
user may type in a new command which will be ran and added to the
history.
Arguments provided to plauncher will be interpreted as a "supervisor
command" to run the user's selected command with (i.e. plauncher i3-msg
exec, plauncher swaymsg exec). The supervisor command as an argument will
be given the user's selected command as a single argument instead of
word-splitting the user's command.
plauncher's user interface is basic, use Tab or ^P to traverse backward
through the command history, use ^N to traverse forward through the
command history, and most everything else will be interpreted as a query
to search through the command history. ^W is also available for deleting
words and BACKSPACE for deleting characters. Other line editing is not
implemented, since the idea is to type short commands and then never
type them again.
You must set the \$TERMCMD environment variable, something like "xterm
-e", so applications may be launched in your terminal of choice.
EOF
}
getch() { dd bs=1 count=1 2> /dev/null ; }
cleanterm() { stty sane; printf '\n'; }
write_history() {
if [ "$anonymous" ]; then
return 0
else
deduped=$(grep -Fxve "$*" -e "$2" < "$PLAUNCHER_HISTORY" || :)
cat > "$PLAUNCHER_HISTORY" <<-EOF
$deduped
$*
EOF
fi
}
case "$1" in --help|-h) help; exit 0;; esac
: "${TERMCMD:?'$TERMCMD must be set (i.e. xterm -e)'}"
# you can use showkey -a to figure out the octal value for a key
KEY_BACKSPACE=$(printf '\177')
KEY_CTRL_U=$(printf '\025')
KEY_CTRL_W=$(printf '\027')
KEY_CTRL_P=$(printf '\020')
KEY_CTRL_N=$(printf '\016')
KEY_ESCAPE=$(printf '\033')
KEY_TAB=$(printf '\t')
EL=$(printf '\033[K')
ED=$(printf '\033[J')
CP=$(printf '\033[H')
NL="
"
# ensure $PLAUNCHER_HISTORY is set and the file exists
: >> "${PLAUNCHER_HISTORY:="${HOME:?}/.plauncher"}"
trap 'trap - EXIT QUIT TERM INT ABRT; cleanterm' EXIT QUIT TERM INT ABRT
stty -icanon -echo -nl
unset -v cmd cursor list_length appended
while :; do
if [ "$cursor" ]; then
cmd=$(sed -n "${cursor}p") <<-EOF
$list
EOF
# handle the command context (background/terminal) number if available
case "$cmd" in [0-9]' '*)
cmdctx="${cmd%% *}"
cmd="${cmd#[0-9] }"
esac
printf "\r> %s$ED" "$cmd" >&2
elif [ ! "$list" ] && [ "$appended" ]; then
printf '%s' "$c"
else
list=$(grep -Fie "$cmd" < "$PLAUNCHER_HISTORY" || :)
visual_list=$(sed "s/$/$EL/g ; s/^[0-9] //g") <<-EOF
$list
EOF
printf "$CP%s" "${list:+${visual_list}${NL}}" >&2
printf "\r> %s$ED" "$cmd" >&2
fi
c=$(getch)
case "$c" in
"$KEY_CTRL_P"|"$KEY_TAB")
if [ "$cursor" ]; then
if [ "$cursor" -gt 1 ]; then
cursor=$((cursor - 1))
fi
else
list_length=$(wc -l) <<-EOF
$list
EOF
cursor="$list_length"
fi
;;
"$KEY_CTRL_N")
if [ "$cursor" ] && [ "$cursor" -lt "$list_length" ]; then
cursor=$((cursor + 1))
else # reached end of history
unset -v cmd cursor list_length appended
fi
;;
"$KEY_CTRL_W") # delete last word from line
cmd=$(sed 's/[^ ]*[ ]*$//') <<-EOF
$cmd
EOF
unset -v cursor list_length appended
;;
"$KEY_BACKSPACE") cmd=${cmd%?}; unset -v cursor list_length appended ;;
'') break ;; # Enter
"$KEY_CTRL_U") unset -v cmd cursor list_length appended ;;
"$KEY_ESCAPE") cleanterm; exit 0 ;;
*)
# only append non-whacky characters to the command
# case trick saves a lot of time, noticeable when pasting
case "$c" in
[!' '-'~'])
cval=$(od -A n -N 1 -t u1) <<-EOF
$c
EOF
if [ "$cval" -lt 32 ]; then
continue
fi
;;
esac
cmd="${cmd}${c}"
appended=1
unset -v cursor list_length
;;
esac
done
case "$cmd" in
' '*) anonymous=1 ;;
'') exit 0 ;;
*) unset -v anonymous ;;
esac
if [ ! "$cmdctx" ]; then
printf '\n'
printf '%s\n' "How should $cmd be ran?" \
'[1] terminal' \
'[2] background (default)' >&2
cmdctx=$(getch)
fi
cleanterm
case "$cmdctx" in
1) terminal=1 ;;
"$KEY_ESCAPE") exit 0 ;;
*) unset -v terminal; cmdctx=2 ;;
esac
write_history "$cmdctx" "$cmd"
if [ "$*" ]; then
exec "$@" "${terminal:+$TERMCMD }$cmd"
else
eval exec "${terminal:+$TERMCMD }$cmd"
fi