言語ゲーム

とあるエンジニアが嘘ばかり書く日記

Twitter: @propella

emacs における undo 操作

と、構える程の事も無く、必要十分に単純な事が分かった。

まずどういった動作が行われるかを書く。emacs の undo バッファは直線状で、一通りの過去しか記憶出来ない。しかし、一度ある時点にまで遡って別の編集を始める際に、「遡った」という記憶自体を undo バッファに記憶するため、実用上はあたかもツリー状の undo バッファを持つかのように振舞う。

分かりにくい説明だけど、たとえばウェブブラウザなんかでバックボタンを押して前のページに戻り、そこから今度は別のページに飛ぶと、バックボタンを押した時にどのページに居たのかという情報はブラウザから消えるわけです。しかし、emacs の場合は消えずにそこからバックで全経路をたどって戻るという事です。

これを実現するために、emacs では連続した undo と断続した undo を区別します。undo を連続して実行すると、当然押したぶんだけ過去に戻りますが、その際に undo したという情報自身が undo バッファに入ります。そして、undo と undo の間に少しでも別の編集作業を行うと、今度は undo の undo という事で redo のようになり、今度は最新バージョンに戻って行くことが出来ます(これには人それぞれお気に入りのキーシーケンスがあると思うが、僕はもっぱら C-f C-/)。

実装の中心は、バッファごとに用意されたリスト buffer-undo-list です。この中に連続して undo 情報が入っています。リストの要素によって undo の際に行うべき作業を示します。

  • 数字 - 戻すべきポイント位置
  • (数字 . 数字) - 削除すべきテキスト位置
  • (テキスト . 数字) - 挿入すべきテキスト位置
  • (t 数字 . 数字) - バッファの未変更フラグを変えるかどうか試す値
  • (nil なんとか 数字 . 数字) - テキスト属性変更
  • (MAKER . 数字) - マーカを再配置
  • nil - undo 境界

こんな単純な事で可能なのが、emacs がテキスト編集という明確な目的を持ったソフトウェアであり、状態(テキスト) を変更するために使われる関数が数える程しかないため、実装しやすいからだと思います。そこが etoys の undo と違う所。