completions/git: Handle untracked files separately

This uses `git ls-files`, which has a simpler format (just the
filenames on separate lines), in order to print the untracked files.

This allows us to skip them in the `git status` call, which reduces
the output a lot and removes two `string match`.

In a repository with over half a million files (my home directory, if
I made it one), this improves time by a third (12s to 8s).

In a smaller repo (fish-shell) it's barely measurable.
This commit is contained in:
Fabian Boehm 2025-01-27 18:19:18 +01:00
parent 514f4b9e23
commit 4370fb755d

View File

@ -166,11 +166,6 @@ function __fish_git_files
# (don't use --ignored=no because that was only added in git 2.16, from Jan 2018.
set -q ignored; and set -a status_opt --ignored
# If we're looking for untracked files, we give untracked files even inside untracked directories.
# This makes it nicer if e.g. you're in an untracked directory and want to just add one file.
set -q untracked; and set -a status_opt -uall
or set -a status_opt -uno
# We need to set status.relativePaths to true because the porcelain v2 format still honors that,
# and core.quotePath to false so characters > 0x80 (i.e. non-ASCII) aren't considered special.
# We explicitly enable globs so we can use that to match the current token.
@ -192,12 +187,11 @@ function __fish_git_files
# Version >= 2.11.* has the v2 format.
if test "$ver[1]" -gt 2 2>/dev/null; or test "$ver[1]" -eq 2 -a "$ver[2]" -ge 11 2>/dev/null
set -l fish_read_limit 0 # this can print a lot, better not to error
set -l stats (__fish_git $git_opt status --porcelain=2 $status_opt)
set -l stats (__fish_git $git_opt status --porcelain=2 -uno $status_opt)
if set -ql untracked
# Fast path for untracked files - it is extremely easy to get a lot of these,
# so we handle them first
set -l files (string match -rg '^\? "?(.*)"?' -- $stats)
set stats (string match -rv '^\? ' -- $stats)
# so we handle them separately.
set -l files (__fish_git $git_opt ls-files -o --exclude-standard)
printf "$rel%s\n" $files\t$untracked_desc
if set -ql colon[1]
or set files (string match '../*' -- $files)