zsh は cd -[TAB]
で補完できる directory stack が setopt autopushd
と組み合わせていると非常に便利なので、 directory stack を自前で保存する仕組みを作ったり、 GNU screen の他の WINDOW のディレクトリに移動するための cdsというコマンド を作ったりして、 現状でもあまり困っていませんでした。
しかし、 zshcontrib(1)
に入っているものも試してみるのが 良さそうと思って試してみました。
ドキュメント
ドキュメントは man zshcontrib
か、 pager $^fpath/cdr(N)
で読めます。
cdr コマンドの使い方
cdr [TAB]
で補完して使ったり、 cdr -l
で一覧を出したり、 cdr -e
で一覧を編集したりできます。
cdr -e
の編集は zle
なので、 bindkey -e
なら、 普通のカーソル移動などの他に ただの Enter
だと編集終了になってしまうので、 ^[^M
(ESC
に続けて Enter
) で改行を入力して行を増やしたり分割したり 出来ることを知っておけば充分だと思います。
設定全体
全体としては以下のように設定してみました。
以降は設定内容を個別に解説していきます。
if [[ -n $(echo ${^fpath}/chpwd_recent_dirs(N)) && -n $(echo ${^fpath}/cdr(N)) ]]; then
autoload -Uz chpwd_recent_dirs cdr add-zsh-hook
add-zsh-hook chpwd chpwd_recent_dirs
zstyle ':completion:*:*:cdr:*:*' menu selection
zstyle ':completion:*' recent-dirs-insert both
zstyle ':chpwd:*' recent-dirs-max 500
zstyle ':chpwd:*' recent-dirs-default true
zstyle ':chpwd:*' recent-dirs-file "${XDG_CACHE_HOME:-$HOME/.cache}/shell/chpwd-recent-dirs"
zstyle ':chpwd:*' recent-dirs-pushd true
fi
使えるかどうかのガード条件
昔、 zsh の設定を環境ごとに分岐させようとした時、 is-at-least
は古い zsh で使えなかったのと、 バックポートで使える可能性があったり、 自前の fpath
にファイルを追加した場合などを考慮して、 機能自体の存在をチェックするようにしています。
ruby で推奨されているやり方として、 RUBY_VERSION
をチェックするのではなく、 機能の存在をチェックするべき、 という話があったことも影響しています。
if [[ -n $(echo ${^fpath}/chpwd_recent_dirs(N)) && -n $(echo ${^fpath}/cdr(N)) ]]; then
Glob Qualifiers の (N)
(NULL_GLOB
) を使っている関係で、 一度 echo
してから -n
でチェックしています。 もっと簡潔に書ける方法があれば教えてください。
autoload
autoload -U
と書いてある設定例もありますが、 ドキュメントにあったように autoload -Uz
を使っています。
-z
を付けないと KSH_AUTOLOAD
の設定の影響を受けるそうなので、 基本的には -z
を明示的に付けるのがおすすめのようです。
add-zsh-hook
chpwd_functions
への追加は
typeset -ga chpwd_functions
chpwd_functions+=chpwd_recent_dirs
としても良かったのですが、 念のため typeset
するのが最近の zsh しか使わないのなら無駄に感じたのと、 cdr
のドキュメントに書いてあったこともあり、 add-zsh-hook
を使ってみました。
menu selection
Web で設定例を見ると zstyle ':completion:*' menu select
になっていることが多いのですが、 基本的に menu select は使っていなかったので、 zshcontrib(1)
や ${^fpath}/cdr(N)
に書いてあった通りに ':completion:*'
ではなく ':completion:*:*:cdr:*:*'
で、 値も select
ではなく selection
で設定しています。
zstyle ':completion:*:*:cdr:*:*' menu selection
recent-dirs-insert
これは cdr [TAB]
の挙動の設定で、 好みが分かれると思うので、 always
, fallback
, both
を一通り試してみるのをおすすめします。
both
だと通常の cd
の補完にメニューから選ぶ補完候補に履歴が入っているという感じに見えました。 あまりうまく使えていないので、そのうち他の設定に変えて試してみようと思っています。
recent-dirs-max
設定を保存する最大数です。 デフォルト値は 20 です。
recent-dirs-file
XDG Base Directory Specification に合わせて ~/.cache
を使うようにしています。
他の部分で既に mkdir -p
しているので、ここでは省略しています。
#mkdir -p "${XDG_CACHE_HOME:-$HOME/.cache}/shell"
zstyle ':chpwd:*' recent-dirs-file "${XDG_CACHE_HOME:-$HOME/.cache}/shell/chpwd-recent-dirs"
ドキュメントにあるように、 以下のような設定にして TTY ごとのファイルと グローバルのファイルにわけるのも良いかもしれません。
zstyle recent-dirs-file ':chpwd:*' ~/.chpwd-recent-dirs-${TTY##*/} +
recent-dirs-pushd
他の設定が影響していたのか、 何が原因だったのかは追求していないのですが、 recent-dirs-pushd
を true
にしないと 最初はうまく動かなかったのですが、 履歴がたまったからなのか、 なぜか今はこの設定に関係なくちゃんと動いているようです。
recent-dirs-prune
recent の一覧に追加しないディレクトリのパターンなどを設定できるようですが、 必要性を感じていないので、 まだ何も設定していません。