ぽらろいどの日記

新しい知見を得たり、得られた知見を記録したり共有したりする場を予定しています。

bash-completion:Git & Bashが古いけど、タブ補完したいから半ば自作する

作成の動機

ゴール

  • linuxでgitコマンドを補完したい

制限

  • git-completion.bashがあるが、最新はgit --list-cmdsを内部で使うため、Gitは2.18以上である必要がある
  • git、及びbashのバージョンが古く、バージョンアップするのは難しい
  • 適切な古いバージョンのgit-completion.bashを入れるのは難しい

解決案

  • 幾つかのコマンドに対応するだけなら、自力でなんとかできないか?
    • 個人用なので、品質は不問

調査

作成のヒント

結論

スクリプト

  • .bashrcに記載
    • あるいは別ファイルにして読み込む
# 必要なモジュールを読み込む(bash-completion.shの内容は以下のコピー)
# https://github.com/scop/bash-completion/blob/master/bash_completion
. ~/bash-completion.sh

# 補完候補
declare -r GIT_OPT="branch checkout diff"

_git(){
  # cur=入力中の語、prev=一個前に入力した語、cword=入力済みの語数
  local cur prev cword
  local git_checkout_opt

  # cur, prev, cwordに値をセットする
  _init_completion || return 

  case "${cword}" in
    1)
      # COMPREPLYに格納した文字列が、タブ補完される
      # compgenは${GIT_OPT}の内、${cur}から始まるものだけを出力する
      COMPREPLY=( $(compgen -W "${GIT_OPT}" -- "${cur}") )
      ;;
    *)
      if [[ "${prev}" == "checkout" ]]; then
        # 都度ブランチを取得して、補完候補とする
        git_checkout_opt="$(git branch | sed ':a;N;$!ba;s/[\n|*]/ /g' 2>/dev/null)"
        COMPREPLY=( $(compgen -W "${git_checkout_opt}" -- "${cur}") )
      fi
      ;;
  esac
}

# gitコマンド補完の関数として設定
complete -F _git git

拡張予定

  • 他のコマンド例を参考に、モジュールを利用して拡張する
  • 例えば
    1. fileを補完してほしい場合は_filedirを呼ぶ
    2. cur, prev以外に全ての入力を取得したい場合は、_init_completionの前にlocal cur prev words cwordと宣言し、wordsで入力を取得する

まとめ

ひとまずこれでgitコマンドで幾つか補完できるようになった。凝ると余計な時間がかかってしまいそうなので、コスパを考えつつ可能な範囲で拡張していきたい。とはいえ、既に用意されたものをそのまま利用できればそれが一番であることは間違いない……。