bash-completionで独自の補完関数を作成する方法(gistyのサブコマンドを補完するやつ書いてみた)

歳のせいか最近記憶力が落ちてるので補完に頼ってみることにした。

以下を行なうにはbash-completionパッケージが必要です。
macportsだと

sudo port install bash-completion

でインストールされるはず。

バージョン1

とりあえず、サブコマンドを全部登録してみました版

_gisty()
{
    COMPREPLY=(list post private_post sync sync_delete pull_all about help)
}
complete -F _gisty gisty

上記を/opt/local/etc/bash_completion.d/の配下にgistyという名前で保存
以下のように設定ファイルを読み込み

$ . /opt/local/etc/bash_completion

"gisty "と打ってtabを押すと

about         list          private_post  sync          
help          post          pull_all      sync_delete   

と補完候補が表示されるようになる。

ようは、COMPREPLYという変数に補完候補の配列を格納する関数を書くだけで良いということ。
それをshellが拾って補完候補として使用するという仕組み。

バージョン2

ただ、このままだとつねに全ての補完候補が表示されてしまうので、入力した文字の一部で
補完候補を絞り込むようにしてみる。

_gisty() 
{
    COMPREPLY=( $( \
        compgen -W "list post private_post sync sync_delete pull_all about help" \
                ${COMP_WORDS[COMP_CWORD]} \
    ) )
}

compgenという組み込みコマンドを使うと文字列のリストを絞り込むことができる。
このcompgenの最後の引数${COMP_WORDS[COMP_CWORD]}は「現在のカーソル位置のワード」を表している。
COMP_WORDSコマンドラインで入力している文字列を単語の単位で配列にしたもの。
COMP_CWORDはその配列の中での現在位置を表している。

試しにgisty pまで入力してtabを押すと、

post          private_post  pull_all      

という感じで、先頭が"p"で始まるサブコマンドだけが表示される。

これで入力した文字で補完候補を絞り込むことができるようになった。

バージョン3

サブコマンドに応じてファイル名を補完するようにしてみる。
gisty の opst または private_post コマンドはポスト対象のファイル名を受け取るようになっているので、これらのサブコマンドを入力した場合は、ファイル名の補完を行なうようにしてみる。

これを保存/反映したのち、gisty post の後でtab補完してみると、ファイルの一覧が表示されはず。

コードを見てみる。
prev="${COMP_WORDS[COMP_CWORD-1]}"は一個前の単語をprevという変数に格納することを表していてる。

    case "${prev}" in
        post|private_post)
            COMPREPLY=( $(compgen -f ${cur}) )
            return 0
            ;;

上記のところで、一個前の単語がpostまたはprivate_postだった場合はcompgen -f ${cur}の結果を補完リストに表示するようになっている。
ここでの-fは「ファイルの補完」を表している、compgenで使用可能な組み込みの補完候補はほかにもいろいろあるのでman bashで調べてみるといい。


これでとりあえずgisty用の補完関数ができた。

意外と簡単でしょ。