昔,「Emacs キーバインドを一元管理するマイナーモード」を書いたことがある。いま切実に復活させたいのだが,この辺の仕様はややこしすぎて復習に時間がかかりそう。
昔,「Emacs キーバインドを一元管理するマイナーモード」を書いたことがある。いま切実に復活させたいのだが,この辺の仕様はややこしすぎて復習に時間がかかりそう。
この描出は,2007年12月23日投稿の旧ブログ記事を再録したものです。長らく更新されていませんので,最新の情報は著者のページからお探し下さい。また,当記事で参照されているファイルの配布は停止しています。
前回では、Emacs での標準的なキー定義の仕方を解説しました。
しかし、標準的な方法では、キーの定義に強制力がないため、それぞれのモードが勝手に定義を変更してしまいます。ある一つのキーに割りあてられた機能を全般的に保証するには、あらゆるモードの内部処理に、 (フックなどを使って) しらみつぶしに定義を追加していく以外にないのですが、一部にはフックをかけるだけでは有効にならない実装のモードも存在しており、作業的に困難があります。
この問題を解決するために今回紹介する方法では、 標準的な方法とは逆の発想でキー定義を行なっていきます。
この新しい方法では、一度定義したキーは他のモードによって変更されることはありません。ただし今度は逆に、モードごとに異なる操作性を要求される場面で自動的に挙動がかわらないため、各々のモードに対応する定義を追加していくことになります。
なお、この記事では英語での用語に独自の訳語をあてています。その対応関係はこちらの記事を、それぞれの意味についてはこちらの記事を参照して下さい。
Wellmap モード
Wellmap モードは筆者が本記事のために作成した解説用のモードです。基本的な要素を盛りこんでありますが、肝心の定義部分は空に近いので、自由に書き換えて使ってみてください。
wellmap-b1.zip (モード一式)
以下は、各ファイルの簡単な説明です。
インストール方法
ダウンロードしたファイルを el ファイル検索パスに入れ、以下の一行を .emacs などに入れるだけで使うことが出来ます。
(load "wellmap")
この例では、wellmap.el で定義してある通りに、対象となるバッファを開いた時点で自動的に起動されます。もし、自動的に起動させたくない場合は、下の形に直して下さい。エラーで制御不能になった場合に有効です。
(load "wellmap-manually")
この場合、起動させるにはそれぞれのバッファで M-x wellmap [RET] とする必要があります。
使い方
基本的な使い方は、wellmap-layout-of-common.el と wellmap-layout-of-modes.el にあるキー配置用関数内にキー定義を書いていくだけです。前者にはいろいろなモードで共有できる定義を、後者にはそれぞれのモード特有の定義を書いていきます。
キー配置用関数の書式は以下の形式になっています。
(defun wellmap-layout-of-[対象] (&optional copy-flag) (let ((map [引き継ぐキー配置名])) ;; (define-key map [キー] [コマンド]) ;; の形式でここに書いていく (wellmap-set-keymap 'wellmap-[対象] map copy-flag)))
[対象] の部分にはモード名 ("-mode" は省略) や "common-なんとか" のようにキー配置を適用する対象の名前を入れます。(詳細は後述)
[引き継ぐキー配置名] の部分には、ここで作りたいキー配置のもととなるキー配置のコピーを (copy-keymap 関数などを使い) 指定します。この形式では、すでにあるキー配置の一部を書きかえた新しいキー配置を簡単に作成できます。もし、白紙から定義を始めたい場合には、"(make-sparse-keymap)" や "(make-keymap)" を入れます。前者ではバッファ内の通常のキー配置を、ここで行なった定義が一部上書きするのに対し、後者ではここで定義されていないキーは完全に無効になる、という違いがあります。
どのモードであっても共通に利用したい定義や、使用頻度が高く特殊な形式をもつモードへの定義を記述しておくためのファイルが wellmap-layout-of-common.el です。初期状態で5つの関数が定義してあり、どれも変数名は wellmap-[名前]、関数名は wellmap-layout-of-[名前] で、名前は common* という形式になっています。
新しくモードに適用する
上述の「使い方」は、既に Wellmap に適用されているモードでのみ有効です。仮に全てのモードに Wellmap が適用されているとすればそれだけで済むのですが、今回の Wellmap モードは解説のために、基本的な規則に従えば問題の無い部分は削り、つまづきやすい例外の部分に要点を絞り込んであるので、初期状態で対応しているのは下記のモード (replace は例外的に非モード) のみです。
以下は、新しくモードに適用するための手順です。
<ol>キー定義の例
例として、fundamental モード (最も単純で無機能な編集モード) にキー配置をどのように設定するかを見てみます。
(defun wellmap-layout-of-common (&optional copy-flag) (let ((map (make-sparse-keymap))) ;; 新しくキー配置を作成している ;; (define-key map [キー] [コマンド]) ;; の形式でここに書いていく (wellmap-set-keymap 'wellmap-common map copy-flag)))
(defun wellmap-layout-of-common-editing (&optional copy-flag) (let ((map (wellmap-layout-of-common t))) ;; "common" の配置を引き継いでいる ;; (define-key map [キー] [コマンド]) ;; の形式でここに書いていく (wellmap-set-keymap 'wellmap-common-editing map copy-flag)))
(defun wellmap-layout-of-fundamental (&optional copy-flag) (let ((map (wellmap-layout-of-common-editing t))) ;; "common-editing" の配置を引き継いでいる ;; (define-key map [キー] [コマンド]) ;; の形式でここに書いていく (wellmap-set-keymap 'wellmap-fundamental map copy-flag)))
※通常のキー配置を引き継ぎたい場合は copy-keymap 関数を使用する必要がありますが、Wellmap のキー配置用関数は、引数 (copy-flag) に t を渡せば自動的に配置のコピーを返すようになっています。
既知の問題点と対処方法
このモードと wdired-mode とを併用する場合、稀に wdired 用のキー配置が適用されないことがあります。wellmap-adjust-wdired 関数内での対応が正確ではない可能性がありますが、現在調査中です。もし wdired 編集を終了できなくなった場合、M-x wdired-finish-edit として下さい。
Wellmap の起動しない対応外のモード (バッファ) では効果がないため、特殊なキー配置をしていると、Emacs 標準のキー配置との間で感覚的に混乱することがあります。その場合、wellmap.el に global-set-key 関数などを使って、最低限確保しておきたい定義を一般配置に設定しておくことで回避できます。一番始めに読み込まれるファイルであるため、他のファイルの編集中にエラーが発生してモードが起動しない場合でも、最低限の操作性は共通化できます。
最後に
若干の問題点はありますが、このモードでは、各場面でこのモードを有効にする方法、対象とするモードへの適用処理、そのキー配置、と段階的に問題を切り分けていることで、複雑な関係をもった各モードへの対応方法を形式化でき、まとめて管理しておけるという利点があります。
筆者はこの方式をもとにしたモードを実用しており、Emacs 上でのキー配置を完全に管理する、という目的には必要十分であると考えています。
しかし、ここまではあくまで本来の目的の前置き、枠組みにすぎません。本当に難しい問題は、どのようにキーを配置するべきか、ということです。ともかく、その問題に取りかかる準備はできたことになります。次回は、Emacs におけるキー配置の問題点、解決方針などを探っていきたいと思います。
2008/01/13, 2008/02/15 改訂
謝辞
あらゆるモードでキー配置を有効にするためにマイナーモードを利用するというアイデアは pqrs.org さんの my-keyjack-mode のページを、特定のマイナーモードのキー配置を常に最優先にするコードは blankspace さんのこちらのページの記述を、それぞれ参考にさせて頂きました。