🔖

Lem Advent Calendar 2023 - Multiple cursors

2023/12/17に公開

これは Lem Advent Calendar の記事です。

LemはMultiple cursorsに対応しています。
これによってカーソルを複数追加し、それらのカーソルを一度に操作することが出来ます。

デモ

M-Cで現在のカーソルの下に新しいカーソルが作られます。

C-sで文字列を検索中にC-M-nで現在のカーソルの次にマッチしている箇所に新しいカーソルが作られます。

クリップボード(Killring)はカーソル毎に保持します。
C-gで作ったカーソルを全て削除でき、クリップボードの内容は一つにマージされます。

内部実装

lemは最近まで、カーソルを複数使えるようにすることを想定していませんでした。
multiple cursorsの実装に着手するころに初めて、複数のカーソルを同時に操作できるようにすることを考えはじめました。
各カーソル操作系コマンドを全て対応する必要があり、最小限の変更で全て対応するためにコマンドに対してadviceと呼ばれる仕組みを導入しました。

define-commandでコマンドを定義します。
https://github.com/lem-project/lem/blob/be98202b2001fad07e3b108ce190a017d7a3ba3b/src/commands/move.lisp#L78

各コマンドはクラスとして定義しており、移動に関するコマンドクラスの場合はmovable-adviceというadviceクラスを継承します。
adviceクラスはmixinと似たようなものですが、commandクラスに対して振舞いを拡張するためのものです。

コマンドが呼び出されるとき、executeというメソッドが呼び出されます。
(execute current-mode command arg)

以下のようなメソッドを定義することで、全てのmovable-adviceを指定したコマンドに対して振舞いを加えられます。
https://github.com/lem-project/lem/blob/be98202b2001fad07e3b108ce190a017d7a3ba3b/src/command-advices.lisp#L22-L25

既知の問題

カーソルを移動したり、一文字挿入するような単純なコマンドは上記のように簡単に対応できるのですが、
複雑な振舞いをするコマンドは一部multiple cursorsに対応できてなかったりします。
例えばTabによる補完を行う機能や、C-sでのバッファ検索機能では一つのカーソルしか扱えません。
これらに対しては一つずつ内部設計を変更していく必要がありそうです。

Discussion