Edited at

コマンドラインでの選択的インターフェイスについて考える

More than 3 years have passed since last update.


はじめに

ここで言う選択的インターフェイスというのは、EmacsでのAnything的なツールのことを言います。この点については、イメージ画像を見たほうが分かりやすいでしょう。

このようなツールは、様々な応用可能性があります。

選択的インターフェイスでは、パイプで繋ぐことにより、出力結果を選択できるようになります。そして、選択されたものが最終的に出力されることになります。

この出力を使うことによって、様々なツールの仲介を任せたり、値を取得したりすることができます。


percol

pythonで書かれた選択的インターフェイスツールです。

https://github.com/mooz/percol


percolのインストール

$ sudo pip install percol

または、

$ git clone https://github.com/mooz/percol

$ cd !$:t

$ sudo python setup.py install


percolの基本的な使い方

$ ls | percol

最初から特定の文字列にマッチさせます。

$ ls ~ | percol --query="s"

プロンプトの左をカスタマイズする。

$ ls | percol --right-prompt=prompt1


percolのキーバインド

percolでは、設定ファイルを作ることでキーバインドを設定することもできます。

$ mkdir ~/.percol.d

$ vim ~/.percol.d/rc.py


~/.percol.d/rc.py

# https://gist.github.com/mitukiii/4234173

import sys, commands
from percol.command import SelectorCommand
from percol.key import SPECIAL_KEYS
from percol.finder import FinderMultiQueryMigemo, FinderMultiQueryRegex

## prompt
# Case Insensitive / Match Method に応じてプロンプトに表示
def dynamic_prompt():
prompt = ur""
if percol.model.finder.__class__ == FinderMultiQueryMigemo:
prompt += "[Migemo]"
elif percol.model.finder.__class__ == FinderMultiQueryRegex:
prompt += "[Regexp]"
else:
prompt += "[String]"
if percol.model.finder.case_insensitive:
prompt += "[a]"
else:
prompt += "[A]"
prompt += "> %q"
return prompt

percol.view.__class__.PROMPT = property(lambda self: dynamic_prompt())

## migemo
# Mac と Ubuntu で辞書のパスを変える
if sys.platform == "darwin":
FinderMultiQueryMigemo.dictionary_path = "/usr/local/Cellar/cmigemo/20110227/share/migemo/utf-8/migemo-dict"
else:
FinderMultiQueryMigemo.dictionary_path = "/usr/local/share/migemo/utf-8/migemo-dict"

## kill
# Mac の場合は kill(yank)をクリップボードと共有する
if sys.platform == "darwin":
def copy_end_of_line_as_kill(self):
commands.getoutput("echo " + self.model.query[self.model.caret:] + " | pbcopy")
self.model.query = self.model.query[:self.model.caret]

def paste_as_yank(self):
self.model.insert_string(commands.getoutput("pbpaste"))

SelectorCommand.kill_end_of_line = copy_end_of_line_as_kill
SelectorCommand.yank = paste_as_yank

## keymap
# Mac で delete(backspace)が効くようにする
SPECIAL_KEYS.update({
127: '<backspace>'
})
percol.import_keymap({
"C-a" : lambda percol: percol.command.beginning_of_line(),
"C-e" : lambda percol: percol.command.end_of_line(),
"C-b" : lambda percol: percol.command.backward_char(),
"C-f" : lambda percol: percol.command.forward_char(),
"C-d" : lambda percol: percol.command.delete_forward_char(),
"C-h" : lambda percol: percol.command.delete_backward_char(),
"C-k" : lambda percol: percol.command.kill_end_of_line(),
"C-y" : lambda percol: percol.command.yank(),
"C-n" : lambda percol: percol.command.select_next(),
"C-p" : lambda percol: percol.command.select_previous(),
"C-v" : lambda percol: percol.command.select_next_page(),
"M-v" : lambda percol: percol.command.select_previous_page(),
"M-<" : lambda percol: percol.command.select_top(),
"M->" : lambda percol: percol.command.select_bottom(),
"C-m" : lambda percol: percol.finish(),
"C-j" : lambda percol: percol.finish(),
"C-g" : lambda percol: percol.cancel(),
"M-c" : lambda percol: percol.command.toggle_case_sensitive(),
"M-m" : lambda percol: percol.command.toggle_finder(FinderMultiQueryMigemo),
"M-r" : lambda percol: percol.command.toggle_finder(FinderMultiQueryRegex)
})


参考:

percol 入れて zsh と組み合わせたら超便利

ターミナル版anything的なpercolをzawの代わりに試してみた


percolの応用的な使い方


percolで複数行選択する

複数行を選択する場合は、percol.command.toggle_mark_and_next()を使います。デフォルトでは、C-Sに設定されているようです。

$ ps ax | percol | awk '{ print $1 }' | xargs kill

私の場合は、以下の設定ファイルを書いています。複数行マークとマークの解除です。


~/.percol.d/rc.py

    "C-n" : lambda percol: percol.command.toggle_mark_and_next(),

"C-p" : lambda percol: percol.command.unmark_all(),

また、区切り文字を設定するには、以下のコマンドで行けます。

$ ls | percol | tr '\n' ';'


percolのzsh補完

GitHubからcloneする場合は、最初から用意されているみたいです。

https://github.com/mooz/percol/blob/master/tools/zsh/_percol

$ curl -o ~/.zsh/functions/_percol https://raw.githubusercontent.com/mooz/percol/master/tools/zsh/_percol

$ exec $SHELL


percolでcdする

cdrができれば、以下の方法で移動を簡単にできるようです。


~/.zshrc

# http://piyopiyoducky.net/blog/2013/08/17/cdr-with-percol/

### search a destination from cdr list
function percol-get-destination-from-cdr() {
cdr -l | \
sed -e 's/^[[:digit:]]*[[:blank:]]*//' | \
percol --match-method migemo --query "$LBUFFER"
}

### search a destination from cdr list and cd the destination
function percol-cdr() {
local destination="$(percol-get-destination-from-cdr)"
if [ -n "$destination" ]; then
BUFFER="cd $destination"
zle accept-line
else
zle reset-prompt
fi
}
zle -N percol-cdr
bindkey '^xb' percol-cdr


それ以外はこちら。


~/.zshrc

# https://github.com/shibayu36/config-file/blob/master/.zsh/percol-sources/cdr.zsh

function percol-cdr () {
local selected_dir=$(cdr -l | awk '{ print $2 }' | percol)
if [ -n "$selected_dir" ]; then
BUFFER="cd ${selected_dir}"
zle accept-line
fi
zle clear-screen
}
zle -N percol-cdr
bindkey '^@' percol-cdr

参考:

percolで最近行ったdirectoryにcdするやつを書きました

Zshのcdrとpercolで最近移動したディレクトリにAnythingライクに移動する - PiyoPiyoDucky

autojumpからpercolベースのディレクトリジャンプに移行する | Web scratch


percolとghq

自身のディレクトリ構造を使いやすくします。

$ go get github.com/motemen/ghq

詳しくは以下の記事で紹介されています。

ghq + percol + docc | SOTA

ghqを使ったローカルリポジトリの統一的・効率的な管理について - delirious thoughts

ghq コマンドの zsh 補完ファイルを修正したので、その過程を解説する - Qiita


percolとgit

gitコマンドを使いやすくするためにもpercolは大活躍です。

詳しくは以下の記事で紹介されています。

git-issue + git-flow + percol

percolとgit-issueを使って、redmineのチケットをブランチに切って作業するのが捗る設定 | Technology-Gym

percolを使って、gitのコミットハッシュ値をクリップボードにコピーする - Qiita

Git - プルリクエストを自動補完してcheckoutする - Qiita


peco

percolを元にgolangで書かれた選択的インターフェイスツールです。

https://github.com/lestrrat/peco

設定ファイルは以下の様な感じに編集できます。


~/.peco/config.json

{

"Keymap": {
"C-p": "peco.SelectPrevious",
"C-n": "peco.SelectNext",
"C-c": "peco.Cancel"
}
}

詳しくは以下の記事で紹介されています。

Windows のコマンドプロンプトを10倍便利にするコマンド「peco」

pecoを導入してzshのhistoryに使うようにした - さよならインターネット