[git completions] Use status v1 output

Apparently the v2 format is too new (released Nov 2016), and the v1
format has everything we need.
This commit is contained in:
Fabian Homborg 2018-01-26 10:28:40 +01:00
parent 64c8d4c265
commit 4fac2f98c2

View file

@ -84,19 +84,17 @@ function __fish_git_files
# to get _all_ kinds of staged files.
# git status --porcelain gives us all the info we need, in a format we don't.
# The v2 format thankfully doesn't use " M" to denote a changed unstaged file
# and "M " to denote a changed staged file, opting for a "." in place of the space.
# So the v1 format would require something other than this `while read` loop.
#
# Unfortunately, the v2 format is really 4 different subformats
# - see the explanation inline. (Or on https://git-scm.com/docs/git-status)
# The v2 format has better documentation and doesn't use " " to denote anything,
# but it's only been added in git 2.11.0, which was released November 2016.
# Instead, we use the v1 format, without explicitly specifying it (since that errors out as well).
#
# Also, we ignore submodules because they aren't useful as arguments (generally),
# and they slow things down quite significantly.
# E.g. `git reset $submodule` won't do anything (not even print an error).
# --ignore-submodules=all was added in git 1.7.2, released July 2010.
set -l use_next
command git status --porcelain=2 -z --ignore-submodules=all \
| while read -laz -d ' ' line
command git status --porcelain -z --ignore-submodules=all \
| while read -lz -d '' line
# The entire line is the "from" from a rename.
if set -q use_next[1]
contains -- $use_next $argv
@ -105,67 +103,66 @@ function __fish_git_files
continue
end
# The format is two characters for status, then a space and then
# up to a NUL for the filename.
#
# Use IFS to handle newlines in filenames.
set -l IFS
set -l stat (string sub -l 2 -- $line)
set -l file (string sub -s 4 -- $line)
set -e IFS
# The basic status format is "XY", where X is "our" state (meaning the staging area),
# and "Y" is "their" state.
# A "." means it's unmodified.
switch "$line[1..2]"
case 'u *'
# and "Y" is "their" state (meaning the work tree).
# A " " means it's unmodified.
switch "$stat"
case DD AU UD UA DU AA UU
# Unmerged
# "Unmerged entries have the following format; the first character is a "u" to distinguish from ordinary changed entries."
# "u <xy> <sub> <m1> <m2> <m3> <mW> <h1> <h2> <h3> <path>"
# This is first to distinguish it from normal modifications et al.
contains -- unmerged $argv
and printf '%s\t%s\n' "$line[11..-1]" (_ "Unmerged file")
case '? .R*' '? R.*'
and printf '%s\t%s\n' "$file" (_ "Unmerged file")
case 'R ' RM RD
# Renamed/Copied
# From the docs: "Renamed or copied entries have the following format:"
# "2 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <X><score> <path><sep><origPath>"
# Since <sep> is NUL, the <origPath> (meaning the old name) is in the next batch.
# TODO: Do we care about the new one?
# These have the "from" name as the next batch.
# TODO: Do we care about the new name?
set use_next renamed
continue
case '? .C*' '? C.*'
case 'C ' CM CD
set use_next copied
continue
case '? A.*'
case 'A ' AM AD
# Additions are only shown here if they are staged.
# Otherwise it's an untracked file.
contains -- added $argv; or contains -- all-staged $argv
and printf '%s\t%s\n' "$line[9..-1]" (_ "Added file")
case '? .M*'
and printf '%s\t%s\n' "$file" (_ "Added file")
case '?M'
# Modified
# From the docs: "Ordinary changed entries have the following format:"
# "1 <XY> <sub> <mH> <mI> <mW> <hH> <hI> <path>"
# Since <path> can contain spaces, print from element 9 onwards
contains -- modified $argv
and printf '%s\t%s\n' "$line[9..-1]" (_ "Modified file")
case '? M.*'
# If the character is first ("M."), then that means it's "our" change,
and printf '%s\t%s\n' "$file" (_ "Modified file")
case 'M?'
# If the character is first ("M "), then that means it's "our" change,
# which means it is staged.
# This is useless for many commands - e.g. `checkout` won't do anything with this.
# So it needs to be requested explicitly.
contains -- modified-staged $argv; or contains -- all-staged $argv
and printf '%s\t%s\n' "$line[9..-1]" (_ "Staged modified file")
case '? .D*'
and printf '%s\t%s\n' "$file" (_ "Staged modified file")
case '?D'
contains -- deleted $argv
and printf '%s\t%s\n' "$line[9..-1]" (_ "Deleted file")
case '? D.*'
and printf '%s\t%s\n' "$file" (_ "Deleted file")
case 'D?'
# TODO: The docs are unclear on this.
# There is both X unmodified and Y either M or D ("not updated")
# and Y is D and X is unmodified or [MARC] ("deleted in work tree").
# For our purposes, we assume this is a staged deletion.
contains -- deleted-staged $argv; or contains -- all-staged $argv
and printf '%s\t%s\n' "$line[9..-1]" (_ "Staged deleted file")
case '\? *'
and printf '%s\t%s\n' "$file" (_ "Staged deleted file")
case '\?\?'
# Untracked
# "? <path>" - print from element 2 on.
contains -- untracked $argv
and printf '%s\t%s\n' "$line[2..-1]" (_ "Untracked file")
case '! *'
and printf '%s\t%s\n' "$file" (_ "Untracked file")
case '!!'
# Ignored
# "! <path>" - print from element 2 on.
contains -- ignored $argv
and printf '%s\t%s\n' "$line[2..-1]" (_ "Ignored file")
and printf '%s\t%s\n' "$file" (_ "Ignored file")
end
end
end