GNU Emacs 32.0.50 (9008bf64c3) のマニュアルを PLaMo 翻訳で機械翻訳したものです。誤訳を含むことがあります。原文: https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Keymaps.html ・ emacs-doc.conao3.com

23.4 キーマップの作成

ここでは、キーマップを作成するための関数について説明します。

関数: make-sparse-keymap &optional prompt

この関数は、エントリのない新しいスパースキーマップを作成して返します。(スパースキーマップは、通常必要とされる種類のキーマップです。)新しいキーマップは、make-keymapとは異なり文字テーブルを含まず、いかなるイベントもバインドしません。

(make-sparse-keymap)
    ⇒ (keymap)

prompt を指定すると、それがキーマップ全体のプロンプト文字列になります。これはメニューキーマップに対してのみ指定してください(メニューの定義を参照)。全体のプロンプト文字列が設定されたキーマップは、次の入力イベントを調べるためにアクティブな場合、常にマウスメニューまたはキーボードメニューを表示します。メジャーモードやマイナーモードのメインマップに全体のプロンプト文字列を指定しないでください。そうすると、コマンドループが実行されるたびにキーボードメニューが表示されるようになります。

関数: make-keymap &optional prompt

この関数は、新しい完全なキーマップを作成して返します。このキーマップには、修飾子のないすべての文字用のスロットを持つ文字テーブル(文字テーブルを参照)が含まれています。新しいキーマップは、初期状態でこれらすべての文字をnilにバインドし、それ以外の種類のイベントはバインドしません。引数promptは、make-sparse-keymapと同様にプロンプト文字列を指定します。

(make-keymap)
    ⇒ (keymap #^[nil nil keymap nil nil nil ...])

キーマップに多くのバインドがある場合、フルキーマップの方がスパースキーマップよりも効率的です。バインドがわずか数個であれば、スパースキーマップの方が適しています。

関数: define-keymap &key options... &rest pairs...

上述の機能を用いてキーマップを作成し、そのマップ内でキーバインドを指定するために keymap-set を使用できます(キーバインドの変更 を参照)。ただし、書き込みモードでは、一度に多数のキーをバインドする必要があることが多く、すべてに keymap-set を使用するのは煩雑でミスの原因にもなりかねません。代わりに define-keymap を使用すれば、キーマップを作成して複数のキーをバインドできます。以下に非常に基本的な例を示します:

(define-keymap
  "n" #'forward-line
  "f" #'previous-line
  "C-c C-c" #'quit-window)

この関数は、新しいスパースキーマップを作成し、pairs でキーストロークを定義して、新しいキーマップを返します。pairs に重複するキーバインドがある場合は、エラーを通知します。

pairs は、keymap-set で受け付けられるキーバインドとキー定義を交互に並べたリストです。また、キーに特殊記号 :menu を指定することもでき、その場合は定義を easy-menu-define で受け付けられるメニュー定義とする必要があります(Easy Menu を参照)。以下に、この用法の簡単な例を示します。

(define-keymap :full t
  "g" #'eww-reload
  :menu '("Eww"
          ["Exit" quit-window t]
          ["Reload" eww-reload t]))

キー/定義ペアの前に複数のキーワードを指定することで、新しいキーマップの機能を変更できます。define-keymap の呼び出しにおいて機能キーワードのいずれかが省略されている場合、その機能のデフォルト値は nil となります。利用可能な機能キーワードの一覧は以下の通りです:

:full

nil 以外の場合は、スパースキーマップ(make-sparse-keymap と同様。キーマップの作成 を参照)ではなく、char-table キーマップ(make-keymap と同様)を作成します。スパースキーマップがデフォルトです。

:parent

nil 以外の場合、その値は親として使用するキーマップである必要があります(継承とキーマップを参照)。

:keymap

nil 以外の場合、値はキーマップである必要があります。新しいキーマップを作成するのではなく、指定されたキーマップが変更されます。

:suppress

nil 以外の場合、キーマップは suppress-keymap で抑制されます(キーバインドの変更 を参照)。デフォルトでは、数字とマイナス記号は抑制の対象外となりますが、値が nodigits の場合は、他の文字と同様に数字とマイナス記号も抑制されます。

:name

nil 以外の場合、x-popup-menu でメニューとして使用するのであれば、その値はキーマップのメニューとして使用する文字列とする必要があります(ポップアップメニューを参照)。

:prefix

nil 以外の場合、値はプレフィックスコマンドとして使用されるシンボルである必要があります(プレフィックスキーを参照)。この場合、マップ自体の代わりに、このシンボルが define-keymap によって返されます。

マクロ: defvar-keymap name &key options... &rest pairs...

キーマップで最も一般的な使い方は、変数にバインドすることです。ほぼすべてのモードがそうしており、foo というモードには、ほぼ必ず foo-mode-map という変数が用意されています。

このマクロは、nameを変数として定義し、optionsとpairsをdefine-keymapに渡し、その結果を変数のデフォルト値として使用します。また、pairsに重複するキーバインドがある場合はエラーを通知します。

options は基本的に define-keymap のキーワードと同様です。さらに、定義された変数の docstring を提供する :doc キーワードもあります。以下に例を示します:

(defvar-keymap eww-textarea-map
  :parent text-mode-map
  :doc "Keymap for the eww text area."
  "RET" #'forward-line
  "TAB" #'shr-next-link)

:prefix キーワードには、追加の値として t を指定できます。これは name をそのオプションの値として使用することの略記です。つまり、次のように記述する代わりに

(defvar-keymap foo-map
  :prefix 'foo-map
  ...)

書けます

(defvar-keymap foo-map
  :prefix t
  ...)

キーマップ内の各コマンドには、例えば次のようにrepeat-mapプロパティを付与することで、「繰り返し可能」、すなわちrepeat-modeで使用可能としてマークできます。

(put 'undo 'repeat-map 'undo-repeat-map)

ここで、プロパティの値が repeat-mode で使用されるマップとなります。

put の繰り返し呼び出しを避けるため、defvar-keymap には :repeat キーワードも用意されており、これを用いてキーマップ内のどのコマンドを repeat-mode で使用可能にするかを指定できます。利用可能な値は以下の通りです。

t

つまり、キーマップ内のすべてのコマンドが繰り返し実行可能であり、これが最も一般的な使い方です。

(:enter (commands ...) :exit (commands ...)
:continue (commands ...) :hints ((command . "hint") ...))

これは、:enter リストのコマンドが repeat-mode に入り、:exit リストのコマンドがリピートモードを抜けることを指定します。

:enter リストが空の場合、マップ内のすべてのコマンドが repeat-mode に入ります。このリストに1つ以上のコマンドを指定することは、定義対象のマップに存在しないものの、repeat-map プロパティを持つべきコマンドがある場合に有用です。

:exit リストが空の場合、マップ内のどのコマンドも repeat-mode を終了しません。定義するキーマップに、repeat-map プロパティを持つべきではないコマンドが含まれている場合、このリストに1つ以上のコマンドを指定すると便利です。

:continue リストは、repeat-mode に入ってはならないコマンドを指定します。これらのコマンドは、すでに有効化されている繰り返しシーケンスを継続させるものである必要があります。

:hints リストには、CAR がコマンドで、CDR がエコー領域で繰り返し可能なキーと共に表示される文字列であるコンスペアを含めることができます。

例えば u に undo コマンドを繰り返させるには、以下の2つのスタンザは同等です。

(defvar-keymap undo-repeat-map
  "u" #'undo)
(put 'undo 'repeat-map 'undo-repeat-map)

および

(defvar-keymap undo-repeat-map
  :repeat t
  "u" #'undo)

マップ内にコマンドが多く、そのすべてを繰り返せるようにしたい場合は、後者が好ましい。

関数: copy-keymap keymap

この関数は keymap のコピーを返します。このような処理が必要になることはほとんどありません。別のキーマップと似ているが、一部に変更を加えたものが欲しい場合は、コピーではなくマップ継承を使用してください。具体的には、次のような形になります:

(let ((map (make-sparse-keymap)))
  (set-keymap-parent map <theirmap>)
  (keymap-set map ...)
  ...)

copy-keymap を実行すると、keymap で直接バインディングとして現れるキーマップも再帰的にコピーされ、これが何段階にもわたって繰り返されます。ただし、文字の定義が、その関数定義がキーマップであるシンボルである場合には、再帰的なコピーは行われず、新しいコピーにも同じシンボルが現れます。

(setq map (copy-keymap (current-local-map)))
⇒ (keymap
     ;; (This implements meta characters.)
     (27 keymap
         (83 . center-paragraph)
         (115 . center-line))
     (9 . tab-to-tab-stop))

(eq map (current-local-map))
    ⇒ nil
(equal map (current-local-map))
    ⇒ t