View difference between Paste ID: m1KCzjdk and 0Y64rCvL
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
#PDF
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'