Eshell に zsh の history-beginning-search-forward (backward) を移植した.

三日坊主ってレベルじゃないけど気にしない!

Eshell は Emacs 上に実装されたシェルで,Emacs lisp で自由に拡張することが可能です.
が,デフォルトだと zsh などの他のシェルと比較して機能が少なく,そのまま使うには結構不便です.

機能がないなら実装すればいいじゃない!
というわけで,他のシェルの素敵機能を Eshell 上に実装していくことにしました.

history-beginning-search-forward (backward) って何?

これは zsh で使える素敵機能です (bash 等でも使えるのかは知りません).
例えば,プロンプトに以下を入力したとします(_ は現在のカーソル位置).

$ sudo _

この状態で history-beginning-search-forward や history-beginning-search-backward を使うことで,履歴の中から "sudo " で始まるものだけをたどることができます.
超便利です.この機能を使っていない人は,今すぐ .zshrc に

bindkey '^P' history-beginning-search-backward
bindkey '^N' history-beginning-search-forward

を追加しましょう.

今回はこの機能を Eshell に移植しました.
以下を .emacs.el などにコピーすることで使えるようになります.

(require 'em-hist)

(defun eshell-history-beginning-search-backward (arg)
  "arg で始まる履歴を検索して補完する.
zsh の history-beginning-search-backward にあたる機能."
  (interactive "p")
  (if (equal eshell-history-index
          (1- (ring-length eshell-history-ring)))
      (progn
        (eshell-bol)
        (delete-region (point) (point-max)))
      (let ((cur (point)))
        (eshell-previous-matching-input-from-input arg)
        (delete-region (point) (point-max))
        (goto-char cur)
        (setq this-command
              'eshell-previous-matching-input-from-input))))

(defun eshell-history-beginning-search-forward (arg)
  "arg で始まる履歴を検索して補完する.
zsh の history-beginning-search-forward にあたる機能."
  (interactive "p")
  (if (or (null eshell-history-index)
          (zerop eshell-history-index))
      (progn
        (eshell-bol)
        (delete-region (point) (point-max)))
      (let ((cur (point)))
        (eshell-next-matching-input-from-input arg)
        (delete-region (point) (point-max))
        (goto-char cur)
        (setq this-command
              'eshell-next-matching-input-from-input))))

(add-hook 'eshell-mode-hook
          (lambda ()
            (local-set-key [?\C-p]
                           'eshell-history-beginning-search-backward)
            (local-set-key [?\C-n]
                           'eshell-history-beginning-search-forward)))