Go to the first, previous, next, last section, table of contents.
メジャーモードは...
ある特殊化されたエディティング(タスク)を行なうために多くのコードを書かなくては
いけない場合、メジャーモードを(新規に) 作りたいと思うことがあります。メジャー
モードを新規に作るということに関しては、既存のメジャーモードをカスタマイズする
ことが考えられます。メジャーモードのいくつかの例を標準の `lisp' ライブラリ(こ
れを指す標準的な方法は何だろう??)に見ることができます。 rmail-mode はかなり複
雑で、完全な機能を持ったものの例です。 rmail-edit-mode はいくつかのコマンドを
インプリメントするために作られたメジャーモードの例です。コマンドが 3 つ与えら
れている点を除くと、このモードは text モードに(非常に)良く似ています。 1つのメ
ジャーモードに複数の仕事をさせるのは(その) コードや使用法を混乱させることにな
るため、メジャーモードを新規に作るのは役に立ちます。
メールをエディットするような仕事の(いくつか)は、リカーシブエディットを必要とし
ます。 rmail-edit-mode はカレントな rmail メッセージのエディットを可能にする
モードであるため、カレントなメッセージをリカーシブにエディットすることは意味の
あることのように思われます。しかし、リカーシブエディットはユーザーにとって混乱
のもととなるため、メジャーモードを新規に作ったほうが良いでしょう。リカーシブエ
ディットを用いるのは、インプリメントにおいて別の方法が存在しない場合のみに限る
べきです。その 1つの例が Emacs デバッガの場合です。
メジャーモードを設定するためには、コーディング上の慣習(訳注:conventions)に従
い、いくつかの点に注意しなくてはいけません。この慣習はグローバル名、ローカル
キーマップ、シンタックステーブルの初期化、及びフックに関するものです。
-
最もトリビアルなこととして、ユーザーは `-mode' のサフィックスを持つ名前のコ
マンドで(その)メジャーモードを初期化できなくてはいけません。モードに入る方法
が別にあってもかまいませんが、(全てを)初期化するのに呼ぶことのできる関数が 1
つ存在しなくてはいけません。
-
グローバル名は(全て)同じネームスペースに入るため、 (全ての)コンスタント、グ
ローバル変数、及び関数の名前の前にそのメジャーモード名(それが長いようでした
ら、その省略形)を付けるようにしなくてはいけません。
-
メジャーモード関数は、C-h m (describe-mode) で表示されるドキュメンテーション
を持ってなくてはいけません。このドキュメンテーションはキーバインディングのリ
ストや(適切な)バッファローカル変数を含むことがあります。
-
メジャーモード関数は、そのメジャーモード関数のシンボルを変数 major-mode に、
そのモードの "pretty" 名を mode-name に設定しなくてはいけません。
-
ローカルキーを(ある)デフォールト値に明示的に設定するのではなく、そのモードに
固有のキーマップ変数を用いるべきです。すでにそれが設定されてある場合、メ
ジャーモードの初期化はそのキーマップ変数を変更すべきではありません。これによ
り、(キーマップを用いる前に)ユーザーがそのキーマップ変数の設定を行なうこと
で、ローカルキーバインディングをカスタマイズできるようにします。
-
シンタックステーブル変数や abbrev テーブルもキーマップ変数と同じ理由で用いら
れるべきです。そうでない場合、関連したモードのテーブルを用いるべきです。
-
メジャーモード関数は、変数にバッファローカルバインディングを与える際(通常)
make-variable-buffer-local ではなく make-local-variable を用いるべきです。こ
の 2つの関数の違いに関しては、セクション 9.5 [バッファローカル変数]、ページ
79 を参照して下さい。
-
フックが適切なものである場合、 (ユーザーがローカル変数をカスタマイズする場合
があるため) メジャーモード関数は(通常)初期化を全て終えた後、フックを走らせる
べきです。
以下に示す `Lisp-mode.el' からの抜粋は、上記の慣例の多くを示しています。
(lisp-mode と emacs-lisp-mode の) 2 種類のモードがこのコードを用いています。
(defvar lisp-mode-syntax-table nil "")
(defvar lisp-mode-abbrev-table nil "")
;; まだ設定されてない場合、シンタックステーブルを作る
(if (not lisp-mode-syntax-table)
(let ((i 0))
(setq lisp-mode-syntax-table (make-syntax-table))
(while (< i ?0)
(modify-syntax-entry i "_ " lisp-mode-syntax-table)
(setq i (1+ i)))
...
(modify-syntax-entry ?\) ")( " lisp-mode-syntax-table)))
(define-abbrev-table 'lisp-mode-abbrev-table ())
;; lisp モードのためバッファローカル変数を定義する
(defun lisp-mode-variables ()
(set-syntax-table lisp-mode-syntax-table)
(setq local-abbrev-table lisp-mode-abbrev-table)
...
(make-local-variable 'comment-indent-hook)
(setq comment-indent-hook 'lisp-comment-indent))
;; lisp モードコマンドを 指定されたマップにバインドする
(defun lisp-mode-commands (map)
(define-key map "\e\C-q" 'indent-sexp)
(define-key map "\177" 'backward-delete-char-untabify)
(define-key map "\t" 'lisp-indent-line))
;; emacs-lisp-mode-map を作る
(defvar emacs-lisp-mode-map () "") ; デフォルト値は nil
(if emacs-lisp-mode-map
() ; すでに non-nil の場合、何もしない
(setq emacs-lisp-mode-map (make-sparse-keymap))
(define-key emacs-lisp-mode-map "\e\C-x" 'eval-defun)
(lisp-mode-commands emacs-lisp-mode-map))
;; メジャーモードコマンドを定義する。
(defun emacs-lisp-mode ()
"Major mode for editing Lisp code to run in Emacs.
Commands:
Delete converts tabs to spaces as it moves back.
Blank lines separate paragraphs. Semicolons start comments.
\\emacs-lisp-mode-map
Entry to this mode calls the value of emacs-lisp-mode-hook
if that value is non-nil."
(interactive)
(kill-all-map emacs-lisp-mode-map)
(setq major-mode 'emacs-lisp-mode)
(setq mode-name "Emacs-Lisp")
(lisp-mode-variables)
(run-hooks 'emacs-lisp-mode-hook))
Go to the first, previous, next, last section, table of contents.