major-mode のつくり方 -- 調査中 #1

major-mode というのは current buffer に対していろいろする関数。以下の「major-mode を適用するときに...」という部分はこの関数でやる。

(defun example-mode ()
  (interactive)
  ...)

お約束: 既存の buffer-local 変数、モード名、buffer-mode 変数

関数 kill-all-local-variables でそれ以前に設定されてた buffer-local な変数は全部開放。
モード名(モードラインに表示される)は変数 mode-name にセットしておく。
buffer-mode 変数にその major-mode コマンドのシンボルを入れておくことになってる。これはどの major-mode でも実行される hook で、特定の major-mode だったときだけ何かしたい場合などに (eql buffer-mode 'lisp-mode) などと使う。

  (kill-all-local-variables)
  (setq mode-name "Example"
        buffer-mode 'example-mode)

フック

事前に hook 変数として *example-mode-hook* を defvar しておく。初期値は nil でおk。

(defvar *example-mode-hook* nil)

major-mode を適用するときに、関数 run-hooks でその hook を起動する。これは major-mode command の最後でやる。

  (run-hooks '*example-mode-hook*)

キーマップ

事前に make-sparse-keymap で keymap を作って(key-bindingsも設定して)おいて、 *example-mode-map* という special 変数に入れておく。ほとんどの場合は make-keymap じゃなくて make-sparse-keymap でいいと思う(よくわかってない)。
普通はこうする。この lisp code を最初に評価したときは keymap を作るけど、再評価したときに再定義はしない(ユーザが変更した key-bindings を元に戻さないように?)。

(defvar *example-mode-map* nil)
(unless *example-mode-map*
  (setq *example-mode-map* (make-sparse-keymap))
  (define-key *example-mode-map* #\KEY 'COMMAND)
  ...)

major-mode を適用するときに、関数 use-keymap でその keymap を使うようにする。

  (use-keymap *example-mode-map*)

シンタックステーブル

事前に syntax-table を作って、*example-mode-syntax-table* という special 変数に入れておき、関数 set-syntax-* で syntax を定義しておく。

(defvar *example-mode-syntax-table* nil)
(unless *example-mode-syntax-table*
  (setq *example-mode-syntax-table* (make-syntax-table))
  (set-syntax-string *example-mode-syntax-table* #\")
  ...)

syntax を指定する関数たち:

  • set-syntax-start-column-comment
  • set-syntax-escape
  • set-syntax-end-c++-comment
  • set-syntax-start-c++-comment
  • set-syntax-tag
  • set-syntax-start-multi-comment
  • set-syntax-start-comment
  • set-syntax-end-multi-comment
  • set-syntax-symbol-prefix
  • set-syntax-comment-column
  • set-syntax-whitespace
  • set-syntax-word
  • set-syntax-string
  • set-syntax-junk
  • set-syntax-symbol
  • set-syntax-quote
  • set-syntax-math
  • set-syntax-option
  • set-syntax-match
  • set-syntax-punctuation
  • set-syntax-end-comment

major-mode を適用するときに、関数 use-syntax-table でその syntax-table を使うようにする。

  (use-syntax-table *example-mode-syntax-table*)

キーワードハイライト

まずキーワードファイルを用意しておき、special 変数 *example-keyword-file* にそのファイル名を設定しておく。
次にキーワードファイルから生成される keyword-hash-table を保存する special 変数 *example-keyword-hash-table* を用意しておく。この時点では値は nil でおk。

(defvar *example-mode-file* "Example")
(defvar *example-keyword-hash-table* nil)

major-mode を適用するときに、キーワードファイルを読み込んで keyword-hash-table をつくって *example-keyword-hash-table* に保存しておく。既に保存してあったらやらない。
んでもってこの keyword-hash-table を buffer-local 変数 keyword-hash-table に入れることで適用する。

  (when (and *example-keyword-file*
             (null *example-keyword-hash-table*))
    (setq *example-keyword-hash-table*
          (load-keyword-file *example-keyword-file*)))
  (when *example-keyword-hash-table*
    (make-local-variable 'keyword-hash-table)
    (setq keyword-hash-table *example-keyword-hash-table*))

メモ: 関係ありそうなもの、調べなきゃならなさそうなもの

  • regexp-keyword-list
  • paragraph-separate, paragraph-start
  • package と prefix と
  • export するもの
  • c-indent 関係