SHOW:
|
|
- or go back to the newest paste.
1 | #! /bin/echo This file must be sourced: . | |
2 | ||
3 | function kb_highlight() { | |
4 | case $cmdname in | |
5 | #Video | |
6 | mplayer|mwrap|vlc|gmplayer|smplayer|mencoder|kmplayer|Parole|whaawmp|dragonplayer|ffmpeg) | |
7 | extlist='mkv|m4v|mp.|avi|wmv|rmvb|as?|divx|vob|ogm|rm|flv|part|iso|ogg|wav|flac|m4a' | |
8 | ;; | |
9 | #Audio | |
10 | mpg123|mpg123s|mpg321|mp3blaster|cmus|cplay|moc|xmms|xmms2|sonata|deadbeef|ogg123|mnama) | |
11 | extlist='mp?|aac|wav|ogg|gsm|dct|flac|au|aiff|vox|wma|aac|ra|m4a' | |
12 | ;; | |
13 | ||
14 | llpp|xpdf|epdfview|evince|foxit|mupdf|okular|apvlv|zathura) | |
15 | extlist='pdf' | |
16 | ;; | |
17 | #Images | |
18 | feh|geeqie|gqview|eog|gpicview|gthumb|mirage|qiv|ristretto|xnview|xv|viewnior) | |
19 | extlist='jpg|jpeg|png|gif|bmp|icon?|tiff?' | |
20 | ;; | |
21 | #Games | |
22 | sdlmame|openmsx|msxplay|zsnes|desmume|VirtualBoy) | |
23 | extlist='rom|dsk' | |
24 | ;; | |
25 | #Wine | |
26 | wine|winewrap|wineconsole) | |
27 | extlist='exe|com|bat' | |
28 | ;; | |
29 | #Archives | |
30 | atool|x|xi|gunzip|extract|unzip|unrar|zip|rar|7z|mcomix|v) | |
31 | extlist='tgz|zip|rar|bz2|gz|tar|exe|pk3|lha|Z|lzma' | |
32 | ;; | |
33 | #Text | |
34 | vim|nano|acme|beaver|geany|leafpad|medit|mousepad|pyroom|sam|vi|gvim|emacs|tea|scite) | |
35 | extlist='txt|rc|sh|c|bash|py|ini' | |
36 | ;; | |
37 | *) extlist='-Unmatch-';; | |
38 | esac | |
39 | } | |
40 | ||
41 | function kb_menu() { | |
42 | local end=0 h goodlist badlist total colorsw page pages sel=0 count key newk change=1 lim=7 displayres tempfile | |
43 | tput rmam #don't wrap long lines | |
44 | IFS=$'\n' | |
45 | prompt="$2" | |
46 | ||
47 | while ((end==0)); do | |
48 | ||
49 | # build a new list | |
50 | if ((change == 1)); then | |
51 | change=0 | |
52 | sel=0 | |
53 | if [[ "$1" == command ]]; then | |
54 | displayres=( $(compgen -A command -A alias -A builtin -A function $prompt | sort -u) ) | |
55 | elif [[ "$1" == file ]]; then | |
56 | colorsw=0 | |
57 | goodlist=() | |
58 | badlist=() | |
59 | displayres=() | |
60 | for tempfile in $prompt*; do | |
61 | if [[ -d "$tempfile" ]]; then | |
62 | tempfile+=/ | |
63 | fi | |
64 | if [[ "$cmdname" =~ ^(c|cd|popd|rmdir)$ ]]; then | |
65 | if [[ -d "$tempfile" ]]; then | |
66 | goodlist+=( "$tempfile" ) | |
67 | ((colorsw++)) | |
68 | else | |
69 | badlist+=( "$tempfile" ) | |
70 | fi | |
71 | elif [[ "$tempfile" =~ \.($extlist)$ ]]; then | |
72 | goodlist+=( "$tempfile" ) | |
73 | ((colorsw++)) | |
74 | else | |
75 | badlist+=( "$tempfile" ) | |
76 | fi | |
77 | done | |
78 | fi | |
79 | [[ "$1" == file ]] && colorsw=${#goodlist[@]} && displayres=( "${goodlist[@]}" "${badlist[@]}" ) | |
80 | total=${#displayres[@]} | |
81 | ||
82 | # on zero results retry without front match | |
83 | if [[ "$1" == file ]] && ((total==0)); then | |
84 | colorsw=0 | |
85 | if [[ "${prompt//[^\/]}" ]]; then | |
86 | for tempfile in ${prompt%/*}/*${prompt##*/}*; do | |
87 | if [[ -d "$tempfile" ]]; then | |
88 | tempfile+=/ | |
89 | fi | |
90 | if [[ "$cmdname" =~ ^(c|cd|popd|rmdir)$ ]]; then | |
91 | if [[ -d "$tempfile" ]]; then | |
92 | goodlist+=( "$tempfile" ) | |
93 | ((colorsw++)) | |
94 | else | |
95 | badlist+=( "$tempfile" ) | |
96 | fi | |
97 | elif [[ "$tempfile" =~ \.($extlist)$ ]]; then | |
98 | goodlist+=( "$tempfile" ) | |
99 | ((colorsw++)) | |
100 | else | |
101 | badlist+=( "$tempfile" ) | |
102 | fi | |
103 | done | |
104 | else | |
105 | for tempfile in *$prompt*; do | |
106 | if [[ -d "$tempfile" ]]; then | |
107 | tempfile+=/ | |
108 | fi | |
109 | if [[ "$cmdname" =~ ^(c|cd|popd|rmdir)$ ]]; then | |
110 | if [[ -d "$tempfile" ]]; then | |
111 | goodlist+=( "$tempfile" ) | |
112 | ((colorsw++)) | |
113 | else | |
114 | badlist+=( "$tempfile" ) | |
115 | fi | |
116 | elif [[ "$tempfile" =~ \.($extlist)$ ]]; then | |
117 | goodlist+=( "$tempfile" ) | |
118 | ((colorsw++)) | |
119 | else | |
120 | badlist+=( "$tempfile" ) | |
121 | fi | |
122 | done | |
123 | fi | |
124 | colorsw=${#goodlist[@]} | |
125 | displayres=( "${goodlist[@]}" "${badlist[@]}" ) | |
126 | total=${#displayres[@]} | |
127 | fi | |
128 | ((total==1)) && prompt=${displayres[0]} && break | |
129 | (( total < lim )) && h=$total || h=$lim | |
130 | pages=$(( total /lim)) | |
131 | fi | |
132 | ((sel < 0)) && sel=0 | |
133 | ((sel >= total)) && sel=$((total -1)) | |
134 | ||
135 | page=$((sel /lim)) | |
136 | echo "p$page/$pages: $before$prompt"$'\e[47m \e[0m ' | |
137 | echo -ne '\e[A' | |
138 | for ((count = lim *(sel /lim); count < lim +lim *(sel /lim); count++)); do | |
139 | echo -ne '\e[0m' | |
140 | [[ $count == $total && $page == 0 ]] && break || echo | |
141 | (($sel == $count)) && echo -n "X " || echo -n " " | |
142 | ((count < colorsw)) && echo -ne '\e[31m' | |
143 | echo -n "${displayres[$count]}" | |
144 | done | |
145 | ||
146 | tput civis >&2 #turn cursor invisible | |
147 | read -n1 key | |
148 | [[ $key ]] || key=ENTER | |
149 | #[[ "$key" == ' ' ]] && key=Space | |
150 | if [[ "$key" == $'\e' ]]; then | |
151 | key=ESC | |
152 | while true; do | |
153 | read -n 1 -t 0.0001 -s newk | |
154 | [[ "$newk" == $'\e' ]] && newk=ESC | |
155 | key=${key}${newk} | |
156 | [[ -z "$newk" || "$newk" =~ [~A-Da-d] ]] && break | |
157 | done | |
158 | fi | |
159 | case "$key" in | |
160 | 'ESC[A') ((sel--));; #UP | |
161 | 'ESC[B') ((sel++));; #DOWN | |
162 | 'ESC[6~') ((sel+=7));; #PGDN | |
163 | 'ESC[5~') ((sel-=7));; #PGUP | |
164 | 'ESC[4~'|'ESC[F'|'ESC[8~'|'ESCOF') ((sel=$total));; #END | |
165 | 'ESC[1~'|'ESC[H'|'ESC[7~'|'ESCOH') ((sel=0));; #HOME | |
166 | 'ENTER') [[ "${displayres[$sel]}" ]] && prompt="${displayres[$sel]}"; end=1;; #ENTER | |
167 | 'ESC[2~') appendprompt=\ $prompt; prompt="${displayres[$sel]}"; end=1;; #INSERT | |
168 | 'ESC') nospace=1; end=1;; #ESC | |
169 | $'\x7f'|$'\x08') change=1; [[ $prompt ]] && prompt=${prompt::-1};; #BACKSPACE | |
170 | 'ESC'*) :;; #UNUSED KEY | |
171 | *) change=1; prompt+=$key;; | |
172 | esac | |
173 | ||
174 | for (( count=0; count < $h; count++)); do | |
175 | echo -ne "\e[2K\e[A\r" | |
176 | done | |
177 | tput cnorm >&2 #restore cursor visibility | |
178 | echo -ne '\e[2K\r' | |
179 | done | |
180 | } | |
181 | function kb_replace_var() { | |
182 | local var fill | |
183 | OIFS=$IFS | |
184 | IFS=$'\n' | |
185 | last="${last/\~/$HOME}" | |
186 | [[ "${last//[^$]}" ]] && \ | |
187 | for var in $(echo "$last" | /usr/bin/grep -o '\$[a-zA-Z_][a-zA-Z0-9_]*' | tr -d '$'); do | |
188 | fill=${!var} | |
189 | last="${last/\$$var/$fill}" | |
190 | done | |
191 | IFS=$OIFS | |
192 | } | |
193 | function kb_write_prompt() { | |
194 | local out escquote lang | |
195 | IFS=$' \t\n' | |
196 | dir=${1: -1} | |
197 | [[ "$dir" == / ]] && dir= || dir=' ' | |
198 | (( nospace == 1 )) && { dir= && nospace=; } || nospace=\' | |
199 | escquote=${1//\'/\'\\\'\'} | |
200 | out="$before$nospace$escquote$nospace$dir$appendprompt" | |
201 | lang=$LC_ALL | |
202 | LC_ALL=C | |
203 | ((READLINE_POINT+=${#out} - ${#READFIRST})) | |
204 | LC_ALL=$LC_ALL | |
205 | READLINE_LINE=$out$READLAST | |
206 | } | |
207 | function kb_main() { | |
208 | local cmdname extlist appendprompt recursive quotes last before psheight nospace=0 extglob nocaseglob nullglob globstar READFIRST READLAST | |
209 | READFIRST="${READLINE_LINE::$READLINE_POINT}" | |
210 | READLAST="${READLINE_LINE:$READLINE_POINT}" | |
211 | psheight=$( echo -e "$PS1" | wc -l) | |
212 | ((psheight--)) | |
213 | IFS=$' \t\n' | |
214 | ||
215 | # is the line has no words, add a tab. | |
216 | - | if [[ "$READFIRST" == ^[[:blank:]]*$ ]]; then |
216 | + | if [[ "$READFIRST" =~ ^[[:blank:]]*$ ]]; then |
217 | READLINE_LINE="$READFIRST"$'\t'"$READLAST" | |
218 | ((READLINE_POINT++)) | |
219 | return | |
220 | fi | |
221 | ||
222 | # count non-escaped quotes | |
223 | quotes=${READFIRST//\\\'} | |
224 | quotes=${quotes//[^\']} | |
225 | quotes=${#quotes} | |
226 | ||
227 | # the last word is empty, start completing from scratch | |
228 | if [[ "${READFIRST: -1}" == ' ' && "${READFIRST: -2:1}" != '\' ]] && (( quotes % 2 == 0)); then | |
229 | before=$READFIRST | |
230 | last= | |
231 | # complete a command (TODO:add sudo and such) | |
232 | elif [[ $READFIRST =~ ^\ *[^\ ]+$ ]]; then | |
233 | kb_menu command "$READFIRST" | |
234 | prompt+=" " | |
235 | ((READLINE_POINT+=${#prompt} - ${#READFIRST})) | |
236 | READLINE_LINE=$prompt$READLAST | |
237 | IFS=$' \t\n' | |
238 | echo -ne "\e[${psheight}A\r\e[2K" | |
239 | return | |
240 | ||
241 | # complete part of a word | |
242 | else | |
243 | last="${READFIRST##* }" | |
244 | recursive="${READFIRST% *}" | |
245 | # last="${a[$((words -1))]}" | |
246 | fi | |
247 | ||
248 | nocaseglob=$(shopt nocaseglob | /usr/bin/grep -F on) | |
249 | [[ $nocaseglob ]] || shopt -s nocaseglob | |
250 | nullglob=$(shopt nullglob | /usr/bin/grep -F on) | |
251 | [[ $nullglob ]] || shopt -s nullglob | |
252 | extglob=$(shopt extglob | /usr/bin/grep -F on) | |
253 | [[ $extglob ]] || shopt -s extglob | |
254 | globstar=$(shopt globstar | /usr/bin/grep -F off) | |
255 | [[ $globstar ]] || shopt -u globstar | |
256 | cmdname=$(echo $READFIRST) | |
257 | cmdname=${cmdname%% *} | |
258 | kb_highlight "$cmdname" | |
259 | ||
260 | # add words that end in \ to the $last word | |
261 | while [[ -z "$before" ]] ; do | |
262 | if [[ "${recursive: -1}" == '\' ]]; then | |
263 | last="${recursive##* } $last" | |
264 | recursive=${recursive% *} | |
265 | else | |
266 | before=$recursive\ | |
267 | fi | |
268 | done | |
269 | ||
270 | if (( quotes % 2 == 1 )) && ! [[ "$last" =~ \' ]]; then | |
271 | # $last will be part of a quote instead. | |
272 | # assume last quote is not escape. | |
273 | before="${READFIRST%\'*}" | |
274 | last="${READFIRST##*\'}" | |
275 | fi | |
276 | ||
277 | kb_replace_var | |
278 | ||
279 | last=${last//\'} | |
280 | ||
281 | kb_menu 'file' "$last" | |
282 | kb_write_prompt "$prompt" | |
283 | ||
284 | IFS=$' \t\n' | |
285 | echo -ne "\r\e[2K\e[${psheight}A\r\e[2K" | |
286 | [[ $nocaseglob ]] || shopt -u nocaseglob | |
287 | [[ $nullglob ]] || shopt -u nullglob | |
288 | [[ $extglob ]] || shopt -u extglob | |
289 | [[ $globstar ]] || shopt -s globstar | |
290 | tput smam >&2 #restore line wrap | |
291 | } | |
292 | bind -x '"\t":kb_main' |