Quantcast
Channel: Vimタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 5608

pecoる

$
0
0

pecoは標準入力で受け取ったテキストデータをインクリメンタルに絞り込んで、選択した行を標準出力に出力するコマンド。

リポジトリのdemoに動きがわかるGIFがある。
似たようなものでfzfも良さそう → おい、peco もいいけど fzf 使えよ - Qiita

インストール

使うだけならgo getする必要はなく、Releases · peco/pecoにあるバイナリをダウンロードすればよい。
macだとbrewでインストールすることも可。
拙作のghinstを使うと

$ ghinst peco/peco

~/binにインストールできる

使い方

ファイルがいっぱいあるディレクトリで

$ ls | peco

で目的にファイルを見つけたり、見つけたものをvimで開くには

$ vim `ls | peco`

などとやる。よく使うものはシェルの設定ファイルに書いておくと良い。

Macでの下準備

bash, zshを最新版にしておく。
bashを使うなら

$ brew install bash
$ echo'/usr/local/bin/bash'| sudo tee -a /etc/shells
$ chsh -s /usr/local/bin/bash

zshを使うなら

$ brew install zsh
$ echo'/usr/local/bin/zsh'| sudo tee -a /etc/shells
$ chsh -s /usr/local/bin/zsh

macの標準コマンドはlinuxと挙動が違うので、brewを使ってlinuxに合わせる。

$ brew install coreutils gnu-sed

PATH等を設定しておく

# coreutilsexport PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH"export MANPATH="/usr/local/opt/coreutils/libexec/gnuman:$MANPATH"# gnu-sedexport PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"export MANPATH="/usr/local/opt/gnu-sed/libexec/gnuman:$MANPATH"

コマンド履歴でpecoる

C-rでコマンド履歴を検索できるけど、pecoを使ったほうが一覧性がよくて、絞り込みも柔軟なので使いやすい。

例えばzshの場合は

function peco-select-history(){# historyを番号なし、逆順、最初から表示。# 順番を保持して重複を削除。# カーソルの左側の文字列をクエリにしてpecoを起動# \nを改行に変換BUFFER="$(history -nr 1 | awk '!a[$0]++' | peco --query "$LBUFFER" | sed 's/\\n/\n/')"CURSOR=$#BUFFER# カーソルを文末に移動
    zle -R -c                   # refresh}
zle -N peco-select-history
bindkey '^R' peco-select-history

を.zshrcに書いておくとctrl+rでpecoを使ったコマンド履歴の絞り込みができる。
改行を含むコマンド実行した場合は、historyで改行部分が文字列の\nで出力されるため、sedで変換している。

bashの場合は

function peco-select-history(){local tac
    which gtac &> /dev/null &&tac="gtac"||\
        which tac &> /dev/null &&tac="tac"||\tac="tail -r"READLINE_LINE=$(HISTTIMEFORMAT=history|$tac| sed -e 's/^\s*[0-9]\+\s\+//'| awk '!a[$0]++'| peco --query "$READLINE_LINE")READLINE_POINT=${#READLINE_LINE}}bind -x '"\C-r": peco-select-history'

とする。以降bashの例は省く。

sshでpecoる

ホスト名を絞り込んでsshする設定。最近入ったサーバを上に持ってきたいので履歴でsshから始まるのを抽出後、known_hostsからも抽出。

function _get_hosts(){# historyを番号なし、逆順、ssh*にマッチするものを1番目から表示# 最後の項をhost名と仮定してhost部分を取り出すlocal hosts
    hosts="$(history -nrm 'ssh*' 1 | awk '{print $NF}')"# know_hostsからもホスト名を取り出す# portを指定したり、ip指定でsshしていると#   [hoge.com]:2222,[\d{3}.\d{3].\d{3}.\d{3}]:2222# といったものもあるのでそれにも対応しているhosts="$hosts\n$(cut -d' ' -f1  ~/.ssh/known_hosts | tr -d '[]' | tr ',' '\n' | cut -d: -f1)"hosts=$(echo$hosts| awk '!a[$0]++')echo$hosts}function peco-ssh(){hosts=`_get_hosts`local selected_host=$(echo$hosts| peco --prompt="ssh >" --query "$LBUFFER")if[ -n "$selected_host"];thenBUFFER="ssh ${selected_host}"
        zle accept-line
    fi}
zle -N peco-ssh
bindkey '^[s' peco-ssh

今回の例だとzle accept-lineを使って、選択後はすぐにsshをする。

ghqでpecoる

ghqはリポジトリをhost/user/repo形式で管理するためのツール。Rebuild: 42の後、ghqを使ったローカルリポジトリの統一的・効率的な管理について - Kentaro Kuribayashi's blogをきっかけに流行ったと思う。

ghqを使うと、リポジトリのディレクトリがかぶらないし、ディレクトリを自分で切らなくていいのが利点だけど、その分ディレクトリが深くなって、移動が面倒になるけど、pecoをつかって解決する。

$ ghinst motemen/ghq

などでインストールする。

デフォルトだと~/.ghq以下にディレクトリが作られるが、ghq以外で管理するようになる可能性もあるので~/src以下で管理するように.gitconfigに以下の設定をしている。

.gitconfig
[ghq]root=~/src

こうしておいて

$ ghq get tmsanrinsha/dotfiles

などと打つと~/src/github.com/tmsanrinsha/dotfilesにgit cloneされる。
-pをつけてるか、ssh形式で指定するとsshプロトコルでcloneされる。

$ ghq get -p tmsanrinsha/dotfiles
$ ghq get git@github.com:tmsanrinsha/dotfiles.git

余談だけど、

.gitconfig
[url "git@github.com:"]pushInsteadOf=https://github.com/

を設定しておくと、https形式でcloneしても、pushはssh形式になる。
こうするとfetchはhttps形式なので、パスフレーズが必要なくなり、cronでgit pullすることができる。pushはsshでできる。
各サーバのdotfilesなどをcronで最新に保つときに便利。

で、ghq lookを使うとリポジトリに移動することができるけど、pecoを使って移動することにする。また今git cloneしてきたリポジトリや、最近更新したリポジトリが上に来て欲しいので、ちょっと工夫する。

function peco-ghq-cd (){# Gitリポジトリを.gitの更新時間でソートするlocal ghq_roots="$(git config --path --get-all ghq.root)"local selected_dir=$(ghq list --full-path |\
        xargs -I{} ls -dl --time-style=+%s {}/.git | sed 's/.*\([0-9]\{10\}\)/\1/'| sort -nr |\
        sed "s,.*\(${ghq_roots/$'\n'/\|}\)/,,"|\
        sed 's/\/.git//'|\
        peco --prompt="cd-ghq >" --query "$LBUFFER")if[ -n "$selected_dir"];thenBUFFER="cd $(ghq list --full-path | grep -E "/$selected_dir$")"
        zle accept-line
    fi}
zle -N peco-ghq-cd
bindkey '^[g' peco-ghq-cd

コメントをつけると

ghq list --full-path |\ # repositoryのfull pathを取得
        xargs -I{} ls -dl --time-style=+%s {}/.git |\ # .gitの更新時間を表示
        sed 's/.*\([0-9]\{10\}\)/\1/'|\ # タイムスタンプ部分と.gitのフルパス部分を取り出す
        sort -nr |\ # タイムスタンプでソート
        sed "s,.*\(${ghq_roots/$'\n'/\|}\)/,,"|\ # 複数ある改行切りのghq.rootの改行を\|(sedの正規表現の|)にして、ghq.root部分を削除
        sed 's/\/.git//'|\ # .gitを削除
        peco --prompt="cd-ghq >" --query "$LBUFFER")

これで.gitの更新時間順で

cd-ghq >
github.com/tmsanrinsha/dotfiles
github.com/motemen/ghq

こんな風に表示される。選択されたら

BUFFER="cd $(ghq list --full-path | grep -E "/$selected_dir$")"

でフルパスを取得して移動する。

vimでも移動できるようにunite-ghqを使う。

もともとsorahさんが作ったのを上記のようなソートをするためにforkしたもの。
あと、選択したらvimfilerが開いて欲しい場合は

call unite#custom_default_action('source/ghq/directory','vimfiler')

としておくとよい。

cdrでpecoる

cdrは移動したディレクトリを記録して、そこに移動するためのzshのコマンド。bashの人とかはenhancdとか使うといいかも。

以下の様な設定をすると使える。

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:*' recent-dirs-insert both
    zstyle ':chpwd:*' recent-dirs-default truezstyle ':chpwd:*' recent-dirs-max 1000
    zstyle ':chpwd:*' recent-dirs-file "$ZDOTDIR/.cache/chpwd-recent-dirs"fi

$ZDOTDIRを設定してない場合は$HOMEにするなど。

pecoで使う設定は以下。

function peco-cdr (){local selected_dir="$(cdr -l | sed 's/^[0-9]\+ \+//' | peco --prompt="cdr >" --query "$LBUFFER")"if[ -n "$selected_dir"];thenBUFFER="cd ${selected_dir}"
        zle accept-line
    fi}
zle -N peco-cdr
bindkey '^[r' peco-cdr

これをvimからも使うためにはunite-zsh-cdrを使う。

zshの設定でrecent-dirs-fileをを変更している場合は設定してやる

letg:recent_dirs_file = $ZDOTDIR.'/.cache/chpwd-recent-dirs'letg:unite_zsh_cdr_chpwd_recent_dirs =g:recent_dirs_file

これでvimからcdrで記録されたディレクトリに移動することはできた。しかし、逆にvimで開いているファイルのディレクトリにシェルから行きたい場合もある。
それをやるには以下のような設定をする。

letg:recent_dirs_file = $ZDOTDIR.'/.cache/chpwd-recent-dirs'
augroup cdr
    autocmd!autocmdBufEnter * calls:update_cdr(expand('%:p:h'))
augroup END

function!s:update_cdr(dir)    " .gitなどのdirectoryは書き込まないletl:ignore_pattern ='\%(^\|/\)\.\%(hg\|git\|bzr\|svn\)\%($\|/\)'.
    \   '\|^\%(\\\\\|/mnt/\|/media/\|/temp/\|/tmp/\|\%(/private\)\=/var/folders/\)'if!isdirectory(a:dir)||a:dir=~l:ignore_pattern
        returnendif filereadable(g:recent_dirs_file)letl:recent_dirs = readfile(g:recent_dirs_file)call insert(l:recent_dirs,"$'".a:dir."'",0)letl:V = vital#of('vital')letl:List =l:V.import('Data.List')letl:recent_dirs =l:List.uniq(l:recent_dirs)call writefile(l:recent_dirs,g:recent_dirs_file)endifendfunction

バッファを変更するごとにディレクトリをcdrのファイルに書き込んでいる。この時ユニークなディレクトリを得るためにvital.vimの関数を使っているので、vital.vimが必要。
l:ignore_patternのパターンはneomru.vimg:neomru#directory_mru_ignore_patternから拝借した。

pecoり方を変える

$ vim `ls | peco`

とかなんとなく嫌だ。絞り込んだ後にコマンドを入力したい。

GHQ - r7km/sで書かれているp()という関数を使うと心理的なハードルが下がる。

$ ghq list -p | p cd

などと入力する。

他に、実行結果をpecoに送って、絞り込んだ内容をバッファに出すキーバインドを設定しているといい気がする。

function peco-buffer(){BUFFER=$(eval${BUFFER}| peco)CURSOR=0
}
zle -N peco-buffer
bindkey "^[p" peco-buffer

このように設定すると

$ ls<M-p>    # <M-p>でコマンドを実行して、結果をpecoに送る
# 選択すると
$ <選択した行>

な感じになる。

以上です。m(*_ _)m pecoり。


Viewing all articles
Browse latest Browse all 5608

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>