xyzzyで対応する括弧や引用符を自動的に挿入したり消したりする

Eclipseの挙動をイメージ。いずれもsiteinit.lに設定。

括弧や文字列を勝手に閉じる設定

特定のキーを入力したときに、指定した文字列をカーソルの後ろに挿入するようにした。
例えば"("を入力すると"()"と入力され、カーソルは括弧の中に入る。

;; 括弧や文字列は勝手に閉じる
(defun define-auto-suffix (keymap key suffix)
  "add suffixes automatically"
  (define-key keymap key #'(lambda () (interactive "*") (insert key) (save-excursion (insert suffix)))))
(define-auto-suffix *global-keymap* #\{ "}")
(define-auto-suffix *global-keymap* #\[ "]")
(define-auto-suffix *global-keymap* #\( ")")
(define-auto-suffix *global-keymap* #\' "'")
(define-auto-suffix *global-keymap* #\" "\"")

開始括弧や引用符を消したときに、閉じ括弧や対応する引用符を削除する設定

自動挿入する設定だけだと、間違って入力したときに前後を削除するのが面倒。
そこで、開き括弧などを消そうとしたときに、
カーソルが開き括弧と閉じ括弧に挟まれていれば、閉じ括弧側も消去する関数を用意した。
例えばカーソルが"()"の中にあるときに"("を消すと、自動的に")"も削除する。

;; 対応する括弧や引用符は勝手に消す
(defun delete-backward-char-or-suffix-or-selection-factory (prefix-suffix-pair-list)
  #'(lambda (&optional (n 1))
      (interactive "*p")
      ; selectionがあればそれを消す
      (if (pre-selection-p)
          (delete-selection)
        ; カーソル位置が接頭・接尾ペアに挟まれているかどうか各組み合わせについて確認し、一致するものがあればまとめて消す
        (if (not (dolist (element prefix-suffix-pair-list)
                   (let ((prefix (car element))
                         (suffix (cdr element)))
                     (if (and (string= prefix (buffer-substring (point) (save-excursion (backward-char (length prefix)) (point))))
                              (string= suffix (buffer-substring (point) (save-excursion (forward-char (length suffix)) (point)))))
                         (progn (delete-backward-char (length prefix))
                           (delete-char (length suffix))
                           (return t))))))
            ; マッチするものが無ければ普通のバックスペース
            (delete-backward-char n)))))

使用する際は、モードごとに前方消去のコマンドを上書きする。

;;; javascript-mode
(load-library "javascript-mode")
...
(define-key *javascript-mode-map* #\C-h
            (delete-backward-char-or-suffix-or-selection-factory
             '(("{"."}") ("[" . "]") ("(" . ")") ("'" . "'") ("\"" . "\""))))

設定ファイル全体は以下
https://github.com/phithon/dotfiles/blob/master/siteinit.l