Bash
Zsh
xonsh
XonshDay 10

俺はzshからxonshに乗り換えるぞ!ジョジョーーッ!

zshからxonshに乗り越えるために

基本的にxonshは、source-zshを利用することで、zshの設定をある程度読み込むことができます。
しかし、zshで利用していたzの設定をうまく読み込めなかったので、xonshで書き換えてxonshをメインのshellとして利用することを目指します。

zについて

過去のディレクトリの移動履歴をカウントするものです。
自分はzとpecoを使って、よく移動するディレクトリを選択し、移動するインターフェースを常時利用しており、これがないままのxonshの利用は快適ではありません。

zshでzの結果をpecoって爆速でディレクトリ移動する

z

zは引数なしで実行した時,よく移動するディレクトリ順と,頻度の指標が表示されます

z

参考: https://qiita.com/maxmellon/items/23325c22581e9187639e

zをxonshで読み込んでみる

zの利用は、z.shをshellでsourceすることにより利用できる仕組みになっています。.zshrcでの設定は、下記の感じです。

.zshrc
export _Z_CMD=z
. $(brew --prefix)/etc/profile.d/z.sh

xonshは外部のshellを読み込む機能があるため、xonshでz.shをsourceしてみましたが、うまく動作しないようです。

a.sh
$ source-bash /usr/local/etc/profile.d/z.sh
$ z
xonsh: subprocess mode: command not found: _z
Did you mean one of the following?
    z:   Alias
    xz:  Command (/Users/htaguchi/.pyenv/versions/anaconda3-5.0.1/bin/xz)
    w:   Command (/usr/bin/w)
    [:   Command (/bin/[)
    cd:  Alias
$ _z
xonsh: subprocess mode: command not found: _z
Did you mean one of the following?
    z:   Alias
    xz:  Command (/Users/htaguchi/.pyenv/versions/anaconda3-5.0.1/bin/xz)
    w:   Command (/usr/bin/w)
    [:   Command (/bin/[)
    cd:  Alias

何かうまくsourceする方法がありそうですが、.xonshrcにてzと同等の機能を作成した方が、目的をすぐに達成できそうなので、今回はそちらの手法を試みます。

zの書き換え

zで利用していた機能は、「よく移動するディレクトリ順と,頻度の指標の表示」でした。
そのため、zと同等の機能を得るために

  1. ディレクトリ移動のタイミングで、カレントディレクトリのパスのログを落とす
  2. カレントディレクトリのパスのログから、頻度順にパスを並び替える

の順番で実装を行っていこうと思います。

実装

xonshのチュートリアルを確認すると、関数に@events.on_chdirのデコレータを利用するだけで、ディレクトリ移動をフックできるようなので、これを利用します

参考: http://xon.sh/tutorial_events.html

.xonsh
from collections import Counter
from prompt_toolkit.keys import Keys

$DIR_HIST_PATH = "/Users/htaguchi/.dirhist"

"""
1. ディレクトリの移動タイミングで、カレントディレクトリのパスをファイルに保存
"""
@events.on_chdir
def add_to_file(olddir, newdir, **kw):
    with open($DIR_HIST_PATH[0], 'a') as dh:
        print(newdir, file=dh)

"""
2. パスの出現頻度を算出し、降順に並べる
"""
def z():
    lines = open($DIR_HIST_PATH[0]).read().rstrip("\n").split("\n")
    return("\n".join([p for p, c in Counter(lines).most_common()]))

"""
3. CTRL-F + CTRL-R のキーで関数を呼び出し
"""
@events.on_ptk_create
def custom_keybindings(bindings, **kw):
    handler = bindings.registry.add_binding

    @handler(Keys.ControlF, Keys.ControlR)
    def _z(event):
        selected = $(echo @(z()) | peco)
        cd_cmd = "cd " + selected.strip()
        event.current_buffer.insert_text(cd_cmd)

まとめ

zの設定を乗り越えたので、これでxonshをメインのshellとして利用できそうです。
Pythonの資産を利用したshellの拡張がすぐできるのは、とても良いですね。