Emacsのアドベントカレンダー2022、8日目の記事です。
Emacs上でNotionみたいなリッチなテキストが表示/編集できたらよいなと思い、なんとかできないか考えてみました。とりあえずproof of conceptレベルにはなったので公開します。
svg-table.elをevalして、svg-table-demo
を実行してみてください。C-n C-p C-f C-bによるカーソルの移動や、テキストの挿入・削除ができます。
Emacsには画像を表示する機能があります。「オーバーレイ」という機能を使うとテキストの一部を画像で置き替えて表示できます。そして画像としてSVGが表示できます(rsvgライブラリが使われています)。つまり、Emacsで画面が更新されるごとにSVGでGUIっぽい画像を作成して表示すれば、リッチなテキストが表示できるはずです。
具体的にはpre-redisplay-functions
というフックを使います。これは画面が更新される前に呼ばれますので、その中でSVGを作成してバッファ全体にオーバーレイを設定します。
SVGにはテキストに合わせて図形のサイズを変える機能は無いので、自分でテキストのサイズを測って図形のサイズを設定する必要があります。いろいろ調べた結果、window-text-pixel-size
関数を使うとテキストのサイズがピクセル単位で計測できるということがわかりました。LinuxのX11上ではEmacsの表示とrsvgによる表示はほぼ一致しているようですが、他の環境ではテストしていません。
C-pやC-nで上下のセルに移動する機能はまだ未完成です。今のところ文字の幅は1か2であるという仮定でカーソルを移動させています(current-column
が返す値を使っています)。しかし、プロポーショナルフォントを使っている場合はその仮定は崩れてEmacsの標準の動作とずれてしまいます。
マウスによる操作も未実装です。Emacsではマウスイベントが取れるので、座標から文字の位置を調べれば原理的には実装できるはずです。
fundamental-mode
に切り替えると生のテキストが見えます。
各セルはASCIIのunit separatorのみを持つ行で区切られていて、テーブルの各行はrecord separatorでのみを持つ行で区切られています。
CSVや、Org modeの表形式なども考えましたが、セルに複数行のテキストを入れたかったのと、C-aやC-eやreplace-string
などがなるべくそのまま動くようにしたかったのでこうなりました。