diff --git a/television/utils/shell/completion.fish b/television/utils/shell/completion.fish index 97fd9a2..7a85350 100644 --- a/television/utils/shell/completion.fish +++ b/television/utils/shell/completion.fish @@ -1,15 +1,118 @@ -function tv_smart_autocomplete - # prefix (lhs of cursor) - set -l current_prompt (commandline -cp) +function __tv_parse_commandline --description 'Parse the current command line token and return split of existing filepath, and tv query' + # credits to the junegunn/fzf project + # https://github.com/junegunn/fzf/blob/9c1a47acf7453f9dad5905b7f23ad06e5195d51f/shell/key-bindings.fish#L53-L131 - set -l output (tv --autocomplete-prompt "$current_prompt") + set -l tv_query '' + set -l prefix '' + set -l dir '.' - if test -n "$output" - # add a space if the prompt does not end with one (unless the prompt is an implicit cd, e.g. '\.') - string match -q -r '.*( |./)$' -- "$current_prompt" || set output " $output" - commandline -i "$output" - commandline -f repaint + # Set variables containing the major and minor fish version numbers, using + # a method compatible with all supported fish versions. + set -l -- fish_major (string match -r -- '^\d+' $version) + set -l -- fish_minor (string match -r -- '^\d+\.(\d+)' $version)[2] + + # fish v3.3.0 and newer: Don't use option prefix if " -- " is preceded. + set -l -- match_regex '(?[\s\S]*?(?=\n?$)$)' + set -l -- prefix_regex '^-[^\s=]+=|^-(?!-)\S' + if test "$fish_major" -eq 3 -a "$fish_minor" -lt 3 + or string match -q -v -- '* -- *' (string sub -l (commandline -Cp) -- (commandline -p)) + set -- match_regex "(?$prefix_regex)?$match_regex" end + + # Set $prefix and expanded $tv_query with preserved trailing newlines. + if test "$fish_major" -ge 4 + # fish v4.0.0 and newer + string match -q -r -- $match_regex (commandline --current-token --tokens-expanded | string collect -N) + else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2 + # fish v3.2.0 - v3.7.1 (last v3) + string match -q -r -- $match_regex (commandline --current-token --tokenize | string collect -N) + eval set -- tv_query (string escape -n -- $tv_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)' '') + else + # fish older than v3.2.0 (v3.1b1 - v3.1.2) + set -l -- cl_token (commandline --current-token --tokenize | string collect -N) + set -- prefix (string match -r -- $prefix_regex $cl_token) + set -- tv_query (string replace -- "$prefix" '' $cl_token | string collect -N) + eval set -- tv_query (string escape -n -- $tv_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)|\\\n\\\n$' '') + end + + if test -n "$tv_query" + # Normalize path in $tv_query, set $dir to the longest existing directory. + if test \( "$fish_major" -ge 4 \) -o \( "$fish_major" -eq 3 -a "$fish_minor" -ge 5 \) + # fish v3.5.0 and newer + set -- tv_query (path normalize -- $tv_query) + set -- dir $tv_query + while not path is -d $dir + set -- dir (path dirname $dir) + end + else + # fish older than v3.5.0 (v3.1b1 - v3.4.1) + if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2 + # fish v3.2.0 - v3.4.1 + string match -q -r -- '(?^[\s\S]*?(?=\n?$)$)' \ + (string replace -r -a -- '(?<=/)/|(?[\s\S]*)' $tv_query + else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2 + # fish v3.2.0 - v3.7.1 (last v3) + string match -q -r -- '^/?(?[\s\S]*?(?=\n?$)$)' \ + (string replace -- "$dir" '' $tv_query | string collect -N) + else + # fish older than v3.2.0 (v3.1b1 - v3.1.2) + set -- tv_query (string replace -- "$dir" '' $tv_query | string collect -N) + eval set -- tv_query (string escape -n -- $tv_query | string replace -r -a '^/?|\\\n$' '') + end + end + end + + # Ensure $dir ends with a slash if it's a directory + if test -d "$dir"; and not string match -q '*/$' -- $dir + set dir "$dir/" + end + + string escape -n -- "$dir" "$tv_query" "$prefix" + +end + +function tv_smart_autocomplete + set -l commandline (__tv_parse_commandline) + set -lx dir $commandline[1] + set -l tv_query $commandline[2] + + # prefix (lhs of cursor) + set -l current_prompt (commandline --current-process) + + if set -l result (tv $dir --autocomplete-prompt "$current_prompt" --input $tv_query) + # Remove last token from commandline. + commandline -t '' + + # If dir is the current directory, i.e. './' , clear it. + # If the pattern './foo' './bar' instead of 'foo' 'bar' is desired then comment out the check below + if test "$dir" = "./" + set dir "" + end + + for i in $result + commandline -it -- $dir(string escape -- $i)' ' + # optional, if you want to replace '/home/foo/' with '~/', comment out above and uncomment below + # commandline -it -- $dir(string replace --all $HOME '~' (string escape -- $i))' ' + end + end + + commandline -f repaint end function tv_shell_history