bashタブの完成:gitコマンドの単一のタブのフルパス?

bashタブの完成:gitコマンドの単一のタブのフルパス?

たとえば、bashのgitコマンドの後にファイルパスを完成させるには、タブを押すたびにファイル内のサブフォルダの数に応じて実際のファイル名を完了するために複数回押す必要がありますgit add<TAB>

例: ファイルを追加し、次のようにmy/example/file入力したいと思います。

git add <TAB>
git add my/<TAB>
git add my/example/<TAB>
git add my/example/file

my/example/fileこれは変更された唯一のファイルでも同様であるため、現在利用可能な唯一のタブ補完オプションです。この場合、bashは最初のパスでフルパスを完了できますが、<TAB>そうではありません。

これは実際には基本的に行われます。

git add <TAB>
git add my/example/file

Bashでこの動作を設定する方法はありますか?

私は基本的なbash完成を使用してUbuntu 20.04を使用しています。

ベストアンサー1

これを達成する1つの方法は、git補完スクリプトをコピーし、完全な /usr/share/bash-completion/completions/gitインデックス ~/.local/share/bash-completion/completions/パス補完を使用するように変更することです。

mkdir -p ~/.local/share/bash-completion/completions
cd ~/.local/share/bash-completion/completions

cp /usr/share/bash-completion/completions/git .

# See diff below
patch -lp0 </tmp/index_paths.diff
echo GIT_COMPLETION_FULL_INDEX_PATHS=1 >>~/.bashrc

exec bash

私が知る限り、必要な変更は次のとおりです。

  1. __git_index_files()最初のパスコンポーネントだけでなく、フルインデックスパスを出力するように変更します。

  2. では set を使用するので、デフォルト名だけを出力するので__git_complete_index_file()使用を中止します。このオプションはシェルの引用も処理するので、今は手動で実行してください。__gitcomp_file_directCOMPREPLYcompopt -o filenames

__git_complete_index_file、、、および他のいくつかのgitコマンドを完了するために使用されるため、フルパスadd補完cleanはそのコマンドでも機能します。シェル変数の後に機能を追加するこれらの変更の試みの違いは次のとおりです。commitrmGIT_COMPLETION_FULL_INDEX_PATHS

--- git
+++ git
@@ -39,6 +39,11 @@
 #     When set to "1", do not include "DWIM" suggestions in git-checkout
 #     and git-switch completion (e.g., completing "foo" when "origin/foo"
 #     exists).
+#
+#   GIT_COMPLETION_FULL_INDEX_PATHS
+#
+#     Normally index path completions return only the next path component. When
+#     set to "1", the whole path will be completed.
 
 case "$COMP_WORDBREAKS" in
 *:*) : great ;;
@@ -435,6 +440,19 @@
    __gitcomp_nl_append "$@"
 }
 
+# Shell quotes each word and fills the COMPREPLY array.
+# 1: List of newline-separated completion words.
+__gitcomp_quote_direct ()
+{
+   local IFS=$'\n'
+   local quoted="$1"
+   [[ -n $1 ]] && quoted=$(printf '%q\n' $1)
+
+   COMPREPLY=($quoted)
+
+   compopt +o nospace 2>/dev/null || true
+}
+
 # Fills the COMPREPLY array with prefiltered paths without any additional
 # processing.
 # Callers must take care of providing only paths that match the current path
@@ -503,10 +521,12 @@
 __git_index_files ()
 {
    local root="$2" match="$3"
+   local field=1
+   [ "$GIT_COMPLETION_FULL_INDEX_PATHS" = "1" ] && field=0
 
    __git_ls_files_helper "$root" "$1" "$match" |
    awk -F / -v pfx="${2//\\/\\\\}" '{
-       paths[$1] = 1
+       paths[$f] = 1
    }
    END {
        for (p in paths) {
@@ -518,19 +538,13 @@
 
            # The path is quoted.
            p = dequote(p)
-           if (p == "")
-               continue
 
-           # Even when a directory name itself does not contain
-           # any special characters, it will still be quoted if
-           # any of its (stripped) trailing path components do.
-           # Because of this we may have seen the same directory
-           # both quoted and unquoted.
-           if (p in paths)
-               # We have seen the same directory unquoted,
-               # skip it.
-               continue
-           else
+           # When not using full index paths, p in paths is checked
+           # because the dequoted directory name may already be in
+           # paths. This is the case when the directory name itself
+           # does not contain special characters, but a (stripped)
+           # trailing path component does.
+           if (p != "" && (f == 0 || !(p in paths)))
                print pfx p
        }
    }
@@ -573,7 +587,7 @@
            out = out p
 
        return out
-   }'
+   }' "f=$field"
 }
 
 # __git_complete_index_file requires 1 argument:
@@ -595,7 +609,11 @@
        cur_="$dequoted_word"
    esac
 
-   __gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
+   if [ "$GIT_COMPLETION_FULL_INDEX_PATHS" = "1" ]; then
+       __gitcomp_quote_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
+   else
+       __gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")"
+   fi
 }
 
 # Lists branches from the local repository.

おすすめ記事