Emacsからperltidyでバッファを整形するとoverlayやrepositoryが消える、ずれる問題

elispのshell-command-on-regionでREPLACEパラメータを設定してperltidyを呼び出してソースの整形を行った場合、バッファの内容をdelete-regionで削除しているので、設定してあったoverlayが消えてしまう。個人的に利用しているbm.elがoverlayを利用してブックマークを実現しているので、上書き保存のたびにブックマークが消えてしまう(write-file-hookでperltidyを実行しているため)。その他設定してあったrepositoryなどもずれてしまう。

実行前の位置を覚えておいて、整形後に復元するようにすると、多少のずれは出てくるものの、とりあえず両者を併用できる状態になる。

bmの復元は、perltidyの呼び出し前に、ブックマークをpersistentにtoggleし、ファイルに書き出し、呼び出し後に復元し、persistent状態を元に戻す。イメージは下記。

    (bm-toggle-buffer-persistence)
    (bm-buffer-save)
    (shell-command-on-region (point) (mark) "perltidy -i=2  -csc -ce" nil t)
    (setq bm-restore-on-mismatch t)
    (bm-buffer-restore)
    (bm-toggle-buffer-persistence)

bm-restore-on-mismatchはブックマークを復元する場合に元ファイルのサイズが変わっているかチェックするかどうかを判定する変数。サイズが異なっているとずれが発生する可能性が高いのでデフォルトは復元しないようnilになっているが、perltidy実施でサイズは変わっているはずなので、無視してrestoreするようにtに設定している。

registoryの場合は個人的にはpositionしか保存していないので、カレントバッファのmarkerだけ退避しておき、整形後に位置を復元するようにしている。下記をそれぞれ整形の前後に呼び出す。

(setq bkup-marker-register-position '())
(defun bkup-marker-registers ()
  "Backup the marker in the registory which marks the position of the current buffer."
  (interactive)
  (let ((list (copy-sequence register-alist))
        (bname (buffer-name)))
    (setq list (sort list (lambda (a b) (< (car a) (car b)))))
    (dolist (elt list)
      (when (get-register (car elt))
        (let ((val (get-register (car elt)))
              (key-desc (single-key-description (car elt))))
          (cond
           ((markerp val)
            (let ((buf (marker-buffer val)))
              (if (and buf (string= (buffer-name buf) bname))
                  (setq bkup-marker-register-position (append bkup-marker-register-position (list (list key-desc (marker-position val)))))
                )))))))))

(defun restore-marker-registers ()
  (dolist (elt bkup-marker-register-position)
    (goto-char (second elt))
    (point-to-register (string-to-char (car elt))))
  (setq bkup-marker-register-position '()))