124124 # grab current time
125125 local now=" ${EPOCHSECONDS:- $(printf " %(%s)T\n" -1)} "
126126 # accept options
127- local name=" ${FUNCNAME[1]:- hold} " expire=0 new=0 mode=' run' out=' name'
127+ local name=" ${FUNCNAME[1]:- hold} " # string cache name
128+ local expire=0 # integer seconds to expire cache
129+ local new=0 # boolean to clear cache
130+ local mode=' run' # program mode: run/file/load
131+ local out=' name' # output mode: name/content/quiet
128132 local opt OPTIND OPTARG
129133 while getopts " :hefgn:pqt:x" opt; do
130134 case " $opt " in
370374 case " $next " in
371375 [CEPQ]) # accept transform formats
372376 fmt=" $next "
373- let index++
377+ (( index++ ))
374378 ;;
375379 * ) # anything else is an error
376380 printf " Invalid format string '%s'\n%s\n" " $next " " $use " >&2
387391 esac
388392 fi
389393 # next character
390- let index++
394+ (( index++ ))
391395 done
392396 # check if parsing ended cleanly
393397 if [[ " $mode " == " var" ]]; then
@@ -639,6 +643,13 @@ TEMPLATES
639643 {X:} - fields X through end of fields
640644 {X:Y} - fields X through X + Y
641645 {X,Y,Z} - fields X, Y, and Z
646+
647+ Append @C, @E, @P, or @Q to transform selected fields:
648+ @C - Insert argument directly. This is risky for command strings!
649+ @E - Replace backslash escape sequences in arguments with bash $'...' quotes.
650+ @P - Expand arguments for use in prompt strings.
651+ @Q - Quote arguments for use in command input. This is the default.
652+
642653 FIELDS consists of one of the above without the enclosing '{}'.
643654
644655ENVIRONMENT
700711 ;;
701712 f) # fields to be extracted
702713 fld=" ${fld:- ${OPTARG} } "
703- if ! [[ " $fld " =~ ^(-? [[:digit:]]+)(:([[:digit:]]+)? )? (@[CEPQ])? $ ]]; then
704- printf " Invalid field template '%s'\n" " $fld " >&2
705- return 2
706- fi
707714 run=1
708715 ;;
709716 g) # buffer stdin for command
891898 else
892899 printf " %s\n" " ${lines[@]} "
893900 fi)
894- )
901+ ) || return 4
895902 # require that selector succeeded and got a line
896- if (( $? )) || [ -z " $out " ]; then
903+ if [ -z " $out " ]; then
897904 return 4
898905 fi
899906 # rectify shell quoted line
@@ -913,15 +920,15 @@ EOF
913920 printf " %s\n" " $out "
914921 ;;
915922 1) # print some fields extracted from the line
916- if ! out=" $( nth " {${fld} }" " ${toks[@]} " ) " ; then
917- printf " Failed to parse template.\n %s\n" " $fld " >&2
923+ if ! out=" $( nth -p " {${fld} }" " ${toks[@]} " 2> /dev/null ) " ; then
924+ printf " Failed to parse template: %s\n" " $fld " >&2
918925 return 5
919926 fi
920927 printf " %s\n" " $out "
921928 ;;
922929 2) # render the command string template then eval it
923- if ! cmd=" $( nth " ${tpl} " " ${toks[@]} " ) " ; then
924- printf " Failed to parse template.\n %s\n" " $tpl " >&2
930+ if ! cmd=" $( nth " ${tpl} " " ${toks[@]} " 2> /dev/null ) " ; then
931+ printf " Failed to parse template: %s\n" " $tpl " >&2
925932 return 5
926933 fi
927934 # eval the command string maybe passing buffered input
946953
947954# cz command completion
948955function _cz() {
956+ local reply=()
949957 # get lists of supported tools and plugins
950958 local tools=() plugs=()
951959 mapfile -t tools < <( cz -k)
@@ -978,23 +986,26 @@ function _cz() {
978986 # maybe the previous word is a redirection
979987 local rd=' ^[&12]?[><]'
980988 if [[ " $prev " =~ $rd ]]; then
981- COMPREPLY=($( compgen -f -- " $curr " ) )
989+ mapfile -t reply < <( compgen -f -- " $curr " )
990+ COMPREPLY=(" ${reply[@]} " )
982991 return
983992 fi
984993 # maybe the previous word is an option that expects an argument
985994 if [[ " $prev " =~ ^-[defiz]$ ]]; then
986995 case " $prev " in
987- -d) COMPREPLY =(); ;;
988- -e) COMPREPLY=( $( compgen -c -- " $curr " ) ) ;;
989- -f) COMPREPLY=( $( compgen -W " 0 1 2 3 4 5 6 7 8 9" -- " $curr " ) ) ;;
990- -i) COMPREPLY=( $( compgen -f -- " $curr " ) ) ;;
991- -z) COMPREPLY=( $( compgen -W " ${tools[*]%% * } " -- " $curr " ) ) ;;
996+ -d) reply =(); ;;
997+ -e) mapfile -t reply < <( compgen -c -- " $curr " ) ;;
998+ -f) mapfile -t reply < <( compgen -W " 0 1 2 3 4 5 6 7 8 9" -- " $curr " ) ;;
999+ -i) mapfile -t reply < <( compgen -f -- " $curr " ) ;;
1000+ -z) mapfile -t reply < <( compgen -W " ${tools[*]%% * } " -- " $curr " ) ;;
9921001 esac
1002+ COMPREPLY=(" ${reply[@]} " )
9931003 return
9941004 fi
9951005 # first complete initial command token and options
9961006 if [ -z " $base " ]; then
997- COMPREPLY=($( compgen -W " ${! opts[*]} ${plugs[*]%% _* } " -- " $curr " ) )
1007+ mapfile -t reply < <( compgen -W " ${! opts[*]} ${plugs[*]%% _* } " -- " $curr " )
1008+ COMPREPLY=(" ${reply[@]} " )
9981009 return
9991010 fi
10001011 # determine next command token
@@ -1006,7 +1017,8 @@ function _cz() {
10061017 done
10071018 # maybe complete next command token
10081019 if (( "${# next[@]} ")) ; then
1009- COMPREPLY=($( compgen -W " ${next[*]} " -- " $curr " ) )
1020+ mapfile -t reply < <( compgen -W " ${next[*]} " -- " $curr " )
1021+ COMPREPLY=(" ${reply[@]} " )
10101022 return
10111023 fi
10121024 # TODO maybe complete something specific for a plugin
@@ -1038,14 +1050,15 @@ EOF
10381050}
10391051
10401052anc () {
1041- local d=" ${1:- $PWD } "
1042- if ! [ -d " $d " ]; then return 2; fi ;
1043- IFS=/ read -ra t <<< " ${d#/}"
1044- local b s n
1045- for (( n= 0 ; n<= ${# t[@]} ; n++ )) ; do
1046- b=" ${t[$n]} "
1047- printf " %s\n" " ${s:-/ } "
1048- s=" ${s} /${b} "
1053+ local dir=" ${1:- $PWD } "
1054+ if ! [ -d " $dir " ]; then return 2; fi ;
1055+ local toks=()
1056+ IFS=/ read -ra toks <<< " ${dir#/}"
1057+ local seg=" " cur=" " idx=0
1058+ for (( idx= 0 ; idx<= ${# toks[@]} ; idx++ )) ; do
1059+ seg=" ${toks[$idx]} "
1060+ printf " %s\n" " ${cur:-/ } "
1061+ cur=" ${cur} /${seg} "
10491062 done
10501063}
10511064
@@ -1655,7 +1668,7 @@ cz gcloud project
16551668Select a Google cloud project and describe it in JSON.
16561669EOF
16571670 req gcloud jq || return 5
1658- cz -f 0 -e ' gcloud --format json projects describe {0}' \
1671+ cz -f ' 0@C ' -e ' gcloud --format json projects describe {0}' \
16591672 -i <( gcloud --format json projects list | jq -r ' .[] | [.projectId, .name] | @tsv' )
16601673}
16611674
@@ -1832,6 +1845,26 @@ EOF
18321845 cz -e ' cz -h {0}' -i <( cz -l)
18331846}
18341847
1848+ cz_haskell_package () {
1849+ { hep " $CZ_HELP " && return ; } << EOF
1850+ cz haskell package
1851+ Select a haskell cabal package then show info about it.
1852+ EOF
1853+ req cabal || return 5
1854+ cz -e ' cabal info {0}' -f 0 \
1855+ -i <( hold -ept 300 -- cabal list --simple-output)
1856+ }
1857+
1858+ cz_haskell_installed () {
1859+ { hep " $CZ_HELP " && return ; } << EOF
1860+ cz haskell installed
1861+ Select an installed haskell cabal package then show info about it.
1862+ EOF
1863+ req cabal || return 5
1864+ cz -f 0 -e ' cabal info {0}' -f 0 \
1865+ -i <( hold -ept 300 -- cabal list --installed --simple-output)
1866+ }
1867+
18351868cz_hg_branch () {
18361869 { hep " $CZ_HELP " && return ; } << EOF
18371870cz hg branch [DIRECTORY]
@@ -1974,7 +2007,7 @@ EOF
19742007 line=" ${lines[$index]} "
19752008 case " $symbol " in
19762009 ' ' ) # next
1977- let index++
2010+ (( index++ ))
19782011 continue
19792012 ;;
19802013 ' ?' ) # guess
@@ -2111,17 +2144,6 @@ EOF
21112144 cz -0 -i <( locate -i -0 " ${@:- $PWD } " )
21122145}
21132146
2114- cz_locate_mimetype () {
2115- { hep " $CZ_HELP " && return ; } << EOF
2116- cz locate [QUERY ...]
2117- Select a mimetype then select a file from the locate database matching its known extensions.
2118- EOF
2119- req locate || return 5
2120- local e=($( cz -q -f 1: mimetype) )
2121- if ! (( ${# e} )) ; then return 2; fi
2122- cz locate " ${e[@]/#/* .} "
2123- }
2124-
21252147cz_locate_regex () {
21262148 { hep " $CZ_HELP " && return ; } << EOF
21272149cz locate regex [PATTERN ...]
@@ -2200,8 +2222,8 @@ cz_mpd_output() {
22002222cz mpd output
22012223Select an mpd output and toggle it between enabled and disabled.
22022224EOF
2203- req mpc || return 5
2204- cz -e " mpc toggleoutput {1}" -i <( mpc outputs)
2225+ req grep mpc || return 5
2226+ cz -e " mpc toggleoutput {1}" -i <( mpc outputs | grep -v ' ^[[:space:]] ' )
22052227}
22062228
22072229cz_mpd_playlist () {
@@ -2330,12 +2352,12 @@ EOF
23302352 cz -f 0 -i <( lspci)
23312353}
23322354
2333- cz_perl_module () {
2355+ cz_perl_installed () {
23342356 { hep " $CZ_HELP " && return ; } << EOF
23352357cz perl module
23362358Select an installed perl module.
23372359EOF
2338- req perldoc perldoc-search || return 5
2360+ req perl || return 5
23392361 cz -f 0 -i <( perl -MExtUtils::Installed -E ' say for ExtUtils::Installed->new->modules' )
23402362}
23412363
@@ -2373,6 +2395,15 @@ EOF
23732395 cz -f 0 -e " pydoc {0}" < <( pydoc -k .)
23742396}
23752397
2398+ cz_python_installed () {
2399+ { hep " $CZ_HELP " && return ; } << EOF
2400+ cz python installed
2401+ Select an installed python package and show info about it.
2402+ EOF
2403+ req pip || return 5
2404+ cz -f 0 -e " pip show {0}" < <( pip list)
2405+ }
2406+
23762407cz_pulseaudio_sink () {
23772408 { hep " $CZ_HELP " && return ; } << EOF
23782409cz pulseaudio sink
0 commit comments