Previous: , Up: Major Modes   [Contents][Index]


22.2.9 メジャーモードの例

おそらくTextモードは、Fundamentalを除いてもっともシンプルなモードです。上述した慣習の多くを説明するために以下にtext-mode.elの抜粋を示します:

;; このモード用に構文テーブルを作成
(defvar text-mode-syntax-table
  (let ((st (make-syntax-table)))
    (modify-syntax-entry ?\" ".   " st)
    (modify-syntax-entry ?\\ ".   " st)
    ;; M-cで`hello'が`hello'でなく`Hello'になるよう`p'を追加
    (modify-syntax-entry ?' "w p" st)
    st)
  "`text-mode'で使用される構文テーブル")

;; このモード用にキーマップを作成
(defvar text-mode-map
  (let ((map (make-sparse-keymap)))
    (define-key map "\e\t" 'ispell-complete-word)
    map)
  "`text-mode'のキーマップ
`mail-mode'、`outline-mode'、`indented-text-mode'のような
他の多くのモードはこのマップ内で定義した全コマンドを継承する")

そして実際にモードコマンドが定義される方法が以下になります:

(define-derived-mode text-mode nil "Text"
  "人間が読むために記述されたテキストを編集するためのメジャーモード
このモードではパラグラフを区切るのはブランク行か空白行だけである
したがって適応型フィル(adaptive filling)の全恩恵を受けられる
 (変数`adaptive-fill-mode'を参照のこと)
\\{text-mode-map}
Textモードのオンによりノーマルフック`text-mode-hook'が実行される"
  (set (make-local-variable 'text-mode-variant) t)
  (set (make-local-variable 'require-final-newline)
       mode-require-final-newline)
  (set (make-local-variable 'indent-line-function) 'indent-relative))

(現在はデフォルト値がindent-relativeなので最後の行が冗長だが将来のバージョンで削除する予定。)

3つのLisp用モード(Lispモード、Emacs Lispモード、Lisp Interactionモード)はTextモードより多くの機能をもち、それにふさわしくコードもより複雑です。そのようなモードの記述方法を説明するためにlisp-mode.elの抜粋を示します。

以下はLispモードの構文テーブルとabbrevテーブルを定義する方法です:

;; モード固有のテーブル変数の作成
(defvar lisp-mode-abbrev-table nil)
(define-abbrev-table 'lisp-mode-abbrev-table ())

(defvar lisp-mode-syntax-table
  (let ((table (copy-syntax-table emacs-lisp-mode-syntax-table)))
    (modify-syntax-entry ?\[ "_   " table)
    (modify-syntax-entry ?\] "_   " table)
    (modify-syntax-entry ?# "' 14" table)
    (modify-syntax-entry ?| "\" 23bn" table)
    table)
  "`lisp-mode'で使用される構文テーブル")

Lisp用の3つのモードは多くのコードを共有します。たとえば以下の関数呼び出しによってさまざまな変数がセットされます:

(defun lisp-mode-variables (&optional syntax keywords-case-insensitive)
  (when syntax
    (set-syntax-table lisp-mode-syntax-table))
  (setq local-abbrev-table lisp-mode-abbrev-table)
  …

その中でも特に以下の関数はLispコメントを処理するために変数comment-startをセットアップします:

  (make-local-variable 'comment-start)
  (setq comment-start ";")
  …

これらの異なるLisp用モードは、微妙に異なるキーマップをもちます。たとえばLispモードはC-c C-zrun-lispにバインドしますが、他のLisp用モードはこれを行いません。とはいえすべてのLisp用モードに共通なコマンドがいくつかあります。以下のコードはそれらの共通コマンドをセットアップします:

(defvar lisp-mode-shared-map
  (let ((map (make-sparse-keymap)))
    (define-key map "\e\C-q" 'indent-sexp)
    (define-key map "\177" 'backward-delete-char-untabify)
    map)
  "すべてのLisp用モードでコマンドを共有するためのキーマップ")

そして以下がLispモードのためのキーマップをセットアップするコードです:

(defvar lisp-mode-map
  (let ((map (make-sparse-keymap))
	(menu-map (make-sparse-keymap "Lisp")))
    (set-keymap-parent map lisp-mode-shared-map)
    (define-key map "\e\C-x" 'lisp-eval-defun)
    (define-key map "\C-c\C-z" 'run-lisp)
    …
    map)
  "通常のLispモード用キーマップ
`lisp-mode-shared-map'のすべてのコマンドはこのマップを継承する")

最後はLispモードのためのメジャーモードコマンドです:

(define-derived-mode lisp-mode prog-mode "Lisp"
  "GNU Emacs Lisp以外のLispコードを編集するためのメジャーモード
コマンド:
あたかも後方に移動するようにタブをスペースに削除変換する
パラグラフ区切りはブランク行でコメント開始はセミコロン

\\{lisp-mode-map}
`run-lisp'はinferior Lispジョブの開始と既存ジョブ
から戻るための両方に使われるかもしれないことに注意

このモードへのエントリーによって
`lisp-mode-hook'の値が非nilならそれを呼び出す"
  (lisp-mode-variables nil t)
  (set (make-local-variable 'find-tag-default-function)
       'lisp-find-tag-default)
  (set (make-local-variable 'comment-start-skip)
       "\\(\\(^\\|[^\\\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *")
  (setq imenu-case-fold-search t))