Emacsで3の倍数の行に色をつける

正確に言えば「行番号が3で割ったときに1と2の時に緑と青の背景にしたい」という目的。http://www.bookshelf.jp/soft/meadow_26.html#SEC314 を参考にしようとしたが結局小手先の修正では目的通りの挙動にならないので色々勉強した。
まずは行だとかエディタの一部に色をつけるのにはOverlays - GNU Emacs Lisp Reference Manualを使う。オーバーレイは始点と終点を指定して作成する。

; stripes.el

(defun stripes-create ()
  "Colors lines in current buffer alternatively.
This will not monitor changes of the buffer."
  (save-excursion
    (save-restriction
      (widen)
      (stripes-remove)
      (goto-char (point-min))
      (while (not (eobp))
	(forward-line stripes-lcount)
	(let ((ppp (point))
	      ovl)
	  (unless (eobp)
	    (forward-line stripes-lcount)
	    (setq ovl (make-overlay ppp (point)))
	    (overlay-put ovl 'face 'stripes-face)))))))

(widen)はナローイングの解除。(goto-char (point-min))でバッファ先頭に移動してからforward-lineでstripes-lcount(通常1)行ずつ下に進み、進む前pppと後(point)の範囲でmake-overlayして、そのオーバーレイにoverlay-putでfaceを指定している。

行番号を3で割った余りは(% (line-number-at-pos) 3)でわかる。

stripes.elでは全オーバーレイを取得してからそのfaceの値をチェックして削除する関数を自分で実装しているけど、(remove-overlays (point-min) (point-max) 'category 'stripe)とかでOK。

stripes.elではモードに入ったときにバッファの全体に対してオーバーレイを設置するけど、僕のニーズではバッファが100万行とかあるのでそれをされると困る。(window-start)と(window-end)の間だけ付けるようにしたけどスクロールしたときの更新はどうしようかなぁ。スクロールのコマンドに対してアドバイスを付ければいいのかなあ。Defining Advice - GNU Emacs Lisp Reference Manual

stripes.elでは編集されたときにはこうやって作り直しているな

(defun stripes-after-change-function (beg end length)
  "After change function for color alternation mode.
Refreshes all the highlighting.  This is slow, but as mostly lists are
not changed that often, it should be acceptable.  Arguments BEG END
and LENGTH are not used."
  (if stripes-mode
      (stripes-create)))

(add-hook 'after-change-functions
   'stripes-after-change-function)

おお、スクロールのフックが用意されている:Standard Hooks - GNU Emacs Lisp Reference Manual これでよさそうだな。