これは何?
zshの操作で、pecoとかpercolとか、Anything風インターフェースで選択するやつがよく使われてる。これを使うと、例えばコマンドライン履歴からインクリメンタルに検索して、それを実行、とかできるようになる。
でも、pecoとかpercolはシェルとは関係なくて、単に「インクリメンタルに絞り込む」ってところだけしかやってくれない。それだけでは役に立たなくて、「選んだ結果を実行する」とかのシェルの処理が必要になる。
それで、そういうシェルの処理を自分で書きたくない人向けにanyframeというのを作った。
これはzsh用のプラグインで、これを使うと自分でシェルの関数を書かなくても、キーバインドとかaliasを設定するだけでpeco/percolの便利なやつをすぐ使えるようになる。
特徴
- 普通の人が使いたいと思う関数がだいたい入ってる
- peco、percol、fzfに対応してる
- aliasでもbindkey(キーボード ショートカットから呼び出すやつ)でも、どちらからでも使える
- 選んだ結果をすぐに実行するのも、コマンドラインに挿入するのもできる
- 拡張しやすい
インストール
まずは先にpeco、percol、fzfをインストールしておく。どれかひとつ好きなやつでOK。その後anyframeを次の方法でインストールする。
1. 手動でインストールする場合
手動でインストールする場合、$fpathの通ったところにanyframe以下のファイルを全部配置する。$HOME/.zsh/の下にインストールする場合の例は以下。
# ディレクトリがまだない場合は作成する
% mkdir $HOME/.zsh/
% cd $HOME/.zsh/
% git clone git@github.com:mollifier/anyframe.git
そのあと~/.zshrcに次の設定を追加する
fpath=($HOME/.zsh/anyframe(N-/) $fpath)
autoload -Uz anyframe-init
anyframe-init
2. Antigenでインストールする場合
Antigenを使ってる人は、~/.zshrcに1行追加するだけでOK。
if [[ -f ~/.zsh/antigen/antigen.zsh ]]; then
source ~/.zsh/antigen/antigen.zsh
antigen bundle mollifier/anyframe # <= これを追加
antigen apply
fi
使い方
適当にsource ~/.zshrc
するとanyframe-functions/widgetsにある関数(anyframe-widgetと呼ぶことにする)が全部使えるようになる。こいつに対してbindkeyで好きなキーバインドを設定する。あとはそのキーを押せばOK。
僕が使っているキーバインドはこんな感じ。
bindkey '^xb' anyframe-widget-cdr
bindkey '^x^b' anyframe-widget-checkout-git-branch
bindkey '^xr' anyframe-widget-execute-history
bindkey '^x^r' anyframe-widget-execute-history
bindkey '^xp' anyframe-widget-put-history
bindkey '^x^p' anyframe-widget-put-history
bindkey '^xg' anyframe-widget-cd-ghq-repository
bindkey '^x^g' anyframe-widget-cd-ghq-repository
bindkey '^xk' anyframe-widget-kill
bindkey '^x^k' anyframe-widget-kill
bindkey '^xi' anyframe-widget-insert-git-branch
bindkey '^x^i' anyframe-widget-insert-git-branch
bindkey '^xf' anyframe-widget-insert-filename
bindkey '^x^f' anyframe-widget-insert-filename
あとは、aliasで短い名前をつけてそれを呼び出しても良い。
alias aw=anyframe-widget-select-widget
もっと言うと、anyframe-widget-select-widget
とか直接打ち込んで呼び出しても良い。
anyframe-widget一覧
anyframe-functions/widgetsにある関数一覧とその使い方は次の通り。
関数名 | 内容 |
---|---|
anyframe-widget-execute-history | コマンドライン履歴から選んで実行する |
anyframe-widget-put-history | コマンドライン履歴から選んでコマンドラインに挿入する |
anyframe-widget-checkout-git-branch | Gitブランチを切り替える |
anyframe-widget-insert-git-branch | Gitブランチ名をコマンドラインに挿入する |
anyframe-widget-cdr | 過去に移動したことのあるディレクトリに移動する(cdrが必要) |
anyframe-widget-kill | プロセスをkillする |
anyframe-widget-cd-ghq-repository | ghqコマンドで管理しているリポジトリに移動する(ghqが必要) |
anyframe-widget-insert-filename | ファイル名をコマンドラインに挿入する |
anyframe-widget-tmux-attach | tmuxセッションを選んでアタッチする |
anyframe-widget-select-widget | anyframe-widgetから選んでそれを実行する |
少し説明が必要な奴があるので、補足しておく。
anyframe-widget-cdr
過去に移動したことのあるディレクトリに移動する。cdrが必要。
cdrは、zsh標準で添付されている、ディレクトリ移動の履歴を管理して最近移動したディレクトリに移動するためのプラグイン。これを使うには、最低限次の2行を~/.zshrcに書いておく。
autoload -Uz chpwd_recent_dirs cdr add-zsh-hook
add-zsh-hook chpwd chpwd_recent_dirs
参考 : zshでcdの履歴管理に標準添付のcdrを使う - @znz blog
anyframe-widget-cd-ghq-repository
ghqコマンドで管理しているリポジトリに移動する。別途ghqが必要。ghqは、Gitリポジトリをクローンして、その一覧を管理するためのコマンド。
anyframe-widget-select-widget
anyframe-widgetから選んでそれを実行する。つまり、こいつを実行すると
cd-ghq-repository
cdr
checkout-git-branch
... 以下省略 ...
というふうにanyframe-widget一覧が表示されてpeco/percolで選択できる。で、それを選ぶとその選んだanyframe-widgetが実行される。使用頻度が低くてわざわざキーバインドを設定する程でもないanyframe-widgetを呼び出すときに便利。
普通の人はここまでの設定で便利に使えると思う。
カスタマイズする
anyframeは、peco、percol、fzfに関してカスタマイズができるようになってるので、それについて解説する。
anyframeでは、インクリメンタルに検索するコマンドのことをselectorと呼ぶことにしてる。今のところselectorとしてはpeco、percol、fzfに対応してて、そのなかでインストールされているやつを自動的に使うようになってる。それで、複数インストールしている人は、どれを使いたいか明示的に指定することもできる。
pecoを使うと明示的に指定するときは、次の行を~/.zshrcに書く。
zstyle ":anyframe:selector:" use peco
percolを使うと指定したいときはこんな感じ。
zstyle ":anyframe:selector:" use percol
fzfを使うと指定したいときは、こう書く。
zstyle ":anyframe:selector:" use fzf
どれかひとつしかインストールしていない人は、別にこれを書かなくても大丈夫。
あとは、peco/percol/fzfコマンドのパスとコマンドライン引数も指定できる。これは、パスの通ってないところにインストールしたpeco/percol/fzfを使うときとか、オプションを追加したいときに使う。
# 例1: pecoで--no-ignore-caseオプションを指定する
zstyle ":anyframe:selector:peco:" command 'peco --no-ignore-case'
# 例2: percolで--case-sensitiveオプションを指定する
zstyle ":anyframe:selector:percol:" command 'percol --case-sensitive'
# 例3: fzfで--extendedオプションを指定する
zstyle ":anyframe:selector:fzf:" command 'fzf --extended'
僕の場合は${HOME}/.peco_config.json
というところにpecoの設定ファイルを置いていて、次のようにしてそれを設定ファイルとして使うように指定してる。
zstyle ":anyframe:selector:peco:" command "peco --rcfile=${HOME}/.peco_config.json"
自分で独自の関数を追加する
anyframeは自分でanyframe-widgetとかの関数を追加して拡張することを考慮している。自分でzshの関数を書くことになるんだけど、そのときでもanyframeに含まれている関数が使えるので、一から書くよりだいぶ簡単になる。
書く場所として2つある。まず、~/.zshrcに独自の関数を足していくのがお手軽な方法。そうやっていっぱい追加すると~/.zshrcが大きくなってわけわかんなくなるので、別の場所に切り出して配置したい、という人もいると思う。そういうこともできるので、最後にその方法についても解説する。
~/.zshrcに独自のanyframe-widgetを追加する
まずはお手軽な、~/.zshrcに関数を追加して呼び出す方法について解説する。
anyframeでは、peco/percol/fzfで選択した結果をどうするか、という動作として
- 選択した結果をzshですぐに実行する
- 選択した結果で現在のコマンドラインを置き換える
- 選択した結果をコマンドラインのカーソル位置に挿入する
という3つのパターンに対応している。
そして、1.のパターンのときは、基本的には次のような形の関数を書く。
# 1. 選択した結果をzshですぐに実行する関数のひな形
function 関数名 () {
<(a)選択する候補を標準出力に出力する処理> \
| anyframe-selector-auto \
| <(b)選択結果に対するフィルタ(必要なときだけ)> \
| anyframe-action-execute
}
「(a)選択する候補を標準出力に出力する処理」は、まさにそのままで、選びたい候補を単純に標準出力に出力するコマンドとか関数を書く。history
コマンドでもgit log
でもファイルをcat
で出力したやつでも、なんでも良い。
それをパイプラインで繋いでanyframe-selector-auto
に渡すと、peco/percolが起動する。選んだ結果はまた標準出力に出力される。
すぐにzshで実行したいときは、その結果をさらにパイプラインで繋いでanyframe-action-execute
に渡せばOK。
peco/percolで選んだ結果に対してさらに絞り込みとか変換とか書けたいときは「(b)選択結果に対するフィルタ」の位置にフィルタプログラムを書く。ここも普通のフィルタなので、grepでもsedでもrubyでもなんでも好きなように書ける。
例えば、標準で入っているanyframe-widget-execute-history(コマンドライン履歴から選んで実行する)を自分で書くとすると、こんな感じ。
function anyframe-widget-execute-history () {
history -n -r 1 \
| anyframe-selector-auto \
| anyframe-action-execute
}
あとは、aliasから呼び出したいときは単純にaliasで別名を付ける。
alias ah=anyframe-widget-execute-history
これでah
というaliasで呼び出せるようになる。
キーボードショートカットから呼び出したいときは、次の2行を~/.zshrcに書く。
zle -N anyframe-widget-execute-history
bindkey '^xr' anyframe-widget-execute-history
これでCtrl+x rで呼び出せるようになる。
本当は「peco、percol、fzfのうちインストールされている方を起動する」とか「選んだ結果を今のコマンドラインに挿入してそれを実行する」とか、そういう処理が必要なんだけど、そういうのは全部anyframe-selector-autoとanyframe-action-executeがやってくれてる。
処理の内容も意図して標準入力/標準出力だけを使うようにしてる。変数とか$()
とか、そういういかにもシェル特有っぽい書き方は必要ない。なので他のコマンドと簡単に組み合わせれるし、シェルスクリプトが苦手な人でも書きやすいと思う。
「1. 選択した結果をzshですぐに実行する」の派生系として、「選択した結果を特定のコマンドの引数に渡して実行する」というのをしたいことがある。そういうときは最後のanyframe-action-execute
の後に実行したいコマンドを書く。
例えば、標準で入っているanyframe-widget-kill(プロセスをkillする)を自分で書くとすると、こんな感じ。
function anyframe-widget-kill () {
ps -u $USER -o pid,stat,%cpu,%mem,cputime,command \
| anyframe-selector-auto \
| awk '{print $1}' \
| anyframe-action-execute kill
}
zle -N anyframe-widget-kill
bindkey '^xk' anyframe-widget-kill
最後のanyframe-action-execute kill
のところは「標準入力で受け取った文字列を引数としてkillコマンドを実行する」という意味になる。
ここまでが「1. 選択した結果をzshですぐに実行する」の書き方。これが「2. 選択した結果で現在のコマンドラインを置き換える」「3. 選択した結果をコマンドラインのカーソル位置に挿入する」になると、それぞれ次のようになる。
# 2. 選択した結果で現在のコマンドラインを置き換える関数のひな形
function 関数名 () {
<(a)選択する候補を標準出力に出力する処理> \
| anyframe-selector-auto \
| <(b)選択結果に対するフィルタ(必要なときだけ)> \
| anyframe-action-put
}
# 3. 選択した結果をコマンドラインのカーソル位置に挿入する関数のひな形
function 関数名 () {
<(a)選択する候補を標準出力に出力する処理> \
| anyframe-selector-auto \
| <(b)選択結果に対するフィルタ(必要なときだけ)> \
| anyframe-action-insert
}
書き方はほとんど同じで、最後のanyframe-action-execute
がanyframe-action-put
、anyframe-action-insert
に変わっただけ。
特定のディレクトリに独自のanyframe-widgetを配置する
~/.zshrcに関数をいっぱい追加すると、ファイルが大きくなりすぎて分かりにくいし、将来anyframeとかpecoを使うのをやめるときにどこを消せばよいのか分かりにくいので、別のファイルとして書きたいという人もいると思う。anyframeはそういうこともできるようになっていて、$fpathの通ったところにanyframe-functions/widgetsというディレクトリを作って、その下に自分の作ったanyframe-widgetを置けば良い。
$HOME/.zsh/anyframe-customの下に配置する場合の例は以下。
# ディレクトリがまだない場合は作成する
% mkdir -p $HOME/.zsh/anyframe-custom # <= このディレクトリ名は何でも良い
% cd $HOME/.zsh/anyframe-custom
% mkdir -p anyframe-functions/widgets # <= このディレクトリ名は固定
そして、anyframe-functions/widgetsの下にファイルを作って、独自のanyframe-widgetの中身を書く。ファイル名は何でも良くて、その名前が関数名になる。
例えば、標準で入っているanyframe-widget-execute-historyを自分で追加するとすると、次の内容のファイルを$HOME/.zsh/anyframe-custom/anyframe-functions/widgetsの下にanyframe-widget-execute-historyという名前で作成する。
history -n -r 1 \
| anyframe-selector-auto \
| anyframe-action-execute
function
とかは書かずに、{}
の中身だけ書くことに注意する。
使い方としては、これを~/.zshrcで、anyframe-init
を呼び出す前に$fpathに指定して読み込む。
fpath=($HOME/.zsh/anyframe(N-/) $fpath)
fpath=($HOME/.zsh/anyframe-custom(N-/) $fpath) # <= これを追加
autoload -Uz anyframe-init
anyframe-init
Antigenでインストールした人は**antigen bundle mollifier/anyframe
の前に**$fpathに指定して読み込む。
if [[ -f ~/.zsh/antigen/antigen.zsh ]]; then
source ~/.zsh/antigen/antigen.zsh
fpath=($HOME/.zsh/anyframe-custom(N-/) $fpath) # <= これを追加
antigen bundle mollifier/anyframe
antigen apply
fi
$HOME/.zsh/anyframe-custom/anyframe-functions/widgets
ではなくて$HOME/.zsh/anyframe-custom
をfpathに追加することに注意。
あとはaliasかbindkeyを設定する。
alias ah=anyframe-widget-execute-history
# または
bindkey '^xr' anyframe-widget-execute-history
このときはzle -N anyframe-widget-execute-history
というのは必要ない(anyframe-init内でそれをやってる)。
おわりに
anyframeの使い方とカスタマイズ方法について解説しました。後半は少し難しいお話になったけど、単に使うだけならカスタマイズしなくてもキーバインド設定するだけで大丈夫なので、pecoとかpercolとか使って簡単に便利になりたい人は、ぜひ試してみてください!