[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22. メジャーモードとマイナモード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Modes"
"texi/elisp21/メジャーモードとマイナモード"へのコメント(無し)

モード(mode)とは、Emacsをカスタマイズする定義の集まりであり、 読者は編集中にそれをオン/オフできます。 モードには2種類あります。 メジャーモード(major mode)は、互いに排他的で、 特定種類のテキストの編集に使います。 マイナモード(minor mode)は、 ユーザーがそれぞれを独立にオンにできる機能を提供します。

本章では、メジャーモードやマイナモードの書き方、 それらをモード行に表示する方法、 ユーザーが指定したフックをモードがどのように実行するかについて述べます。 キーマップや構文テーブルなどの関連事項については、 21. キーマップ34. 構文テーブルを参照してください。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.1 メジャーモード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Major%20Modes"
"texi/elisp21/メジャーモード"へのコメント(無し)

メジャーモードは、特定種類のテキストの編集向けにEmacsを特化します。 各バッファには、ある時点では1つのメジャーモードしかありません。

もっとも特化されていないメジャーモードは、 基本(fundamental)モードです。 このモードには、モードに固有な定義や変数の設定がありません。 そのため、Emacsの各コマンドはデフォルトのふるまいをし、 各オプションもデフォルトの状態です。 他のすべてのメジャーモードでは、さまざまなキーやオプションを再定義します。 たとえば、lisp対話モードでは、 C-jeval-print-last-sexp)や TABlisp-indent-line)など他のキーに対しても 特別なキーバインディングがあります。

読者の特別な編集作業を補佐するために一群の編集コマンドを書く必要がある場合、 新たなメジャーモードを作ることは一般にはよいことです。 実際、メジャーモードを書くことは (マイナモードを書くことはしばしば難しくなるが、 それに対比すれば)簡単です。

新たなモードが既存のモードに類似していても、 既存のモードを2つの目的を果たすように修正するのは 賢いことではありません。 そのようにすると、使い難く保守し難くなるからです。 そのかわりに、既存のメジャーモードの定義をコピーし名前変えてから、 コピーを変更します。 あるいは、派生モード (derived mode) (see 節 22.1.5 派生モードの定義)を定義します。 たとえば、`emacs/lisp/rmailedit.el'にあるrmail編集モードは、 テキスト(text)モードに非常によく似たメジャーモードですが、 追加コマンドが3つあります。 そのような定義がテキスト(text)モードとの違いになるのですが、 rmail編集モードはテキスト(text)モードから派生したものです。

rmail編集モードは、バッファのメジャーモードを一時的に変更して バッファを別の方法(rmailのコマンドではなく Emacsの普通のコマンド)で編集できるようにする例題です。 そのような場合、一時的なメジャーモードには、普通、 バッファの通常のモード(この場合にはrmailモード)に戻る コマンドがあります。 読者は、再帰編集の中で一時的に再定義し、 ユーザーが再帰編集を抜けるともとに戻す方法に魅了されるかもしれません。 しかし、これを複数のバッファで行うと、 再帰編集はもっとも最近に入った再帰からまず抜けるので、 ユーザーの選択に制約を課すことになり悪い方法です。 別のメジャーモードを使えばこのような制約を回避できます。 See 節 20.11 再帰編集

標準のGNU Emacs Lispのライブラリのディレクトリには、 `text-mode.el'、`texinfo.el'、`lisp-mode.el'、 `c-mode.el'、`rmail.el'などのファイルに いくつかのメジャーモードのコードが収めてあります。 モードの書き方を理解するためにこれらのライブラリを調べられます。 テキスト(text)モードは、基本(fundamental)モードについで、 もっとも単純なメジャーモードです。 rmailモードは複雑な特化されたモードです。

22.1.1 メジャーモードの慣習    Coding conventions for keymaps, etc.
22.1.2 メジャーモードの例    Text mode and Lisp modes.
22.1.3 メジャーモードの選択方法    How Emacs chooses the major mode automatically.
22.1.4 メジャーモードに関するヘルプ    Finding out how to use a mode.
22.1.5 派生モードの定義    Defining a new major mode based on another major mode.



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.1.1 メジャーモードの慣習

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Major%20Mode%20Conventions"
"texi/elisp21/メジャーモードの慣習"へのコメント(無し)

既存のメジャーモードのコードでは、 ローカルキーマップや構文テーブルの初期化、グローバルな名前、フックなどの さまざまなコーディング上の慣習を踏襲しています。 読者が新たなメジャーモードを定義するときには、 これらの慣習に従ってください。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.1.2 メジャーモードの例

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Example%20Major%20Modes"
"texi/elisp21/メジャーモードの例"へのコメント(無し)

基本(fundamental)モードを除くと、 テキスト(text)モードはもっとも単純なモードです。 上に述べた慣習の例示として、`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" 'indent-relative)
  (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 local-abbrev-table text-mode-abbrev-table)
  (set-syntax-table text-mode-syntax-table)
  (make-local-variable 'paragraph-start)
  (setq paragraph-start (concat "[ \t]*$\\|" page-delimiter))
  (make-local-variable 'paragraph-separate)
  (setq paragraph-separate paragraph-start)
  (setq mode-name "Text")
  (setq major-mode 'text-mode)
  (run-hooks 'text-mode-hook))      ; 最後に、フックによるモードの
                                    ;   カスタマイズをユーザーに許す

3つのlispモード(lispモード、emacs-lispモード、lisp対話モード)には、 テキスト(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モード向けの略語表を作る
(define-abbrev-table 'lisp-mode-abbrev-table ())

3つのlispモードは多くのコードを共有しています。 つぎの関数はさまざまな変数に設定します。 lispモードの各メジャーモード関数が呼び出します。

 
(defun lisp-mode-variables (lisp-syntax)
  (cond (lisp-syntax
          (set-syntax-table lisp-mode-syntax-table)))
  (setq local-abbrev-table lisp-mode-abbrev-table)
  ...

forward-paragraphなどの関数は、 変数paragraph-startの値を使います。 Lispのコードは普通のテキストとは異なるので、 Lispを扱えるように変数paragraph-startを特別に設定する必要があります。 また、Lispではコメントの字下げは特殊な形なので、 各lispモードには独自のモード固有のcomment-indent-functionが必要です。 これらの変数に設定するコードが、 lisp-mode-variablesの残りの部分です。

 
  (make-local-variable 'paragraph-start)
  (setq paragraph-start (concat page-delimiter "\\|$" ))
  (make-local-variable 'paragraph-separate)
  (setq paragraph-separate paragraph-start)
  ...
  (make-local-variable 'comment-indent-function)
  (setq comment-indent-function 'lisp-comment-indent))

各lispモードでは、キーマップが多少異なります。 たとえば、lispモードではC-c C-zrun-lispにバインドしますが、 他のlispモードではそうしません。 つぎのコードは、共通するコマンドを設定します。

 
(defvar shared-lisp-mode-map ()
  "Keymap for commands shared by all sorts of Lisp modes.")

(if shared-lisp-mode-map
    ()
   (setq shared-lisp-mode-map (make-sparse-keymap))
   (define-key shared-lisp-mode-map "\e\C-q" 'indent-sexp)
   (define-key shared-lisp-mode-map "\177"
               'backward-delete-char-untabify))

つぎはlispモード向けのキーマップを設定するコードです。

 
(defvar lisp-mode-map ()
  "Keymap for ordinary Lisp mode....")

(if lisp-mode-map
    ()
  (setq lisp-mode-map (make-sparse-keymap))
  (set-keymap-parent lisp-mode-map shared-lisp-mode-map)
  (define-key lisp-mode-map "\e\C-x" 'lisp-eval-defun)
  (define-key lisp-mode-map "\C-c\C-z" 'run-lisp))

最後に、emacs-lispモードのメジャーモード関数の完全な定義を示します。

 
(defun lisp-mode ()
  "Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp.
Commands:
Delete converts tabs to spaces as it moves back.
Blank lines separate paragraphs.  Semicolons start comments.
\\{lisp-mode-map}
Note that `run-lisp' may be used either to start an inferior Lisp job
or to switch back to an existing one.

Entry to this mode calls the value of `lisp-mode-hook'
if that value is non-nil."
  (interactive)
  (kill-all-local-variables)
  (use-local-map lisp-mode-map)          ; モードのキーマップを選択する
  (setq major-mode 'lisp-mode)           ; これによりdescribe-modeは
                                         ; 説明文を探し出せる
  (setq mode-name "Lisp")                ; モード行に表示される
  (lisp-mode-variables t)                ; さまざまな変数を定義する
  (setq imenu-case-fold-search t)
  (set-syntax-table lisp-mode-syntax-table)
  (run-hooks 'lisp-mode-hook))           ; フックによるモードの
                                         ; カスタマイズをユーザーに許す



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.1.3 メジャーモードの選択方法

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Auto%20Major%20Mode"
"texi/elisp21/メジャーモードの選択方法"へのコメント(無し)

Emacsは、ファイル名やファイル自体の情報をもとに、 当該ファイルを訪問するときの新しいバッファに対する メジャーモードを自動的に選択します。 また、ファイル内のテキストで指定されたローカル変数も処理します。

コマンド: fundamental-mode
基本(fundamental)モードは、特化してないメジャーモードである。 他のメジャーモードは、実質的には、このモードとの対比で定義されている。 つまり、基本(fundamental)モードから始めて、 それらのメジャーモードではなにを変更するかを定義している。 関数fundamental-modeはフックを実行しないため、 読者はカスタマイズできない。 (Emacsの基本(fundamental)モードのふるまいを変えたければ、 Emacsの大局的な状態を変える必要がある。)

コマンド: normal-mode &optional find-file
この関数は、カレントバッファに対して 適切なメジャーモードとバッファローカルな変数を確立する。 この関数はまずset-auto-modeを呼び出し、 続いて、ファイルのローカル変数を必要に応じて解析、束縛、評価するために hack-local-variablesを実行する。

normal-modeに対する引数find-filenil以外であると、 normal-modefind-fileから呼び出されたと仮定する。 その場合、ファイルの末尾や`-*-'の形式の行にある ローカル変数リストを処理することもある。 変数enable-local-variablesは、この処理を行うかどうかを制御する。 ファイル内でのローカル変数リストの構文については、 See GNU Emacs マニュアル。

読者が対話的にnormal-modeを実行すると 引数find-fileは通常nilである。 その場合、normal-modeは、ローカル変数リストを無条件に処理する。

normal-modeは、メジャーモード関数を呼び出す周りでは condition-caseを使うので、エラーを補足して `File mode specification error'にもとのエラーメッセージを続けて エラーを報告する。

User Option: enable-local-variables
この変数は、訪問したファイル内のローカル変数リストを処理するかどうかを 制御する。 値tは、ローカル変数リストを無条件に処理することを意味する。 nilは、それらを無視することを意味する。 それ以外の値であると、各ファイルごとにユーザーに問い合わせる。 デフォルト値はtである。

Variable: ignored-local-variables
この変数は、ファイルのローカル変数リストで設定してはならない 変数のリストを保持する。 それらの変数に対して指定した値は無視される。

このリストに加えて、 属性risky-local-variablenil以外の値である変数も無視されます。

User Option: enable-local-eval
この変数は、訪問したファイル内のローカル変数リストの`Eval:'を 処理するかどうかを制御する。 値tは、それらを無条件に処理することを意味する。 nilは、それらを無視することを意味する。 それ以外の値であると、各ファイルごとにユーザーに問い合わせる。 デフォルト値はmaybeである。

Function: set-auto-mode
この関数は、カレントバッファに対して適切なメジャーモードを選択する。 `-*-'行の値、 (auto-mode-alistを使って)訪問したファイルの名前、 (interpreter-mode-alistを使って)`#!'行、 ファイルのローカル変数リストをもとに決定する。 しかし、この関数はファイルの末尾付近にある ローカル変数`mode:'は調べないが、 関数hack-local-variablesは調べる。 See GNU Emacs マニュアル。

User Option: default-major-mode
この変数は、新たなバッファに対するデフォルトのメジャーモードを保持する。 標準値はfundamental-modeである。

default-major-modeの値がnilであると、 Emacsは(以前の)カレントバッファのメジャーモードを 新たなバッファのメジャーモードとする。 しかし、メジャーモードコマンドのシンボルの属性mode-classの 値がspecialであると、新たなバッファのメジャーモードにはせず、 かわりに基本(fundamental)モードを使う。 この属性を持つモードは、 特別に準備したテキストに対してのみ有用であるdiredやrmailなどである。

Function: set-buffer-major-mode buffer
この関数はバッファbufferのメジャーモードを default-major-modeの値とする。 この変数がnilであると、 (適切ならば)カレントバッファのメジャーモードを使う。

バッファを作成する低レベルの基本関数ではこの関数を使わないが、 switch-to-bufferfind-file-noselectなどの 中レベルのコマンドではバッファを作成するときにこのコマンドを使う。

Variable: initial-major-mode
この変数の値は、最初のバッファ`*scratch*'のメジャーモードを決定する。 値は、メジャーモードコマンドのシンボルであること。 デフォルト値は、lisp-interaction-modeである。

Variable: auto-mode-alist
この変数は、ファイル名のパターン(正規表現、see 節 33.2 正規表現)と 対応するメジャーモードの連想リストを保持する。 通常、ファイル名パターンでは`.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 節 24.8.4 ファイル名を展開する関数)がregexpに一致する ファイルを訪問すると、 set-auto-modeは対応するmode-functionを呼び出す。 この機能により、Emacsはほとんどのファイルに対して 適切なメジャーモードを選択する。

auto-mode-alistの要素が(regexp function t)の 形であると、functionを呼び出したあとで、 Emacsはファイル名のそれまで一致しなかった部分についてauto-mode-alistを 再度探索する。 この機能は解凍パッケージには有用である。 ("\\.gz\\'" function t)の形の要素で、 ファイルを解凍し、`.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を使うことを意味する。 interpreterの値は、実際には正規表現である。

auto-mode-alistが使用すべきメジャーモードが 指定しなかった場合にのみこの変数を使う。

Function: hack-local-variables &optional force
この関数は、カレントバッファの内容に指定されたローカル変数を 必要に応じて、解析、束縛、評価する。

normal-modeで述べたenable-local-variablesの処理は、 実際にはここで行う。 引数forceは、通常、 normal-modeに与えられた引数find-fileからくる。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.1.4 メジャーモードに関するヘルプ

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Mode%20Help"
"texi/elisp21/メジャーモードに関するヘルプ"へのコメント(無し)

関数describe-modeは、メジャーモードに関する情報を 得るために使います。 通常、C-h mで呼び出されます。 関数describe-modemajor-modeの値を使いますが、 そのために各メジャーモード関数が 変数major-modeに設定する必要があるのです。

コマンド: describe-mode
この関数は、現在のメジャーモードの説明文を表示する。

関数describe-modeは、major-modeの値を引数として 関数documentationを呼び出す。 そうして、メジャーモード関数の説明文字列を表示する。 (see 節 23.2 説明文字列の参照。)

Variable: major-mode
この変数は、カレントバッファのメジャーモードに対するシンボルを保持する。 このシンボルは、当該メジャーモードに切り替えるためのコマンドを 関数定義として持つこと。 関数describe-modeは、 メジャーモードの説明文として当該関数の説明文字列を使う。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.1.5 派生モードの定義

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Derived%20Modes"
"texi/elisp21/派生モードの定義"へのコメント(無し)

既存のメジャーモードを用いて新たなメジャーモードを定義できると便利です。 これを行う簡単な方法はdefine-derived-modeを使うことです。

Macro: define-derived-mode variant parent name docstring body...
これは、nameをモード名を表す文字列として使って variantをメジャーモードコマンドとして定義する。

新たなコマンドvariantは、関数parentを呼び出してから 親モードの特定の機能を無効にするように定義される。

さらに、bodyparentの他の部分を無効にする方法を指定できる。 コマンド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)



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.2 マイナモード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Minor%20Modes"
"texi/elisp21/マイナモード"へのコメント(無し)

マイナモード(minor mode)は、メジャーモードの選択とは独立に ユーザーがオン/オフできる機能を提供します。 マイナモードは、個別にも組み合わせてもオンにできます。 マイナモードは、長すぎますが『汎用的に使えるオプション機能のモード』と 命名したようがよいかもしれません。

マイナモードは、普通、1つのメジャーモードを変更するだけではありません。 たとえば、自動詰め込みモード(auto-fillモード)は、 テキスト挿入を許す任意のメジャーモードで使えます。 汎用的であるためには、マイナモードは メジャーモードが行うこととは実質的に独立である必要があります。

マイナモードは、メジャーモードに比べて、実装するのがしばしば困難です。 1つの理由は、任意の順でマイナモードをオン/オフできるようにする 必要があるからです。 マイナモードは、メジャーモードや他のオンになっているマイナモードとは 無関係にその望みの効果を発揮できる必要があります。

しばしば、マイナモードを実装するうえでもっとも大きな問題は、 Emacsの残りの部分に対して必要なフックを探すことです。 マイナモードキーマップにより、従来に比べて簡単になります。

22.2.1 マイナモードを書くための慣習    Tips for writing a minor mode.
22.2.2 キーマップとマイナモード    How a minor mode can have its own keymap.
22.2.3 Easy-Mmode    A convenient facility for defining minor modes.



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.2.1 マイナモードを書くための慣習

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Minor%20Mode%20Conventions"
"texi/elisp21/マイナモードを書くための慣習"へのコメント(無し)

メジャーモードに対するのと同じように、 マイナモードを書くうえでの慣習があります。 メジャーモードの慣習には、マイナモードにも適用されるものがあります。 つまり、モードを初期化する関数の名前、 グローバルシンボルの名前、キーマップやその他のテーブルや表の使い方です。

それらに加えて、マイナモードに固有な慣習もあります。

このリストに要素を1回だけ追加するならばadd-to-listも使えます (see 節 10.8 変数値の変更)。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.2.2 キーマップとマイナモード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Keymaps%20and%20Minor%20Modes"
"texi/elisp21/キーマップとマイナモード"へのコメント(無し)

各マイナモードは、モードがオンのときに活性になる独自のキーマップを持てます。 マイナモード向けのキーマップを設定するには、 minor-mode-map-alistに要素を追加します。 See 節 21.6 活性なキーマップ

マイナモードキーマップの1つの用途は、 ある種の自己挿入文字のふるまいを変更して、 自己挿入に加えてなにかを行わせるようにすることです。 一般に、self-insert-commandをカスタマイズする機構は (略語モードや自動詰め込みモード向けに設計された)特別な場合に限られるので、 このようなことを行う唯一の方法です。 (標準のself-insert-commandの定義を読者独自の定義で置き換えないこと。 エディタコマンドループはこの関数を特別扱いしている。)

マイナモードでバインドしているキー列は、C-cで始まり、 {}<>:;以外の 句読点文字の1つが続くようにします。 (除外した句読点文字はメジャーモード向けに予約されている。)



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.2.3 Easy-Mmode

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Easy-Mmode"
"texi/elisp21/Easy-Mmode"へのコメント(無し)

パッケージeasy-mmodeは、マイナモードを実装する便利な方法を提供します。 これを使うと、単純なマイナモードを1つの自己完結した定義に指定できます。

Macro: easy-mmode-define-minor-mode mode doc &optional init-value mode-indicator keymap
このマクロは、mode(シンボル)という名前の新しいマイナモードを定義する。

このマクロは、マイナモードをトグルする modeという名前のコマンドを定義し、 その説明文字列をdocとする。

また、modeという名前の変数も定義する。 この変数はモードのオン/オフにしたがってt/nilに設定される。 この変数はinit-valueに初期化される。

文字列mode-indicatorは、モードがオンのときにモード行に 表示される文字列である。 それがnilであるとモード行にはモードを表示しない。

省略可能な引数keymapは、マイナモードのキーマップを指定する。 これは、値がキーマップであるような変数の名前か、 つぎの形のバインディングを指定した連想リストであること。

 
(key-sequence . definition)

easy-mmode-define-minor-modeを使った例を示します。

 
(easy-mmode-define-minor-mode hungry-mode
  "Toggle Hungry mode.
With no argument, this command toggles the mode. 
Non-null prefix argument turns on the mode.
Null prefix argument turns off the mode.

When Hungry mode is enabled, the control delete key
gobbles all preceding whitespace except the last.
See the command \\[hungry-electric-delete]."
 ;; 初期値
 nil
 ;; モード行への表示
 " Hungry"
 ;; マイナモードのバインディング
 '(("\C-\^?" . hungry-electric-delete)
   ("\C-\M-\^?"
    . (lambda () 
        (interactive)
        (hungry-electric-delete t)))))

これは、『hungryモード』という名前のマイナモードを定義します。 モードをトグルするコマンドの名前はhungry-mode、 モードのオン/オフを表す変数の名前はhungry-mode、 モードがオンのときに活性なキーマップを保持する 変数の名前はhungry-mode-mapです。 C-DELとC-M-DELに対するキーバインディングで キーマップを初期化します。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.3 モード行の書式

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Mode%20Line%20Format"
"texi/elisp21/モード行の書式"へのコメント(無し)

Emacsの(ミニバッファ専用ウィンドウを除く)各ウィンドウにはモード行があって、 ウィンドウに表示しているバッファに関する状態情報を表示しています。 モード行には、バッファ名、対応するファイル、再帰編集の深さ、 メジャーモードとマイナモードなどのバッファに関する情報が含まれます。

本節では、モード行の内容の制御方法について述べます。 モード行に表示される情報のほとんどは オンになっているメジャーモードとマイナモードに関係するので、 本章に含めます。

mode-line-formatは、カレントバッファのモード行に表示する 雛型を保持しているバッファローカルな変数です。 同一バッファに対するすべてのウィンドウは同じmode-line-formatを使い、 それらのモード行は(スクロールの割合や行やコラム位置を除いて) 同じように表示されます。

ウィンドウのモード行は、通常、ウィンドウに別のバッファを表示したときや、 バッファの変更状態がnilからtへあるいはその逆の変化をしたときに 更新されます。 mode-line-format(see 節 22.3.2 モード行に使われる変数)が参照する 変数を修正したり、テキストの表示方法に影響するその他の変数やデータ構造 (see 節 37. Emacsの画面表示)を変更したときには、新しい情報を表示したり 新たな方法で表示するためにモード行の更新を強制できます。

Function: force-mode-line-update
カレントバッファのモード行の更新を強制する。

モード行は、通常、反転表示されます。 37.12 反転表示mode-line-inverse-videoを参照してください。

22.3.1 モード行のデータ構造    The data structure that controls the mode line.
22.3.2 モード行に使われる変数    Variables used in that data structure.
22.3.3 モード行の%記法    Putting information into a mode line.



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.3.1 モード行のデータ構造

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Mode%20Line%20Data"
"texi/elisp21/モード行のデータ構造"へのコメント(無し)

モード行の内容は、バッファローカルな変数mode-line-formatに 保持されたリスト、文字列、シンボル、数から成るデータ構造で制御されます。 このデータ構造をモード行構成(mode line construct)と呼びます。 これは単純なモード行構成から再帰的に構築します。 同じデータ構造はフレームタイトル(see 節 28.4 フレームタイトル)を 構築するためにも使われます。

Variable: mode-line-format
この変数の値は、モード行全体の書式に責任を持つモード行構成である。 この変数の値は、モード行のテキストを作るためにどの変数を使うか、 それらはモード行のどこに現れるかを制御する。

モード行構成は、定まったテキストの文字列のように単純でもかまいませんが、 普通は、テキストを作るための別の変数の使い方を指定します。 それらの変数の多くはそれ自身、それらの値として モード行構成を持つように定義されています。

mode-line-formatのデフォルト値は、 mode-nameminor-mode-alistなどの変数の値を使います。 多くの目的には、mode-line-formatが参照するいくつかの変数を 変えるだけで十分です。

モード行構成は、リスト、シンボル、文字列のいずれかです。 その値がリストであれば、その各要素はリスト、シンボル、文字列のいずれかです。

string
モード行構成としての文字列は、 %記法を除いて、モード行にそのまま表示される。 `%'のうしろの10進数は、右側に空白を埋める (つまりデータは左端に揃えられる)ときのフィールド幅を指定する。 see 節 22.3.3 モード行の%記法

symbol
モード行構成としてのシンボルは、その値を表す。 symbolの値は、symbolのかわりにモード行構成として使われる。 しかし、tnilのシンボル、および、シンボルの値が空のものは 無視する。

例外が1つある: 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幅に) 右端から切り詰める。

たとえば、ウィンドウの上端より上にバッファの何割があるかを表示するには、 (-3 "%p")のようなリストを使う。

読者がmode-line-format自体を変更するときには、 新しい値では、デフォルト値(see 節 22.3.2 モード行に使われる変数)に現れる ものと同じ変数を使い、それらの値をコピーして使ったり、 別の書式で情報を表示したりしないでください。 こうしておけば、それらの変数に対する変更を介した ユーザーや(display-timeやメジャーモードなどの)Lispプログラムが行った カスタマイズが効果を発揮できます。

ホスト名やデフォルトディレクトリを含んだ shell-modeに有用なmode-line-formatの例を示します。

 
(setq mode-line-format
  (list "-"
   'mode-line-mule-info
   'mode-line-modified
   'mode-line-frame-identification
   "%b--" 
   ;; リストを作るときに評価されることに注意
   ;; 単なる文字列のモード行構成を作る
   (getenv "HOST")
   ":" 
   'default-directory
   "   "
   'global-mode-string
   "   %[("
   'mode-name 
   'mode-line-process  
   'minor-mode-alist 
   "%n" 
   ")%]--"
   '(which-func-mode ("" which-func-format "--"))
   '(line-number-mode "L%l--")
   '(column-number-mode "C%c--")
   '(-3 . "%p")
   "-%-"))

(変数line-number-modecolumn-number-modewhich-func-modeは特定のマイナモードをオンにする。 通常どおり、これらの変数の名前はマイナモードコマンドの名前でもある。)



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.3.2 モード行に使われる変数

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Mode%20Line%20Variables"
"texi/elisp21/モード行に使われる変数"へのコメント(無し)

本節では、mode-line-formatの標準値でモード行のテキストに 含められる変数について述べます。 これらの変数に関しては、本来特別なことはありません。 別の変数を使うようにmode-line-formatを変更すれば、 別の変数でもモード行において同じ効果を発揮します。

Variable: mode-line-mule-info
この変数は、言語環境、バッファのコーディングシステム、 現在の入力方式に関する情報を表示するモード行構成の値を保持する。 see 節 32. 非ASCII文字

Variable: mode-line-modified
この変数は、カレントバッファが変更されたかどうかを表示する モード行構成の値を保持する。

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

この変数を変更してもモード行の更新を強制しない。

Variable: mode-line-frame-identification
この変数はカレントフレームを識別する。 複数のフレームを表示できるウィンドウシステムを使用している場合には デフォルト値は" "であり、 ある時点で1つのフレームしか表示できない普通の端末を使用している場合には "-%F "である。

Variable: mode-line-buffer-identification
この変数はウィンドウに表示しているバッファを識別する。 デフォルト値は("%12b")であり、 空白で埋めて最低12コラムでバッファ名を表示する。

Variable: global-mode-string
この変数は、デフォルトでモード行のバッファ名の直後に現れる モード行指定を保持する。 コマンドdisplay-timeは、 global-mode-stringが時刻と負荷情報を含んだ 変数display-time-stringを参照するように設定する。

`%M'記法はglobal-mode-stringの値を使うが、 この変数はmode-line-formatでモード行に含まれるため `%M'は廃れた記法である。

Variable: mode-name
このバッファローカルな変数は、 カレントバッファのメジャーモードの『愛称』を保持する。 各メジャーモードは、モード行にモード名が現れるようにこの変数に設定すること。

Variable: minor-mode-alist
この変数は、モード行にマイナモードがオンであることを表示する方法を 指定する要素からなる連想リストを保持する。 minor-mode-alistの各要素は、2要素リストであること。

 
(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を変更していないバッファの デフォルトのmode-line-formatの値を保持する。 これは(default-value 'mode-line-format)と同じである。

default-mode-line-formatのデフォルト値はつぎのリストである。

 
("-"
 mode-line-mule-info
 mode-line-modified
 mode-line-frame-identification
 mode-line-buffer-identification
 "   "
 global-mode-string
 "   %[("
 mode-name 
 mode-line-process
 minor-mode-alist 
 "%n" 
 ")%]--"
 (which-func-mode ("" which-func-format "--"))
 (line-number-mode "L%l--")
 (column-number-mode "C%c--")
 (-3 . "%p")
 "-%-")

Variable: vc-mode
各バッファにおいてバッファローカルな変数vc-modeは、 バッファで訪問したファイルが版管理されているか、 そうならばその方式を記録している。 版管理されていない場合はその値はnil、 さもなければモード行に表示される文字列である。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.3.3 モード行の%記法

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=%-Constructs"
"texi/elisp21/モード行の%記法"へのコメント(無し)

以下は、認識される%記法とその意味の表です。 `%%'以外の記法では、 最大表示文字数を指定する10進数を`%'のあとに追加できます。

%b
関数buffer-nameで得られたカレントバッファ名。 see 節 26.3 バッファ名 (2003/10/30)

%f
関数buffer-file-nameで得られた訪問したファイルの名前。 see 節 26.4 バッファファイル名 (2003/10/30)

%F
選択しているフレームのタイトル(ウィンドウシステム上のみ)か名前。 see 節 28.3.3 ウィンドウフレームのパラメータ

%c
ポイントの現在のコラム番号。

%l
ポイントの現在の行番号。

%*
バッファが読み出し専用であれば`%'(buffer-read-onlyを参照)、
バッファが変更されていれば`*'(buffer-modified-pを参照)、
さもなければ`-'。 see 節 26.5 バッファの変更 (2003/10/30)

%+
バッファが変更されていれば`*'(buffer-modified-pを参照)、
バッファが読み出し専用であれば`%'(buffer-read-onlyを参照)、
さもなければ`-'。 `%*'との違いは、変更された読み出し専用バッファに対してのみである。 see 節 26.5 バッファの変更 (2003/10/30)

%&
バッファが変更されていれば`*'、さもなければ`-'である。

%s
process-statusで得たカレントバッファに属するサブプロセスの状態。 see 節 36.6 プロセス情報

%t
訪問したファイルがテキストファイルであるかバイナリファイルであるかを表す。 (特定のオペレーティングシステムでのみ意味を持つ。)

%p
ウィンドウの上端の上にあるバッファのテキストの割合、 あるいは、`Top'、`Bottom'、`All'のいずれかである。

%P
ウィンドウの下端の上にあるバッファのテキスト (ウィンドウに見えてるテキストと上端の上にあるテキスト)の割合に バッファの先頭が見えていれば`Top'を加えたもの、 あるいは、`Bottom'、`All'のいずれかである。

%n
ナロイングしていると`Narrow'、さもなければなにもなし。 (29.4 ナロイングnarrow-to-regionを参照)。

%[
(ミニバッファのレベルを除く)再帰編集レベルの深さを表す。 各編集レベルごとに1つの`['。 see 節 20.11 再帰編集

%]
(ミニバッファのレベルを除く)各再帰編集レベルごとに1つの`]'。

%%
文字`%'。 %記法を許す文字列に`%'をそのまま含めるための方法である。

%-
モード行の残り部分を埋めるに十分な個数のダッシュ。

つぎの2つの%記法はまだ使えますが、 変数mode-nameglobal-mode-stringを 使って同じ効果を得られるのでこれらは廃れた記法です。

%m
mode-nameの値。

%M
global-mode-stringの値。 現在、display-timeglobal-mode-stringの値を変更する。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.4 iメニュー

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Imenu"
"texi/elisp21/iメニュー"へのコメント(無し)

iメニュー(Imenu)とは、ユーザーが バッファ内の定義や節の一覧からその1つを選ぶと バッファ内の当該箇所へ直接移動できる機能です。 iメニューは、 バッファ内の定義や部分の名前や位置を表すバッファインデックスを 構築しておくことで動作し、 当該箇所へ移動するためにユーザーがそれらの1つを選べるようにします。 本節ではメジャーモードに対するiメニューをカスタマイズする方法を説明します。

普通のもっとも単純な方法は、 変数imenu-generic-expressionに設定することです。

Variable: imenu-generic-expression
この変数がnil以外であると、 iメニュー向けの定義を探すための正規表現を指定する。 もっとも単純な場合、要素はつぎのような形である。

 
(menu-title regexp subexp)

ここで、menu-titlenil以外であると、 この要素に一致したものはバッファインデックスのサブメニューに置くことを 意味する。 menu-title自体はサブメニューの名前を指定する。 menu-titlenilであると、 この要素に一致したものはバッファインデックスのメニューに直接置かれる。

リストの2番目の要素regexpは正規表現 (see 節 33.2 正規表現)であり、 これに一致した箇所がバッファインデックスに現れる定義になる。 3番目の要素subexpは、 定義の名前に一致するregexpの部分式である。

要素はつぎの形でもよい。

 
(menu-title regexp index function arguments...)

この要素に一致するものは、バッファインデックスの特別な項目になり、 ユーザーが当該項目を選ぶと、 item-name、バッファ位置、argumentsを引数として functionを呼び出す。

emacs-lispモード向けには、patternはつぎのようになる。

 
((nil "^\\s-*(def\\(un\\|subst\\|macro\\|advice\\)\
\\s-+\\([-A-Za-z0-9+]+\\)" 2)
 ("*Vars*" "^\\s-*(def\\(var\\|const\\)\
\\s-+\\([-A-Za-z0-9+]+\\)" 2)
 ("*Types*"
  "^\\s-*\
(def\\(type\\|struct\\|class\\|ine-condition\\)\
\\s-+\\([-A-Za-z0-9+]+\\)" 2))

この変数に設定すると、 カレントバッファにおいてバッファローカルな変数になる。

Variable: imenu-case-fold-search
この変数は、imenu-generic-expressionとの一致に際して 大文字小文字を区別するかどうかを制御する。 デフォルトはtであり、大文字小文字を区別せずに一致をとる。

この変数に設定すると、 カレントバッファにおいてバッファローカルな変数になる。

Variable: imenu-syntax-alist
この変数は、imenu-generic-expressionを処理中に カレントバッファの構文テーブルに優先する 構文テーブルの変更部分の連想リストである。 各要素はつぎの形であること。

 
(characters . syntax-description)

CARのcharactersは、文字か文字列である。 それらの文字は、指定した構文syntax-descriptionであることを意味する。 これはmodify-syntax-entry(see 節 34.3 構文テーブル向け関数)に 渡される。

この機能は典型的には、 通常のシンボル構成文字を単語構成文字として扱い、 imenu-generic-expressionを単純化し一致処理を速くする。 たとえば、fortranモードではつぎのように使っている。

 
  (setq imenu-syntax-alist '(("_$" . "w")))

こうすると、imenu-generic-expressionのパターンでは、 `\\(\\sw\\|\\s_\\)+'のかわりに`\\sw+'を使える。 この技法は、名前の先頭文字の集合を名前の残りの文字の集合よりも 小さく制限する必要があるモードで使うには不便であることに注意してほしい。

この変数に設定すると、 カレントバッファにおいてバッファローカルな変数になる。

メジャーモードのiメニューをカスタマイズする別の方法は、 変数imenu-prev-index-position-functionimenu-extract-index-name-functionに設定することです。

Variable: imenu-prev-index-position-function
この変数がnil以外であると、その値は、 バッファインデックスに置くつぎの定義を ファイルで後向きに探すための関数であること。

その関数は、バッファインデックスの項目に対応する箇所にポイントを置くこと。 項目がみつからなければnilを返すこと。

この変数に設定すると、 カレントバッファにおいてバッファローカルな変数になる。

Variable: imenu-extract-index-name-function
この関数がnil以外であると、その値は、 ポイントが変数imenu-prev-index-position-functionが返した 定義の部分にあると仮定して、当該定義の名前を返す関数であること。

この変数に設定すると、 カレントバッファにおいてバッファローカルな変数になる。

メジャーモードのiメニューをカスタマイズする最後の方法は、 変数imenu-create-index-functionに設定することです。

Variable: imenu-create-index-function
この関数は、バッファインデックスの作成に使う関数を指定する。 その関数は引数なしで、カレントバッファに対するインデックスを返すこと。 save-excursionの内側から呼ばれるので、 その関数がポイントをどこに置こうと関係ない。

デフォルト値は、インデックスの連想リストを生成するために imenu-generic-expressionを使う関数である。 読者が別の関数を指定すれば、imenu-generic-expressionは使われない。

この変数に設定すると、 カレントバッファにおいてバッファローカルな変数になる。

Variable: imenu-index-alist
この変数は、カレントバッファに対するインデックスの連想リストを保持する。 この変数に設定すると、 カレントバッファにおいてバッファローカルな変数になる。

連想リストの単純な要素は(index-name . index-position) のような形である。 このような単純な要素を選ぶと、 バッファ内でindex-positionへ移動する効果がある。

特別な要素は(index-name position function arguments...)のような形である。 このような特別な要素を選ぶと、 つぎのようなフォームを実行する。

 
(funcall function index-name position arguments...)

入れ子になった部分連想リストの要素は (index-name sub-alist)のような形である。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.5 フォントロック(font-lock)モード

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Font%20Lock%20Mode"
"texi/elisp21/フォントロック(font-lock)モード"へのコメント(無し)

フォントロック(font-lock)モードとは、 バッファ内の特定部分に対して、それらの構文上の役割に応じた 属性faceを自動的に付加する機能のことです。 バッファを解析する方法はメジャーモードに依存しますが、 ほとんどのメジャーモードでは、 どの文脈でどのフェイスを使うかを指示する条件を定義します。 本節では、特定の言語向けに、いいかえれば、 特定のメジャーモード向けに フォントロックをカスタマイズする方法を説明します。

フォントロック(font-lock)モードは、強調表示すべきテキストを 2つの方法で、つまり、構文テーブルに基づいた構文解析、あるいは、 (通常、正規表現による)探索で探します。 構文解析による処理を最初に行ってコメントや文字列定数を探し、 font-lock-comment-facefont-lock-string-face (see 節 22.5.5 フォントロックのフェイス)を使ってそれらを強調表示します。 探索による処理がこれに続きます。

22.5.1 フォントロック(font-lock)の基本   
22.5.2 探索に基づくフォント選択   
22.5.3 その他のフォントロック変数   
22.5.4 フォントロックのレベル   
22.5.5 フォントロックのフェイス   
22.5.6 構文的なフォントロック   



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.5.1 フォントロック(font-lock)の基本

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Font%20Lock%20Basics"
"texi/elisp21/フォントロック(font-lock)の基本"へのコメント(無し)

フォントロック(font-lock)モードがテキストを強調表示する方法を 制御する変数がいくつかあります。 しかし、メジャーモードでこれらの変数を直接に設定するべきではありません。 そのかわりに、バッファローカルな 変数font-lock-defaultsに設定すべきです。 フォントロック(font-lock)モードがオンになると、 この変数に設定された値を使って他のすべての変数に設定します。

Variable: font-lock-defaults
この変数はメジャーモードがバッファローカルな変数として設定し、 当該モードにおいてテキストをどのように表示するかを指定する。 値はつぎの形であること。

 
(keywords keywords-only case-fold
 syntax-alist syntax-begin other-vars...)

最初の要素keywordsは、 間接的にfont-lock-keywordsの値を指定する。 要素keywordsがシンボルであると、 その変数としての値がfont-lock-keywordsに使われる。 あるいは、要素keywordsがそのようなシンボルのリストであると、 各シンボルが1つのレベルの表示方法を指定する。 最初のシンボルはレベル1の表示方法、 2番目のシンボルはレベル2の表示方法といった具合である。

2番目の要素keywords-onlyは、 変数font-lock-keywords-onlyの値を指定する。 これがnil以外であると(文字列やコメントの)構文による処理を行わない。

3番目の要素case-foldは、 font-lock-case-fold-searchの値を指定する。 これがnil以外であると、フォントロック(font-lock)モードは font-lock-keywordsで指定された探索で 大文字小文字を区別しない。

4番目の要素syntax-alistnil以外である場合、 それは(char-or-string . string)の形の コンスセルのリストであること。 これらは表示方法を選ぶための構文テーブルの設定に使われる (see 節 34.3 構文テーブル向け関数)。 得られた構文テーブルはfont-lock-syntax-tableに保持される。

5番目の要素syntax-beginは、 font-lock-beginning-of-syntax-functionの値を指定する (下記参照)。

other-vars以降の要素は、 (variable . value)という形である。 この種の要素は、表示方法の選択に影響する その他の変数に設定するために使われる。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.5.2 探索に基づくフォント選択

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Search-based%20Fontification"
"texi/elisp21/探索に基づくフォント選択"へのコメント(無し)

フォントロック(font-lock)モードのカスタマイズにおいて もっとも重要な変数はfont-lock-keywordsです。 探索に基づく表示方法の選択における探索条件を指定します。

Variable: font-lock-keywords
この変数の値は、強調表示するべきキーワードのリストである。 このリストに正規表現を書く場合には注意すること。 貧弱な書き方をしたパターンであると、動作を劇的に遅くする!

font-lock-keywordsの各要素は、 特定のテキストの探し方と 当該テキストをどのように強調表示するか指定します。 フォントロック(font-lock)モードは、 font-lock-keywordsの要素を1つ1つ処理し、 各要素において、それに一致するものすべてを探して処理します。 通常、すでに表示方法を選択済みのテキスト部分については、 それ以降の要素に一致しても表示方法を変えません。 しかし、highlighterの要素overrideを使って、 異なるふるまいを指定できます。

font-lock-keywordsの各要素はつぎのいずれかの形です。

regexp
正規表現regexpに一致したものはすべて font-lock-keyword-faceを使って強調表示する。

 
;; 孤立した`foo'の出現は
;; font-lock-keyword-faceで強調表示する。
"\\"

関数regexp-opt(see 節 33.2.1 正規表現の構文)は、 異なる複数個のキーワードに一致する最適な正規表現を 計算するのに有用である。

function
関数functionを呼び出してテキストを探し、 それが探し出したものをfont-lock-keyword-faceを使って強調表示する。

functionは、探索限界を引数として呼び出される。 みつかればnil以外を返すとともに みつけた部分を表すマッチデータを設定する。

(matcher . match)
この種の要素では、matcherは、上に述べた正規表現か関数を表す。 CDRのmatchは、(matcherに一致した部分全体のかわりに) 強調表示すべきmatcherの部分式を指定する。

 
;; `fubar'の各出現の`bar'を
;; font-lock-keyword-faceで強調表示
("fu\\(bar\\)" . 1)

正規表現matcherを作るためにregexp-optを使った場合、 matchの値を計算するには regexp-opt-depth(see 節 33.2.1 正規表現の構文)を使える。

(matcher . facename)
この種の要素では、facenameは、 強調表示に使うフェイス名を指定する値を表す式である。

 
;; `fubar'の出現は、fubar-faceの値で
;; 表されたフェイスを使って強調表示
("fubar" . fubar-face)

(matcher . highlighter)
この種の要素では、highlighterは、 matcherに一致した部分の強調表示方法を指定するリストである。 つぎの形であること。

 
(subexp facename override laxmatch)

CARのsubexpは、 強調表示すべき一致部分の部分式を指定する整数 (0は一致部分全体を意味する)である。 2番目の要素facenameは、上に述べたようにフェイスを指定する。

highlighterの最後の2つの要素、 overridelaxmatchはフラグである。 overridetであると、当該要素は、 font-lock-keywordsのまえの要素で決定済みの 表示方法に優先することを表す。 keepであると、他の要素では表示方法が決定していない 各文字の表示方法を表す。 prependであると、 属性faceの先頭にフェイスfacenameを追加する。 appendであると、 属性faceの末尾にフェイスfacenameを追加する。

laxmatchnil以外であると、 matcherで一致したものの中にsubexp番目の部分式が なくてもエラーとしないことを意味する。

この種の要素とその動作の例を示す。

 
;; `foo'や`bar'の出現の表示方法がすでに決まっていても
;; foo-bar-faceで強調表示する
;; foo-bar-faceの値はフェイスであること
("foo\\|bar" 0 foo-bar-face t)

;; 関数fubar-matchがみつけた各出現内の最初の部分式を
;; fubar-faceの値が表すフェイスで強調表示する
(fubar-match 1 fubar-face)

(matcher highlighters...)
この種の要素は、1つのmatcherに対して 複数のリストhighlighterを指定する。 これが有用であるためには、 各highlightersubexpの値が異なること。 つまり、それぞれをmatcherの異なる部分式に適用できること。

(eval . form)
formは、バッファにおいてfont-lock-keywordsのこの値が 始めて使われたときに評価すべき式である。 その値は、この表にあげた形の1つであること。

警告: font-lock-keywordsの要素は、 行をまたがって一致するように設計しないこと。 そのような処理は信頼性がない。 font-lock-fontify-bufferは、行にまたがるパターンを正しく扱えるが、 読者がバッファを編集したときの更新処理では、 一度に1行ずつ処理するために正しく扱えない。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.5.3 その他のフォントロック変数

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Other%20Font%20Lock%20Variables"
"texi/elisp21/その他のフォントロック変数"へのコメント(無し)

本節では、font-lock-defaultsを用いてメジャーモードで 設定できる他の変数について述べます。

Variable: font-lock-keywords-only
nil以外であると、フォントロック(font-lock)モードは、 構文に基づいてコメントや文字列を強調表示すべきでないことを意味する。 font-lock-keywordsに基づく強調表示のみを行う。

Variable: font-lock-keywords-case-fold-search
nil以外であると、font-lock-keywordsの 正規表現探索では大文字小文字を区別しないことを意味する。

Variable: font-lock-syntax-table
この変数は、コメントや文字列の表示方法に用いる 構文テーブルを指定する。

Variable: font-lock-beginning-of-syntax-function
この変数がnil以外であると、 ポイントを構文上の『トップレベル』で文字列やコメントの外側に 後方移動する関数であること。 フォントロック(font-lock)モードは、 構文に基づく処理において正しい結果を得るために 必要に応じてこの関数を使う。

関数は引数なしで呼び出される。 ポイントを構文ブロックの先頭に置くこと。 典型的な値は、 beginning-of-line(行頭は構文ブロックの外側である)、 あるいは、 プログラム向けのモードではbeginning-of-defun、 テキスト向けのモードではbackward-paragraph (モード固有の関数は構文ブロックの外側にポイントを移動する)である。

値がnilであると、バッファの先頭を構文ブロックの外側の位置として使う。 これは誤りではないが、動作を遅くする。

Variable: font-lock-mark-block-function
この変数がnil以外であると、 コマンドM-g M-gfont-lock-fontify-block)による 再表示のためにテキストの括られた範囲を選ぶために 引数なしで呼ばれ関数であること。

関数は、選んだ範囲にリージョンを設定すること。 正しい結果を得られるように大きめのテキスト範囲を選ぶのがよいが、 再表示処理が遅くならないように大きすぎないこと。 典型的な値は、プログラム向けモードではmark-defun、 テキスト向けモードではmark-paragraphである。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.5.4 フォントロックのレベル

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Levels%20of%20Font%20Lock"
"texi/elisp21/フォントロックのレベル"へのコメント(無し)

多くのメジャーモードでは、3段階の表示方法を提供します。 font-lock-defaultskeywordsに シンボルのリストを使って複数レベルを定義できます。 各シンボルは1つのレベルの表示方法を指定します。 どのレベルを選ぶかはユーザーの責任です。 指定したレベルのシンボルの値はfont-lock-keywordsの初期化に使われます。

表示方法のレベルを定義する際の慣習をあげておきます。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.5.5 フォントロックのフェイス

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Faces%20for%20Font%20Lock"
"texi/elisp21/フォントロックのフェイス"へのコメント(無し)

フォントロック(font-lock)モードでは任意のフェイスを使えますが、 フォントロック(font-lock)モード向けに特別に定義さたフェイスがあります。 これらのシンボルのおのおのは、フェイス名でもあり、 シンボル自身をデフォルト値とする変数でもあります。 つまり、font-lock-comment-faceのデフォルト値は、 font-lock-comment-faceです。 これは、 フェイス名を値に持つような式を書くfont-lock-keywordsなどの場面で、 font-lock-comment-faceと書けることを意味します。

font-lock-comment-face
(典型的には)コメントに使われる。

font-lock-string-face
(典型的には)文字列に使われる。

font-lock-keyword-face
(典型的には)キーワード、つまり、 Cのforifのように構文的に重要な名前に使われる。

font-lock-builtin-face
(典型的には)組み込み関数の名前に使われる。

font-lock-function-name-face
(典型的には)関数定義/宣言内において、 定義/宣言されている関数の名前に使われる。

font-lock-variable-name-face
(典型的には)変数定義/宣言内において、 定義/宣言されている変数の名前に使われる。

font-lock-type-face
(典型的には)ユーザー定義のデータ型の名前が定義/参照される場所において、 それらの名前に使われる。

font-lock-constant-face
(典型的には)定数の名前に使われる。

font-lock-warning-face
(典型的には)独特な構文や別のテキストの意味を大きく変えるようなものに 使われる。 たとえば、Emacs Lispの`;;;###autoload'や Cの#error指定に使われる。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.5.6 構文的なフォントロック

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Syntactic%20Font%20Lock"
"texi/elisp21/構文的なフォントロック"へのコメント(無し)

フォントロック(font-lock)モードは、 属性syntax-tableを自動更新するためにも使えます。 1つの構文テーブルだけでは十分でないような言語において有用です。

Variable: font-lock-syntactic-keywords
この変数は構文的なフォントロックをオンにし制御する。 その値はつぎの形の要素からなるリストであること。

 
(matcher subexp syntax override laxmatch)

この要素の各部分には、つぎのfont-lock-keywordsの対応する種類の要素と 同じ意味がある。

 
(matcher subexp facename override laxmatch)

しかし、属性faceに使う値facenameを指定するかわりに、 属性syntax-tableに使う値syntaxを指定する。 ここで、syntaxは、構文テーブルを値とする変数、 (syntax-code . matching-char)の形の構文テーブルの項目、 あるいは、この2種類のどちらかを値とする式である。



[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [表紙] [目次] [索引] [検索] [上端 / 下端]

22.6 フック

URL="https://bookshelf.jp/cgi-bin/goto.cgi?file=elisp21&node=Hooks"
"texi/elisp21/フック"へのコメント(無し)

フック(hook)とは、既存のプログラムから特定の場面で 呼び出される(1つか一連の)関数を収めた変数です。 Emacsは、カスタマイズのためにフックを用意しています。 ほとんどの場合、フックはファイル`.emacs'で設定しますが、 Lispプログラムが行ってもかまいません。 標準のフック関数一覧については、See 節 G. 標準のフック。

Emacsの多くのフックはノーマルフック(normal hook)です。 これらの変数は、引数なしで呼び出される関数のリストを保持しています。 フック名が`-hook'で終っていると、ノーマルフックを意味します。 読者がそれらを単一の方法で使えるように、 可能な限りノーマルフックにするように心掛けています。

各メジャーモード関数は、 その初期化の最終段階でモードフック(mode hook)と呼ばれる ノーマルフックを実行すると期待されます。 これにより、モードがすでに設定したバッファローカルな変数を上書きすることで、 ユーザーがモードのふるまいをカスタマイズしやすくしています。 しかし、フックは別の場面でも使われています。 たとえば、フックsuspend-hookは、 Emacsが自身を一時休止する直前に実行されます。 (see 節 39.2.2 Emacsの休止)。

ノーマルフックにフック関数を追加する推奨方法は、 add-hook(下記参照)を呼ぶことです。 フック関数は、funcall(see 節 11.1 関数とはなにか)が 受け付けるならばどんな種類の関数でもかまいません。 ほとんどのノーマルフック変数は最初は空ですが、 add-hookはその扱い方を知っています。

フック変数の名前が`-hook'で終らない場合、 それがアブノーマルフック(abnormal hook)であることを表します。 読者は、そのようなフックの正しい使い方を説明書で調べるべきです。

変数名が`-functions'や`-hooks'で終っていると、 その値は関数のリストですが、 それらの関数を引数ありで呼び出したり、 関数の戻り値をどこかで使うという意味でアブノーマル(異常)なのです。 リストに関数を追加するにはadd-hookを使えますが、 関数を書くときには注意する必要があります。 (これらの変数のうち、実際にはノーマルフックであるものもある。 ノーマルフックには`-hook'を使うという慣習を 確立するまえに命名したものである。)

変数名が`-function'で終っていると、 その値は、関数のリストではなく、1つの関数です。

lisp対話モードで自動詰め込み(auto-fill)モードをオンにするために モードフックを使った例を示します。

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

適当な時期に、Emacsは関数run-hooksを使って 特定のフックを実行します。 この関数は、add-hookで追加されたフック関数を呼び出します。

Function: run-hooks &rest hookvar
この関数は複数個のフック変数名を引数にとり、各フックを順に実行する。 各引数hookvarは、フック変数のシンボルであること。 これらの引数は、指定された順に処理される。

フック変数がnil以外の値であると、 その値は、関数か関数のリストである。 値が関数(ラムダ式や関数定義を持つシンボル)であると、それを呼び出す。 値がリストであると、順番にその要素を呼び出す。 フック関数は、引数なしで呼び出される。 現在、フック変数に1つの関数を入れることは廃れかけている。 つねに関数のリストを使うべきである。

例として、emacs-lisp-modeがそのモードフックをどのように 実行するかを示す。

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

Function: run-hook-with-args hook &rest args
この関数は、フック関数に引数を渡すアブノーマルフックを実行する方法である。 各フック関数に引数argsを渡して呼び出す。

Function: run-hook-with-args-until-failure hook &rest args
この関数は、フック関数に引数を渡すアブノーマルフックを実行するが、 フック関数が失敗するとただちに止める方法である。 フック関数がnilを返すまで、 各フック関数に引数argsを渡して呼び出す。 nilが返ってくるとnilで戻る。 さもなければ、nil以外の値を返す。

Function: run-hook-with-args-until-success hook &rest args
この関数は、フック関数に引数を渡すアブノーマルフックを実行するが、 フック関数が成功するとただちに止める方法である。 フック関数がnil以外を返すまで、 各フック関数に引数argsを渡して呼び出す。 nil以外が返ってくると 最後に呼び出したフック関数の戻り値を返す。

Function: add-hook hook function &optional append local
この関数はフック変数hookに関数functionを追加する 手軽な方法である。 引数functionは、正しい個数の引数をとる任意の正しいLisp関数であること。 たとえば、

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

は、text-mode-hookというフックに my-text-hook-functionを追加する。

add-hookは、ノーマルフックに加えてアブノーマルフックにも使える。

フック関数は実行順序に依存しないように設計するのが最良である。 実行順序に依存すると『トラブルを呼び込む』ようなものである。 しかし、順序は予測できる。 通常、functionはフックリストの先頭に置かれるので、 (ほかにadd-hookの呼び出しがなければ)最初に実行される。 省略可能な引数appendnil以外であると、 新たなフック関数はフックリストの末尾に置かれ、 最後に実行される。

localnil以外であると、 新たなフック関数をカレントバッファにバッファローカルにすることを意味する。 これを行うまえに、(make-local-variableではなくmake-local-hookを呼んで フック自身をバッファローカルにしておく必要がある。 フック自身がバッファローカルでないと、localの値は意味を持たない。 フック関数はつねにグローバルである。

Function: remove-hook hook function &optional local
この関数は、フック変数hookからfunctionを取り除く。

localnil以外であると、 グローバルなフックリストではなくバッファローカルなフックリストから functionを削除することを指定する。 フック変数自身がバッファローカルでないと、localの値は意味を持たない。

Function: make-local-hook hook
この関数は、フック変数hookをカレントバッファにバッファローカルにする。 フック変数がバッファローカルであると、 バッファローカルなフック関数とグローバルなフック関数を持つことができ、 run-hooksはそれらすべてを実行する。

この関数は、バッファローカルな値の要素をtにすることで動作する。 これは、バッファローカルな値に加えてフック変数のデフォルト値にある フック関数を使うことを表すフラグである。 run-hooksはこのフラグを理解し、 make-local-hookはすべてのノーマルフックを処理できる。 アブノーマルフックに関しては、 tの意味を理解するように更新したものだけが処理できる。

フック変数に対してmake-local-variableを直接使わないこと。 それだけでは不十分である。


[ << ] [ >> ]           [表紙] [目次] [索引] [検索] [上端 / 下端]