diff --git a/extra/_beet b/extra/_beet index 9e4a3437b..dd3f6570b 100644 --- a/extra/_beet +++ b/extra/_beet @@ -1,6 +1,13 @@ #compdef beet -# Completion for beets music library manager and MusicBrainz tagger: http://beets.io/ +# zsh completion for beets music library manager and MusicBrainz tagger: http://beets.radbox.org/ + +# NOTE: it will be very slow the first time you try to complete in a zsh shell (especially if you've enable many plugins) +# You can make it faster in future by saving the generated completion function: which _beet > _beet2 +# to the top of the file add: #compdef beet +# to the bottom of the file add: _beet "$@" +# add this file to your zsh completions directory, and then in your .zshrc file add: compdef _beet2 beet +# You will need to repeat this proceedure each time you enable new plugins if you want them to complete properly. # useful: argument to _regex_arguments for matching any word local matchany=/$'[^\0]##\0'/ @@ -13,15 +20,23 @@ fields=(`beet fields | grep -G '^ ' | sort -u | colrm 1 2`) # regexps for matching query and modify terms on the command line matchquery=/"(${(j/|/)fields[@]})"$':[^\0]##\0'/ matchmodify=/"(${(j/|/)fields[@]})"$'(=[^\0]##|!)\0'/ + +# Function for joining grouped lines of output into single lines (taken from _completion_helpers) +function _join_lines() { + awk -v SEP="$1" -v ARG2="$2" -v START="$3" -v END2="$4" 'BEGIN {if(START==""){f=1}{f=0}; + if(ARG2 ~ "^[0-9]+"){LINE1 = "^[[:space:]]{,"ARG2"}[^[:space:]]"}else{LINE1 = ARG2}} + ($0 ~ END2 && f>0 && END2!="") {exit} + ($0 ~ START && f<1) {f=1; if(length(START)!=0){next}} + ($0 ~ LINE1 && f>0) {if(f<2){f=2; printf("%s",$0)}else{printf("\n%s",$0)}; next} + (f>1) {gsub(/^[[:space:]]+|[[:space:]]+$/,"",$0); printf("%s%s",SEP, $0); next} + END {print ""}' +} + # Function for getting unique values for field from database (you may need to change the path to the database). function _beet_field_values() { local -a output fieldvals local library="$(beet config|grep library|cut -f 2 -d ' ')" - if [ -z "$library" ]; then - # Use default library location if there is no user defined one - library="~/.config/beets/library.db" - fi output=$(sqlite3 ${~library} "select distinct $1 from items;") case $1 in @@ -54,7 +69,7 @@ query=( \( "$matchquery" ":query:query string:{_beet_query}" \) \( "$matchquery" modify=( \( "$matchmodify" ":modify:modify string:$modifyelem" \) \( "$matchmodify" ":modify:modify string:$modifyelem" \) \# ) # arguments to _regex_arguments for completing files and directories -local -a files dirs +local -a files dirs files=("$matchany" ':file:file:_files') dirs=("$matchany" ':dir:directory:_dirs') @@ -86,7 +101,7 @@ retagopt='-L:retag items matching a query:${query[@]}' skipopt='-i:skip already-imported directories' noskipopt='-I:do not skip already-imported directories' flatopt='--flat:import an entire tree as a single album' -groupopt='-g:group tracks in a folder into seperate albums' +groupopt='-g:group tracks in a folder into seperate albums' editopt='-e:edit user configuration with $EDITOR' defaultopt='-d:include the default configuration' copynomoveopt='-c:copy instead of moving' @@ -106,45 +121,45 @@ function _beet_subcmd_options() regex_words=() for i in ${${(f)"$(beet help $1 | awk '/^ +-/{if(x)print x;x=$0;next}/^ *$/{if(x) exit}{if(x) x=x$0}END{print x}')"}[@]} do - shortopt="${i[(w)1]/,/}" - optarg="${$(echo ${i[(w)2]}|grep -o '[A-Z]\+')[(w)1]}" - optdesc="${${${${${i[(w)2,-1]/[A-Z, ]#--[a-z]##[=A-Z]# #/}//:/-}//\[/(}//\]/)}//\'/}" + opt="${i[(w)1]/,/}" + optarg="${${${i## #[-a-zA-Z]# }##[- ]##*}%%[, ]*}" + optdesc="${${${${${i[(w)2,-1]/[A-Z, ]#--[-a-z]##[=A-Z]# #/}//:/-}//\[/(}//\]/)}//\'/}" case $optarg in ("") - if [[ "$1" == "import" && "$shortopt" == "-L" ]]; then - regex_words+=("$shortopt:$optdesc:\${query[@]}") + if [[ "$1" == "import" && "$opt" == "-L" ]]; then + regex_words+=("$opt:$optdesc:\${query[@]}") else - regex_words+=("$shortopt:$optdesc") + regex_words+=("$opt:$optdesc") fi ;; (LOG) - regex_words+=("$shortopt:$optdesc:\$files") + regex_words+=("$opt:$optdesc:\$files") ;; (CONFIG) local -a configfile configfile=("$matchany" ':file:config file:{_files -g *.yaml}') - regex_words+=("$shortopt:$optdesc:\$configfile") + regex_words+=("$opt:$optdesc:\$configfile") ;; (LIB|LIBRARY) local -a libfile libfile=("$matchany" ':file:database file:{_files -g *.db}') - regex_words+=("$shortopt:$optdesc:\$libfile") + regex_words+=("$opt:$optdesc:\$libfile") ;; (DIR|DIRECTORY) - regex_words+=("$shortopt:$optdesc:\$dirs") + regex_words+=("$opt:$optdesc:\$dirs") ;; (SOURCE) if [[ $1 -eq lastgenre ]]; then local -a lastgenresource lastgenresource=(/$'(artist|album|track)\0'/ ':source:genre source:(artist album track)') - regex_words+=("$shortopt:$optdesc:\$lastgenresource") + regex_words+=("$opt:$optdesc:\$lastgenresource") else - regex_words+=("$shortopt:$optdesc:\$matchany") + regex_words+=("$opt:$optdesc:\$matchany") fi ;; (*) - regex_words+=("$shortopt:$optdesc:\$matchany") + regex_words+=("$opt:$optdesc:\$matchany") ;; esac done @@ -154,20 +169,21 @@ function _beet_subcmd_options() # Now build the arguments to _regex_arguments for each subcommand. local -a options regex_words_subcmds regex_words_help local subcmd cmddesc -for i in ${${(f)"$(beet help | awk 'f;/Commands:/{f=1}' | grep '^ \w.*')"[@]}[@]} +for i in ${${(f)"$(beet help | _join_lines ' ' 3 'Commands:')"[@]}[@]} do subcmd="${i[(w)1]}" + # remove first word and parenthesised alias, replace : with -, [ with (, ] with ), and remove single quotes cmddesc="${${${${${i[(w)2,-1]##\(*\) #}//:/-}//\[/(}//\]/)}//\'/}" case $subcmd in (config) - _regex_words options "config options" "$helpopt" "$pathopt" "$editopt" "$defaultopt" + _regex_words options "config options" "$helpopt" "$pathopt" "$editopt" "$defaultopt" options=("${reply[@]}") ;; (import) - _regex_words options "import options" "$helpopt" "$writeopt" "$nowriteopt" "$copyopt" "$nocopyopt" "$inferopt" \ - "$noinferopt" "$resumeopt" "$noresumeopt" "$nopromptopt" "$logopt" "$individualopt" "$confirmopt" "$retagopt" \ - "$skipopt" "$noskipopt" "$flatopt" "$groupopt" + _regex_words options "import options" "$helpopt" "$writeopt" "$nowriteopt" "$copyopt" "$nocopyopt"\ + "$inferopt" "$noinferopt" "$resumeopt" "$noresumeopt" "$nopromptopt" "$logopt" "$individualopt" "$confirmopt"\ + "$retagopt" "$skipopt" "$noskipopt" "$flatopt" "$groupopt" options=( "${reply[@]}" \# "${files[@]}" \# ) ;; (list) @@ -188,7 +204,7 @@ do options=( "${reply[@]}" \# "${query[@]}" ) ;; (stats) - _regex_words options "stats options" "$helpopt" "$exactopt" + _regex_words options "stats options" "$helpopt" "$exactopt" options=( "${reply[@]}" \# "${query[@]}" ) ;; (update) @@ -204,9 +220,9 @@ do ;; (help) # The help subcommand is treated separately - continue + continue ;; - (*) # completions for plugin commands are generated using _beet_subcmd_options + (*) # completions for plugin commands are generated using _beet_subcmd_options _beet_subcmd_options "$subcmd" options=( \( "${reply[@]}" \# "${query[@]}" \) ) ;; @@ -241,6 +257,6 @@ zstyle ":completion:${curcontext}:" tag-order '! options' # Execute the completion function _beet "$@" -# Local Variables: +# Local Variables: # mode:shell-script # End: