Emacs アウトラインモードのハッキング |
アウトラインの深さは,行頭のアスタリスクの数によって表現される. つまり見出しの下に,さらに階層を作るには,アスタリスクの数を増やせば良い.
例を以下に示そう.まず,"M-x outline-mode"を実行し,現在のバッファをアウトラ インモードにする.そして以下を入力してみる.
M-x outline-modeでの入力例
*これが一番上の階層のヘッダ1 ここがヘッダ1のコンテンツです. ** 2番目の階層のヘッダ1 これは,2番目の階層のコンテンツ. *これが一番上の階層のヘッダ2 ここがヘッダ2のコンテンツ. ** 2番目の階層のヘッダ2 今日は,晴れです. ***これは3番目の階層のヘッダ この書類の中では,一番下の階層です.アスタリスクを繋げることによって,もっと 階層を増やすこともできる. |
M-x hide-bodyで各階層のコンテンツを隠す
*これが一番上の階層のヘッダ1... ** 2番目の階層のヘッダ1... *これが一番上の階層のヘッダ2... ** 2番目の階層のヘッダ2... ***これは3番目の階層のヘッダ... |
利用可能なコマンドの一覧は,"M-x describe-function"を実行し,"outline-mode" と入力すれば得られる.
コードの使用に関するライセンス条項と,このパッケージが提供するモードに関する コメントが書かれている.
実際のコードは,35行目 から始まる.35行目から152行目までは,アウトラインモードの動作を定義する 関数ではなく,コード中に用いられる変数,ショートカットキーのマッピング(55行目から)や,メニューバー 作成用のマップ(75行目から )などの,下準備に関するコードが書かれている.
アウトラインモードのメイン関数.ここから,アウトラインモードで使用される全て の機能が呼び出される.
アウトラインのマイナーモードに関する関数定義に用いられる変数や,キーマップの 定義など,マイナーモードの下準備を行っている.
アウトラインモードが,マイナーモードで呼び出された場合の動作を定義するメイン 関数.
アウトラインモードで用いられる,様々な機能(コマンド)の動作を定義する関数群.
outline-regexpグローバル変数をnilで初期化する.defvarの第3引数で,変数の説明 が記述されている.この説明は,シンボルのvariable-documentation属性に格納され る.Emacsのヘルプ機能は,この属性を検索して表示する.この説明文の先頭に付い ているアスタリスクは,この変数がユーザオプション変数であることを表している. したがって,ユーザが"M-x set-variable"で変数を設定することを考慮している. このアスタリスクは,"M-x edit-options"で変数を設定することを便利にする.
それではここで,このシンボルの説明を表示させてみよう. まず,outlineパッケージを"M-x load-library"でロードする. 次に,"M-x describe-variable"コマンドで outline-regexpを指定すれば,下のような解説が表示される.
outline-regexpグローバル変数の説明
outline-regexp's value is "^.*<[Hh][1-6]\\>" Local in buffer outline_code.html; global value is "[*^L]+" Documentation: *Regular expression to match the beginning of a heading. Any line whose beginning matches this regexp is considered to start a heading. The recommended way to set this is with a Local Variables: list in the file it applies to. See also outline-heading-end-regexp. |
上の結果の1行目で,outline-regexpの値は"^.*<[Hh][1-6]\\>"となっている. しかし,その下でヘルプが呼び出されたoutline_code.htmlバッファにおいては, グローバル値が"[*^L]+"になっていると言っている.これは,outline-regexpの一番 深い束縛(一番最近の束縛)が"^.*<[Hh][1-6]\\>"だが,グローバル値(デフォルト値) は,"[*^L]+"であることを表している.これを確認するには,以下の関数を評価すれ ばよい.
outline-regexp変数の束縛
(symbol-value 'outline-regexp) => ^.*<[Hh][1-6]\\> (default-value 'outline-regexp) => [*^L]+ |
symbol-valueは,変数の一番最近の束縛値を返す.それに対し,default-valueはバッ ファに関係ないデフォルト値を返す.したがって,outline-regexpは初めグローバル 変数としてデフォルト値"[*^L]+"で初期化されたが,後に現在のバッファで "^.*<[Hh][1-6]\\>"に設定されたことが分かる.
それぞれの正規表現の意味を確認しておこう. "[*^L]+"は,44行目 から分かるように,実際には,"[*\^L]+"である."^L"は"?\^L"で12と評価されるので, "?\f"の評価値と同じである."?\f"は,C-lで改ページの意味である. したがって,"[*\^L]+"は,アスタリスク文字または,改ページコードが 少なくとも1回以上出現する場合に一致する.正規表現のアスタリスクは,後置表現 なので,ここのアスタリスクは正規表現のアスタリスクではない.アスタリスク文字そ のものを表している.
"^.*<[Hh][1-6]\\>"の正規表現がマッチする文字列は,改行以外の任意の文字列が 行頭からゼロ回以上繰り返され,その後にHTMLのコマンド終了を表すタグのように <H1\>にマッチする.ただしHは大文字小文字に関係なく数字は1から6の場合 にマッチする.
35行目 のdefvarは,outline-regexpシンボルに値が設定されていないときにnilを 設定する.defvarやdefconstが値を設定する場合,ローカル値ではなくグローバル値 (デフォルト値)をセットすることに注意.
次に43行目 でdefault-valueが,outline-regexpのデフォルト値を返す.もし, 35行目 でnilに設定されなかった場合(既にデフォルト値が存在していた場合) 44行目 でデフォルト値を"[*\^L]+"に設定する.
上で示したように,outline_code.htmlバッファではデフォルト値が"[*\^L]+"であっ たことを見ると,以上の手順で初期化が行われたことが分かる.もし,デフォルト値 "[*\^L]+"以外が設定されていると, 43行目のdefault-value の式が真になり,新しい値は設定されない.
最後に,outline-regexpの"[*\^L]+"が本当にデフォルト値で,"^.*<[Hh][1-6]\\>"が バッファローカル値であることを示すために,以下の関数を評価してみよう.
バッファローカル値を削除する
(kill-local-variable 'outline-regexp) (symbol-value 'outline-regexp) => [*^L]+ (insert (default-value 'outline-regexp) => [*^L]+ |
Line 46--51.outline-heading-end-regexpグローバル変数の初期化
上で説明したdefvarで,outline-heading-end-regexpグローバル変数が既に値を持っ ていない場合に,"[\n\^M]"で初期化する. ?\^Mを評価すると13で,これは,?\rのキャリッジ・リターンを表すので,"[\n\^M]" は,改行かまたはキャリッジ・リターンのいずれかの文字が出現した場合にマッチす る正規表現である.47行目 からの解説から分かるように,この正規表現は,アウトラインのヘッディング行 の終りを示す正規表現に使われる.
Line 53.outline-mode-prefix-mapグローバル変数の初期化
outline-mode-prefix-mapグローバル変数が値を持っていない場合,nilに初期化.値 を持っている場合は,何もしない.
outline-mode-prefix-mapは,後にアウトラインモード中のコマンドへのショートカッ トキーを定義する,キーマップに使われる.
Line 55--73.outline-mode-prefix-mapキーマップの作成
55行目のif文は,もし, outline-mode-prefix-mapが真ならば56行目のnilを評価し,そうでなければ, 57--73行目を順に評価 する.
make-sparse-keymap関数は,空のキーマップを作成して返す.この関数で新たに作成 されたキーマップを,outline-mode-prefix-mapにバインドして,新たにキーを登録 していく.
Line 75--122.outline-mode-menu-bar-mapメニューバー用マップの作成
つづく.....