From 0ea670366183723a96fcb18aa25d9766c3649b83 Mon Sep 17 00:00:00 2001 From: Fabian Boehm Date: Tue, 7 Jun 2022 20:10:13 +0200 Subject: [PATCH] completions/git: Terminate pathspec magic Git's pathspec system is kind of annoying: > A pathspec that begins with a colon : has special meaning. In the short form, the leading colon : is followed by zero or more "magic signature" letters (which optionally is terminated by another colon :), and the remainder is the pattern to match against the path. The "magic signature" consists of ASCII symbols that are neither alphanumeric, glob, regex special characters nor colon. The optional colon that terminates the "magic signature" can be omitted if the pattern begins with a character that does not belong to "magic signature" symbol set and is not a colon. So if we complete `:/foo`, that "works" because "f" is alphanumeric and so the "/" is the only magic character here. If, however the filename starts with a magic character, that's used as a magic signature. So we do what the docs say and terminate the magic signature after the "/" (which means "from the repo root"). Fixes #9004 --- share/completions/git.fish | 10 +++++++--- tests/checks/git.fish | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/share/completions/git.fish b/share/completions/git.fish index 95dc605e9..35cd87faa 100644 --- a/share/completions/git.fish +++ b/share/completions/git.fish @@ -342,7 +342,11 @@ function __fish_git_files if string match -q '../*' -- $file or string match -q ':*' -- (commandline -ct) set -l fromroot (builtin realpath -- $file 2>/dev/null) - and set fromroot (string replace -- "$root/" ":/" "$fromroot") + # `:` starts pathspec "magic", and the second `:` terminates it. + # `/` is the magic letter for "from repo root". + # If we didn't terminate it we'd have to escape any special chars + # (non-alphanumeric, glob or regex special characters, in whatever dialect git uses) + and set fromroot (string replace -- "$root/" ":/:" "$fromroot") and printf '%s\t%s\n' "$fromroot" $d end end @@ -476,10 +480,10 @@ function __fish_git_files end set -a file (string join / -- $previous) - # The filename with ":/" prepended. + # The filename with ":/:" prepended. if string match -q '../*' -- $file or string match -q ':*' -- (commandline -ct) - set file (string replace -- "$root/" ":/" "$root/$relfile") + set file (string replace -- "$root/" ":/:" "$root/$relfile") end if test "$root/$relfile" = (pwd -P)/$relfile diff --git a/tests/checks/git.fish b/tests/checks/git.fish index de7403baf..324c5ce28 100644 --- a/tests/checks/git.fish +++ b/tests/checks/git.fish @@ -40,6 +40,9 @@ touch foo complete -C'git add ' #CHECK: foo Untracked file +complete -C'git add :' +#CHECK: :/:foo Untracked file + git config alias.s status complete 'git s --s' # CHECK --short