diff options
Diffstat (limited to 'Completion')
-rw-r--r-- | Completion/Base/Utility/_regex_arguments | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/Completion/Base/Utility/_regex_arguments b/Completion/Base/Utility/_regex_arguments new file mode 100644 index 000000000..635cd0e5f --- /dev/null +++ b/Completion/Base/Utility/_regex_arguments @@ -0,0 +1,93 @@ +#autoload + +## usage: _regex_arguments funcname regex + +## configuration key used: + +# regex_arguments_path +# The path to a directory for caching. (default: ~/.zsh/regex_arguments) + +## + +# _regex_arguments compiles `regex' and emit the result of the state +# machine into the function `funcname'. `funcname' parses a command line +# according to `regex' and evaluate appropriate actions in `regex'. Before +# parsing the command line string is genereted by concatinating `words' +# (before `PREFIX') and `PREFIX' with a separator NUL ($'\0'). + +# The `regex' is defined as follows. + +## regex word definition: + +# pattern = "/" ( glob | "[]" ) "/" [ "+" | "-" ] +# lookahead = "%" glob "%" +# guard = "-" zsh-code-to-eval +# caction = ":" tag ":" descr ":" zsh-code-to-eval +# action = "{" zsh-code-to-eval "}" + +## regex word sequence definition: + +# element = pattern [ lookahead ] [ guard ] [ caction ] +# +# regex = element +# | "(" regex ")" +# | regex "#" +# | ( regex | action ) # +# | regex "|" regex + +# example: + +# compdef _tst tst + +# _regex_arguments _tst /$'[^\0]#\0'/ /$'[^\0]#\0'/ :'compadd aaa' +# _tst complete `aaa' for first argument. +# First $'[^\0]#\0' is required to match with command name. + +# _regex_arguments _tst /$'[^\0]#\0'/ \( /$'[^\0]#\0'/ :'compadd aaa' /$'[^\0]#\0'/ :'compadd bbb' \) \# +# _tst complete `aaa' for (2i+1)th argument and `bbb' for (2i)th argument. + +# _regex_arguments _tst /$'[^\0]#\0'/ \( /$'[^\0]#\0'/ :'compadd aaa' \| /$'[^\0]#\0'/ :'compadd bbb' \) \# +# _tst complete `aaa' or `bbb'. + +## Recursive decent regex parser + +# return status of parser functions: + +# 0 : success +# 1 : parse error +# 2 : fatal parse error + +_ra_comp () { + _ra_actions=("$_ra_actions[@]" "$1") +} + +_regex_arguments () { + local regex funcname="$1" + shift + regex=(${@:/(#b):(*)/":_ra_comp ${(qqqq)match[1]}"}) + + eval \ + "$funcname"' () { + local _ra_p1 _ra_p2 _ra_left _ra_right _ra_com expl tmp nm="$compstate[nmatches]" + local _ra_actions _ra_line="${(pj:\0:)${(@)words[1,CURRENT - 1]:Q}}"$'\''\0'\''"$PREFIX" + _ra_actions=() + zregexparse -c _ra_p1 _ra_p2 "$_ra_line" '"${(j: :)${(qqqq)regex[@]}}"' + case "$?" in + 0|2) _message "no more arguments";; + 1) + if [[ "$_ra_line[_ra_p1 + 1, -1]" = *$'\''\0'\''* ]]; then + _message "parse failed before current word" + else + _ra_left="$_ra_line[_ra_p1 + 1, _ra_p2]" + _ra_right="$_ra_line[_ra_p2 + 1, -1]" + compset -p $(( $#PREFIX - $#_ra_line + $_ra_p1 )) + (( $#_ra_actions )) && _alternative "$_ra_actions[@]" + fi + ;; + 3) _message "invalid regex";; + esac + [[ nm -ne "$compstate[nmatches]" ]] + }' +} + +_regex_arguments "$@" |