-
Devilモードの0.6.0のMANUAL.orgの日本語訳です
-
ライセンス: パッケージのライセンスと同じ、すなわちMITライセンスです
TOC
- Devilモード
Devilモード
Devilモードはカンマキーと引き換えに、Emacsでの修飾キーなしの編集経験を提供するモードだ。そう、カンマキー(comma key)だ! これは普通ならテキストのほぼすべての隅に句読点を挿入するためのキーである。そう、このモードは少しへそ曲がりなモードと言えよう! でなければ悪魔(Devil)などと呼ばれないのではないだろうか? もっと理に適ったモードであればもっと神聖な、そうGod(神)モードとでも呼ぶかもしれない。しかし悲しいかな、このモードには神聖な何かなどは存在しない。かわりにと言っては何だが、悪魔のテリトリーにようこそ! ときには句読点を入力するためにカンマキーを使用する権利が与えられることもあるが、それは悪魔を誘惑できた場合に限られる。この邪悪なドメインにおいてはカンマキーを諦めること、そしてよこしまな秘密を指先に唱えるような編集体験を受容しなければならないことに注意して欲しい!
1. イントロダクション
Devilモードは設定可能な変換ルールにしたがって、横取りしたキーストロークをEmacsのキーシーケンスに変換する。たとえばデフォルトの変換ルールでは, x , f
とタイプすると、DevilモードがそれをC-x C-f
に変換する。カンマキー(,
)を修飾キーのcontrol(C-
)とみなすのはとんでもない選択に思えるかもしれない。結局のところカンマキーは散文とコードの両方において、非常に重要な句読点文字なのだ。本当に,
を修飾キーC-
として使っていくことができるのだろうか? この恐ろしいアイデアだが、実際にはそれほど手間を掛けずに機能させられることが判ったのだ。少なくともわたしの場合は問題なかったので、あなたも問題なく使うことができるだろう。もしカンマキーの使用に問題があっても、Devilでは別のキーを修飾キーC-
に設定することもできる。カスタムDevilキーとそれに続くセクションに、いくつか例を挙げてあるので参考にして欲しい。
疑り深い読者であれば当然こう尋ねるだろう: ,
がC-
に変換されるとしたら、一体どうやってリテラルの,
をテキストに挿入できるのか? その答えについてはセクションカンマのタイプを参照して欲しい。しかしその前に基本事項をいくつか補足しておく必要がある。本腰を入れて解明していこう。多分気に入る筈だ。もしお気に召さなければGodモードやEvilモード、素のキーバインディング、あるいは何か他の面白いことに戻るのは何時でもできるのだから。
2. 表記
ドキュメント内で使用する表記に関する簡単な注意: 前に挙げた例では, x , f
をC-x C-f
に変換する例を見てもらった。これはキーストローク,x,f
がctrl+x ctrl+f
に変換されというのが本当の意味だ。実際にはカンマの後のスペースはタイプせず、キー,
の後に直接キーx
をタイプすることになる。しかしこのドキュメントで使用するキーシーケンスでは、、キーストロークそれぞれの間にスペースを挟んだ表記を使用する。この表記はEmacsにおいてキーシーケンスを表すときやkey-description
、describe-key
といったEmacs関数がキーシーケンスを表す際に一般的に用いる方法と整合性があるからだ。本当にスペースをタイプする必要がある場合には、SPC
と表すことにしよう。
3. インストール
DevilはNonGNU ELPAかMELPAから入手できる。あなたには既にELPA/MELPAからパッケージをインストールする際のお気に入りのやり方があるのかもしれない。その場合にはdevilというパッケージ名で入手したDevilをインストールすればよい。Emacsのバージョンが28.1以降であればデフォルトでNonGNU ELPAが有効になっているので追加ステップなし、M-x package-install RET devil RET
とするだけで、Devilを簡単にインストールできるだろう。しかしより万全を期する場合向けに、次のいくつかのサブセクションではDevilをインストールできる基本的な方法をいくつか紹介しよう(具体的なやり方としてはそれぞれまったく異なる方法だ)。
3.1 MELPA経由のインタラクティブなインストール
以下はDevilの最新バージョンをMELPAからインストールするステップだ:
- Emacsのinitファイル(
~/.emacs
、~/.emacs.d/init.el
、または~/.config/emacs/init.el
)に以下を追加:
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
- 変更したinitファイルでEmacsを起動して、以下のコマンドをタイプ:
M-x package-refresh-contents RET
M-x package-install RET devil RET
- 以下のコマンドでDevilが正常にインストールされたか確認:
C-h f devil RET
- 以下のコマンドでDevilモードを有効化:
M-x global-devil-mode RET
-
, x , f
とタイプしてDevilがそれをC-x C-f
に変換すること、そのキーに応じたコマンドが呼び出されることを確認する
3.2 MELPA経由の自動インストール
以下はDevilのインストールと有効化にElispを使う、基本的だが別のやり方:
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
(unless package-archive-contents
(package-refresh-contents))
(unless (package-installed-p 'devil)
(package-install 'devil))
(global-devil-mode)
(global-set-key (kbd "C-,") 'global-devil-mode)
, x , f
とタイプすればDevilがそれをC-x C-f
に変換するし、そのキーに応じたコマンドが呼び出されるだろう。C-,
とタイプすればDevilが無効になり、もう一度C-,
とタイプすれば有効になる
3.3 Gitソースのインストール
DevilをGitレポジトリから取得したい場合は以下のステップ:
- システムにDevilをclone :
git clone https://github.com/susam/devil.git
- Emacsのinitファイルに以下を追加:
(add-to-list 'load-path "/path/to/devil/")
(require 'devil)
(global-devil-mode)
(global-set-key (kbd "C-,") 'global-devil-mode)
-
Emacsエディターを起動すればすべてのバッファーでDevilモードが有効になっていて、モードラインにはそれぞれ
Devil
が表示されている筈だ -
, x , f
とタイプすればDevilがそれをC-x C-f
に変換するし、そのキーに応じたコマンドが呼び出されるだろう。C-,
とタイプすればDevilが無効になり、もう一度C-,
とタイプすれば有効になる
4. Devilを使う
以下にDevilの使い方をデモンストレーションするいくつかの例を示す(Emacsの素のキーバインディングのまま変更されておらず、Devilのカスタマイズもしていないものとする):
-
, x , f
をタイプするとDevilがC-x C-f
に変換して、find-file
コマンドを呼び出す -
, p
とタイプすると1行上に移動 -
複数行の移動は
, p p p ...
。Devilの一部のキーシーケンスは、デフォルトではrepeat(繰り返し)ができる。repeat可能なDevilキーシーケンスの場合には、そのDevilキーシーケンスの最後のキーをタイプして何回でも繰り返すことができる -
repeat可能なキーシーケンスは、すべてrepeat可能なキーシーケンスグループに属している。前と同様に
, p p p
とタイプして、カーソルを3行上に移動してから間を開けずにn n
とタイプすれば、カーソルは2行下に移動する。さらに続けてp n b f
とタイプすればカーソルが上下、左右に移動するだろう。, p
、, n
、, f
、, b
は1つのrepeat可能なキーシーケンスグループを形成するキーシーケンスなのだ。したがってこれら4つのキーシーケンスのいずれかをタイプした後の場合には、同一グループのキーシーケンスならキーシーケンスの最後の文字をタイプすれば何回でも繰り返すことができる。他のキーを何かタイプすれば繰り返しは終了して、タイプしたキーのデフォルトの動作を確認できるだろう。repeat可能なキーシーケンスグループは、C-h v devil-repeatable-keys RET
とタイプすれば完全なリスト確認できる。 -
repeat可能なキーシーケンスグループに属しているキーシーケンスが、1つのrepeat可能なキーシーケンスだけという場合もある。そのようなキーシーケンスの一例が
, m ^
だ。これはM-^
に変換されて、カレント行と前の行を結合するコマンドを呼び出す。複数行のテキストバッファーで, m ^
とタイプした場合でもカレント行と前の行が結合されるが、間を開けずに^
をタイプすれば、行の結合を繰り返し行うことができる。他のキーをタイプすれば、繰り返しは終了する。 -
, s
とタイプするとDevilがそれをC-s
に変換して、インクリメンタル検索が呼び出されるだろう。 -
, m x
とタイプするとDevilがそれをM-x
に変換して、対応するコマンドが呼び出される。そうだ、, m
がM-
に変換されているのだ。 -
, m m s
とタイプするとDevilがそれをC-M-s
に変換して、正規表現ベースのインクリメンタル検索が呼び出される。, m m
はC-M-
に変換されるキーシーケンスだからだ。 -
, u , f
とタイプするとDevilがそれをC-u C-f
に変換して、カーソルは4文字前方に移動する。 -
, u u , f
とタイプすると16文字前方にカーソルが移動する筈だ。Devil自身の変換ルールと追加のキーマップにより、この入力キーシーケンスはC-u C-u C-f
(カーソルを16文字前方に移動)のように振る舞う。 -
カンマの後にスペースをタイプしたい場合には
, SPC
とタイプする。これはテキスト内で簡単にカンマをタイプできるようにするための、スペシャルキーシーケンスだ。このキーシーケンスは(マークをセットする場合に役に立ったかもしれない)C-SPC
という意味での, SPC
の使用を犠牲にしていることに注意。この犠牲が望ましくない場合については、セクション", SPC"をマークのセットにするにはを参照のこと。 -
, z SPC
とタイプするとDevilがそれをC-SPC
に変換して、マークをセットするだろう。そうだ、, z
もC-
に変換されるのだ。 -
同様に
, RET
とタイプすれば、カンマの後にenter
キーをタイプできる。これもスペシャルキー。 -
単一のカンマは
, ,
でタイプできる。このスペシャルキーは、リテラルのカンマ1文字のタイプが必要なときに役に立つだろう。 -
, h , k
とタイプするとdevil-describe-key
が呼び出される。これは素のEmacsに含まれているdescribe-key
のDevil版を呼び出すスペシャルキーだ。キーの入力プロンプトが表示された後にDevilのキーシーケンス, x , f
をタイプすると、Devilはそのキーシーケンスで呼び出される関数のドキュメントをを表示する。キーシーケンス, h k
だとC-h k
に変換されて、素のdescribe-key
が呼び出されることに注意。Devilキーシーケンスの, h , k
が呼び出すのがdevil-describe-key
ということだ。
5. カンマのタイプ
Devilをアクティブにするキーとして、Devilはカンマの採用という怪しげな道を選んだ。前セクションで述べたように、, x , f
をタイプするとC-x C-f
をタイプしたときと同じ効果が得られるのだ。ではリテラルのカンマはどうやって入力するか不思議に思うことは自然なことだろう
テキスト編集においてカンマを単独で入力することは、実際のところほとんどないだろう。カンマの後に間を開けずに1つのスペースか改行を入力することはよくある。これは通常のテキスト編集時ならよく当て嵌まる見立てだ。しかし既存の行の終端に1つのカンマ追加が必要なコードで作業する場合のように、同じ仮定が当てはまらない状況もあり得るだろう。
上記の仮定が当てはまるようなシナリオでは, SPC
をタイプしてカンマとスペース、, RET
をタイプしてカンマと改行を挿入する。
1つのカンマが必要なシナリオであれば、かわりに, ,
タイプすればよい。
1つのカンマは, q ,
とタイプして挿入することもできることに注意。このキーはC-q ,
に変換されて、リテラルのカンマが挿入されるのだ。EmacsでC-q
というキーシーケンスは、次に入力された文字を挿入するコマンドquoted-insert
を呼び出す。しかしこれよりスペシャルキーシーケンス, ,
の方が多分簡単だろう。
カンマキーを弄るのがどうにも腑に落ちないのであれば、Devilキーをよりしっくりする何らかのキーにいつでもカスタマイズできるという点についても、記しておく価値があるだろう。セクションインストールで触れたように、C-,
でDevilモードを一時的に無効にしたり有効にすることもできる。
6. Devilのリーダー
以下にDevilがDevilキーシーケンスの読み込み、Emacsキーシーケンスへの変換、変換したキーシーケンスにバインドされたコマンドの実行をどのように行うかについて要点をまとめた。
- Devilキー(デフォルトでは
,
)をタイプすることでDevilが起動、Devilキーシーケンスの読み取りを開始する。C-h v devil-key RET
とタイプすればカレントのDevilキーを確認できる。
- キーストロークをすべて読み取った後に、蓄積されたキーシーケンスがスペシャルキーかどうかをDevilがチェック、もしそうならスペシャルキーにバインドされているスペシャルコマンドを即座に実行する。このステップは入力キーシーケンスに変換ルールが適用される前に処理されることに注意。この方法によってDevilキーシーケンス
, SPC
はカンマとスペースを挿入している。C-h v devil-special-keys RET
タイプすればスペシャルキー、キーにバインドされているコマンドのリストを確認できる。
- ここまで蓄積されたキーシーケンスがスペシャルキーでなければ、DevilはDevilキーシーケンスを通常のEmacsキーシーケンスに変換する。通常のEmacsキーシーケンスがコンプリートキーシーケンスであり、それにバインドされているコマンドがあれば、そのコマンドを即座に実行する。これがDevilキーシーケンス
, x , f
がC-x C-f
に変換されて、それにバインドされたコマンドが実行される仕組み。変換されたキーシーケンスがコンプリートキーシーケンスであるもののコマンドがバインドされていなければ、Devilはそのキーシーケンスが未定義である旨を示すメッセージを表示する。C-h v devil-translations RET
とタイプすれば変換ルールのリストを確認できる。
- DevilキーシーケンスからEmacsキーシーケンスへの変換、バインドされているコマンドの実行に成功したら、キーシーケンスがrepeat可能なキーシーケンスかどうかをDevilがチェック、repeat可能なキーシーケンスにバインドされていれば、Devilキーシーケンスとしてタイプされたキーと同じグループに属すrepeat可能キーを、入力キーシーケンスの最後の文字だけで実行できるように、Devilが一時的なマップをセットする。
, p p p f f
で3行上、2文字前方に移動できるのは、この仕組みによる。C-h v devil-repeatable-keys RET
とタイプすればrepeat可能なDevilキーシーケンスを確認できる。
変数devil-special-keys
、devil-translations
、devil-repeatable-keys
にはキーまたは値として文字列%k
が含まれているかもしれない。これはdevil-key
にたいするプレースホルダ。スペシャルキー、変換ルール、repeatルールの適用中は、ルールを適用する前に%k
はそれぞれ実際のdevil-key
の値に置き換えられる。
7. 変換メカニズム
以下はユーザーが入力したDevilキーシーケンスをEmacsキーシーケンスに変換するためにDevilが使用している変換メカニズムに関する要点の説明。
- ユーザーからのキーベクター入力は、(
describe-key
やkey-description
が生成する文字列のような)キー表記(key description: キー記述)へと変換される。たとえばユーザーがタイプした,x,f
は, x , f
に変換される。
- これで得られたキー表記は、シンプルな文字列置換によって変換される。この文字列の任意の部分が
devil-translations
のいずれかのキーとマッチしたら、そのキーに応じた数値へと置き換えられる。たとえば, x , f
はC- x C- f
.に変換される。修飾キーの後の半端なスペースは、結果がC-x C-f
になるようにDevilによって正規化される。
- 上記で議論した文字列ベースのシンプルな置換によって得られるのが不正なEmacsキーシーケンスであれば、不正な結果とならないようにその置換はスキップされる。たとえば
, m m ,
にたいしてこのシンプルな文字列置換で処理するとC-M-C-
が得られる(デフォルトの編ルールにより先頭の, m m
がC-M-
、末尾の,
がC-
に変換されるからである。しかしC-M-C-
は無効なキーシーケンスなので、末尾の,
からC-
への変換はスキップされる。したがって入力, m m ,
はC-M-,
へと変換されるのである。
- 最後にDevilはキーシーケンスから、修飾キー
C-
と大文字アルファベットの両方を含むようなキーコードを探す。そのようなキーコードがあれば大文字は小文字をシフト修飾した文字なので、たとえば, m m V
にたいして上記の変換を行うとC-M-V
が得られるが、ここで説明した変換によりC-M-S-v
が得られることになる。
8. デフォルトの変換ルール
デフォルトでDevilがサポートしているのはさまざまなタイプのキーシーケンスの入力から修飾キーを取り除くための、小さくて一風変わった一連の変換ルールである。変換ルールについてはC-h v devil-translations RET
で確認できる。以下にデフォルトの変換ルールのデモンストレーションをいくつか示そう。明快な例から始めて、最後に向かうにつれて複雑な変換をお見せしていく。このサブセクション最後のパラグラフでは、いかにしてこれらのキーシーケンスを徐々に無理なく、日常の編集活動に取り入れていくかについてのガイドラインも示しておいた。
入力 | 置換後 | 備考 |
---|---|---|
, s |
C-s |
Rule 1: , はC- に置き換え |
, m x |
M-x |
Rule 2: , m はM- に置き換え |
, [ x |
C-[ x |
M-x と同じ |
, m m s |
C-M-s |
Rule 3: , m m はC-M- に置き換え |
, m , |
M-, |
Rule 4: , m , はM-, に置き換え |
, m z m |
M-m |
Rule 5: , m z もM- に置き換え |
, c , , |
C-c , |
Rule 6: , , は, に置き換え |
, z SPC |
C-SPC |
Rule 7: , z もC- に置き換え |
, z z |
C-z |
同上 |
, z , |
C-, |
同上 |
, SPC
をマークのセットに使用できないは、そのキーシーケンスが既にdevil-special-keys
でスペシャルキーシーケンスとして予約済みであるという点に注意。利便性のためにDevilは, z
もC-
に変換する。そうすれば, z SPC
とタイプすればC-SPC
に変換されるので、簡単にマークをセットできるだろう。
M-
のタイプには, m
を使うことができるが、M-
を含んだキーシーケンスをタイプする別の方法に, [
がある。これはC-[
やC-[ <key>
に変換されるが、ESC <key>
はM-<key>
と等価なのだ。
上の表で示したデフォルトの変換例は下にいくほど奇妙に見えるかもしれない。しかし初見で感じるほど独断的に決められた訳でもないのだ。この表は以下のような効果を期待して編成した:
-
Devilは
,
をC-
、, m
をM-
、, m m
をC-M-
に変換する -
Devilキーで本当の
,
をタイプしたければ、このキーシーケンスを2回連続でタイプする必要がある。スペシャル文字を2回連続でタイプするということには、Devilキーの特別な意味を打ち消してリテラル形式が得られるようにするエスケープメカニズムとしての役目がある -
, ,
は,
に変換されるのでC-,
をタイプするための、もう1つ別のエスケープメカニズムが必要になった。それが間にz
をタイプするというエスケープメカニズムだ。つまりDevilキーシーケンスの, z ,
はC-,
に変換される。 -
, m m
はC-M-
に変換されるのでM-m
をタイプするためのエスケープメカニズムも必要になる。そこで同じように間にz
をタイプする、すなわち, m z m
はM-m
に変換するというのが、このエスケープメカニズムなのだ。
以上がこのキーシーケンスを採用するに至った経緯の簡単なガイドラインになる。Devil初心者がこれらのすべてを覚えておく必要はない。とりあえず始めるにあたっては,
がC-
、, m
はM-
に変換されることだけ理解していれば十分だ。使い始めてから, m m
がC-M-
に変換されると学習すれば, m m s
(C-M-s
)や, m m f
(C-M-f
)といったより多くのキーシーケンスへの扉が開くだろう。 Devilを日常的に使用していく過程でこれらの初歩的ルールが網羅しないキーシーケンスに出会ったら、そのときは上記の表に立ち戻って新たな変換ルールを採用して欲しい。
9. DevilキーのDescribe
DevilはDevilキーシーケンスの記述に使用できるコマンドとしてdevil-describe-key
を提供する。素のEmacsにおいてC-h k
で呼び出せるdescribe-key
コマンドと同じように機能する。Devil版のdevil-describe-key
はスペシャルキーシーケンス, h , k
で呼び出すことができる。, h , k
とタイプすると、キーシーケンスを読み込むためのプロンプトが表示されるだろう。何かDevilキーシーケンス、たとえば, x , f
をタイプすれば、このキーシーケンスによって呼び出される関数のドキュメントをDevilが即座に表示するのだ。
C-x C-f
のような素のEmacsキーシーケンスのドキュメント参照にも, x , f
(devil-describe-key
)を使用できることに注意。
Devilキーシーケンスである, h k
の方は依然としてC-h k
(素のEmacsのdevil-describe-key
)を自由に呼び出せることにも注意して欲しい。
10. ボーナスのキーバインディング
Devilはglobal-devil-mode
によってグローバルにDevilが有効化されている場合に限り、以下のキーバインディングを追加提供する:
-
isearch-mode-map
へのDevilキーの追加(インクリメンタル検索でもDevilキーシーケンスが機能する) -
universal-argument-more
へのu
の追加(u
だけでユニバーサル引数コマンドC-u
を繰り返すことができる)
繰り返しになるが、これらの機能はglobal-devil-mode
でグローバルにDevilを有効化した場合のみ利用できる。
devil-mode
でローカルにDevilを有効にした場合には、これらの機能は利用できない。
11. カスタム設定の例
以下の例において(require 'devil)
呼び出しについては、ELPAやMELPAのようなパッケージアーカイブ経由でDevilをインストールした場合には不要かもしれない。Devilパッケージには適切なautoloadがあるので、Devilモードを有効化することで自動的にロードされる筈だ。しかしここでは万全を期すために、require
呼び出しも含めてある。
11.1 ローカルモード
セクション,インストールではDevilモードをグローバルに有効にする方法を紹介したが、ここではローカルに有効にする方法について説明しよう。以下はテキストバッファーでのみローカルにDevilを有効化する初期化コードの例だ。
(require 'devil)
(add-hook 'text-mode-hook 'devil-mode)
(global-set-key (kbd "C-,") 'devil-mode)
ただしシームレスなDevil経験は得られないのでお勧めはしない。たとえばこの例のようにテキストバッファーでローカルにDevilを有効にすると、ミニバッファーで, x , f
をタイプしてfind-file
を起動できなくなる。ミニバッファーでDevilキーシーケンスが使えなくなるのだ。更に前のセクションで述べた機能は、Devilモードがグローバルに有効なときしか使用できない。
11.2 バッファーのデフォルトモード
global-devil-mode
で有効にするだけで、通常ユーザーが目にするであろうすべてのバッファーでDevilを使うには十分かもしれないが、従来のセットアップフックをバイパスして作成されたバッファーについては、デフォルトではモードは有効にならない。この問題にもっとも遭遇しやすい場所が、Emacsのスタートアップスクリーンだ。このバッファーはユーザーのinitファイルの処理後に作成されるバッファーだが、Devilを有効化する如何なるフックも実行しないのだ。
この特定的な問題を解決するには必要なフックを実行するようにスタートアップスクリーンをカスタマイズするか、あるいはバッファーの作成後にDevilを有効化するようにdisplay-startup-screen
にadviseするかのいずれかをお勧めする。以下はglobal-devil-mode
を有効にしてデフォルトのEmacsスタートアップスクリーンでアクティブにする例だ。
(require 'devil)
(global-devil-mode)
(advice-add 'display-startup-screen
:after (lambda (&optional _) (devil-mode 1)))
これで出会う可能性がある問題は解決する筈だ。しかしあなたが正真正銘すべてのバッファーでDevilをアクティブにする必要があるときはどうするか? devil-global-sets-buffer-default
がt
のときにglobal-minor-mode
を呼び出すと、新たに作成されるすべてのバッファーではデフォルトでDevilが有効になる。この機能を有効にするのは魅力的に思えるかもしれないが、すべてのバッファーが対話的であることを意図している訳ではないこと、適用されるかもしれないフックをマイナーモードが外すのはおそらく意図があってのことである点を考慮すること。推奨はしないが、以下はすべてのバッファーでデフォルトでDevilをアクティブにする例を示す。
(require 'devil)
(setq devil-global-sets-buffer-default t)
(global-devil-mode)
11.3 外観のカスタマイズ
以下の初期化コードはモードラインとDevilプロンプトにDevilスマイル(😈)を表示させるカスタマイズ例だ。
(require 'devil)
(setq devil-lighter " \U0001F608")
(setq devil-prompt "\U0001F608 %t")
(global-devil-mode)
(global-set-key (kbd "C-,") 'global-devil-mode)
11.4 ", SPC"をマークのセットにするには
デフォルトの設定では, SPC
はカンマとスペースを挿入するスペシャルキーとして予約済みだ。このデフォルトはさまざまなコンテキストにおいてカンマのタイプを簡単にするためだ。しかしこれは, SPC
がC-SPC
に変換されないという意味でもある。つまり, SPC
ではマークをセットできない。その代替えとしてデフォルトの変換ルールでは、マークをセットする方法として, z SPC
を提供している。
リテラルのカンマを挿入するためにスペシャルキー, ,
をタイプすることが面倒でなければ、以下の設定を使えば, SPC
でマークがセットできる:
(require 'devil)
(global-devil-mode)
(global-set-key (kbd "C-,") 'global-devil-mode)
(assoc-delete-all "%k SPC" devil-special-keys)
これによりdevil-special-keys
からスペシャルキー, SPC
が削除されるのでC-SPC
に変換されてset-mark-command
を呼び出すようになる筈だ。
11.5 カスタムDevilキー
以下は違うDevilキーを使うようにDevilをカスタマイズする初期化コードの例を示す。
(require 'devil)
(global-devil-mode)
(global-set-key (kbd "C-;") 'global-devil-mode)
(devil-set-key (kbd ";"))
この例ではDevilキーとして(もしかしたらDevilキーに相応しいより邪悪な別解かもしれない)セミコロンをセットしている。この設定の場合には; x ; f
とタイプするとDevilがそれをC-x C-f
に変換するだろう。
11.6 Devilキーを別のキーにカスタマイズする
以下の例では他のDevilを使用するようにカスタマイズする別の初期化コードをお見せしよう。
(require 'devil)
(global-devil-mode)
(global-set-key (kbd "C-<left>") 'global-devil-mode)
(devil-set-key (kbd "<left>"))
(dolist (key '("%k SPC" "%k RET" "%k <return>"))
(assoc-delete-all key devil-special-keys))
上記の例では左矢印キーをDevilキーにセットしている。この設定の場合だと<left> x <left> f
とタイプすればDevilがC-x C-f
に変換する。スペシャルキー<left> <left>
が元の<left>
を生成する効果は同じだ。
上記の例では最早有用とはいえなくなったスペシャルキーもいくつか削除している。特に<left> SPC
がスペシャルキーとして予約されなくなったので、これをマークのセットに使用することができる。
11.7 複数のDevilキー
このパッケージはデフォルトとしてカンマ(,
)を、それも唯一のDevilキーとして提供しているが、複数のDevilキーをサポートするためのモードの拡張を妨げるものはない。たとえばDevilをアクティブにすることで,
にC-
の役目をもたせるだけではなく、Devilをアクティブにすれば.
がM-
の役目をもつようにしたいと考えたとしよう。この目標を達成するための開始点として以下の初期化コードを使用して、その後は要件に基づいて更にカスタマイズするということもできるだろう:
(require 'devil)
(global-devil-mode)
(define-key devil-mode-map (kbd ".") #'devil)
(add-to-list 'devil-special-keys `(". ." . ,(devil-key-executor ".")))
(setq devil-translations '((", z" . "C-")
(". z" . "M-")
(", ," . ",")
(". ." . ".")
("," . "C-")
("." . "M-")))
この設定なら前と同じように, x , f
でC-x C-f
をタイプできる。しかし今度は. x
でM-x
をタイプできるのだ。そして, . s
でC-M-s
とか、他にも組み合わせはあるだろう。さらに, ,
はリテラルのカンマ、. .
はリテラルのドットを挿入する。更に, z ,
でC-,
、. z .
でM-.
もタイプできるようになった。
デフォルトのDevilの設定ではDevilアクティブ化のキーは1つだけ(,
)であること、そしてアクティブにするキーをより多く追加することによって、通常の編集タスク中にDevilがでしゃばる機会がより多くなることに注意。Devilのアクティブ化のために予約済みのキーはすべてデフォルトの機能性を失い、そのキーに割り当てられているデフォルトの機能を呼び出すためには、何らかの余計な手間が必要になる(たとえば上述のように1つの.
の挿入に.
を2回繰り返す等)。したがって、Devilキーはできるだけ少ない個数に保っておいたほうがよいだろう。
11.8 すべてのキーをrepeat可能に
Devilにはデフォルトでrepeat可能とみなすキーシーケンスの小さなリストが用意されている。これは変数devil-repeatable-keys
で定義されているリストだ。このリストの内容はC-h v devil-repeatable-keys RET
で確認できる。たとえばこのリストにrepeat可能なキーシーケンスのグループ("%k p" "%k n" "%k f" "%k b")
が定義されているとしよう。DevilとEmacsのデフォルトのキーバインディングが変更されていなければ、この定義は, p
をタイプした後にカーソルを前の行に移動すること、p
をタイプする度に何度もこれを繰り返せることを意味している。間を開けずにf
をタイプすれば1文字分カーソルが右に移動する。この繰り返しはグループ内のキーシーケンスであればどれでも、最後の文字をタイプするだけで繰り返すことができる。何か別のキーをタイプすれば繰り返しが終わって、タイプしたキーのデフォルトの動作に戻るだろう。
変数devil-all-keys-repeatable
をt
にセットすれば、すべてのキーシーケンスを繰り返しできるようにすることも可能だ。以下はその設定例:
(require 'devil)
(setq devil-all-keys-repeatable t)
(global-devil-mode)
この設定でも上述のrepeat可能なキーシーケンスグループの機能は失われない。しかしこれらのキーシーケンスに加えて、最終的にはEmacsコマンドを実行するようなDevilキーシーケンスすべてが繰り返し可能になったのだ。つまりdevil-all-keys-repeatable
には属していないがEmacsコマンドを呼び出すDevilキーシーケンスはrepeat可能、すなわち間を開けずにそのキーシーケンスの最後の文字で繰り返すことができる。
正規のEmacsキーシーケンスに変換されること、変換した結果としてEmacsコマンドが実行されるようなDevilキーシーケンスだけが繰り返し可能であることに注意。devil-special-keys
で定義されているキーシーケンスが繰り返し可能になることはないのだ。
11.9 Repeatモードとの相互作用
Devilのrepeat可能なキーの機能は、Emacs 28.1で導入されたrepeat-mode
と類似する機能だ。以下はDevilのrepeat可能キーを無効にして、repeat可能なコマンドの定義にrepeat-mode
を用いる設定の例を示す。
(require 'devil)
(global-devil-mode)
(setq devil-repeatable-keys nil)
(defvar movement-repeat-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "p") #'previous-line)
(define-key map (kbd "n") #'next-line)
(define-key map (kbd "b") #'backward-char)
(define-key map (kbd "f") #'forward-char)
map))
(dolist (cmd '(previous-line next-line backward-char forward-char))
(put cmd 'repeat-map 'movement-repeat-map))
(repeat-mode)
ここで1行上にカーソルを移動するためにC-p
をタイプしたとすると間を開けずにp
をタイプすれば繰り返し移動できるしn
、b
、f
でもカーソルを下、左、あるいは右に移動できる。
repeatモードはDevilと良好に機能するので、上の設定であれば前の行へカーソルを移動するために, p
をタイプしたらp
、n
、b
、f
で上下左右にカーソルを移動できる。
実際のところrepeatモードを使用中にDevilのrepeatキーを不要にする必要はない。両者は共存できるのだ。しかし両者の間に存在する特定の差異によっては、驚くべき結果となることもある。たとえば以下のような設定だと:
(require 'devil)
(global-devil-mode)
(defvar movement-repeat-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "p") #'previous-line)
(define-key map (kbd "n") #'next-line)
map))
(dolist (cmd '(previous-line next-line))
(put cmd 'repeat-map 'movement-repeat-map))
(repeat-mode)
これでDevilのrepeat可能キーとrepeatモードの両方がアクティブになった。ここで, p
をタイプすると、p
やn
でカーソルを繰り返し上下できる。今度は繰り返しを実現しているのはrepeatモードだ。更に, p
をタイプした後であれば、b
やf
でカーソルを繰り返し左右に移動できる。こちらを実現しているのはDevilモードだ。repeatモードが処理するrepeat可能コマンドと、Devilモードが処理するrepeat可能キーとの違いは、エコーエリアを注視すれば判るだろう。p
を繰り返しはrepeatモードによって処理されて、エコーエリアには"Repeat with p, n"のメッセージが確認できる筈だ。しかしDevilが処理するb
を繰り返した場合には、Devilがrepeat可能を暗黙にセットアップするのでこのようなメッセージを目にすることはないだろう。
11.10 Repeatモードとの比較
前のセクションではrepeat可能なキーシーケンスをDevil、およびEmacsのバージョン28.1以降で同梱されるようになったrepeatモードそれぞれが実現する度合いをデモンストレーションした。
とはいえDevilのrepeat可能キーとrepeat-mode
の間には厳然たる違いが存在する。repeatモードが提供するのはrepeat可能なコマンドだが、Devilがサポートしているのはrepeat可能なキーであるという点だ。この重要な違いにより、Devilでrepeat可能キーを構成するほうがほぼ間違いなく簡単なのだ。この違いをキーシーケンスM-e
で実証してみよう。このキーシーケンスにはデフォルトでは、グローバルマップでforward-sentence
コマンドにバインドされている。しかしOrgモードではorg-forward-sentence
にバインドされているキーシーケンスだ。これに相当するDevilキーシーケンスは, m e
であり、これはDevilではrepeat可能なキーシーケンスである。したがって, m e
をタイプした後ならtextモードと同じくOrgでも、e e e
と間を開けずにタイプすることによって、カーソルを前方に連続して移動させることができるのだ。repeat モードで同じ挙動を実現するためには、以下のような設定が必要になるだろう:
(require 'devil)
(global-devil-mode)
(setq devil-repeatable-keys nil)
(defvar forward-sentence-repeat-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "e") #'forward-sentence)
map))
(defvar org-forward-sentence-repeat-map
(let ((map (make-sparse-keymap)))
(define-key map (kbd "e") #'org-forward-sentence)
map))
(put #'forward-sentence 'repeat-map 'forward-sentence-repeat-map)
(put #'org-forward-sentence 'repeat-map 'org-forward-sentence-repeat-map)
(repeat-mode)
どちらもM-e
にバインドされている2つのコマンド用に、repeatモードをどのように設定する必要があるかに注目して欲しい。この設定であればtextモードとOrgモードの両方で、, m e
をタイプした後にe e e
と続けて前方に複数センテンス移動できるだろう。ただしM-e
に何らかののコマンドをバインドしている、他のモードにたいするrepeatモードの設定を忘れていなければよいが。たとえばそう、M-e
にコマンドc-end-of-statement
をバインドしているCモードのようなモードのことだ。上記の設定ではこのコマンドをe e e
で繰り返すには足りていないらしい。
しかしDevilであればすべてのモードにおいてM-e
にバインドされているコマンドを繰り返すことができるのだ。Devilは単に特定のモードでバインドされたコマンドをrepeat可能にするのではなく、, m e
というキーシーケンス自体をrepeat可能にする。したがってDevil独自のrepeat可能なキーシーケンスのサポートを使用すればアクティブなモード、あるいはキーシーケンス, m e
にバインドされているコマンドが何であれe e e
でそのコマンドを繰り返すことができる。
12. どうしてこうなった?
わざわざこのようなモードを作成、使用するのはなぜだろう? 他のまともな人のようにcaps lock
をctrl
にリマップするだけでよいのでは? そんなに修飾キーを避けることが重要なのであれば、GodモードやEvilモードのようなモードを使えばよいではないか?
まずGodモードとEvilモードはいずれもモーダル編集モードであることが理由の1つだ。一方DevilではEmacsにおける非モーダル編集のエクスペリエンスは保たれる。
当初Devilは小さな実験として始まった。カンマのような重要なキーを使って修飾キーを指定することが災いの元であることは、初めから明らかだった。しかしどこまでそれが可能なのかを試してみたかったのだ。そして数日使用してみて、Emacsで行うすべてのことに常用できることが判った。
この実験は右側にctrl
キーがないMacbookのキーボードによって動機づけられた部分もある。タッチタイプを行う者としてはC-x
、C-s
、C-r
、C-d
、C-f
、C-w
、C-a
、C-e
のような修飾キーと被修飾キーの両方を左手で押下する必要があるキー組み合わせをタイプするのに不便だと感じていたのだ。caps lock
がctrl
のように振る舞うようにリマップするという方法にたいしても、特に食指を動かされることはなかった。依然としてC-x
やC-a
のようなキー組み合わせは、修飾キーと被修飾キーの両方を左手で押下する必要があるからだ。ctrl
として振る舞うように、caps lock
とenter
の両方をリマップする人が沢山いるのは知っていた。素晴らしい解決策だとは思ったが、わたしが作業を行っているさまざまなオペレーティングシステムすべてにおいて、これをシームレスに動作させるために要される作業を行う気にはなれなかったのだ。
気まぐれで始まった小さな実験ではあるが、数年を経て少なくともわたしにとっては非常に効果的だということが判った。純粋にElispだけで実装したので、外部への依存性がない解決策という点でも気に入っている。これが役に立つと思うかもしれない他の人たちがいるかもしれないという場合に備えて、この解決策をマイナーモードという形式で共有する。
13. Godモードとの比較
Godモードはモーダル編集エクスペリエンスを提供するがDevilは違う。Devilはユーザーが新たにキーバインディングを学習する必要がないという、Godモードと同じ基本哲学をもっている。しかしGodモードのように挿入モードとコマンドモードの間を厳格に区別しないのがDevilだ。そのかわりにDevilはアクティベーションキー(デフォルトでは,
を待機して、そのキーがタイプされたらアクティブになりキーの横取りと変換を行い対応するコマンドを実行して引っ込むのだ。そうすることにより、Devilは素のEmacsにおける非モーダル編集エクスペリエンスを保とうと試みている。
god-modeのgod-execute-with-current-bindings
関数を使えば、非モーダルな編集エクスペリエンスを部分的に再現可能であることにも触れておいたほうがよいだろう:
(global-set-key (kbd ",") #'god-execute-with-current-bindings)
この設定であれば, x f
をGodモードがC-x C-f
に変換する。同じく, g x
はM-x
、, G s
はC-M-x
を呼び出すだろう。これならGodモードでも非モーダル編集エクスペリエンスを手に入れることができる。ただしこのエクスペリエンスはミニバッファーにたいしてはシームレスに拡張されない。Devilの方はDevilキー変換をミニバッファーにも拡張する。
さらにGodモードではctrl
修飾キーの振る舞いが粘着性(sticky)をもつことにも注意を要する。つまりキーシーケンス全体が完了するまでは、修飾キーが自動的にアクティブなままになるのだ。したがって上記の例では, x f
のように一度だけ,
をタイプしてC-x C-f
を呼び出している。しかしこの粘着性の振る舞いは、C-x C-f
(find-file
)とC-x f
(set-fill-column
)のようなキーシーケンスを区別する何らかの手段が必要であることを暗に含んでいる。GodモードはSPC
を導入するという解決策によって、修飾キーの非アクティブ化を行っている。しかしDevilの方は少しキーをタイプするコストより、シンプルなキーシーケンスのメリットの方が勝るという考えから、修飾キーに粘着性をもたせていない。つまり, x , f
はC-x C-f
、, x f
はC-x f
に変換される。
まとめよう。Devilと比較すると主に4つの違いがある:
-
最初から非モーダル編集エクスペリエンスを提供するか
-
同じ編集エクスペリエンスをミニバッファー、インクリメンタル検索等にシームレスに拡張するか
-
洗練された任意のキー変換を可能にする、文字列置換を用いたキーシーケンス変換(チャレンジャー向け)
-
修飾キーにたいする粘着的振る舞いの選択
これらの違いにより、Devilを使う方がGodモードより簡単な人もいれば、扱いにくくなる人もいるだろうし、これは好みの問題だと思う。
14. FAQ
-
Devilキーのデフォルトにカンマ(
,
)を選んだのはなぜ? セミコロン(;
)の方がホームポジションにあるので良くない?意見はさまざまだろう。わたしがこのマイナーモードの作者兼メンテナーとして選んだデフォルトのDevilキーがカンマだったというだけだ。ほとんどのキーボードではセミコロンはホームポジションにありカンマキーは違うのだが、わたしにはセミコロンに小指を届かせるために要する水平移動よりも、カンマキーに中指を届かせる垂直移動のほうが楽だったからだ。
タッチタイプを行う際に、わたしにはアイドル時にホームポジションの8つのキーに指をおいている。セミコロンのタイプに必要な水平移動は、手首の有意な角度移動をともなうのだ。中指を曲げてカンマキーをタイプすれば、手首の負担を回避できる。このデフォルトが気に入らなければ、セミコロンや何であれあなたが選択する任意のキーをDevilキーにカスタマイズするのはとても簡単だ。方法についてはセクションカスタムDevilキー、その後の数セクションを参照して欲しい。
-
カンマをタイプする必要があるとき毎回
, ,
をタイプするのが全然苦ではない。, SPC
を解放してset-mark-command
を呼び出すようにしてもいい?問題ない。
devil-special-keys
からスペシャルキー, SPC
を削除するだけだ。これを行う方法についてはセクション", SPC"をマークのセットにするにはを参照のこと。
-
Devilキーをstickyなキー、つまり粘着的にできない?
, x , f
ではなく, x f
でC-x C-f
を呼び出せるようにしたいんだ。Devilはstickyキーをサポートしない。たとえばもしDevilが
, x f
をC-x C-f
に変換するとして、C-x f
はどうやって呼び出すのか?C-x C-f
とC-x f
の間にある曖昧さを解決する何らか手段が必要だ。異なるツールがこの2つのキーシーケンスの曖昧さにたいして、異なるアプローチを採択したのだ。Godモードはx f
をC-x C-f
、x SPC f
をC-x f
に変換する。すなわちC-
修飾はデフォルトでstickyであり、その粘着性を解消するためにgod-modeではSPC
をタイプする必要がある。これによりC-x C-f
のような一部のキーシーケンスは短くなったが、C-x f
のようなキーシーケンスは長くなった。DevilはDevilキーを非stickyとして扱うので、stickyあるいは非stickyな挙動を切り替える特異なルールを追加で定める必要がないのだ。したがって
C-x C-f
とC-x f
のようなキーシーケンスの曖昧さはDevilであれば, x , f
をC-x C-f
、, x f
をC-x f
に変換することで解決されている。追加で少し多くタイプするというコストを要する場合もあるものの、変換ルールはより単純になる。Devil故に追加でカンマのタイプが必要な場合のほとんどは、カンマがstickyであれば回避できたであろう。しかしそれ以外の場合ではDevilが修飾キーを非stickyにしている故に、余計なキーのタイプを不要にしているのだ。
-
Devilの方がgod-modeより簡単にできることって何がある?
Devilの方がgod-modeより簡単である必要はない。両者は違うものだ。好みはさまざまなのでDevilが簡単だと思う人もいれば、god-modeの方が使いやすいと思う人もいるだろう。2つのモードの違いについて知りたければ、セクションGodモードとの比較を参照して欲しい。
-
設定ファイルで関数
global-devil-mode
を呼び出したけど、EmacsがDevilをオープンしてもアクティブにならないみたい、何が悪いんだろう?一番有り得そうなのは最初バッファーがに表示されたのがEmacsのデフォルトのスタートアップスクリーンの場合だろう。このスクリーンはDevilを適用する機会となるフックを何も実行せずに作成されるのだ。詳細と解決策についてはセクションバッファーのデフォルトモードを参照して欲しい。
15. 結び
Devilとはキーシーケンスを変換するマイナーモードだ。Devilはモーダル編集に頼ることなく、修飾キーいらずの編集エクスペリエンスを提供するためにこの変換能力を活用している。Devilが拘っているのは、素のEmacsにおける非モーダルの編集体験だ。このモードは修飾キーなしでEmacsを簡単に使えるようにするという風変わりな実験として記述された。しかし結果としては客観的に見て非常に使いやすく役に立つモードが得られたと思う。Devilを使って快適に感じるかもしれないし、あるいは酷いアイデアと思うかも、もしかしたら役には立つがでしゃばりなモードだとも思うかもしれない。そのような場合には好みに応じてDevilの構成を変更するための、大量のカスタマイズ可能なオプションが存在する。何かサポートが必要だったり問題を見つけたら、issueを作成して教えて欲しい。