Skip to content

Instantly share code, notes, and snippets.

@rummelonp
Last active February 22, 2023 15:06
Show Gist options
  • Select an option

  • Save rummelonp/4954559 to your computer and use it in GitHub Desktop.

Select an option

Save rummelonp/4954559 to your computer and use it in GitHub Desktop.

Revisions

  1. rummelonp revised this gist Feb 15, 2013. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions zsh_completion.md
    Original file line number Diff line number Diff line change
    @@ -217,15 +217,15 @@ __nyan_modes() {
    ![image](http://pic.mitukiii.jp/5u6.png)
    オプションと補完候補に同時に出すために今回は `_arguments` 関数を使う
    オプションと補完候補に同時に出すために `_arguments` 関数を使う
    オプションの指定は `optname[desc]` と指定する
    同じ意味のオプションがある場合は `{optname1,optiname2}` とカンマ区切りで書く
    引数の指定は `n:message:action` と指定する
    `n` は何番目の引数に対して動作するかを表す
    今回は何回でも同じ引数を補完出来て良いので `*` と指定しておく
    何回でも同じ引数を補完出来て良いので `*` と指定しておく
    `message` はその補完候補の説明を表す
    今回は引数を省略する(理由は後述)
    @@ -234,7 +234,7 @@ __nyan_modes() {
    `*: :__nyan_modes` と書くことで、全ての補完候補で `__nyan_modes` 関数が使われる
    `__nyan_modes` 関数内の `_values` 関数で `mode` というグループ名(説明)指定しているため `message` を省略してる
    今回は説明を出すため/見通しをよくするためモードの補完候補を別関数に分けたが、説明を伴わない場合は `'*:mode:(neko usagi kuma github)'` のように書くことも出来る
    説明を出すため/見通しをよくするためモードの補完候補を別関数に分けたが、説明を伴わない場合は `'*:mode:(neko usagi kuma github)'` のように書くことも出来る
    出来れば `--help` が入力された時はそこで補完を終了させたい
    最後にそのための改良をする
  2. rummelonp revised this gist Feb 14, 2013. 1 changed file with 1 addition and 3 deletions.
    4 changes: 1 addition & 3 deletions zsh_completion.md
    Original file line number Diff line number Diff line change
    @@ -48,9 +48,7 @@ _nyan() {
    compdef _nyan nyan
    ```

    ## 実際に作ってみる

    ### nyan コマンドを作る
    ## nyan コマンドを作る

    まずは猫を表示してくれる可愛い `nyan` コマンドを作る

  3. rummelonp revised this gist Feb 14, 2013. 1 changed file with 0 additions and 2 deletions.
    2 changes: 0 additions & 2 deletions zsh_completion.md
    Original file line number Diff line number Diff line change
    @@ -167,7 +167,6 @@ _nyan() {
    'kuma' \
    'github'
    }
    ```
    ![image](http://pic.mitukiii.jp/6ui.png)
    @@ -190,7 +189,6 @@ _nyan() {
    'kuma[kawaii kuma-neko]' \
    'github[kawaii octcat]'
    }
    ```
    ![image](http://pic.mitukiii.jp/4lm.png)
  4. rummelonp created this gist Feb 14, 2013.
    303 changes: 303 additions & 0 deletions zsh_completion.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,303 @@
    # zsh の補完関数の自作導入編

    あまり深く理解してないので識者のツッコミ大歓迎

    ## 補完を有効にする

    取り敢えず最低限だけ

    ```zsh
    # 補完を有効にする
    autoload -U compinit
    compinit -u

    # 補完メッセージを読みやすくする
    zstyle ':completion:*' verbose yes
    zstyle ':completion:*' format '%B%d%b'
    zstyle ':completion:*:warnings' format 'No matches for: %d'
    zstyle ':completion:*' group-name ''
    ```

    ## 補完関数のルール

    $fpath の通ったディレクトリに補完関数を置く
    `nyan` コマンドの補完関数なら `_nyan` という名前で保存する
    補完関数の先頭には `#compdef nyan` と補完対象のコマンド名を書く
    ファイル名と同じ名前の関数を作りその中に補完関数を書く

    `~/zsh/functions/_nyan`

    ```zsh
    #compdef nyan

    _nyan() {
    # 補完関数
    }
    ```

    あるいは下記のように書いたファイルを `source ~/zsh/lib/_nyan.zsh` と読み込むことで補完関数を有効にすることも出来る
    `compdef _nyan nyan``_nyan` 関数を `nyan` コマンドの補完関数として使うという意味になる

    `~/zsh/lib/_nyan.zsh`

    ```zsh
    _nyan() {
    # 補完関数
    }

    compdef _nyan nyan
    ```

    ## 実際に作ってみる

    ### nyan コマンドを作る

    まずは猫を表示してくれる可愛い `nyan` コマンドを作る

    `~/bin/nyan`

    ```zsh
    #!/usr/bin/env zsh

    function nyan() {
    typeset -a modes

    help() {
    echo 'Usage: nyan <mode>'
    echo
    echo 'Modes:'
    echo ' neko, usagi, kuma, github'
    }

    neko() {
    echo ' ∧_∧'
    echo "ฅ'ω'ฅ < ニャーン"
    }

    usagi() {
    echo ' /) /)'
    echo '_( _ ๑❛ᴗ❛)_ < ニャーン'
    }

    kuma() {
    echo '(´(ェ)`) < ニャーン'
    }

    github() {
    echo '=͟͟͞͞=͟͟͞͞=͟͟͞͞ (\ (\'
    echo '=͟͟͞͞=͟͟͞͞=͟͟͞͞(,, 0 ω 0) < ニャーン'
    echo '=͟͟͞͞=͟͟͞͞=͟͟͞͞(/ (/ \) \)'
    }

    while [ $1 ]; do
    case $1 in
    -h|--help)
    help
    return
    ;;
    *)
    modes=($modes[*] $1)
    ;;
    esac
    shift
    done

    if (( $#modes == 0 )); then
    neko
    return
    fi

    for mode in $modes; do
    if type $mode > /dev/null 2>&1; then
    $mode
    else
    echo "No such mode \"$mode\""
    fi
    done
    }

    nyan $@
    ```

    動かしてみる

    ```zsh
    $ nyan
    ∧_∧
    'ω'ฅ < ニャーン

    $ nyan wan
    No such mode "wan"

    $ nyan --help
    Usage: nyan <mode>

    Modes:
    neko, usagi, kuma, github

    $ nyan usagi
    /) /)
    _( _ ๑❛ᴗ❛)_ < ニャーン

    $ nyan kuma github
    (´(ェ)`) < ニャーン
    =͟͟͞͞=͟͟͞͞=͟͟͞͞ (\ (\
    =͟͟͞͞=͟͟͞͞=͟͟͞͞(,, 0 ω 0) < ニャーン
    =͟͟͞͞=͟͟͞͞=͟͟͞͞(/ (/ \) \)
    ```
    neko, usagi, kuma, github の4つのモードと
    --help の1つのオプションがある
    モードは複数指定することが出来る
    ## nyan 補完関数を作る
    まずは4つの全てのモードを補完候補に出してみる
    `~/zsh/functions/_nyan`
    ```zsh
    #compdef nyan
    _nyan() {
    _values \
    'mode' \
    'neko' \
    'usagi' \
    'kuma' \
    'github'
    }
    ```
    ![image](http://pic.mitukiii.jp/6ui.png)
    `_values` 関数を使うとひとつ目の引数が補完候補のグループ名、その後の引数が補完候補となる
    `_values` で指定した補完候補は複数かつ同じものを何度でも補完出来る
    もしひとつの候補を一度しか入力させたくない場合は `_values` 関数に `-w` オプションを渡せば良い
    ついでに説明文も表示してみる
    ```zsh
    #compdef nyan
    _nyan() {
    _values \
    'mode' \
    'neko[kawaii normal neko]' \
    'usagi[kawaii usa-neko]' \
    'kuma[kawaii kuma-neko]' \
    'github[kawaii octcat]'
    }
    ```
    ![image](http://pic.mitukiii.jp/4lm.png)
    `[]` 内に説明を書くことで、補完候補の横に説明が表示される
    次は `--help` オプションを補完候補に出してみる
    ```zsh
    #compdef nyan
    _nyan() {
    _arguments \
    {-h,--help}'[show help]' \
    '*: :__nyan_modes'
    }
    __nyan_modes() {
    _values \
    'mode' \
    'neko[kawaii normal neko]' \
    'usagi[kawaii usa-neko]' \
    'kuma[kawaii kuma-neko]' \
    'github[kawaii octcat]'
    }
    ```
    ![image](http://pic.mitukiii.jp/5u6.png)
    オプションと補完候補に同時に出すために今回は `_arguments` 関数を使う
    オプションの指定は `optname[desc]` と指定する
    同じ意味のオプションがある場合は `{optname1,optiname2}` とカンマ区切りで書く
    引数の指定は `n:message:action` と指定する
    `n` は何番目の引数に対して動作するかを表す
    今回は何回でも同じ引数を補完出来て良いので `*` と指定しておく
    `message` はその補完候補の説明を表す
    今回は引数を省略する(理由は後述)
    `action` はどういう動作をするかを表す
    `*: :__nyan_modes` と書くことで、全ての補完候補で `__nyan_modes` 関数が使われる
    `__nyan_modes` 関数内の `_values` 関数で `mode` というグループ名(説明)指定しているため `message` を省略してる
    今回は説明を出すため/見通しをよくするためモードの補完候補を別関数に分けたが、説明を伴わない場合は `'*:mode:(neko usagi kuma github)'` のように書くことも出来る
    出来れば `--help` が入力された時はそこで補完を終了させたい
    最後にそのための改良をする
    ```zsh
    #compdef nyan
    _nyan() {
    _arguments \
    '(- *)'{-h,--help}'[show help]' \
    '*: :->modes'
    case $state in
    modes)
    _values \
    'mode' \
    'neko[kawaii normal neko]' \
    'usagi[kawaii usa-neko]' \
    'kuma[kawaii kuma-neko]' \
    'github[kawaii octcat]'
    ;;
    esac
    }
    ```
    ![image](http://pic.mitukiii.jp/c88.png)
    `nyan` コマンドの補完関数完全版である
    `'(- *)'` で排他指定をしている
    `-` の部分で `--help``-h`)が補完された時に `-h``--help`)を補完候補から除く
    `*` の部分で `--help``-h`)が補完された時にそれ以降の補完を終了している
    ## その他の便利な補完関数
    `_arguments` は他にもオプションや指定がたくさんあったり
    `_files` でマッチしたファイルのみ候補に出したり
    `_alternative``_describe` を使って複数のグループの補完候補を表示したり
    `_store_cache` を使って補完候補をキャッシュしたり
    他にもたくさんあるけどイマイチ理解が浅いので気が向いた時に続編を書くかも書かないかも
    ## その他
    補完関数は先人たちが書いたものがたくさんある
    `git` の補完関数はでかいが参考になる
    自分が普段よく使うコマンドの補完関数を読んでみると良い
    後、これを入れておくと便利
    [zsh-users/zsh-completions](https://github.com/zsh-users/zsh-completions)
    Mac で homebrew なら `brew install zsh-completions` で入る
    ## 参考文献
    [zsh: 20. Completion System](http://zsh.sourceforge.net/Doc/Release/Completion-System.html)(英語)
    多分これに全て書かれてるけど要所しか読んでない
    [zsh補完関数の書き方(訳)](http://www.ayu.ics.keio.ac.jp/~mukai/translate/write_zsh_functions.html)
    大体の雰囲気が分かる
    [zsh補完関数を自作すると便利 - はこべブログ♨](http://hakobe932.hatenablog.com/entry/2012/02/13/214934)
    ひとつの補完関数を書く過程を書かれてて分かりやすい