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' |