From 6c5e5d35a9fa22474930144457e8842ef071cbeb Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Tue, 17 Apr 2018 14:56:42 -0500 Subject: [PATCH] Add real completions for ./configure This relies on the new `read --line/-L` support as an entire parser for the output of `./configure --help` was written in fishscript. Also doesn't work without 72f32e6d8a7905b064680ec4b578c41dea62bf84. The completion script is slow... a function of both the autotools configure script itself being written in a shell script combined with a fishscript output parser. fish's own `./configure --help` takes around 350ms to execute, while `__fish_parse_configure ./configure` (which runs that behind the scenes) takes around 660ms to run, all-in-all - a not insignificant overhead. Output can be cached (based off of ./configure hash or mtime) in the future if this is a big deal. --- CHANGELOG.md | 7 ++- share/completions/configure.fish | 4 ++ share/functions/__fish_parse_configure.fish | 62 +++++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 share/functions/__fish_parse_configure.fish diff --git a/CHANGELOG.md b/CHANGELOG.md index 42c1d56fa..0c374498c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,17 +59,18 @@ This section is for changes merged to the `major` branch that are not also merge ## Other significant changes - Command substitution output is now limited to 10 MB by default (#3822). - Added completions for - - `j` (autojump #4344) - `bd` (#4472) + - `configure` + - `j` (autojump #4344) - `jhipster` (#4472) - `ngrok` (#4642)  - `port` - Improved completions for - - `git` (#4395, #4396, #4592) - `brew` - `diskutil` - - `yarn` + - `git` (#4395, #4396, #4592) - `ssh` (#4344) + - `yarn` -- diff --git a/share/completions/configure.fish b/share/completions/configure.fish index cd85dc6d8..f431f7db1 100644 --- a/share/completions/configure.fish +++ b/share/completions/configure.fish @@ -10,3 +10,7 @@ complete -c configure -l exec-prefix -d "Architecture-dependent install director complete -c configure -l build -d "Configure for building on BUILD" -x complete -c configure -l host -d "Cross-compile to build programs to run on HOST" -x complete -c configure -l target -d "Configure for building compilers for TARGET" -x + +# use autoconf's --help to generate completions: +echo "sourcing configure completions" +complete -c 'configure' -a '(__fish_parse_configure (commandline | string replace -r "(.*configure) .*" "\$1"))' diff --git a/share/functions/__fish_parse_configure.fish b/share/functions/__fish_parse_configure.fish new file mode 100644 index 000000000..7fcb44dfe --- /dev/null +++ b/share/functions/__fish_parse_configure.fish @@ -0,0 +1,62 @@ +function __fish_parse_configure + if test (count $argv) -ne 1 + echo "Usage: parse_configure path/to/configure" 1>&2 + return 1 + end + + # `complete` parses `./configure` as `configure` so we have to handle all paths, not just ./ + if not test -x $argv[1] + printf "Cannot find or execute '%s'\n" $argv[1] 1>&2 + return 1 + end + +# Must support output along the lines of +# -h, --help display this help and exit +# --help=short display options specific to this package +# --help=recursive display the short help of all the included packages +# -V, --version display version information and exit +# -q, --quiet, --silent do not print `checking ...' messages + + set -l next_line + set -l line + set -l buffer + eval $argv[1] --help 2>/dev/null | while test (string length -- "$next_line") -gt 0 || read -lL next_line + # In autoconfigure scripts, the first column wraps at 26 chars + # echo next_line: $next_line + # echo old_line: $line + if test (string length -- "$line") -eq 0 + set line $next_line + set next_line "" # mark it as consumed + continue + else if string match -qr '^( |\t){2,}[^-]\S*' -- $next_line + # echo "continuation line found. Old value of line: " \"$line\" + set line "$line "(string trim $next_line) + set next_line "" # mark it as consumed + continue + end + + # echo line: $line + + # Search for one or more strings starting with `-` separated by commas + if string replace -fr '^\s+(-.*?)\s+([^\s\-].*)' '$1\n$2' -- $line | read -lL opts description + for opt in (string split -n , -- $opts | string trim) + + if string match -qr -- '--.*=\[.*\]' $opt + # --option=[OPTIONAL_VALUE] + string replace -r -- '(--.*)=.*' '$1' $opt | read opt + else if string match -qr -- '--.*=[A-Z]+' $opt + # --option=CLASS_OF_VALUE (eg FILE or DIR) + string replace -r -- '(--.*)=.*' '$1' $opt | read opt + else if string match -qr -- '--.*=\S+' $opt + # --option=literal_value, leave as-is + else if string match -qr -- '-[^-]\b' $opt + # short option, leave as-is + end + + echo "$opt"\t"$description" # parsed by `complete` as value and description + end + end + + set line "" + end +end