概要
pecoは僕の生活の中で欠かせないものとなっています。
導入やその他は過去にも記事を書いたので良かったら参考にしてください。
そのうち、履歴からディレクトリ移動をするものがあったのですが、少し不満があったので改良しました。
不満点
# ### search a destination from cdr list
function peco-get-destination-from-cdr() {
cdr -l | \
sed -e 's/^[[:digit:]]*[[:blank:]]*//' | \
peco --query "$LBUFFER"
}
### search a destination from cdr list and cd the destination
function peco-cdr() {
local destination="$(peco-get-destination-from-cdr)"
if [ -n "$destination" ]; then
BUFFER="cd $destination"
zle accept-line
else
zle reset-prompt
fi
}
zle -N peco-cdr
bindkey '^x' peco-cdr
今まで上のようなコードを書いていたのですが、これだと履歴の順番で表示されます。
これはこれで便利なのですが、よく以下の様な状態になったりします。
~/a/b/c/d/
~/a/b/
~/a/b/e/
~/a/b/c/
~/a/
このとき、~/a/
に移動したかった場合、絞り込む方法がありません。(少なくとも僕の知る限りでは)
なので、いちいちカーソルを移動するか、適当に~/a/b/
に移動してからcd ..
したりしていました。
改良
なので、表示される順番を文字数でソートするようにしました。
# ### search a destination from cdr list
function peco-get-destination-from-cdr() {
cdr -l | \
sed -e 's/^[[:digit:]]*[[:blank:]]*//' | \
awk '{c=gsub("/","/"); print c,length($0),$0}' | \
sort -n | \
cut -d' ' -f1- | \
peco --query "$LBUFFER"
}
### search a destination from cdr list and cd the destination
function peco-cdr() {
local destination="$(peco-get-destination-from-cdr)"
if [ -n "$destination" ]; then
BUFFER="cd $destination"
zle accept-line
else
zle reset-prompt
fi
}
zle -N peco-cdr
bindkey '^x' peco-cdr
単純にawkで'/'の数と文字数を足して、ソートして、文字数の部分をcutしてからpecoに渡しているだけです。
処理速度が気になるところですが、自分の環境だとそこまで遅くないのでとりあえずこのままにしています。
これで上記の例だと以下のように表示されるので~/a/
に行きやすくなりました!
~/a/
~/a/b/
~/a/b/e/
~/a/b/c/
~/a/b/c/d/
改良
このままだと消去したディレクトリも記録に残っているので、それが上位に来てしまい邪魔になってしまいます。
そこで下記のスクリプトで定期的に存在しないディレクトリをcdrの記録から除去します。
#!/bin/sh
CDRFILE=~/.chpwd-recent-dirs
TMPFILE="$CDRFILE-tmp"
# exec < $CDRFILE
while read line; do
dir=$(echo $line | sed -e 's/\$//g')
# sed -e 's/'\''/"/g' |sed -e 's/\$//g')
eval test -d $dir
if [ $? -eq 0 ]; then
echo $line
fi
done < $CDRFILE > $TMPFILE
mv -f $TMPFILE $CDRFILE
問題点
これの問題点というか不満は、文字数でソートしているので最初の画面に/
,~
,/var
,'/etc'などで埋め尽くされる点です。
移動先の名前をある程度覚えていないと使えないです。
ただ、まあ文字数順=ディレクトリ構造の順ともいえるので、
us lo
とかで /usr/local/がヒットし、上の方は/usr/local/
以下の子ディレクトリが表示されるのでそこまで不満では無いのですが…