completions/git: cache subcommand computation

Whenever completing any git commandline, we invoke __fish_git_using_command
173 times*. Every invocation calls "commandline" and "argparse"
to the same effect. Let's parse the command line once, and reuse the results
later.

I'm observing a speed-up from 200ms to 120ms with

    perf stat -r 10 buildrel/fish -c 'complete -C "git checkout ">/dev/null'

Alternative solutions:
1. teach fish to cache such things automatically.
2. rewrite git completions to compute most completions in a single function,
   which will naturally avoid redundant work. This sounds viable but it's
   a lot of work.

* we have a thousand uses of __fish_git_using_command, so I'm not sure why
it's only 173.

See the discussion in #8266
This commit is contained in:
Johannes Altmanninger 2022-04-30 15:57:07 +02:00
parent ca98325462
commit ad9b4290e5

View file

@ -558,25 +558,6 @@ function __fish_git_ranges
end
end
function __fish_git_needs_command
# Figure out if the current invocation already has a command.
set -l cmd (commandline -opc)
set -e cmd[1]
argparse -s (__fish_git_global_optspecs) -- $cmd 2>/dev/null
or return 0
# These flags function as commands, effectively.
set -q _flag_version; and return 1
set -q _flag_html_path; and return 1
set -q _flag_man_path; and return 1
set -q _flag_info_path; and return 1
if set -q argv[1]
# Also print the command, so this can be used to figure out what it is.
echo $argv[1]
return 1
end
return 0
end
function __fish_git_config_keys
# Print already defined config values first
# Config keys may span multiple lines, so parse using null char
@ -628,19 +609,12 @@ git config -z --get-regexp 'alias\..*' | while read -lz alias cmdline
set -g __fish_git_alias_$alias $command $cmdline
end
function __fish_git_using_command
set -l cmd (__fish_git_needs_command)
test -z "$cmd"
and return 1
contains -- $cmd $argv
and return 0
function __fish_git_needs_command
$__fish_git_needs_command
end
# Check aliases.
set -l varname __fish_git_alias_(string escape --style=var -- $cmd)
set -q $varname
and contains -- $$varname[1][1] $argv
and return 0
return 1
function __fish_git_using_command
contains $__fish_git_subcommand $argv
end
function __fish_git_contains_opt
@ -651,10 +625,8 @@ function __fish_git_contains_opt
# Now check the alias
argparse s= -- $argv
set -l cmd (__fish_git_needs_command)
set -l varname __fish_git_alias_(string escape --style=var -- $cmd)
if set -q $varname
echo -- $$varname | read -lat toks
if set -q __fish_git_expanded_alias[1]
echo -- $__fish_git_expanded_alias | read -lat toks
set toks (string replace -r '(-.*)=.*' '' -- $toks)
for i in $argv
if contains -- --$i $toks
@ -2208,3 +2180,29 @@ for file in $PATH/git-*
complete -c git -f -n "__fish_git_using_command $subcommand" -a "(__fish_git_complete_custom_command $subcommand)"
set -a __fish_git_custom_commands_completion $subcommand
end
complete -c git -f -a '(
set -g __fish_git_needs_command true
set -g __fish_git_subcommand ""
set -g __fish_git_expanded_alias
set -l cmd (commandline -opc)
set -e cmd[1]
argparse -s (__fish_git_global_optspecs) -- $cmd 2>/dev/null
or return
if set -q argv[1] || set -q _flag_version || set -q _flag_html_path || set -q _flag_man_path || set -q _flag_info_path
set __fish_git_needs_command false
end
if set -q argv[1]
set -l subcommand $argv[1]
# TODO Expand recursive aliases.
set -l varname __fish_git_alias_(string escape --style=var -- $subcommand)
if set -q $varname
set -g __fish_git_expanded_alias $$varname
set subcommand $__fish_git_expanded_alias[1]
end
set -g __fish_git_subcommand "$subcommand"
end
)'