読者です 読者をやめる 読者になる 読者になる

Emacsで clever-f.vim的な動作を実現する

emacs

本家を一切使ったことがない上, あまり考えていない実装なのでたぶん機能的に
大幅に劣ると思うのですが, 実装してみました.

コード

(defvar my/last-search-char nil)
(defun my/forward-to-char (arg &optional char)
  (interactive "p\n")
  (unless char
    (if (memq last-command '(my/forward-to-char my/backward-to-char))
        (setq char my/last-search-char)
      (setq char (read-char "Forward Char: "))))
  (setq my/last-search-char char)
  (when (>= arg 0)
    (forward-char 1))
  (let ((case-fold-search nil))
    (search-forward (char-to-string char) nil t arg))
  (when (>= arg 0)
    (backward-char 1)))

(defun my/backward-to-char (arg &optional char)
  (interactive "p\n")
  (unless char
    (if (memq last-command '(my/forward-to-char my/backward-to-char))
        (setq char my/last-search-char)
      (setq char (read-char "Backward Char: "))))
  (backward-char 1)
  (my/forward-to-char (- arg) char))

(defun my/forward-last-char ()
  (interactive)
  (my/forward-to-char 1 my/last-search-char))

(defun my/backward-last-char ()
  (interactive)
  (my/backward-to-char 1 my/last-search-char))

(global-set-key (kbd "C-M-s") 'my/forward-to-char)
(global-set-key (kbd "C-M-r") 'my/backward-to-char)

(smartrep-define-key
    global-map  "C-x" '((";" . 'my/forward-last-char)
                        (":" . 'my/backward-last-char)))


C-M-sが Vimの "f", C-M-rが Vimの "F"相当です. それらが連続して
実行されるとき, 前入力したものと同じ文字を検索します. 3本も
指を使うので楽ではありませんが, Lisp系の言語を書くのに慣れている
人であればあんまり苦することなく押せるのではないかなと思います.


ついでに書いた "C-x ;"のものは, Vimの ";"で, "C-x :"は,
Vimの ","に相当します. こちらは smartrepを使って, 2回目移行は
prefixなしで実行可能にしました. こちらは C-M-sを実行してから
別のコマンドを実行した場合でも機能します.


自分好みの挙動に実装したので, Vimのものとは使い勝手が違うかも
しれません.

おわりに

あんまりこういうことをやりまくるなら, 素直に Evilを使って,
Evilの機構で実装した方が良さそうです.