検索エンジンから来た人に注意

このマニュアルは、Emacs ver. 19.x 向けのマニュアルを Mule 2.x の開発にあたり邦訳したものを、 電脳外道学会がミラーリングしているものであり、旧版製品パラノイアであるところの椅子人の趣味によるものです。

しかしながら、現在の Emacs の主流は ver. 20 以降であり、ver 19.x と ver 20.x とでは、仕様の違いが少なからずあります。

したがって、一般的な Emacs ユーザーにとっては、 このマニュアルと実機の動作とが符合しない場合があります。
特に、公開用の Emacs Lisp コードを書こうとする人は、 新バージョンのマニュアル(英語)を参照することを強くおすすめします。


トップページ&リンク | マニュアルの目次 | 検索
Go to the first, previous, next, last section, table of contents.


主モード、副モード

モード(mode)とは、Emacsをカスタマイズするための定義のセットのこ とであり、また、編集中に自由に使用/不使用を決めることができるものです。 モードは2種類に大別でき、それぞれ、主モード(major mode)副 モード(minor mode)と呼ばれています。主モードとは、ほかの主モードとは同 時に使用できず、また、特定の種類のテキストの編集に適した機能を提供するも のです。また、副モードとは、ユーザが好みに応じて自由に組み合わせて使用で きるものです。

この章では、主モードと副モードの作り方、モード行での表示の仕方、ユーザ によって指定されたフックの実行の仕方について説明します。キーマップ、構文 テーブルといった関連事項についてはそれぞれsection キーマップとsection 構文テーブルを参照してください。

主モード

主モードは、編集中のテキストの種類に合わせてEmacsを変身させます。 一つのバッファで同時に複数の主モードを利用することはできません。

最も普遍的な主モードにはFundamentalモード(Fundamental mode)とい う名前がつけられています。このモードにはモード固有の定義や変数の設定がな いので、Emacsのコマンドはデフォルトの動作をし、すべてのオプションはデフォ ルトの状態に設定されています。ほかの主モードは、さまざまなキーやオプショ ンを再定義しています。たとえば、Lisp InteractionモードではLFD (eval-print-last-sexp)、TAB (lisp-indent-line)やその ほかのキーに関して、機能の割当が変更されています。

特殊な編集作業のために新しいコマンドをいくつも作らなくてはならなくなった とき、新しい主モードを作るのは通常よい選択です。主モードを作る のは(副モードの作成がたいてい困難なのに比べれば)それほど難しくありま せん。

もし、新しいモードによく似たモードがすでにあっても、その古いモードを書 き換えて二つの目的の両方に対応できるようにしようとするのは賢明ではありま せん。なぜなら、そのようなモードは使用するのも維持するのも難しくなりがち だからです。代わりに、既存のモードをコピーし名前を変更してそれを書き換え るようにするか、または、導出モード(derived mode) (see section 導出モードを定義する) を定義するようにしてください。たとえば、Rmail Editモード (`emacs/lisp/rmailedit.el'で定義されています)は、三つの新しいコマン ドが使えるほかはTextモードにそっくりな主モードです。Rmail Editモードの定 義はTextモードの定義とは異なるものですが、全く別に作られたものではなく、 Textモードから導出されたものです。

Rmail Editモードは、テキストを一時的に異なる主モードにして、別の方法で (つまり、Rmailのコマンドではなく、通常のEmacsのコマンドで)テキストを編集 できるようにする場合の例になっています。このような場合に一時的に使用され る主モードは、そのバッファの通常のモード(この例ではRmailモード)に戻すた めのコマンドを持っています。似たような機能を実現するには、コマンドなどの 再定義を再帰編集の中で行ない、ユーザが再帰編集から抜けたところで定義を戻 す、という方法もありますが、ユーザが複数のバッファで同時にこのようなことを 行ったときに不便さを強要することになり、好ましくありません。再帰編集は最後に 始まったものからしか順に抜けられないのです。別の主モードを使用すればこの 制限はありません。See section 再帰編集

GNU Emacsが標準的に使用しているライブラリ・ディレクトリにはいくつかの主 モードのためのコードがあり、`text-mode.el'`texinfo.el'`lisp-mode.el'`c-mode.el'`rmail.el'などに納められて います。これらのファイルを見て、主モードがどのように記述されるのか を知ることができます。Fundamentalモードを除くとTextモードが最も単純なモー ドでしょう。また、Rmailモードは複雑で特殊なモードです。

主モードに関する慣例

既存の主モードのコードは、ローカル・キーマップや構文テーブルの初期化、 グローバルな名前、フックなどに関するさまざまな慣例にしたがって記述されて います。新しい主モードを作るときには、以下の慣例にしたがってください。

Variable: change-major-mode-hook
kill-all-local-variablesは、その最初の処理としてこの正規フックを 実行します。このフックを利用して、ユーザがバッファをほかの主モードに変更 したときに行う特殊な処理を定義できます。続く主モードに悪影響を及ぼさないよ うに、この変数をバッファにローカルにして、フックの実行後にこの変数が消え るようにしてください。See section フック

主モードの例

Textモードは、Fundamentalモードを除くと最も単純な主モードでしょう。以 下は、`text-mode.el'から抜粋した、上述のさまざまな慣例の実例です。 (訳注: 実際のコード中のコメント類は英語で書かれています)

;; モード特有の構文テーブルを作る。
(defvar text-mode-syntax-table nil 
  "Syntax table used while in text mode.")

(if text-mode-syntax-table
    ()              ; すでにテーブルができ上がっていたら書き換えない。
  (setq text-mode-syntax-table (make-syntax-table))
  (modify-syntax-entry ?\" ".   " text-mode-syntax-table)
  (modify-syntax-entry ?\\ ".   " text-mode-syntax-table)
  (modify-syntax-entry ?' "w   " text-mode-syntax-table))

(defvar text-mode-abbrev-table nil
  "Abbrev table used while in text mode.")
(define-abbrev-table 'text-mode-abbrev-table ())

(defvar text-mode-map nil)   ; モード特有のキーマップを作る。

(if text-mode-map
    ()       ; キーマップの中身がすでにでき上がっていたら書き換えない。
  (setq text-mode-map (make-sparse-keymap))
  (define-key text-mode-map "\t" 'tab-to-tab-stop)
  (define-key text-mode-map "\es" 'center-line)
  (define-key text-mode-map "\eS" 'center-paragraph))

以下は、Textモードの主モード関数の完全な定義です。

(defun text-mode ()
  "Major mode for editing text intended for humans to read. 
 Special commands: \\{text-mode-map}
Turning on text-mode runs the hook `text-mode-hook'."
  (interactive)
  (kill-all-local-variables)
  (use-local-map text-mode-map)     ; ローカル・キーマップを使う。
  (setq mode-name "Text")           ; モード行に表示される名前。
  (setq major-mode 'text-mode)      ; describe-modeがきちんと
                                    ; 説明文字列を見つけられるように。
  (setq local-abbrev-table text-mode-abbrev-table)
  (set-syntax-table text-mode-syntax-table)
  (run-hooks 'text-mode-hook))      ; こうしておくと、ユーザがフック
                                    ; を使ってカスタマイズできる。

三つのLispモード(LispモードとEmacs LispモードとLisp Interaction モード)は、Textモードよりも多くの機能を持っていて、どれも非常に複雑です。 以下の例は、`lisp-mode.el'からの抜粋です。これらのモードがどのよう に書かれているかを見てください。

;; モード特有のテーブルを保持する変数を作る。
(defvar lisp-mode-syntax-table nil "")  
(defvar emacs-lisp-mode-syntax-table nil "")
(defvar lisp-mode-abbrev-table nil "")

(if (not emacs-lisp-mode-syntax-table) ; テーブルの中身がすでにでき
                                       ; 上がっていたらそのままに。
    (let ((i 0))
      (setq emacs-lisp-mode-syntax-table (make-syntax-table))

      ;; 数字の0未満の文字について、シンボル名の一部であって
      ;;   ワードではない、と定義する。
      ;;   (数字の0はASCIIコードで48。)
      (while (< i ?0) 
        (modify-syntax-entry i "_   " emacs-lisp-mode-syntax-table)
        (setq i (1+ i)))
      ...
      ;; ほかの文字についても構文を定義する。
      (modify-syntax-entry ?  "    " emacs-lisp-mode-syntax-table)
      (modify-syntax-entry ?\t "    " emacs-lisp-mode-syntax-table)
      ...
      (modify-syntax-entry ?\( "()  " emacs-lisp-mode-syntax-table)
      (modify-syntax-entry ?\) ")(  " emacs-lisp-mode-syntax-table)
      ...))
;; lisp-modeで使用される省略形テーブルを作る。
(define-abbrev-table 'lisp-mode-abbrev-table ())

沢山のコードが三つのLispモードの間で共有されています。以下の関数はさまざま な変数を設定する機能があり、それぞれのLispモードから利用されます。

(defun lisp-mode-variables (lisp-syntax)
  ;; Emacs Lispではlisp-syntax引数はnil、
  ;;   それ以外の二つのLispモードではt。
  (cond (lisp-syntax
         (if (not lisp-mode-syntax-table)
             ;; Emacs Lispモードの構文テーブルは常に存在している。
             ;;   しかしLispモードの構文テーブルは必要になってか
             ;;   ら作る。これは記憶領域の節約のため。
             (progn (setq lisp-mode-syntax-table
                       (copy-syntax-table emacs-lisp-mode-syntax-table))
                    ;; Lispモードのためにいくつかのエントリを変更する
                    (modify-syntax-entry ?\| "\"   "
                                         lisp-mode-syntax-table)
                    (modify-syntax-entry ?\[ "_   "
                                         lisp-mode-syntax-table)
                    (modify-syntax-entry ?\] "_   "
                                         lisp-mode-syntax-table)))
          (set-syntax-table lisp-mode-syntax-table)))
  (setq local-abbrev-table lisp-mode-abbrev-table)
  ...)

forward-paragraphのような関数はparagraph-start変数の値 を使います。Lispコードは通常のテキストとは違うので、 paragraph-start変数の値はLispに合わせて設定されなければなりま せん。また、Lispではコメントは特殊なスタイルで字下げされるので、 Lispモードに特化したcomment-indent-functionも必要です。これら の変数を設定するためのコードが、lisp-mode-variablesの残りの部分 に書かれています。

  (make-local-variable 'paragraph-start)
  ;; こんな形で`^'を入れておかなきゃならないのは美しくないけど、
  ;; すでにpage-delimiterにも混じっているし、取り除くのも面倒。
  (setq paragraph-start (concat "^$\\|" page-delimiter))
  ...
  (make-local-variable 'comment-indent-function)
  (setq comment-indent-function 'lisp-comment-indent))

それぞれのLispモードは、少しずつ異なるキーマップを持っています。たとえ ば、LispモードではC-c C-zrun-lispにバインドされていますが、 ほかの二つのLispモードでは未定義です。 しかしながら、すべての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モードのコードの 中でlisp-mode-commandsを使用する例です。まず最初に、 defvarを使用してモードに特有なキーマップを保持するための変数を宣 言します。このdefvarは、その変数が値を持っていないときは値を nilにセットします。それから、その変数がnilならば、新しく キーマップをセットアップします。

このコードは、もしすでにキーマップがセットアップされていたら、変更せず にそのままにします。これにより、ユーザがキーマップをカスタマイズできます。

(defvar emacs-lisp-mode-map () "") 
(if emacs-lisp-mode-map
    ()
  (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))

で、以下が、Emacs Lispモードのための主モード関数の完全な定義です。

(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 runs the hook `emacs-lisp-mode-hook'."
  (interactive)
  (kill-all-local-variables)
  (use-local-map emacs-lisp-mode-map)    ; ローカル・キーマップを使用する。
  (set-syntax-table emacs-lisp-mode-syntax-table)
  (setq major-mode 'emacs-lisp-mode)     ; describe-modeが説明
                                         ;   文字列を見つけられるように。
  (setq mode-name "Emacs-Lisp")          ; モード行に表示されるモード名。
  (lisp-mode-variables nil)              ; いろいろな変数を定義する。
  (run-hooks 'emacs-lisp-mode-hook))     ; ユーザがカスタマイズのために定
                                         ;   定したフックをここで実行する。

主モードの自動選択の仕組み

ファイルを読み込んで新しくバッファを作る際に、Emacsは、ファイル名やファ イルの内容から主モードを自動的に選び出します。

Command: fundamental-mode
Fundamentalモードは、特別これといって変わったところのないモードです。ほ かの主モードは、このモードを元に何がどう変わるのかという記述で定義されま す。ですから、Fundamentalモードをカスタマイズするべきではなく、また、 fundamental-mode関数はいかなるフックも実行しません。 (Fundamentalモードの振舞を変えたい場合は、Emacsのglobal state(グ ローバル・キーマップなど)を変更するようにしてください)。

Command: normal-mode &optional find-file
この関数は、適切な主モードの立ち上げとローカル変数の設定を、カレント・バッ ファに対して行ないます。この関数は、最初に、set-auto-modeを呼んでモー ドを立ち上げ、次に、hack-local-variablesを呼んでファイルに記述され ているローカル変数の設定や式の評価を行ないます。

もし、normal-mode関数へのfind-file引数が非nil なら、normal-modefind-fileより呼ばれているものと仮定 します。この場合、ファイルの最後尾や`-*-'行にあるローカル変数リス トの処理を行うかもしれません。変数enable-local-variablesが、そ の処理を行うかどうかのコントロールを行ないます。

normal-modeをインタラクティブに(コマンドとして)実行した場合、 通常find-filenilになります。この場合、 normal-modeは無条件に全てのローカル変数リストの処理を行ないます。 (ローカル変数リストについてはSee section `Local Variables in Files' in The GNU Emacs Manualを参照)

normal-modeは、主モード関数の呼出しにcondition-caseを使用 します。そのため、主モード関数の評価中に発生したエラーは捕捉され、 `File mode specification error'としてオリジナルのエラー・メッセージ と一緒に報告されます。

User Option: enable-local-variables
この変数は、読み込まれたファイルのローカル変数リストをどのように扱うかを 決定します。この値がtならば処理し、nilならば無視、それ 以外ならばファイルごとにどのように扱うかをユーザに尋ねます。デフォルト値 はtです。

Variable: ignored-local-variables
この変数は、ローカル変数リストによって設定されたくない変数のリストを表し ます。このリストに含まれる変数に対する値は、もしそれが存在しても、すべて 無視されます。

このリストに加えてさらに、名前のrisky-local-variable属性 が非nilであるような変数に対する値も無視されます。

User Option: enable-local-eval
この変数は、読み込まれたファイルのローカル変数リストに含まれる `Eval:'をどのように扱うかを決定します。この値がtならば処 理し、nilならば無視、それ以外ならばファイルごとにどのように扱うか をユーザに尋ねます。デフォルト値はmaybeです。

Function: set-auto-mode
この関数は、カレント・バッファに適切な主モードを設定します。モードを 選び出す判断材料となるのは、`-*-'行の値、読み込まれたファイルの 名前(auto-mode-alistを使用)、およびローカル変数の値です。 ファイル最後尾付近の`mode:'ローカル変数の値の処理は、この関数ではなく hack-local-variables関数が行ないます。See section `How Major Modes are Chosen' in The GNU Emacs Manual.

User Option: default-major-mode
この変数は、新しく作られるバッファのデフォルトの主モードを保持します。標 準値はfundamental-modeです。

default-major-modeの値がnilの場合は、以前にカレントであっ たバッファの主モードを新しいバッファの主モードとして使います。ただし、主 モード・シンボルがmode-class属性を持ちその値がspecialであ る場合は、このdefault-major-mode変数の値に関わらずFundamentalモー ドが使われます。DiredやRmailのように、特殊なテキストでのみ意味のあるモー ドが、この属性を持っています。

Function: set-buffer-major-mode buffer
この関数は、bufferの主モードをdefault-major-modeの 値にセットします。もしその変数がnilならば、カレント・バッファの主 モードを使用します(もしそれが適当ならば)。

バッファを作るための低レベルなプリミティブはこの関数を呼ぶことはありませ んが、switch-to-bufferfind-file-noselectのような中レ ベルのコマンドは、バッファを作る度にこの関数を呼び出します。

Variable: initial-major-mode
この変数は、Emacsの起動時に最初に作られる`*scratch*'バッファの主モー ドを決めます。この変数の値は、主モードコマンド名を示すシンボルでなければ なりません。デフォルト値はlisp-interaction-modeです。

Variable: auto-mode-alist
この変数は、ファイル名のパターンとそれに対応する主モード関数の連想リスト を保持します。通常、ファイル名のパターンは`.el'`.c'といった 拡張子を識別するものですが、そうでなくても構いません。リストの要素は、 (regexp . mode-function)のような形式をしています。

例:

(("^/tmp/fol/" . text-mode)
 ("\\.texinfo\\'" . texinfo-mode)
 ("\\.texi\\'" . texinfo-mode)
 ("\\.el\\'" . emacs-lisp-mode)
 ("\\.c\\'" . c-mode) 
 ("\\.h\\'" . c-mode)
 ...)

展開されたファイル名(see section ファイル名を展開する関数)がregexpに一致する ファイルを読み込んだとき、set-auto-modeはそれに対応した mode-functionを呼びます。この機能により、ほとんどのファイルにつ いて、適切な主モードの選択が自動化できます。

もし、auto-mode-alistの要素が(regexp function t) のような形式だった場合、functionを呼び出した後、ファイル名の regexpに一致しなかった残りの部分についてauto-mode-alist の検索を再び行ないます。 (訳注: GNU Emacsバージョン19.28のDOCの記述によると (regexp function)の形式となっているが、それは誤り。 19.29では修正された。)

この"もう一度一致(match-again)"の機能は、uncompressionパッケージに おいて便利です。たとえば、("\\.gz\\'" function t)の記述によって、 ファイルをgunzipして、さらにその伸長されたファイルを、`.gz'を除いた ファイル名から求めた適切なモードにする、といった利用ができるでしょう。

複数のパターンのペアをauto-mode-alistに設定する方法の例を挙げま す(このような設定を`.emacs'で行うこともできます)。

(setq auto-mode-alist
  (append 
   ;; `.' (ピリオド)で始まるファイル名。
   '(("/\\.[^/]*\\'" . fundamental-mode)  
     ;; `.' (ピリオド)を含まないファイル名。
     ("[^\\./]*\\'" . fundamental-mode)   
     ;; `.C'で終わるファイル名。
     ("\\.C\\'" . c++-mode))
   auto-mode-alist))

Variable: interpreter-mode-alist
この変数は、`#!'でコマンド・インタープリタを特定しているスクリプトに 使用する主モードを指定します。 この変数の値は、(interpreter . mode)のような形式の要 素をもつリストで、たとえば、デフォルトでは("perl" . perl-mode)などが 指定されています。この要素は、interpreterのスクリプト・ファイルに対して modeを使用することを意味します。

この変数は、使用する主モードをauto-mode-alistで決定できな かったときにのみ適用されます。

Function: hack-local-variables &optional force
この関数は、カレント・バッファの文字列からローカル変数や式の定義を捜し出し、 実際に変数の定義や式の評価を行ないます。

normal-modeの説明中のenable-local-variablesの扱いに関す る記述を参照してください。引数forceは通常の場合、 normal-mode関数のfind-file引数を引き継いだものです。

主モードの使い方をユーザに説明する

describe-mode関数は、主モードに関する情報を提供するために使用さ れます。通常、C-h mにより呼び出されます。describe-mode関数は major-modeの値を使用します。これは、主モード関数が major-mode変数をセットしなければならない理由の一つです。

Command: describe-mode
この関数は現在使用中の主モードの説明を表示します。

describe-mode関数は、major-modeを引数に documentation関数を呼ぶことで、主モード関数の説明 文字列を表示します。(See section 説明文字列へのアクセス)。

Variable: major-mode
この変数は、カレント・バッファの主モードを示すシンボルを保持します。この シンボルは、その主モードへ切替えるためのコマンド関数の定義を持っているは ずです。describe-mode関数は、主モードの説明文字列としてこの関数の 説明文字列を使用します。

導出モードを定義する

新しいモードを定義するときに、既存の主モードを基にしたくなることがよく あります。これを簡単に行う方法の一つはdefine-derived-modeを使うこ とです。

Macro: define-derived-mode variant parent name docstring body...
このマクロは、主モード・コマンドとしてvariantを定義します。このと き、モードの文字列形式の名前としてnameが使用されます。

新しくできるコマンドvariantは、関数parentを呼んだ後、以 下のように親モードのいくつかの側面をオーバーライドするように定義されます。

さらに、bodyを使用することで、parentのほかの面をどのようにオー バーライドするかを指定できます。variantコマンドは、そのオーバーラ イド処理の後、variant-hookを実行する直前で、bodyが保 持する形式を評価します。

引数docstringは、新しいモードの説明文字列を指定します。 docstringを省略した場合、define-derived-modeが説明文字列を 自動的に作ります。

以下は架空の例です。

(define-derived-mode hypertext-mode
  text-mode "Hypertext"
  "Major mode for hypertext.
\\{hypertext-mode-map}"
  (setq case-fold-search nil))

(define-key hypertext-mode-map
  [down-mouse-3] 'do-hyper-link)

副モード

副モード(minor mode)は、それを利用するかしないかを、主モードの選 択とは無関係にユーザが選択できるような機能を提供します。副モード は単独で使用することもできるし、組み合わせて使用することもできます。"副 モード"という呼び名よりは"一般的に利用可能な、オプショナルな機能のモー ド"の方が、長過ぎるけども、より的確でしょう。

副モードは、ほとんどの場合、さまざまな主モードで使用できます。 たとえば、Auto Fillモードは、テキストの挿入を許す主モードであれば、ど のような主モードの中でも利用可能です。一般論として、副モードとは、主 モードの振舞に関わらず利用できるように作られるべきものです。

副モードの実装は、主モードの実装に比べて、たいてい非常に困難です。理由 の一つとして、使用、不使用の選択がどのような順序で行なわれるかわからない ことがあります。副モードは、主モードやほかの副モードの影響を受けずにきち んと動かなければならないのです。

副モードを実装する上で最も大きな問題となり得るのは、モードに必要な フックをEmacsにつけ加える方法です。副モード・キーマップを使えば、 従来使われてきた手段よりも簡単にこの問題を解決できます。

副モードの記述方法に関する慣例

主モードの場合と同様に、副モードの書き方にも慣例があります。主モードで の慣例のいくつか、たとえば、モードを初期化する関数の名前、グローバルなシ ンボルの名前、キーマップなどのテーブルの扱い、などは副モードでもそのまま 当てはまります。

さらに、副モード特有の慣例もいくつかあります。

キーマップと副モード

副モードは、そのモードが有効なときにのみ参照される独自のキーマップを もつことができます。副モード独自のキーマップを持ちたいときは、連想リ ストminor-mode-map-alistに要素を追加します。See section アクティブ・キーマップ

副モード・キーマップの用途の一つは、いくつかの自己挿入文字の振舞を変更 し、自己挿入以外の機能を持たせることです。一般に、このような目的の場合、 副モード・キーマップの使用が唯一の方法です。なぜなら、 self-insert-commandのカスタマイズが可能なのは特殊な場合(abbrevsモー ドとAuto Fillモードのみ)に限られているからです (self-insert-commandの定義を独自のもので置き換えたりしないでくだ さい。self-insert-commandは、エディタのコマンド・ループの中で特殊 な扱いをされています)。

Variable: minor-mode-map-alist
この変数は、以下に示すような形式の要素をもつ連想リストです。
(variable . keymap)

ここで、variableは副モードが有効かを示す変数で、 keymapはキーマップです。このキーマップkeymapは、 variablenilでない値をもつときにのみ有効です。

minor-mode-map-alistの要素の形式は、minor-mode-alistの要 素の形式とは違うことに注意してください。要素は、variablekeymapからなるリストではありません。キーマップが要素のCDR になっていなければなりません。

また、キーマップそのものがCDRに来ていなければなりません。キーマップ を保持する変数を示すシンボルをCDRに置いても、望むような動作はしないでしょう。

複数の副モード・キーマップがアクティブである場合、優先順位は minor-mode-map-alistでの並び順と一緒です。しかし、ほかの副モード の影響を受けないように副モードを設計するべきです。そのようにできれば、順 序について悩むことはありません。

モード行の書式

Emacsのウィンドウはそれぞれにモード行を持ち(ミニバッファ・ウィンドウ は除く)、そのウィンドウに表示されているバッファに関する情報を表示してい ます。モード行に表示される情報には、バッファの名前、結び付いているファ イル、再帰編集の深さ、主モードと副モード、などがあります。

この節では、モード行の表示内容がどのように制御されるかについ て説明します。モードの章で説明するのは、モード行に表示される情報の 多くが、有効な主モードと副モードに関係するからです。

mode-line-formatは、カレント・バッファのモード行の表示に使われ るテンプレートを保持するバッファローカル変数です。同一のバッファを表示 するウィンドウは同一のmode-line-formatを使用するので、モード行の 表示も(表示位置のパーセント表示と行番号は除いて)同一になります。

モード行の表示の更新は、通常、ウィンドウに表示されているバッファが切 り替わったときや、バッファのmodified-statusがnilからt、 あるいはtからnilに変化したときに行なわれます。ですから、 mode-line-formatから参照される変数(see section モード行の中で使用されている変数) を変更しても、直ちに表示に反映されるとはかぎりません。

Function: force-mode-line-update
強制的にカレント・バッファのモード行の再表示を行ないます。

通常、モード行は反転表示されます(section 反転表示(Inverse Video)mode-line-inverse-videoを参照)。

モード行の表示をコントロールするデータ構造

モード行の内容は、バッファローカル変数mode-line-formatに 含まれるリスト、文字列、シンボル、数値からなるデータ構造によりコントロー ルされます。このデータ構造はモード行構成要素(mode line construct)と呼ばれ、より簡 単なモード行構成要素の再帰的な組み合わせにより構成されます。また、 同じデータ構造がフレームのタイトルを作るためにも使用されています (see section フレーム・タイトル)。

Variable: mode-line-format
この変数の値は、モード行全体の書式を制御するモード行構成要素です。この変 数の値は、どの変数がモード行のどの場所に現れるかをコントロールします。

モード行構成要素は単なる文字列でも構いませんが、通常は、ほかの変数をど のようにモード行の構築に使用するかを指定します。これらの変数の多くは、そ れ自身、モード行構成要素を値としてもつように定義されています。

デフォルトのmode-line-formatの値は、mode-nameminor-mode-alistといった変数の値を使用するよう定義されています。 ですから、mode-line-formatを書き換えなければならないモードはほと んどありません。たいていの場合、mode-line-formatから参照される変 数を書き換えるだけで十分間に合います。

モード行構成要素は、リスト、シンボル、または文字列のいずれかです。もし、 値がリストならば、その要素はそれぞれ、リスト、シンボル、または文字列のい ずれかです。

string
文字列であるモード行構成要素は、%-指定子 (%-construct)を除いてそのまま表示されます。`%'に続く10進の 数字列は、あまりがスペースで埋められるフィールドの全体幅を示します(デー タは左詰めされるということです)。See section モード行の表示に使われる%-指定子
symbol
シンボルであるモード行構成要素は、その値を表します。symbolの 値がsymbolの代わりにモード行構成要素として扱われます。ただ し、シンボルがtまたはnilの場合は無視されます。同様に、 値がvoidであるシンボルも無視されます。 一つだけ例外があり、symbolの値が文字列の場合は、その値がそのまま表 示されます。その文字列中の%-指定子は、特別な意味を持ちません。
(string rest...) or (list rest...)
最初の要素が文字列、またはリストであるリストは、全ての要素を再帰的に処理 し、その結果を結合することを意味します。これは、モード行構成要素の形 式として、最もよくある形です。
(symbol then else)
最初の要素がシンボルであるリストは、条件を表します。その意味は、 symbolの値により異なります。値が非nilのときは、2番目 の要素thenがモード行構成要素として再帰的に処理されます。また、 symbolの値がnilならば、3番目の要素elseが再帰的に 処理されます。elseを省略することもでき、省略した場合、 symbolの値がnilならば、そのモード行構成要素は何も表示 しません。
(width rest...)
先頭の要素が整数であるリストは、restの結果の幅詰め、またはパディ ングの指定です。まず、残りの要素restがそれぞれモード行構成要素とし て再帰的に処理され、互いに結合されます。その後、結果がwidth桁 になるようにスペースで埋められるか(widthが正の整数の場合)、あ るいは右側が切り捨てられます(widthが負の整数の場合、 -width桁に)。 たとえば、ウィンドウ上端のバッファ中での位置をパーセンテージ表示するための 通常の指定は、(-3 "%p")のようになります。

mode-line-formatそのものを書き換えてしまう場合でも、デフォルト値 (see section モード行の中で使用されている変数)で使用されている変数を、その内容を複製した り別の方法で表示したりせずに、そのまま新しい値の中でも使用するべきです。 ユーザやLispプログラム(display-timeや主モードなど)に よるモード行の表示に関するカスタマイズの多くは、それらの変数の値の変 更によりなされるからです。

以下は、ホスト名と現在のディレクトリをモード行に表示する mode-line-formatの例です。shell-modeでは便利かも知れません。

(setq mode-line-format
  (list ""
   'mode-line-modified
   "%b--" 
   (getenv "HOST")      ; One element is not constant.
   ":" 
   'default-directory
   "   "
   'global-mode-string
   "   %[("
   'mode-name 
   'mode-line-process  
   'minor-mode-alist 
   "%n" 
   ")%]----"
   '(line-number-mode "L%l--")
   '(-3 . "%p")
   "-%-"))

モード行の中で使用されている変数

この節では、モード行のテキスト表示のために、mode-line-format 内で標準的に使用されている変数について説明します。これらの変数は先天的に 特殊なものではなく、ほかのいかなる変数も、mode-line-formatがそれら を使用するように変更されれば、モード行において同様の効果をもつことが できます。

Variable: mode-line-modified
この変数は、カレント・バッファが変更されたかを示すモード行構成要素の値を 持ちます。

mode-line-modifiedのデフォルト値は("--%1*%1+-")です。こ れは、バッファが変更されているときは`--**-'、バッファが変更されてい ないときは`-----'、バッファが読出し専用のときは`--%%-'、バッ ファが読出し専用でなおかつ変更されているときは`--%*-'を、モード行 に表示することを意味します。

この変数を変更しても、モード行の強制的なアップデートは起こりません。

Variable: mode-line-buffer-identification
この変数は、ウィンドウに表示されているバッファを識別するためのモード行構 成要素を保持します。デフォルト値は("%F: %17b")で、`Emacs:'に 続けてスペース1文字、17文字のバッファ名を表示することを意味します(端末フ レームでは、`Emacs'の代わりにフレーム名(`Emacs-' + フレーム番号) を表示します(訳注: GNU Emacsバージョン19.29から、テキスト端末でも複数の フレームをもつことができるようになった))。Rmailなどのように通常のEmacsと は違う振舞をするモードでは、この変数の値を変更したくなるかも知れません。

Variable: global-mode-string
この変数は、モード行上でバッファ名に続いて表示されるモード行構成要素を保 持します。コマンドdisplay-timeは、時刻とロード情報を保持する display-time-string変数を参照するように、この global-mode-stringを設定します。

`%M'global-mode-stringの値で置き換わります。しかし、これは obsoleteです。代わりに、モード行内でglobal-mode-string変数を直接 使用することができます。

Variable: mode-name
このバッファローカル変数は、カレント・バッファの主モードの"短くわかり やすい"名前を保持します。モード行にモード名が表示されるよう、各主モード はこの変数にモード名を正しく設定しなければなりません。

Variable: minor-mode-alist
この変数は、副モードがアクティブであるとき、どのようにモード行に表示するか を示す要素をもつ連想リストを保持します。minor-mode-alistの要素は、 それぞれ、二つの要素からなる以下のようなリストです。
(minor-mode-variable mode-line-string)

さらに一般的に、mode-line-stringは、どのようなモード行構成要素であっ ても構いません。この値は、minor-mode-variableの値が非nilの とき表示され、そうでないときは表示されません。これらの文字列は、互いにくっ つかないよう、スペースで始まるようにしてください。慣習的に、副モードがア クティブになったときに、そのモードに対応するminor-mode-variableが非 nilにセットされます。

minor-mode-alistのデフォルト値は、以下のようになっています。

minor-mode-alist
=> ((vc-mode vc-mode)
    (abbrev-mode " Abbrev") 
    (overwrite-mode overwrite-mode) 
    (auto-fill-function " Fill")         
    (defining-kbd-macro " Def")
    (isearch-mode isearch-mode))

minor-mode-alistは、バッファローカルではありません。この連想リス トの中に現れる変数は、もしそれに対応する副モードがバッファごとに有効にで きるものなら、バッファローカルでなければなりません。

Variable: mode-line-process
このバッファローカル変数は、サブプロセスとやりとりをするようなモードで、 プロセスの状態をモード行に表示するための文字列を持ちます。この文字列は、 主モード名に続けて、スペースを開けずに表示されます。たとえば、 `*shell*'バッファにおいてこの変数の値が(": %s")なら、 `(Shell: run)'のように表示されます。通常、この変数はnilで す。

Variable: default-mode-line-format
この変数は、mode-line-formatを特に設定しないモードのためのデフォ ルト値を保持します。これは(default-value 'mode-line-format)と同 じです。

default-mode-line-formatのデフォルト値は、以下のようになっています。

(""
 mode-line-modified
 mode-line-buffer-identification
 "   "
 global-mode-string
 "   %[("
 mode-name 
 mode-line-process
 minor-mode-alist 
 "%n" 
 ")%]----"
 (line-number-mode "L%l--")
 (-3 . "%p")
 "-%-")

Variable: vc-mode
それぞれのバッファにローカルな変数vc-modeは、バッファに読み込まれ たファイルがバージョン・コントロールされているか、されているのならその種 類は何か、を表します。この値がnilなら、バージョン・コントロールされ ていないことを表します。また、それ以外なら、バージョン・コントロールされて おり、モード行に表示される文字列を表します。

モード行の表示に使われる%-指定子

使用可能な%-指定子とその意味を、以下に示します。`%%' 以外の全ての%-指定子において、表示する文字数を表す十進数を、 `%'の後ろにつけることができます。

%b
カレント・バッファ名。buffer-name関数の値と同一。See section バッファの名前
%f
バッファに読み込まれたファイルの名前。buffer-file-name関数の値と同 一。See section バッファ・ファイル名
%F
選択されているフレームの名前。
%c
ポイント(カーソル位置)の桁番号。
%l
ポイント(カーソル位置)の行番号。
%*
バッファが読出し専用なら`%' (buffer-read-onlyを参照)、
読出し専用ではなくて変更されていたら`*' (buffer-modified-pを参照)、
それ以外なら`-'。See section バッファの変更
%+
バッファが変更されていたら`*' (buffer-modified-pを参照)、
変更されていなくて読出し専用なら`%' (buffer-read-onlyを参照)、
それ以外なら`-'。変更されていてかつ読出し専用のバッファに関す る振る舞いのみが`%*'と異なります。See section バッファの変更
%&
バッファが変更されていたら`*'、それ以外なら`-'
%s
カレント・バッファに結び付いているサブプロセスの状態。 process-statusの値と同一。See section プロセス情報
%t
読み込まれたファイルがテキスト・ファイルなら`T'、バイナリなら `B'(特定のオペレーティング・システム上でのみ意味がある区別です)。
%p
ウィンドウの上端のバッファ中での位置(バッファ全体に対するパー センテージ)、または`Top'、または`Bottom'、または`All'
%P
ウィンドウの下端のバッファ中での位置(バッファ全体に対するパー センテージ)、または`Top' (バッファの先頭が見えていてバッファの末尾 が見えていない場合)、または`Bottom' (バッファの末尾は見えている場 合)、または`All' (バッファ全体が見えている場合)。
%n
ナローイングが有効なときは`Narrow'、それ以外のときは無( section ナローイングnarrow-to-regionを参照してください)。
%[
再帰編集レベルの表示(ミニバッファ・レベルは含まない)。レベルが深くなるごと に`['が一つ増える。See section 再帰編集
%]
再帰編集レベルが深くなるごとに`]'が一つ増える(ミニバッファ・レベルは 含まない)。
%%
文字`%'%-指定子を使用可能な場所に、文字`%'そのもの を含むことができる。
%-
モード行のあまりを埋めるのに十分な数の`-'

以下の二つの%-指定子は現在でも使えますが、obsoleteです。変数 mode-nameglobal-mode-stringを使用して同じ結果を得るこ とができます。

%m
mode-nameの値。
%M
global-mode-stringの値。現在では、display-timeのみが global-mode-stringの値を変更します。

フック

フック(hook)は、既存のプログラムから呼び出される関数を、ユーザそれ ぞれの事情により収めておくことのできる変数です。Emacsでは、カスタマイズ の目的でフックの仕組みを用意しています。フックは`.emacs'ファイルの 中で設定されることが多いのですが、それ以外のLispプログラムによるフックの 設定も可能です。標準的なフック変数の一覧についてはSee section 標準のフック

Emacsにおけるフックのほとんどは正規フック(normal hook)です。こ れらのフック変数は、引数なしで呼び出される関数のリストを持ちます。ほとん どのフックが正規フックである理由は、一律な扱いが可能だからです。正規フッ クの名前は、必ず`-hook'で終えることが慣例になっています。

正規フックにフック関数を追加するお奨めの方法は、add-hookを呼ぶ ことです(後述します)。フック関数は、funcallが受けつけるものであれ ばどのような関数であっても構いません(see section 関数とは)。ほとん どのフック変数の初期値はvoidですが、add-hookはこのような変数にも 正常にフック関数を追加することができます。

もう一種類のフックである非正規フック(abnormal hook)には、名前が `-function'で終るものと`-hooks'で終わるものとがあります。名前 が`-function'で終わる非正規フックは、一つの関数を値として持ちます。 また、名前が`-hooks'で終る非正規フックは、関数のリストを値として持 ちます。非正規フックは、正規フックでは不可能な場合(たとえば関数が引数を 取ったり、あるいは関数の値に意味があったりする場合)に使用されるという点 で普通ではありません。名前が`-function'`-hooks'で終るフック を使おうとするときは、それが非正規フックであることを思い出し、そのフックの 説明文字列で正しい使用方法を調べるようにしてください。

主モード関数は、その初期化処理の最後に、モード・フック(mode hook)と呼ばれるフックを実行することが慣例になっています。これによりユー ザは、モードにより設定されたローカル変数を書き換えてモードの振舞をカスタ マイズすることができます。また、フックはほかの状況でも使われます。たとえ ば、Emacsがサスペンドする直前に実行されるsuspend-hookというフック があります(see section Emacsのサスペンド)。

以下は、Lisp InteractionモードでAuto Fillモードを起動するためにモード・ フックを使う例です。

(add-hook 'lisp-interaction-mode-hook 'turn-on-auto-fill)

以下は、EmacsがCのコードを字下げする方法をカスタマイズするフックの 例です(人によってコーディング・スタイルの好みはさまざまですよね)。この例 では、名前のないラムダ式をフック関数として使用しています。

(add-hook 'c-mode-hook 
  (function (lambda ()
              (setq c-indent-level 4
                    c-argdecl-indent 0
                    c-label-offset -4
                    c-continued-statement-indent 0
                    c-brace-offset 0
                    comment-column 40))))

(setq c++-mode-hook c-mode-hook)

フックの実行にはrun-hooks関数が使用されます。この関数は add-hooksで追加されたフック関数を呼び出します。

Function: run-hooks &rest hookvar
この関数は一つ以上のフック変数の名前を引数に取り、それぞれのフックを順 に実行します。それぞれのhookvar引数はフック変数を示すシンボルで なければなりません。これらの引数は、与えられた順に実行されます。

フック変数の値が非nilである場合、その値は関数のリストまたは 関数でなければなりません。値が関数(関数定義を示すシンボ ルまたはラムダ式)ならそれが呼ばれます。値がリストなら、それぞれの要素が 順に呼ばれます。いずれの場合も、フック関数の呼出しは引数なしで行なわれ ます。

たとえば、emacs-lisp-modeのモード・フックを実行するには以下のようにします。

(run-hooks 'emacs-lisp-mode-hook)

Function: add-hook hook function &optional append local
(訳注: localはGNU Emacsバージョン19.29から追加された引数)

この関数は、関数functionをフック変数hookに追加します。引 数functionは、Lisp関数として有効で正しい数の引数を取るならど のような関数でも構いません。たとえば、

(add-hook 'text-mode-hook 'my-text-hook-function)

は、my-text-hook-functiontext-mode-hookというフックに 追加します。

add-hookは正規フックと同様に、非正規フックにも使用できます。

フック関数は、実行順序に関わらず問題なく動くように作るのが一番です。順序 に依存するのはトラブルの元になります。もっとも、通常、functionはフッ ク・リストの先頭に追加されるので、さらにadd-hookが呼ばれないかぎ り最初に実行されると予想できます。

オプショナル引数のappendが非nilなら、新しいフック関数 はフック・リストの最後に追加され、実行も最後になされます。

もしlocalが非nilなら、フック関数をカレント・バッファにロー カルにします。ただし、make-local-hook (make-local-variableではありません)を呼ぶことにより、フッ ク変数がバッファローカルにされていなければなりません。もしフックがバッファ ローカルでなければ、フック関数はlocalの値に関わらず常にグローバル になります。

Function: remove-hook hook function &optional local
(訳注: localはGNU Emacsバージョン19.29から追加された引数)

この関数は、フック変数hookからfunctionを取り除きます。

もしlocalが非nilなら、グローバル・フック・リストからではな く、ローカル・フック・リストからfunctionを取り除きます。フック変数 がバッファローカルでなければ、localの値は意味を持ちません。

Function: make-local-hook hook
(訳注: GNU Emacsバージョン19.29から追加された関数)

この関数は、フック変数hookをカレント・バッファにローカルにします。 ローカルなフック変数は、ローカルなフック関数とグローバルなフック関数とを もつことができ、また、run-hooksはその両方を実行します。

この関数は、フック変数のローカルな値として、tを要素として含むリス トを設定します。このtは、フック変数のローカルな値とともにグローバ ルな値にもフック関数が収められていることを示すフラグとして働きます。 run-hooksはこのフラグの意味を理解できるので、 make-local-hookはすべての正規フックに対して使用できます。非正規フッ クに関しては、呼出し元がtの意味を理解できるように対策済みの一部の ものに対してのみ使用できます。

make-local-variableだけではフック変数をローカルにすることはできま せん。フック変数に対して直接make-local-variableを使用しないでくだ さい。


Go to the first, previous, next, last section, table of contents.