ターミナルでのファイルパス指定をpecoを使って高速にする


以前、pecoを使って端末操作を爆速にするで紹介したCtrl + Fでのファイルサーチをもっと使い勝手よくしてみました。

Gitリポジトリ検索やコマンド履歴検索はとても快適だったのですが、ファイル検索が少し使いづらかったので改良してみました。

課題

  • Homeディレクトリで検索すると、対象が多すぎてフィルタリングが辛い
  • 検索して見つかったファイルと、その周辺のファイルを編集したいので、その近辺のディレクトリに移動したいが面倒

改良後

(何も入力せずに) <Ctrl + F>

ファイルを選択した場合

ディレクトリを選択した場合

ターミナルに何も入力していない状態で呼び出した場合、カレントディレクトリ以下のファイルが候補として列挙されます。

選択後はファイルのタイプに応じて挙動が変わります。

  • ファイルを選択する
    • → vimで開く
  • ディレクトリを選択する
    • → cdで移動

command <Ctrl + F>

コマンド等を入力し、スペースを入力した後、呼び出した場合も、カレントディレクトリ以下のファイルが候補として列挙されます。

選択後は、入力途中だったターミナルの末尾にファイルパスが入力されます。

command /path/to/base/<Ctrl + F>

ファイルパスの入力途中で呼び出した場合は、そのパス以下のファイルが候補として列挙されます。(これがやりたかった)

選択後は、入力途中だったターミナルの末尾にファイルパスが入力されます。

なお、入力中のパスが実在しない場合は、カレントディレクトリ以下が候補となります。

.zshrc

.zshrc中に以下の関数を定義すると使えるようになります。

export EDITOR=vi
function peco-find () {
    local base="."
    if [ -n "$LBUFFER" ] && [ ! "$LBUFFER" =~ " $" ]; then
        local last_path="$(echo $LBUFFER | sed -e 's/^.*\ //g')"
        if [ -d "$last_path" ]; then
            base="$last_path"
        fi
    fi
    local filepath="$(find $base | grep -v '/\.' | peco --prompt 'PATH>')"
    [ -z "$filepath" ] && return
    if [ -n "$LBUFFER" ]; then
        if [ "$base" = "." ]; then
            BUFFER="$LBUFFER$filepath"
        else
            BUFFER="$(echo $LBUFFER | sed -e "s#${base}\$##g")$filepath"
        fi
    else
        if [ -d "$filepath" ]; then
            BUFFER="cd $filepath"
        elif [ -f "$filepath" ]; then
            BUFFER="$EDITOR $filepath"
        fi
        zle accept-line
    fi
    CURSOR=$#BUFFER
}
zle -N peco-find
bindkey '^F' peco-find

動作環境

以下の環境で確認しました。

  • Linux Mint 18.3
  • peco v0.4.5
  • zsh 5.1.1 (x86_64-ubuntu-linux-gnu)