search-one-word.el アップデート。リピート移動をより便利に

「Vimの一文字検索を実装してみる」として先日 "search-one-word.el" を公開しました。ただ実際使っていく中でいくつか不便に感じる部分があったのでアップデートしました。
目次
以前のバージョン
以前のバージョンは下記記事で公開しました。
こちらもそれなりに便利だったのですがやや不便に感じる面がありました。例えば "search-forward-repeat-with-char" を "H-f" にキーバインドしたとして、文字"d"の位置にカーソルをリピート移動させようとすると、
<span style="color: #8AE234;">"H-f"</span> <span style="color: #8AE234;">"d"</span> <span style="color: #8AE234;">"H-f"</span> <span style="color: #8AE234;">"H-f"</span> <span style="color: #8AE234;">"H-f"</span> <span style="color: #8AE234;">"H-b"</span> <span style="color: #8AE234;">"H-f"</span>
といった具合に移動する必要がありました。移動先の文字をタイプした後、再度コマンド起動キーを押す必要があり指の移動に問題がありました。
アップデート版(v2.0)概要
というわけで下記のように移動できるように改変しました。今回のバージョンではコマンドを起動するとカーソル移動モードに入るようになっています。
先ほどと同じように "d" の位置にカーソルをリピート移動させる場合
<span style="color: #8AE234;">"H-f"</span> <span style="color: #8AE234;">"d"</span> <span style="color: #8AE234;">"d"</span> <span style="color: #8AE234;">"d"</span> <span style="color: #8AE234;">"d"</span> <span style="color: #8AE234;">"d"</span> .....
この操作で可能になります。
また最初に "d" の位置に移動させていたけれどやはり "k" の位置に移動させたいといった場合
<span style="color: #8AE234;">"H-f"</span> <span style="color: #8AE234;">"d"</span> <span style="color: #8AE234;">"d"</span> <span style="color: #8AE234;">"k"</span> <span style="color: #8AE234;">"k"</span> <span style="color: #8AE234;">"k"</span> .....
こういった感じで途中で押すキーを変えれば良いだけです。非常に簡単です。
また行き過ぎて戻りたいといった場合は "C-s" (forward) と "C-r" (backward) が使えます。 具体的にはこんな感じで。
<span style="color: #8AE234;">"H-f"</span> <span style="color: #8AE234;">"d"</span> <span style="color: #8AE234;">"d"</span> <span style="color: #8AE234;">"C-r"</span> <span style="color: #8AE234;">"C-r"</span> <span style="color: #8AE234;">"C-s"</span> <span style="color: #8AE234;">"C-r"</span> .....
カーソル移動モードを抜けるには "C-g (or C-q, ESC)" をタイプします。こんな感じでカーソル移動がより便利になりました。
ソース
ソースはこんな感じ。
<span style="color: #8c8c8c;">(</span><span style="color: #96CBFE;">require</span> '<span style="color: #99CC99;">cl-lib</span><span style="color: #8c8c8c;">)</span> <span style="color: #8c8c8c;">(</span><span style="color: #96CBFE;">defvar</span> <span style="color: #c5c8c6; background-color: #1d1f21;">last-search-char</span> nil<span style="color: #8c8c8c;">)</span> <span style="color: #8c8c8c;">(</span><span style="color: #96CBFE;">defun</span> <span style="color: #FFD2A7;">direct-search-forward-char</span> <span style="color: #93a8c6;">()</span> <span style="color: #93a8c6;">(</span><span style="color: #96CBFE;">interactive</span><span style="color: #93a8c6;">)</span> <span style="color: #93a8c6;">(</span><span style="color: #96CBFE;">cl-loop</span> <span style="color: #b0b1a3;">(</span><span style="color: #96CBFE;">let</span> <span style="color: #97b098;">(</span><span style="color: #aebed8;">(</span>char <span style="color: #b0b0b3;">(</span>read-key <span style="color: #8AE234;">"Move to Char: "</span><span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span> <span style="color: #97b098;">(</span><span style="color: #96CBFE;">cond</span> <span style="color: #aebed8;">(</span><span style="color: #b0b0b3;">(</span>member <span style="color: #90a890;">(</span>string char<span style="color: #90a890;">)</span> '<span style="color: #90a890;">(</span><span style="color: #8AE234;">""</span> <span style="color: #8AE234;">""</span> <span style="color: #8AE234;">""</span><span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span><span style="color: #96CBFE;">cl-return</span><span style="color: #b0b0b3;">)</span> <span style="color: #aebed8;">)</span> <span style="color: #aebed8;">(</span><span style="color: #b0b0b3;">(</span>string= <span style="color: #8AE234;">""</span> <span style="color: #90a890;">(</span>string char<span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span><span style="color: #96CBFE;">if</span> last-search-char <span style="color: #90a890;">(</span><span style="color: #96CBFE;">progn</span> <span style="color: #a2b6da;">(</span><span style="color: #96CBFE;">when</span> <span style="color: #9cb6ad;">(</span>char-equal <span style="color: #8c8c8c;">(</span>char-after <span style="color: #93a8c6;">(</span>point<span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> last-search-char<span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span>forward-char<span style="color: #9cb6ad;">)</span><span style="color: #a2b6da;">)</span> <span style="color: #a2b6da;">(</span>search-forward <span style="color: #9cb6ad;">(</span>string last-search-char<span style="color: #9cb6ad;">)</span> nil t<span style="color: #a2b6da;">)</span> <span style="color: #a2b6da;">(</span>backward-char<span style="color: #a2b6da;">)</span><span style="color: #90a890;">)</span> <span style="color: #90a890;">(</span><span style="color: #96CBFE;">progn</span> <span style="color: #a2b6da;">(</span><span style="color: #96CBFE;">let</span> <span style="color: #9cb6ad;">(</span><span style="color: #8c8c8c;">(</span>char <span style="color: #93a8c6;">(</span>read-key <span style="color: #8AE234;">"Move to Char: "</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span><span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span><span style="color: #96CBFE;">if</span> <span style="color: #8c8c8c;">(</span>char-equal <span style="color: #93a8c6;">(</span>char-after <span style="color: #b0b1a3;">(</span>point<span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span> char<span style="color: #8c8c8c;">)</span> <span style="color: #8c8c8c;">(</span>forward-char<span style="color: #8c8c8c;">)</span><span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span>search-forward <span style="color: #8c8c8c;">(</span>string char<span style="color: #8c8c8c;">)</span> nil t<span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span>backward-char<span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span><span style="color: #96CBFE;">setq</span> last-search-char char<span style="color: #9cb6ad;">)</span><span style="color: #a2b6da;">)</span><span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #aebed8;">)</span> <span style="color: #aebed8;">(</span><span style="color: #b0b0b3;">(</span>string= <span style="color: #8AE234;">""</span> <span style="color: #90a890;">(</span>string char<span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span><span style="color: #96CBFE;">if</span> last-search-char <span style="color: #90a890;">(</span>search-backward <span style="color: #a2b6da;">(</span>string last-search-char<span style="color: #a2b6da;">)</span> nil t<span style="color: #90a890;">)</span> <span style="color: #90a890;">(</span><span style="color: #96CBFE;">progn</span> <span style="color: #a2b6da;">(</span><span style="color: #96CBFE;">let</span> <span style="color: #9cb6ad;">(</span><span style="color: #8c8c8c;">(</span>char <span style="color: #93a8c6;">(</span>read-key <span style="color: #8AE234;">"Move backward to Char: "</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span><span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span>search-backward <span style="color: #8c8c8c;">(</span>string char<span style="color: #8c8c8c;">)</span> nil t<span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span><span style="color: #96CBFE;">setq</span> last-search-char char<span style="color: #9cb6ad;">)</span><span style="color: #a2b6da;">)</span><span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #aebed8;">)</span> <span style="color: #aebed8;">(</span>t <span style="color: #b0b0b3;">(</span><span style="color: #96CBFE;">when</span> <span style="color: #90a890;">(</span>char-equal <span style="color: #a2b6da;">(</span>char-after <span style="color: #9cb6ad;">(</span>point<span style="color: #9cb6ad;">)</span><span style="color: #a2b6da;">)</span> char<span style="color: #90a890;">)</span> <span style="color: #90a890;">(</span>forward-char<span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span>search-forward <span style="color: #90a890;">(</span>string char<span style="color: #90a890;">)</span> nil t<span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span>backward-char<span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span><span style="color: #96CBFE;">setq</span> last-search-char char<span style="color: #b0b0b3;">)</span> <span style="color: #aebed8;">)</span> <span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> <span style="color: #8c8c8c;">(</span><span style="color: #96CBFE;">defun</span> <span style="color: #FFD2A7;">direct-search-backward-char</span> <span style="color: #93a8c6;">()</span> <span style="color: #93a8c6;">(</span><span style="color: #96CBFE;">interactive</span><span style="color: #93a8c6;">)</span> <span style="color: #93a8c6;">(</span><span style="color: #96CBFE;">cl-loop</span> <span style="color: #b0b1a3;">(</span><span style="color: #96CBFE;">let</span> <span style="color: #97b098;">(</span><span style="color: #aebed8;">(</span>char <span style="color: #b0b0b3;">(</span>read-key <span style="color: #8AE234;">"Move to Char: "</span><span style="color: #b0b0b3;">)</span><span style="color: #aebed8;">)</span><span style="color: #97b098;">)</span> <span style="color: #97b098;">(</span><span style="color: #96CBFE;">cond</span> <span style="color: #aebed8;">(</span><span style="color: #b0b0b3;">(</span>member <span style="color: #90a890;">(</span>string char<span style="color: #90a890;">)</span> '<span style="color: #90a890;">(</span><span style="color: #8AE234;">""</span> <span style="color: #8AE234;">""</span> <span style="color: #8AE234;">""</span><span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span><span style="color: #96CBFE;">cl-return</span><span style="color: #b0b0b3;">)</span> <span style="color: #aebed8;">)</span> <span style="color: #aebed8;">(</span><span style="color: #b0b0b3;">(</span>string= <span style="color: #8AE234;">""</span> <span style="color: #90a890;">(</span>string char<span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span><span style="color: #96CBFE;">if</span> last-search-char <span style="color: #90a890;">(</span><span style="color: #96CBFE;">progn</span> <span style="color: #a2b6da;">(</span><span style="color: #96CBFE;">when</span> <span style="color: #9cb6ad;">(</span>char-equal <span style="color: #8c8c8c;">(</span>char-after <span style="color: #93a8c6;">(</span>point<span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span> last-search-char<span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span>forward-char<span style="color: #9cb6ad;">)</span><span style="color: #a2b6da;">)</span> <span style="color: #a2b6da;">(</span>search-forward <span style="color: #9cb6ad;">(</span>string last-search-char<span style="color: #9cb6ad;">)</span> nil t<span style="color: #a2b6da;">)</span> <span style="color: #a2b6da;">(</span>backward-char<span style="color: #a2b6da;">)</span><span style="color: #90a890;">)</span> <span style="color: #90a890;">(</span><span style="color: #96CBFE;">progn</span> <span style="color: #a2b6da;">(</span><span style="color: #96CBFE;">let</span> <span style="color: #9cb6ad;">(</span><span style="color: #8c8c8c;">(</span>char <span style="color: #93a8c6;">(</span>read-key <span style="color: #8AE234;">"Move to Char: "</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span><span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span><span style="color: #96CBFE;">if</span> <span style="color: #8c8c8c;">(</span>char-equal <span style="color: #93a8c6;">(</span>char-after <span style="color: #b0b1a3;">(</span>point<span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span> char<span style="color: #8c8c8c;">)</span> <span style="color: #8c8c8c;">(</span>forward-char<span style="color: #8c8c8c;">)</span><span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span>search-forward <span style="color: #8c8c8c;">(</span>string char<span style="color: #8c8c8c;">)</span> nil t<span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span>backward-char<span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span><span style="color: #96CBFE;">setq</span> last-search-char char<span style="color: #9cb6ad;">)</span><span style="color: #a2b6da;">)</span><span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #aebed8;">)</span> <span style="color: #aebed8;">(</span><span style="color: #b0b0b3;">(</span>string= <span style="color: #8AE234;">""</span> <span style="color: #90a890;">(</span>string char<span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span><span style="color: #96CBFE;">if</span> last-search-char <span style="color: #90a890;">(</span>search-backward <span style="color: #a2b6da;">(</span>string last-search-char<span style="color: #a2b6da;">)</span> nil t<span style="color: #90a890;">)</span> <span style="color: #90a890;">(</span><span style="color: #96CBFE;">progn</span> <span style="color: #a2b6da;">(</span><span style="color: #96CBFE;">let</span> <span style="color: #9cb6ad;">(</span><span style="color: #8c8c8c;">(</span>char <span style="color: #93a8c6;">(</span>read-key <span style="color: #8AE234;">"Move backward to Char: "</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span><span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span>search-backward <span style="color: #8c8c8c;">(</span>string char<span style="color: #8c8c8c;">)</span> nil t<span style="color: #9cb6ad;">)</span> <span style="color: #9cb6ad;">(</span><span style="color: #96CBFE;">setq</span> last-search-char char<span style="color: #9cb6ad;">)</span><span style="color: #a2b6da;">)</span><span style="color: #90a890;">)</span><span style="color: #b0b0b3;">)</span> <span style="color: #aebed8;">)</span> <span style="color: #aebed8;">(</span>t <span style="color: #b0b0b3;">(</span>search-backward <span style="color: #90a890;">(</span>string char<span style="color: #90a890;">)</span> nil t<span style="color: #b0b0b3;">)</span> <span style="color: #b0b0b3;">(</span><span style="color: #96CBFE;">setq</span> last-search-char char<span style="color: #b0b0b3;">)</span> <span style="color: #aebed8;">)</span> <span style="color: #97b098;">)</span><span style="color: #b0b1a3;">)</span><span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span>
ダウンロード
下記からソースをダウンロードしてload-pathの通った所に置いて (require 'search-one-word) としても利用可能です。
https://www.inabamasaki.com/arc/search-one-word.el
# シェルで $ cd ~/emacs.d/elisp $ wget https://www.inabamasaki.com/arc/search-one-word.el ;; Emacs <span style="color: #8c8c8c;">(</span><span style="color: #96CBFE;">require</span> '<span style="color: #99CC99;">search-one-word</span><span style="color: #8c8c8c;">)</span>
使い方まとめ
M-x direct-search-forward-char もしくは M-x direct-search-backward-char で起動し minibufferの"Move to Char: "プロンプトに移動したい文字をタイプ。
リピートは文字を繰り返しタイプするか、"C-s"、"C-r" で移動。終わる時は"C-g"、または"C-q"か"ESC"。
キーバインドはお好みで。
<span style="color: #8c8c8c;">(</span><span style="color: #96CBFE;">bind-keys</span> <span style="color: #93a8c6;">(</span><span style="color: #8AE234;">"C-{"</span> . direct-search-backward-char<span style="color: #93a8c6;">)</span> <span style="color: #93a8c6;">(</span><span style="color: #8AE234;">"C-}"</span> . direct-search-forward-char<span style="color: #93a8c6;">)</span><span style="color: #8c8c8c;">)</span>