Guest User

kingbash

a guest
Nov 16th, 2016
217
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.03 KB | None | 0 0
  1. #! /usr//bin/bash
  2. # https://bbs.archlinux.org/viewtopic.php?pid=1244804#p1244804
  3. # Usage:
  4. # bind -x '"\t":out=$(kingbash.script "$PS1" "$(compgen -A alias -A function)" nohelp); READLINE_LINE=$(echo "$out" | head -n -1); READLINE_POINT=$(echo "$out" | tail -n 1)'
  5. #
  6. # Usage Explanation
  7. # main command: bind -x '"KEY":COMMAND'
  8. # KEY of \t means tab.
  9. # COMMAND sets the two $READLINE variables from kingbash.script.
  10. # kingbash.script needs 2, 3 or 4 arguments:
  11. # $1 is $PS1 to see how many lines have to be moved up.
  12. # $2 is a list of aliases and functions used for command completion generated with compgen.
  13. # $3 and $4 are optionally one of nohelp or dirfirst
  14. # nohelp removes the helpbar and dirfirst lists directories first always.
  15.  
  16. function kb_ls() { /usr/bin/ls -1dsqh "$@"; }
  17.  
  18. function kb_highlight() {
  19. case $cmdname in
  20. #Video
  21. mplayer|mwrap|mpv|vlc|gmplayer|smplayer|mencoder|kmplayer|Parole|whaawmp|dragonplayer|ffmpeg)
  22. extlist='mkv|m4v|mp.|avi|wmv|rmvb|as?|divx|vob|ogm|rm|flv|part|iso|ogg|wav|flac|m4a' ;;
  23. #Audio
  24. mpg123|ffsplit|mpg123s|mpg321|mpv|mp3blaster|cmus|cplay|moc|xmms|xmms2|sonata|deadbeef|ogg123|mnama)
  25. extlist='mp.|aac|wav|ogg|gsm|dct|flac|au|aiff|vox|wma|aac|ra|m4a' ;;
  26. #PDF
  27. llpp|xpdf|epdfview|evince|foxit|mupdf|okular|apvlv|zathura)
  28. extlist='pdf' ;;
  29. #Images
  30. feh|geeqie|gqview|eog|gpicview|gthumb|mirage|qiv|ristretto|xnview|xv|viewnior)
  31. extlist='jpg|jpeg|png|gif|bmp|icon?|tiff?' ;;
  32. #Games
  33. sdlmame|openmsx|msxplay|zsnes|desmume|VirtualBoy)
  34. extlist='rom|dsk' ;;
  35. #Wine
  36. wine|winewrap|wineme|winenew|wineconsole)
  37. extlist='exe|com|bat' ;;
  38. #Archives
  39. atool|x|xi|gunzip|extract|unzip|unrar|zip|rar|7z|mcomix|v)
  40. extlist='tgz|zip|rar|bz2|gz|tar|exe|pk3|lha|Z|lzma' ;;
  41. #Text
  42. vim|nano|acme|beaver|geany|leafpad|medit|mousepad|pyroom|sam|vi|gvim|emacs|tea|scite)
  43. extlist='txt|rc|sh|c|bash|py|ini' ;;
  44. #Default
  45. *) extlist='';;
  46. esac
  47. }
  48.  
  49. function kb_listcheck() {
  50. for tempfile in $1; do
  51. if [[ $dircmd ]]; then
  52. if [[ -d "$tempfile" ]]; then
  53. displayres+=( "$tempfile" )
  54. ((colorsw++))
  55. else
  56. badlist+=( "$tempfile" )
  57. fi
  58. elif [[ "$extlist" && "$tempfile" =~ \.($extlist)$ ]]; then
  59. displayres+=( "$tempfile" )
  60. ((colorsw++))
  61. elif [[ "$2" == executables ]]; then
  62. [[ -x "$tempfile" ]] && displayres+=( "$tempfile" )
  63. else
  64. if [[ "$dirfirst" ]]; then
  65. if [[ -d "$tempfile" ]]; then
  66. dirlist+=( "$tempfile" )
  67. else
  68. badlist+=( "$tempfile" )
  69. fi
  70. else
  71. badlist+=( "$tempfile" )
  72. fi
  73. fi
  74. done
  75. }
  76.  
  77. function kb_menu() {
  78. end=0
  79. sel=0
  80. change=1
  81. lim=12
  82. declare -A lslist
  83. tput rmam >&2 #don't wrap long lines
  84. IFS=$'\n'
  85. prompt="$2"
  86.  
  87. while ((end==0)); do
  88.  
  89. # the [a-z] or [abcd] structure messes up globbing
  90. prompt=${prompt//]/\\]}
  91. prompt=${prompt//\\\\]/\\]}
  92.  
  93. # build a new list
  94. if ((change != 0)); then
  95. sel=0
  96. resetcounter=0
  97. change=0
  98. if [[ "$1" == command ]]; then
  99. [[ $prompt ]] || { read -sn1 -p "Enter first letter" prompt; echo -ne '\e[2K\r' >&2; }
  100. displayres=( $( { compgen -A command -A alias -A builtin -A function $prompt; echo "$customcmd" | grep "^$prompt"; } | sort -u) )
  101. kb_listcheck "$prompt*" executables
  102. elif [[ "$1" == file ]]; then
  103. colorsw=0
  104. badlist=()
  105. dirlist=()
  106. displayres=()
  107. kb_listcheck "$prompt*"
  108. fi
  109. [[ "$1" == file ]] && colorsw=${#displayres[@]}
  110. displayres+=( "${dirlist[@]}" "${badlist[@]}" )
  111. total=${#displayres[@]}
  112.  
  113. # on zero results retry without front match
  114. if [[ "$1" == file ]] && ((total==0)); then
  115. colorsw=0
  116. if [[ "${prompt//[^\/]}" ]]; then
  117. kb_listcheck "${prompt%/*}/*${prompt##*/}*"
  118. else
  119. kb_listcheck "*$prompt*"
  120. fi
  121. colorsw=${#displayres[@]}
  122. displayres+=( "${dirlist[@]}" "${badlist[@]}" )
  123. total=${#displayres[@]}
  124. fi
  125. ((total==1 && browse==0)) && prompt=${displayres[0]} && break
  126. browse=0
  127. (( total < lim )) && h=$total || h=$lim
  128. pages=$(( total /lim))
  129. (( total % lim == 0)) && ((pages--))
  130. fi
  131. ((sel < 0)) && sel=0
  132. ((sel >= total)) && sel=$((total -1))
  133.  
  134. # With F2 and Left, the selected file does not start at 0
  135. if [[ "$reset" ]]; then
  136. for tempfile in "${displayres[@]}"; do
  137. if [[ "${tempfile##*/}" == "${reset##*/}" ]]; then
  138. sel=$resetcounter
  139. reset=
  140. break
  141. else
  142. ((resetcounter++))
  143. fi
  144. done
  145. fi
  146.  
  147. page=$((sel /lim))
  148. ((page==pages))&&lastpage=$'\e[7m'||lastpage=
  149. ((pages==-1))&&lastpage=$'\e[41m'
  150. echo -n $'\e[0m'"${lastpage}p$page/$pages"$'\e[m'": $before$prompt"$'\e[47m \e[0m ' >&2
  151. [[ "$helptext" ]] && echo -n "$helptext" >&2 && helptext=
  152.  
  153. for ((count = lim *(sel /lim); count < lim +lim *(sel /lim); count++)); do
  154. echo -ne '\e[0m' >&2
  155. [[ $count == $total && $page == 0 ]] && break || echo >&2
  156.  
  157. # The selected file has a X before it
  158. # (($sel == $count)) && echo -n "X "$'\e[7m' || echo -n " " >&2
  159.  
  160. # The selected file is reverse colored
  161. (($sel == $count)) && echo -n $'\e[7m' >&2
  162.  
  163. # Media files that match the command were counted and now highlighted
  164. ((count < colorsw)) && echo -ne '\e[1;34m' >&2
  165.  
  166. if [[ "$1" == file ]]; then
  167.  
  168. # Some characters can give errors when a list subscript
  169. tempfile=${displayres[$count]//\'}
  170. tempfile=${tempfile//[}
  171. tempfile=${tempfile//]}
  172. tempfile=${tempfile//\`}
  173. tempfile=${tempfile//@}
  174. tempfile=${tempfile//\*}
  175.  
  176. if [[ "$tempfile" ]]; then
  177. if ! [[ "${lslist["$tempfile"]}" ]]; then
  178.  
  179. # Get filesize, or special characters for dirs
  180. # Store results in lslist, so they don't have to be acquired twice
  181. ls_reform=$(kb_ls "${displayres[$count]}")
  182. [[ -d "${displayres[$count]}" ]] && ls_reform="(dir)"
  183. printf -v "lslist[$tempfile]" '%4s %s' "${ls_reform%% *}" "${displayres[$count]}"
  184.  
  185. fi
  186. echo -n "${lslist["$tempfile"]}" >&2
  187. fi
  188. else
  189. echo -n "${displayres[$count]}" >&2
  190. fi
  191. (($sel == $count)) && for ((colcount=0;colcount<cols;colcount++)); do echo -n ' ' >&2; done
  192. done
  193. if (( $nohelp == 1 )); then
  194. echo -e '\e[0m' >&2
  195. for item in F1:info F2:command F3:time Left:updir Right:browse Insert:Add\&continue Plus:Add\ all; do
  196. echo -ne "\e[40;31m${item/:/\\e[30;41m}\e[m " >&2
  197. done
  198. echo -ne "\e[0m" >&2
  199. fi
  200.  
  201. key=$(read -n1 -p "$invisible" -s; echo "$REPLY")
  202. [[ $key ]] || key=ENTER
  203. #[[ "$key" == ' ' ]] && key=Space
  204. if [[ "$key" == $'\e' ]]; then
  205. key=ESC
  206. while true; do
  207. read -n 1 -t 0.01 -s newk
  208. [[ "$newk" == $'\e' ]] && newk=ESC
  209. key=${key}${newk}
  210. [[ -z "$newk" || "$newk" =~ [~A-Da-d] ]] && break
  211. done
  212. fi
  213. case "$key" in
  214. 'ESC[A') #UP
  215. ((sel--));;
  216. 'ESC[B') #DOWN
  217. ((sel++));;
  218. 'ESC[6~') #PGDN
  219. ((sel+=lim));;
  220. 'ESC[5~') #PGUP
  221. ((sel-=lim));;
  222. 'ESC[D') #LEFT
  223. change=1
  224. browse=1
  225. reset=${prompt%/*}
  226. reset=$(cd "$reset" 2>/dev/null; pwd -L | sed 's_^.*/__')
  227. reset=$reset
  228. if [[ ${prompt: -3} == ../ ]]; then
  229. prompt+=../
  230. elif [[ "${prompt//[^\/]}" == / ]]; then
  231. prompt=
  232. elif [[ "${prompt//[^\/]}" ]]; then
  233. ! [[ ${prompt: -1} == / ]] && prompt=${prompt%/*}/
  234. prompt=${prompt%/*/*}/
  235. else prompt=../
  236. fi
  237. ;;
  238. 'ESC[11~'|'ESCOP') #F1
  239. if [[ -d "${displayres[$sel]}" ]]; then
  240. helptext=$'\e[31m'"$(/usr/bin/ls "${displayres[$sel]}" | wc -l) files: $(/usr/bin/ls "${displayres[$sel]}" | tr '\n' ' ')"
  241. else
  242. helptext=$'\e[31m'$(/usr/bin/ls -hlF --quoting-style=shell-always "${displayres[$sel]}")
  243. fi
  244. ;;
  245. 'ESC[C') #RIGHT
  246. browse=1
  247. change=1
  248. prompt=${displayres[$sel]}
  249. [[ -d "$prompt" ]] && prompt+=/ || end=1
  250. ;;
  251. 'ESC[4~'|'ESC[F'|'ESC[8~'|'ESCOF') #END
  252. ((sel=$total));;
  253. 'ESC[1~'|'ESC[H'|'ESC[7~'|'ESCOH') #HOME
  254. ((sel=0));;
  255. 'ESC[12~'|'ESCOQ') #F2
  256. oldprompt="$prompt"
  257. oldbefore=$before
  258. prereset=${displayres[$sel]}
  259. before="Enter new command: "
  260. for (( count=0; count < $h; count++)); do
  261. echo -ne "\e[2K\e[A\r" >&2
  262. done
  263. echo -ne '\e[2K\r' >&2
  264. kb_menu command ""
  265. doubleclear=1
  266. change=1
  267. dircmd=
  268. cmdname=$prompt
  269. [[ "$cmdname" =~ ^(c|cd|popd|rmdir)$ ]] && dircmd=1
  270. kb_highlight
  271. end=0
  272. before=$cmdname\ ${oldbefore#* }
  273. prompt=$oldprompt
  274. reset=$prereset
  275. ;;
  276. 'ESC[13~'|'ESCOR') #F3
  277. prompt=$(echo "$prompt" | sed 's/[^/]*$//')
  278. [[ "$prompt" ]] || prompt=.
  279. prompt+=/
  280. sel=0
  281. colorsw=0
  282. displayres=( $(/usr/bin/ls -d1qt $prompt*) )
  283. ;;
  284. \+) #Plus (All)
  285. prompt=
  286. for tempfile in "${displayres[@]}"; do
  287. kb_write_prompt "$tempfile" before
  288. done
  289. end=1
  290. ;;
  291. 'ENTER') #ENTER
  292. if [[ $1 == command && -d "${displayres[$sel]}" ]]; then
  293. prompt=${displayres[$sel]}/
  294. change=1
  295. else
  296. [[ "${displayres[$sel]}" ]] && prompt="${displayres[$sel]}"
  297. end=1
  298. fi
  299. ;;
  300. 'ESC[2~') #INSERT
  301. kb_write_prompt "${displayres[$sel]}" before
  302. ((sel++))
  303. ;;
  304. 'ESC') #ESC
  305. nospace=1
  306. end=1
  307. ;;
  308. $'\x7f'|$'\x08') #BACKSPACE
  309. change=1
  310. [[ $prompt ]] && prompt=${prompt::-1}
  311. ;;
  312. 'ESC'*) #UNUSED KEY
  313. : ;;
  314. *) #Normal key
  315. change=1
  316. prompt+=$key
  317. ;;
  318. esac
  319.  
  320. if [[ $doubleclear ]]; then
  321. doubleclear=
  322. else
  323. for (( count=0; count < h + nohelp; count++)); do
  324. echo -ne "\e[2K\e[A\r" >&2
  325. done
  326. echo -ne '\e[2K\r\e[m' >&2
  327. fi
  328. done
  329. }
  330.  
  331. function kb_replace_var() {
  332. local var fill
  333. OIFS=$IFS
  334. IFS=$'\n'
  335. [[ "${last//[^~]}" ]] && last="${last/\~/$HOME}" && replaceback[$HOME]='~'
  336. [[ "${last//[^$]}" ]] && \
  337. for var in $(echo "$last" | /usr/bin/grep -o '\$[a-zA-Z_][a-zA-Z0-9_]*' | tr -d '$'); do
  338. fill=${!var}
  339. [[ $fill ]] && last="${last/\$$var/$fill}" && replaceback["$fill"]=\$$var
  340. done
  341. IFS=$OIFS
  342. }
  343.  
  344. function kb_write_prompt() {
  345. local out escquote lang
  346. IFS=$' \t\n'
  347. [[ -d "$1" ]] && dir=/ || dir=' '
  348. #single quote
  349. # (( nospace == 1 )) && { dir= && nospace=; } || nospace=\'
  350. # [[ $1 ]] || { nospace=; dir=; }
  351. # escquote=${1//\'/\'\\\'\'}
  352. #escape
  353. (( nospace == 1 )) && dir=
  354. nospace=
  355. escquote=$(echo "$1" | sed 's/[] !@#^&()`"<>\\{};=|'\'' []/\\&/g')
  356. for fill in ${!replaceback[@]}; do
  357. var=${replaceback["$fill"]}
  358. escquote=${escquote/$fill/$var}
  359. done
  360. [[ "$2" == before ]] && before+="$escquote$dir " && return
  361. out="$before$nospace$escquote$nospace$dir"
  362. lang=$LC_CTYPE
  363. LC_CTYPE=C
  364. ((READLINE_POINT+=${#out} - ${#READFIRST}))
  365. LC_CTYPE=$lang
  366. READLINE_LINE=$out$READLAST
  367. }
  368.  
  369. function kb_output() {
  370. echo "$READLINE_LINE"
  371. echo "$READLINE_POINT"
  372. }
  373.  
  374. trap 'echo -n $'\r' >&2; tput smam >&2; tput cnorm >&2; kb_output; exit' EXIT
  375. trap 'echo -n $'\r' >&2; tput smam >&2; tput cnorm >&2; exit' INT QUIT TERM HUP
  376.  
  377. #function kb_main() {
  378. nospace=0
  379. declare -A replaceback
  380. nospace=0
  381. invisible=$(tput civis) #turn cursor invisible
  382. READFIRST="${READLINE_LINE::$READLINE_POINT}"
  383. READLAST="${READLINE_LINE:$READLINE_POINT}"
  384. psheight=$( echo -ne "$1" | wc -l); shift
  385. customcmd=$1; shift
  386. cols=$(( $(tput cols) / 10))
  387. IFS=$' \t\n'
  388. [[ $1 == dirfirst ]] && dirfirst=1
  389. [[ $2 == dirfirst ]] && dirfirst=1
  390. [[ $1 == nohelp ]] && nohelp=0
  391. [[ $2 == nohelp ]] && nohelp=0
  392. [[ $nohelp ]] || nohelp=1
  393.  
  394. # if the line has no words, add a tab.
  395. if [[ "$READFIRST" =~ ^[[:blank:]]*$ ]]; then
  396. IFS=$'\n'
  397. read -n 1 -t 0.002 -s key
  398. if [[ $key ]]; then
  399. IFS=$' \t\n'
  400. READLINE_LINE="$READFIRST"$'\t'"$key$READLAST"
  401. ((READLINE_POINT+=${#key} +1))
  402. ((psheight > 0)) && echo -ne "\e[${psheight}A" >&2
  403. exit
  404. fi
  405. # put cursor at beginning of line to fill in a command later
  406. READLINE_POINT=-999
  407. fi
  408.  
  409. shopt -s nocaseglob
  410. shopt -s nullglob
  411. shopt -s dotglob
  412. shopt -u globstar
  413.  
  414. # count non-escaped quotes
  415. quotes=${READFIRST//\\\'}
  416. quotes=${quotes//[^\']}
  417. quotes=${#quotes}
  418.  
  419. # cannot use the last escape
  420. [[ "${READFIRST: -1}" == '\' ]] && READFIRST=${READFIRST%\\} && ((READLINE_POINT--))
  421.  
  422. # the last word is empty, start completing from scratch
  423. if [[ "${READFIRST: -1}" == ' ' && "${READFIRST: -2:1}" != '\' ]] && (( quotes % 2 == 0)); then
  424. before=$READFIRST
  425. last=
  426.  
  427. # complete a command
  428. elif [[ "$READFIRST" =~ ^\ *[^=\ ]+$ ]]; then
  429. last=$READFIRST
  430. kb_replace_var
  431. kb_menu command "$last"
  432. for fill in ${!replaceback[@]}; do
  433. var=${replaceback["$fill"]}
  434. prompt=${prompt/$fill/$var}
  435. done
  436. prompt+=" "
  437. ((READLINE_POINT+=${#prompt} - ${#READFIRST}))
  438. READLINE_LINE=$prompt$READLAST
  439. IFS=$' \t\n'
  440. ((psheight > 0)) && echo -ne "\e[${psheight}A" >&2
  441. echo -ne '\r\e[2K' >&2
  442. exit
  443.  
  444. #variable=filename on first word.
  445. elif ! [[ "$READFIRST" =~ \ ]]; then
  446. last=$READFIRST
  447. before=
  448. # complete part of a word
  449. else
  450. last="${READFIRST##* }"
  451. recursive="${READFIRST% *}"
  452. fi
  453.  
  454. cmdname=$(echo $READFIRST)
  455. cmdname=${cmdname%% *}
  456. kb_highlight "$cmdname"
  457. [[ "$cmdname" =~ ^(c|cd|popd|rmdir)$ ]] && dircmd=1
  458.  
  459. # add words that end in \ to the $last word
  460. while [[ -z "$before" ]] ; do
  461. if [[ "${recursive: -1}" == '\' ]]; then
  462. last="${recursive##* } $last"
  463. oldrecursive=$recursive
  464. recursive=${recursive% *}
  465. else
  466. before=$recursive\
  467. fi
  468. done
  469.  
  470. # for structures like cat 'word1 word2<TAB>
  471. if (( quotes % 2 == 1 )) && ! [[ "$last" =~ \' ]]; then
  472. # $last will be part of a quote instead.
  473. # assume last quote is not escape.
  474. before="${READFIRST%\'*}"
  475. last="${READFIRST##*\'}"
  476. fi
  477.  
  478. # for structures like cat 'word1 word2'/<TAB>
  479. lastquote="${READFIRST##* }"
  480. beforequote="${READFIRST% *}"
  481. if [[ "${lastquote//[^\']}" == \' && ${lastquote::1} != \' && "${beforequote}" =~ \ \' ]]; then
  482. last=${beforequote##* \'}\ $lastquote
  483. before=${beforequote% \'*}\
  484. fi
  485.  
  486. # for variable=filename
  487. if [[ "$last" =~ ^[a-zA-Z_][a-zA-Z0-9_]+= ]]; then
  488. before=$before${last%%=*}=
  489. last=${last#*=}
  490. fi
  491.  
  492. kb_replace_var
  493.  
  494. # for sudo setsid ; etc
  495. if [[ "$before" =~ (setsid| do|sudo|which|whatis|whereis|\||\(|&|\{|;)\ *$ ]]; then
  496. kb_menu command "$last"
  497. for fill in ${!replaceback[@]}; do
  498. var=${replaceback["$fill"]}
  499. prompt=${prompt/$fill/$var}
  500. done
  501. ((nospace==0)) && prompt+=" "
  502. ((READLINE_POINT+=${#prompt} - ${#last}))
  503. READLINE_LINE=$before$prompt$READLAST
  504. IFS=$' \t\n'
  505. ((psheight > 1)) && echo -ne "\e[${psheight}A" >&2
  506. echo -ne "\r\e[2K" >&2
  507. exit
  508. fi
  509.  
  510. # In the case of completion on 'file.t<tab>
  511. # the ' must be removed to scan the file.
  512. # Completing after typing a ' is then not supported.
  513. last=${last//\'}
  514.  
  515. kb_menu 'file' "$last"
  516. kb_write_prompt "$prompt"
  517.  
  518. ((psheight > 0)) && echo -ne "\r\e[2K\e[${psheight}A" >&2
  519. echo -ne "\r\e[2K" >&2
Advertisement
Add Comment
Please, Sign In to add comment