気づいたら新入社員がはいって来てました。なんか去年も同じこと書いた気がしますが、気のせいでしょう。

まだまだEmacsを現役で利用していますが、カーソルの移動に対するアプローチを変えつつあります。

もともとの課題感

私はEmacs上では multistate という、modal editingの仕組みだけを提供しているpackageを利用して、modal editingそのものは すべて 自前で定義しています。evilとかmeowとかも使ってたので、そういったもののエッセンスも入ってます。

ちなみにevilを利用しなくなったのは単純で、Qwertyを利用しなくなったのでマッスルメモリーが使えなくなった、というのが最大です。ただ、なんだかんだEmacs上でのエミュレートではあるのと、個人的にはtext objectよりもpuni/treesitterベースでの選択ができればそれでよかったです。

そんな中で、ずっと悩ましかったのがカーソル移動です。上下左右についてはそりゃー定義していますが、 10行下にあるfoo に行きたい、となった場合に、大抵10回キーを押してます。word単位の移動とかならまだいいんですが。一応avyとかも入れていたんですが、よくある文字だと候補が多すぎて・・・っていうのにもなります。

avyを激推しする記事

2021年の記事にはなりますが、すっごい長文の記事があります。めちゃくちゃ長いのですが、Emacsを利用している場合は読んでおくといいと思います。

https://karthinks.com/software/avy-can-do-anything/

この記事の要旨としては、

  • カーソルの移動というものは換言すると3stepの話でしかない
    • 同じ筆者が書いた、Emacsのウィンドウ管理に対する記事でも、同じような話があります
  • avyがすでにそれを提供している
  • isearchかavyで十分だ

というところです。間違ってたらごめんなさい。この記事を何回か読んで、なんとなーく把握できました。

移動の優先度を見直す

私がやるカーソル移動(検索含む)は以下です。上から順に頻度が高いです。

  • hjkl likeな文字単位移動
  • word単位移動
  • consult-xxx
    • consult-lineが最も頻度が高いです
  • isearch

色々見直した感じ、以下のようになるようにしてます。

  • hjkl likeな文字移動
  • isearch + avy
  • consult-xxx
  • mode-specificな移動
    • orgだったらheading単位とか

insert modeのままで・・・というのであれば他の選択肢もあると思いますが、いかんせんQwertyじゃないのでキー配置が色々ございまして、移動はnormal mode、と割り切っている次第です。

さて、isearchなんかいらなくて、全部consult-lineでいいじゃん?という方もいるでしょう。そこは自由なので「そうですね」となるのですが。それだと面白くないので、理由を書いてみようかと思います。

isearch vs consult-line

Emacsの検索というとisearchがまずデフォルトであるのですが、大抵は consult-line などの利用を勧めているケースが見られます。これがなんでかなーというところを考えると、

  • スペース区切りだったりで検索できる(ように見える)
  • 結果の一覧が見える

のが大きいのだと思います。これについては全く違和感がないのですが、ことカーソル移動を主眼に置くと、以下の点でoverpowerです。

  • 本質は filtining なので、検索はしていない
  • 今見えてる場所を一覧しても何も嬉しくない
    • 逆にminibuffer/bufferへの視線移動を伴う
  • 同一行に複数の結果がある場合に対応できない

特に最後は、consultの本来的な目的を考えると、サポートは難しいというかしないと思います。が、移動となると頻繁にありえます。isearchならなんの問題もなくできますよね?という。

isearchのカスタマイズ

激推しされるavyには、 avy-isearch というもうそのまんまな機能があります。対象のfilterをisearchでやり、selectをavyでやる、という形で1本化することができます。お、これで解決では?

キー数が増えてる、非効率だ!ってのはあると思いますが、単一操作であらゆるケースに対応できるので、記憶容量はむしろ減ると思います。avy/isearchの使い分けを・・・って考える時間のほうがもったいないんじゃ?と参照元も書いてた気がします。

さて、そんなisearchですが、欠点もあります。それは 検索方向を最初に決めないといけない ということです。 isearch-forwardisearch-backward ですね。isearchをカーソル移動として利用しようとしたとき、これが困ることが多いです。

例えばですが、5行上にある文字なりに移動しようとしたときにいつものノリでisearchすると、大抵は isearch-forward になってると思います。そんな中で検索すると、当然ですが下の方にカーソルが吹っ飛びます。avyは見えている範囲にしか意味がないので、これはこれで嬉しくない・・・。

https://github.com/derui/eyesearch

というわけで、超シンプルな拡張を生成AIで作りました。検索範囲の優先順に、 今見えている範囲 を追加します。forwardだろうとbackwardだろうと関係なく、見えてるところに対して移動、ということができます。ちなみにwindow内になかった場合は、そのまま普通に検索を開始します。

これを利用することで、buffer内の検索という点についてはisearchに1本化することができました。migemoは?とかまあ色々あるのですが、ちょっと現状migemoがややこしいので・・・。

まだ課題はあって、

  • transientを利用したmenuのキーバインド
    • Enterに入れてるんですが、enterでavy、でいいんでは?と思いつつ。
  • 日本語というかIMEが必要な検索がとっても大変
    • migemoが欲しくなる瞬間 NO.1
  • minibufferではない置換体験とかはあるのか?
    • isearchした対象に対して置換・・・とするとき、基本的にminibufferなんですが、一括置換とかは問題ないか?を確認するときにファイル全体を見たいときもしばしば
    • ちょっと考えきれてない & 大抵はmultiple-cursorで十分というのもあるので、優先順位は低めです

カーソル移動という根源的な行為への考察

今回は地味ーな話題ですが、テキストエディタとして最も基本的な機能でありながら、割と軽視されがちなところにフォーカスしました。ちなみに、 純粋に閲覧するだけ なのであれば、マウスを利用するのが最速かつ最善です。私も普通に使いますし、スクロールとかはタッチパッドのほうがわかりやすいですよね。

こういったことは、割と非効率なままマッスルメモリーになっていたりするので、切り替えは大変だったりします。しかし新しい方式に慣れてしまえば、それはそれでまた効率的だったり自然な操作、というところになっていくとも思います。

ちょうど春も半ばですので、心機一転というところで見直しをしてみるのもいいのではないでしょうか。