書いた人:rubikitch
プログラミングなどの知的作業の効率を上げるために、Emacs 上でスムーズに調べ事ができるようにするツール langhelp を紹介します。
langhelp は名前の通り「言語」を扱うことを助けるツールです。 この業界で「言語」といえばプログラミングを連想しますが、それだけではありません。 何十ものオプションがあるコマンドのコマンドラインはまさに言語と呼ぶにふさわしいです。 ソフトウェアの設定ファイルも、制御構造がないものの言語です。 このように目的に応じた大小様々な言語が存在するのです。
本稿では「るびま」の名前通り Ruby プログラミングに焦点をしぼって話を進めていきます。
Emacs の操作に一通り慣れ、もっと便利に使おうとする「言語」使い達が対象です。 langhelp を使うだけならとくに Ruby の知識を必要としません。
langhelp 作成に至った背景について軽く流しておきます。
コンピュータというのはとても気難しい相手です。 プログラミングはプログラミング言語を使ってコンピュータに命令を伝える作業です。 厳格なので、少しでも言語の使い方を間違ってしまうと言うことを聞いてくれません。 人間と違って融通がきかないのです。 そのため、語法を_正確に_記憶する必要があります。
しかし筆者はコンピュータの天才ではないです。 記憶力にも自信がありません。 少しでも疑問に思ったら調べないといけません。 調べる手段として、ブラウザでオンラインリファレンスマニュアルを開いたり、本を読んだり、ウェブ検索をしたり……多種多様ですね。
対象言語の熟練度が低いと一歩進むごとに調べないといけないのでいつまでたっても問題解決ができません。 苦痛そのものですね。 長年親しんだ言語でも、新しいライブラリを使いこなせるまでには時間がかかります。
多くの人にとって_プログラミングは調べ事の連続_なのは間違いないです。
調べ事はプログラマの悩みの種なので、労力を軽減するためのツールが開発されるのは自然な流れです。 Ruby の場合は標準添付の ri と ReFe が有名ですね。 筆者もかつて RDindex というツールを作っていました。(RDindex は現在メンテナンスされていません。) 決まった書式でドキュメントを書いていれば、あとはツールが面倒見てくれます。 これらのツールは開発を劇的に効率よくしてくれました。標準万歳!!
けれども、時とともに状況は変わってくるものです。 昔は RD がデファクトスタンダードだったので RD さえ扱えればよかったです。 今は RDoc が世界標準となり RD の利用率は減少一方です。 マニュアルにおいては、日本語が RD、英語が RDoc というふうに棲み分けされているのが現状です。 こうなると ReFe と ri を使い分ける必要がでてきました。
さらに追い討ちをかけるのが、標準に従っていないドキュメントです。 構造化もされていない plain text だったり、ウェブ上の HTML だったり、自分の日記だったり…… こういうものはいちいちファイルを開いて手検索しなければならず、 検索ツールに慣れた人にとっては耐えがたいです。
この現状を打破するために、情報源によらず情報の目次を一箇所に固めておく必要性を感じました。 もちろん目次から内容を参照することができるべきです。本がそうであるように。 Ruby の場合、ReFe へのリンク、ri へのリンク、RD の特定行などで目次を構成します。 情報を一元化することで、使うツールを選択することなくすかさず検索にうつれます。
langhelp のリンク機能そのものは自分で実装していません。 既存の機能をうまく使っています。 EmacsLisp 式 (S 式) をハイパーリンクとみなすのです。
たとえば、
の行末へカーソルを持っていって C-x C-e を押してください。 すぐさま ~/.emacs が開かれてバッファが切り替わりました。 C-x C-e はマイナーだと思いますが、カーソル直前の S 式を評価するコマンドです。
S 式の評価というと、どうしても変数の値や関数の戻り値に注目されがちですが、 この場合はファイルを開くという_副作用_が目的です。 ブラウザのリンクをクリックするとリンク先のページが表示されることを思い出してください。 C-x C-e は一種のハイパーリンクと思えませんか? さらに S 式に色をつけてみると、見た目上ブラウザのリンクと変わらないでしょう?
もちろん langhelp を使う上では押しやすいキーにバインドしていますが、S 式ハイパーリンクは langhelp の中核をなすものです。
このアイデアのおかげで、「目次作成」と「内容閲覧」を完全に別個の問題として扱え、限りない柔軟性を得ることができました。 ○○へのリンク機能が欲しいならば、関数を書くだけでいいのです。
このアイデアのもうひとつの利点は、S 式が Emacs 上のどこでも評価できることです。 langhelp で調べた結果を表示する S 式をソースコードや自分のメモに簡単に貼り付けることができます。 極論すると、あらゆるテキストが Wiki になるのです。 同じことを調べなおさずにすむので未来の自分へのメッセージになります。 共同開発者が langhelp を使ってくれれば、情報交換もできるでしょう。
langhelp は Unix 指向のプログラムです。 そのため Windows 使いの人は Cygwin をインストールする必要があります。 Ruby も Cygwin 版を使うほうがいいと思います。
あと、環境変数 HOME も忘れずに設定しておいてください。 ホームディレクトリを指定します。
以後、Unix 系 OS を前提に話をすすめていきます。
langhelp は el4r (Emacs Lisp for Ruby) に依存しています。 el4r は Emacs を Ruby でコントロールするプログラムです。 Emacs をコントロールするための Lisp を EmacsLisp と呼ぶように、Emacs をコントロールするための Ruby を EmacsRuby と呼んでいます。 langhelp は EmacsRuby で書かれているため、最初に el4r をインストールする必要があるのです。1
Debian GNU/Linux ならばインストールは簡単です。 以下の行を /etc/apt/sources.list に加えます。
そして
としてください。
その他のシステムではソースからインストールする必要があります。 まず el4r からインストールしてください。執筆時点でバージョン 1.0.4 です。 以下のコマンドを実行してください。 ruby -ropen-uri の行はブラウザや wget でダウンロードしても構いません。 なお ruby setup.rb でインストールするので sudo が必要な環境もあります。
次は langhelp をインストールします。執筆時点でバージョン 0.9.8 です。
langhelp はいろいろなツールを統合するものです。 そのため、外部プログラムを利用しまくります。 langhelp を試用してみるだけなら、とくにインストールする必要はありません。 単体でも Ri と RD の目次は作成できます。 ツールが多ければ多いほど langhelp は力を発揮します。
本稿では Ruby プログラミングに便利なツールを紹介しておきます。 ほかのツールについては附属ドキュメントを参照してください。
ri は英語ですが、 ReFe は日本語でメソッドのドキュメントを参照できます。 日本人 Rubyist 必携です。 是非ともインストールしましょう。
ri をコマンドラインで使うと出力されるまで数秒待たされますが、これを入れることで一瞬でドキュメントを参照することができます。 Emacs 使いは是非ともインストールしておきましょう。
Unix 系 OS の世界で有名なページャ兼テキストブラウザ兼 HTML → Text 変換器です。 動作が軽いのが特徴です。 emacs-w3m は Emacs 内で w3m を使うれっきとしたウェブブラウザです。 emacs-w3m があると HTML ドキュメントを langhelp 内で参照できます。
Debian GNU/Linux ならば
一発でおしまいです。
Windows 使いの人は Cygwin → w3m → emacs-w3m とインストール作業が大変ですが、がんばってください。 ちょっとした調べ物のためにいちいちブラウザを立ち上げるのは面倒でしょう?
Meadow Memo - Cygwin Meadow Memo - emacs-w3m
はっきりと印がつくバッファ内ブックマークです。 通常の編集・閲覧作業にもとても便利なのでインストールする価値は十分あります。 langhelp では後で参照できるように簡単にブックマークできるようになっています。
ローマ字で日本語が検索できる優れ物です。 古いコンピュータでなければかなり快適に動作します。 langhelp は検索ベースのツールなのでインストールして損はありません。
初めて langhelp を使う人はサンプル設定ファイルをコピーしてください。
そして、とりあえずすべての言語の目次を作成しておきます。
を実行して langhelp で定義されているすべての言語の目次ファイルを生成してください。 目次ファイル名は言語名に .e という拡張子をつけたものです。
この際、エラーがたくさん出てくると思いますが、慌てないように。 あくまで設定ファイルは筆者の環境をもとに作られているため、指定された場所にドキュメントが存在しないからです。 それでも現時点でやれるだけのことはしてくれます。
のっけからエラー連発で前途多難な思いをさせて申し訳ありません。 設定ファイルは Ruby スクリプトですが、Ruby を知らない人はぎょっとするかもしれません。 langhelp は様々な形式のドキュメントをサポートする必要があるため、柔軟性が高くないといけません。 悲しいことにドキュメント事情は複雑なのです。
Ruby を知る人が見たら、設定ファイルはたんなるインスタンス変数定義の羅列であることがわかるでしょう。 いろいろな変数が定義されていますが、設定で最重要なのが @lang 変数です。
複雑な設定ファイルですが、コツさえ理解すれば設定はそんなに難しくありません。 langhelp は様々な言語やコマンドをサポートしていますが、_使いたい言語のみ設定する_のが鉄則です。 Ruby の @lang 設定を見てみましょう。(コメントは省略しています)
見てわかるように @lang[“ruby”] は Hash を要素とする配列です。 Hash のキー定義順は大文字から始まるシンボルから始まり、小文字から始まるシンボルがずらりと並んでいます。 もちろん Hash のキー定義順は Ruby 的にどうでもいいですが、可読性のために先頭に書いています。 言い換えると、 langhelp が処理するドキュメントを定義する今流行の「ドメイン特化言語 (DSL)」として見てください。 「ドキュメント定義言語」は次の仕様を満たしています。
mklanghelp –all のエラーを修正するコツを紹介します。
初回の mklanghelp –all でエラーがでたもののうち、使わない言語の設定は_無視_しちゃってください。 エラーを放置するのは気持ち悪いと思いますが、当該言語の目次が生成されないだけなので無視してもかまいません。 コンピュータの世界では一般に、理解できないもの・得体の知れないものは放置するのが安全です。
筆者はできる限りたくさんのドキュメントの目次を設定していますが、利用者が使わないドキュメントもあるでしょう。 そういうドキュメントはコメントアウトしてください。
たとえば HTMLSplit は使わないという人は次のように行頭に # を入れます。
こうすることで mklanghelp は ~/ruby/htmlsplit.html を読みに行かなくなります。
また、 w3m と emacs-w3m を使わない人は RubyRefm もコメントアウトしてください。
また、段階的に設定したい場合もコメントアウトは有効です。
「ドキュメント定義言語」でドキュメント定義を一行にしているのは、Ruby を知らない人でも簡単にコメントアウトできるようにするためです。
処理したいドキュメントにもかかわらず、筆者と利用者で置いている場所が異なる場合もあります。 そういう場合はファイル名 (ディレクトリ名) を書き換える必要があります。
みなさんはどこに何のファイルがあるか意識しているでしょうか? Unix 系 OS に親しんでいる人は自分のホームディレクトリに何があるかほとんど把握していると思います。 自分の家でどこに何があるかを覚えているようなものです。 Windows のみの人は……覚えていないかもしれませんね。
langhelp ではドキュメントを見付ける労力を軽減するために最大限の努力をしています。 設定ファイル中の [EVAL IT] 行を見てください。 これは先程触れた S 式ハイパーリンクです。 [EVAL IT] 行にカーソルを置いて C-e C-x C-e を押してください。 実行の exe と覚えればいいですね。
locate を使う行もありますが、使うためには予め GNU Findutils をインストールして updatedb しておきましょう。 locate はファイル名の一部を入力すると、ファイル名データベース内でマッチするファイル名がフルパスで出力されます。
また、ファイル名を書き換える際には、 ffap と hippie-exp を使うといいでしょう。 ともに Emacs 標準添付です。 hippie-exp を使うと任意の場所でファイル名 (他いろいろ) の補完入力ができます。 ffap はファイル名にカーソルがある場合、 C-x C-f などでそのファイル名を拾ってくれます。 そのため、ファイルの存在確認にうってつけです。 筆者は次のように .emacs に設定しています。
なんとか設定を終え、さっそく使い方の説明に入れます。
設定ファイルを書き換えた後、その設定を反映しなければなりません。 最初は
で全言語の目次を作成しましたが、今回は設定を変えた Ruby の目次を作成してみましょう。
エラーが出なければ無事に目次が完成しました。 エラーが出た場合は設定ファイルに書いてあるドキュメントファイルが存在するか確認してください。 ほかの言語についても同様です。
これで設定ファイルとの格闘はおしまいです。 Emacs で検索を楽しんでください。
Emacs を起動します。 起動後すぐに langhelp が使えるようになっています。 ここで .emacs に設定を加えていないのになぜいきなり langhelp が使えるのか疑問に思うでしょう。
langhelp は el4r を使って書かれた EmacsRuby プログラムです。 また、 el4r のインストール時に el4r-rctool で .emacs を書き換えています。 そのため Emacs 起動時に el4r が使えるようになっています。 その時点で EmacsRuby プログラムの初期化は済んでいます。
langhelp は現在の major-mode で使用言語を決定します。 ruby の目次から検索するためには、 ruby-mode にしてください。 一般に major-mode の名前から -mode を抜いたのが言語名です。 graphviz-dot-mode の言語名は graphviz-dot で、 ratpoisonrc-mode の言語名は ratpoisonrc です。
まずは簡単な例からやってみましょう。 配列の値の合計を計算したい場面で、 Enumerable#inject 2の使い方がよくわからないとしましょう。 デフォルトの langhelp 起動キーは C-c s ですが、好みに応じて変えて構いません。3 本稿ではデフォルトのままで説明します。
とさくっと打ってみましょう。 langhelp のポイントは起動した瞬間に incremental search に入っていることです。 これは、頭によぎった瞬間に検索できるようにするためです。 この 2 つのリンクが見付かるはずです。
そして、リンクの行で Enter 4か l を押せば内容を見ることができます。 incremental search の終了と同時に見たいならば、 Enter をポンポン♪と 2 回叩けばいいでしょう。
リンク先は別窓で表示されます。 別窓のスクロールは c と v です。 通常、 Emacs のスクロールは C-v なのでそれを連想する v と、その隣の c を割り当ててみました。 ページャのように SPC と b を押したら目次がスクロールします。 これは好みの問題なので、この挙動が気に入らない場合は config の @KEY_BINDING を書き換えて
すれば反映されます。
ReFe や ri の目次はクラス・モジュール順に配列しています。 クラス名やモジュール名で検索すると、そのメソッドを一覧することができます。
こうして ReFe と ri の双方のドキュメントを統一的な方法で見ることができました!! Ruby に限らずすべての言語で同様に調べることができるのです。
プログラミング中にふと他の言語・コマンドのドキュメントを見たいこともたまにあります。 こういう場合、
を押してください。 言語名がずらりと並んでいます。 さきほどと同様に incremental search に入っているので、そこから見たい言語を検索・選択してください。
langhelp のウィンドウになっている場合は d でも言語選択画面になります。
カーソル位置の単語を目次から検索することができます。 この場合、目次のうち単語を含むもののみ表示します。
あるいは
としてください。キーに割り当ててもいいですね。
langhelp 検索中に候補を絞り込むこともできます。 検索中に
で目次のうち検索語を含むもののみ表示します。 一覧されていて見易いし、さらに別の検索語で検索をかけることもできます。
これはいろんなクラスで定義されているメソッドのドキュメントを探すのに適しています。
Ruby リファレンスマニュアルも目次に含まれています。 emacs-w3m がインストールされている必要があります。
たとえば組み込み変数について調べたい場合、 Migemo もインストールされていると、
でリファレンスマニュアルの総目次の組み込み変数リンクへ飛びます。
現在サポートしているドキュメント処理クラスを挙げます。 一貫した仕様として、クラス名に対応するハッシュの値はドキュメントのファイル名 (かそれに準ずるもの) です。 ファイル名中の ~ は展開されます。
regexp パラメータを指定するドキュメント処理クラスがいくつかあります。 正規表現にマッチした行を目次にするものです。
title パラメータはドキュメントのタイトルを指定します。 title はすべてのクラスで使えます。 どのドキュメントを読んでいるのかがわかるので、 title は指定しておくべきです。
動作確認には
を使うと便利です。 標準出力に目次が出力されます。
構造化された文書はこれらのクラスで処理できます。
GNU Info 形式のドキュメントを処理します。 サンプル設定ファイルにも Info クラスが多いです。 GNU 標準なので当然といったら当然ですが。
パラメータ | 必須 | 説明 |
---|---|---|
Info | 必須 | Info ファイル。ワイルドカードも指定できます。 |
regexp | 正規表現にマッチする行を抜き出します。省略した場合は主要な情報のみ目次になります。 | |
extract | どの情報を目次として抜き出すかを配列で指定します。 |
extract に指定できるのは :node, :regexp, :section, :description です。 それぞれノード、正規表現、見出し、定義リストを意味します。 省略時はそれらすべてを目次にします。 もし冗長すぎるならば、 extract パラメータを指定してください。
日本語版 EmacsLisp マニュアルを処理します。 このようにファイルが複数に分かれているのでワイルドカードで指定しています。
Plain Text のドキュメントで正規表現にマッチするものを目次にします。
パラメータ | 必須 | 説明 |
---|---|---|
Grep | 必須 | 処理対象ファイル名。 |
regexp | 必須 | 抜き出す正規表現。 |
exclude | regexp にマッチしたもののうち除外するものを正規表現や文字列を要素とする配列で指定します。 |
旧来の定義 (src) も動作しますが、一貫性を保つために変更しました。
説明不要ですね。
Unix 系 OS の man の目次を作成します。 Manpage クラスは例外で Manpage パラメータの値はファイル名では_ありません_。
Manpage クラスは 2 つの使い方があります。 5
単数の man を処理する場合は man の内容を読みます。
パラメータ | 必須 | 説明 |
---|---|---|
Manpage | 必須 | コマンド・項目名。 |
section | 必須 | セクション番号。 |
regexp | 抜き出す正規表現。 |
C や Tcl の関数やシェルコマンドは 1 項目 1 manpage になっています。 そういうものを処理します。
パラメータ | 必須 | 説明 |
---|---|---|
Manpage | 必須 | セクション番号の配列。 |
manpath | 必須 | man が格納されているディレクトリの配列。 |
glob | 処理するファイル名をワイルドカードで指定。 |
コマンド sgrep の man を処理する例です。 通常のコマンドなのでセクションは 1 です。 sgrep の言語仕様はこのように v(〜) という形で書かれているので、正規表現で抜き出しています。
シェルコマンドや設定ファイルの仕様などがセクション 1、5、6、7、8 に含まれています。
manpath は config の初めの方に定義されているローカル変数です。 6
環境に応じて manpath の定義を書き換えてください。
C の関数などがセクション 2、3 に含まれています。
Tcl のコマンドはセクション 3 でファイル名に .3tcl を含んでいます。
ブラウザで見られるよう HTML でドキュメントが配布されていることも多いです。 HTML ドキュメントは構成が多種多様なので臨機応変にクラスを使い分ける必要があります。
HTML ファイルへのハイパーリンクのみを作成します。 HTML の内容は読みに行きません。
パラメータ | 必須 | 説明 |
---|---|---|
W3MLink | 必須 | リンクする HTML ファイル。 |
label | リンクの名前。 |
このドキュメント定義は次のハイパーリンクを作成します。
論理構造でマークアップされた HTML を処理するクラスです。 見出し (H1 〜 H6) と用語定義 (DT の内容) を目次にします。
パラメータ | 必須 | 説明 |
---|---|---|
HTML | 必須 | 処理する HTML ファイル。ワイルドカード可。 |
noconv | true ならば文字コード変換を無効にします。 | |
recursive | :next を指定すると LINK 要素で指定された次の HTML を見に行きます。 |
かなり多いです。
HTML を w3m -dump したもので正規表現にマッチしたものを目次にします。 w3m -dump したものを扱う以外、 Grep クラスと同じです。
HTML クラスが構造指向、 W3MGrep クラスが見た目指向です。 mklanghelp –eval で試行錯誤してみるといいでしょう。
パラメータ | 必須 | 説明 |
---|---|---|
W3MGrep | 必須 | 処理する HTML ファイル。 |
regexp | 必須 | 抜き出す正規表現。 |
exclude | regexp にマッチしたもののうち除外するものを正規表現や文字列を要素とする配列で指定します。 |
このファイルは HTML クラスでも処理できますが、筆者の好みで W3MGrep を使っています。
HTML 内のリンクを目次にします。 目次ページを処理するのに適しています。
パラメータ | 必須 | 説明 |
---|---|---|
W3MExtractLinks | 必須 | 処理する HTML ファイル。 |
exclude_label | 抜き出さないリンク名 (の配列) | |
exclude_url | 抜き出さない URL (の配列) |
exclude_url, exclude_url は単一の文字列・正規表現か、複数の場合はそれらの配列を指定します。 目次ページを処理するときでも、ヘッダ・フッタなど余計なものがついてくるのでそれらで除外しておくといいです。
C++ の STL マニュアルです。 Debian パッケージとして配布されています。 その中でフッタに個々のマニュアルへのリンク以外のもの (会社のページなど) がついているので、除去しています。
ドキュメントそのものだけでなく、専用の検索コマンドが用意されていることもあります。 Emacs 上で検索コマンドを実行して、その結果を別窓に表示します。 クラスの仕様は共通です。
パラメータ | 必須 | 説明 |
---|---|---|
クラス名 | 必須 | true |
cmd | 実行するコマンド |
クラス名に対応するハッシュの値は必ず true になります。 それは、検索コマンドを使用することを意味します。 cmd を指定しない場合、クラス名を小文字にしたものが検索コマンド名となります。
Refe クラスは、 ReFe でドキュメントを検索します。
RefeC クラスは、 Ruby/C API を ReFe で検索します。
Ri クラスは、 ri でドキュメントを検索します。
Ruby リファレンスマニュアル分割 HTML の総目次を取り込みます。
デフォルトのままの設定で使いたいならば、 ~/doc/rubyrefm 上でアーカイブを展開してください。 サブディレクトリを作らずにファイルを蒔き散らすのであらかじめディレクトリを作っておくのが肝心です。
パラメータ | 必須 | 説明 |
---|---|---|
RubyRefm | 必須 | リファレンスマニュアルを置いているディレクトリ |
RubyRefm には総目次のファイル名そのものも指定できますが、リファレンスマニュアルを更新したときには変化してるのでおすすめできません。 ディレクトリを指定すれば、自動的に総目次を探してくれます。
説明不要ですね。
MoonWolf 氏考案の RubyDoc 仕様のうち RubyDoc/HTMLを扱います。 しかし、その中では任意の HTML が書けてしまうので彼が書いた形式のみ動作します。 あらかじめ rubydoctool で HTML に変換してから使ってください。
パラメータ | 必須 | 説明 |
---|---|---|
MoonWolfRubyDoc | 必須 | rubydoctool により変換された HTML ファイル名 |
~/ruby/htmlsplit.rb をあらかじめ rubydoctool で HTML を出力したものをファイル名に指定しています。
Ruby の伝統的なドキュメントフォーマット RD を扱います。 書きやすく読みやすい7ので、筆者も含めドキュメントや日記やメモを書くのに RD を活用している人は多いと思います。 HeadLine や DescList や MethodList を目次にします。
パラメータ | 必須 | 説明 |
---|---|---|
RD | 必須 | RD ファイル名。 |
exclude | 抜き出さない行や正規表現の配列。 |
Ruby 以外の言語に特化したクラスも存在します。
Perl 用クラスには PodSections, PerlFunc, PerlDoc があります。 どれも perldoc コマンドを使用するクラスです。
Lua 用クラスには LuaHelp があります。 LuaHelp は Lua のマニュアルを luahelp コマンドで検索するクラスです。 LuaHelp は検索コマンドを使用する最も簡単な目次作成クラスなので、参考になると思います。
PHP 用クラスには PHPManual があります。 マニュアル中の膨大なファイルをワイルドカードで区別しています。
Python 用クラスには PythonLib があります。
目次ファイルの行末に書かれているのが S 式ハイパーリンクです。 その行がハイパーリンクであることを明示するため、S 式には色がついています。 厳密には lh- で始まる行末の式のみ色がつきます。
ハイパーリンク関数はどれも情報源を別窓に表示します。 情報源はファイルだったり、manpage だったり、シェルコマンドの実行結果だったり、様々です。 そういう詳細は関数内部に隠しています。
また、時間とメモリの節約のためすでに開いたバッファは再利用されます。 とくに man や emacs-w3m で開くのは時間がかかります。 それに毎回新しいバッファを作成していてはすぐに大量のバッファに埋め尽くされてしまいます。
引数 LINE が文字列で指定されている場合、バッファの先頭から LINE を検索し、見付かった行をウィンドウ最上部にして表示します。 つまり、「ここから読んでほしい」という意思表示です。
アンカーとは、<<< と >>> で囲まれた文字列です。 ドキュメント定義で title を指定した文字列が目次のアンカーになっていることに気付くでしょう。 引数 ANCHOR を取る関数は、アンカーを検索し、ウィンドウ最上部に表示します。 末尾に「#文字列」がついている URL をブラウザで開くとページの途中から表示されますが、それと似ています。 もちろんアンカーのかわりに LINE を取る関数に「<<<アンカー文字列>>>」を指定してもうまくいきますが、それだとカッコ悪いですね。
言語 LANG の目次を開きます。 C-u C-c s で全言語の目次を開いたときにずらりと並びます。 現在のところ全言語の目次以外に使っていませんが、関連言語を開くのに便利でしょう。
シェルコマンド COMMAND の実行結果を表示します。
ファイル FILENAME を開きます。
ファイル FILENAME を view-mode で開きます。 8
ファイルを開き、アンカーへ飛びます。
MANPAGE を開きます。
info を開きます。 BOOK とは「(info名)ノード名」のことです。
目次内のアンカーへ飛びます。
emacs-w3m で FILENAME を開きます。
refe, ri コマンドを実行してメソッドのドキュメントを表示します。
SEXP を評価するだけです。 これは明示的に色付けをするためだけに使います。 9
SEXP を評価すると同じウィンドウが選択されてしまう式を評価するのに使います。 実用性のない例ですが
は shell バッファが選択されます。一方
は shell バッファが別窓に出てきます。
ow は other window の略です。
langhelp は目次作成スクリプト mklanghelp と、Emacs をコントロールする EmacsRuby スクリプト langhelp.rb の 2 つで構成されています。
設定ファイルは両者で共有します。 適用場所こそ違うものの、どちらも Ruby スクリプトだからこそ可能なのです。
目次作成クラスはどれも AbstractIndex を継承しています。 新たな目次作成クラスを作成するときは、 AbstractIndex かそのサブクラスを継承しましょう。 ユーザ定義目次作成クラスは ~/.langhelp/mklanghelp-init.rb に書いてください。
クラスの初期化には init メソッドが使われます。 initialize ではないことに注意してください。 ちなみに initialize では目次作成クラス共通の初期化をして最後に init を呼んでいます。 init の引数には「ドキュメント定義」が Hash で渡ります。 慣習上ドキュメント定義は x という変数名を使っています。 10 init では目次作成処理のために必要なインスタンス変数の定義をします。 実際の目次作成処理は書いてはいけません。
さて、ドキュメント定義の「(字面上) 最初」のキーはクラス名だったことを思い出してください。 クラス名に対応するハッシュの値を取り出すには
と書けますが、長いしかっこ悪いので
というアクセサを設けました。 (くどいですがあくまで字面上) 最初の引数という意味です。
使えるアクセサをまとめておきます。
arg1 | 最初の引数。処理される主体 (ファイル名など) が入る。 |
title | ドキュメント定義で :title に指定されたもの。 |
conf | config を Hash のようにアクセスできる。 |
必要な情報をインスタンス変数に取り出した後、ファイル名を normalize します。 ドキュメント定義ではホームディレクトリの ~ をファイル名に含めることができます。 「ドキュメント定義言語」はドメイン特化言語なので_人間にやさしく_なくてはなりません。 この段階で File.expand_path しておきます。 11 簡単のため、normalize_filename! メソッドを用意しています。
と使います。 もちろんファイル名を格納しているインスタンス変数を指定するのです。 破壊的に更新されます。
また、ドキュメント定義中配列が指定できるパラメータがありますが、1 要素の場合は配列ではなくてそのまま指定できます。 これも同じく「人間にやさしく」という理由です。 そのため配列を指定するパラメータについては mkarray メソッドで明示的に配列化してください。
init がやるのはあくまでここまでです。 言い換えると init は「ドキュメント定義」を解釈するメソッドです。
サブクラスで定義するもうひとつのメソッドが to_e です。 このメソッドで実際に目次を書き出します。 e というのは目次ファイルの拡張子 e だと思ってください。 引数の io は出力のための IO オブジェクトかそれと同じインターフェースを持つオブジェクトです。 おおまかな構造はこんな感じになります。
ここの部分も抽象化してしまうと、かえってわかりにくくなると判断したため、to_e をサブクラスで再定義させました。 目次オブジェクトの配列はサブクラスでメソッドに切り分けていることが多いです。
それぞれのクラスの to_e メソッドを参考にしてください。
目次作成クラスを書くときに、これらのメソッドを使ってください。
変数に格納されているファイル名を破壊的に normalize します。 現時点では File.expand_path したものに置き換えるだけです。
obj が配列ならばそのまま、配列以外ならば obj のみを要素とする配列を返します。 Object#to_a とほぼ同じです。 12 配列が指定できるパラメータに使用してください。
ブロック評価結果の文字コードを config の @ENCODING に応じて統一します。 ドキュメントにどの文字コードが使われていても、目次内では統一する必要があります。 さもないと文字化けが起きてしまいます。
なお、Emacs は自動で文字コードを判別してくれるので、目次とドキュメントの文字コードが異なっても大丈夫です。
検索コマンドを使う場合はドキュメント定義を書くだけで自動的にハイパーリンク関数が定義されます。 ドキュメント定義にてクラス名に対応するハッシュの値を true にします。 config は mklanghelp 側でも EmacsRuby 側でも読み込まれます。 13
ハイパーリンク関数は次の仕様を満たしています。
このドキュメント定義から、refe コマンドを実行する lh-refe 関数が定義されます。
このドキュメント定義から、refe -e コマンドを実行する lh-refec 関数が定義されます。
なお、 Ri for (X)Emacs がインストールされている場合、それで定義された ri 関数を利用するように lh-ri 関数を override しています。 ちょっとしたトリックなので詳しくは langhelp.rb の LangHelp::FindXXX クラスを見てください。
もちろんこういうクラスでも to_e メソッドを定義しなくてはいけません。 一番単純な例は他言語ですが langhelp/lh_lua.rb です。
設定ファイルは煩雑なので、
などの質問はいつも受け付けています。 また、 config.sample に書かれていないファイルの設定例も大募集です。 動作確認次第、次期リリースに反映させます。 みなさんの力で langhelp を育てていきましょう。
一風変わった汎用ドキュメント検索ツール langhelp を紹介しました。 ドキュメントを素早く参照することで、みなさんの生産力が向上すれば作者として最高の喜びです。
rubikitch
Emacs と CUI をこよなく愛する rubyist です。 Ruby 歴は8年で、 Debian GNU/Linux を10年ほど使っています。 ratpoison, GNU Screen, GNU eev, conkeror などのキーボード指向のプログラムを愛用しています。
Ruby や Emacs の雑誌記事・書籍を執筆します。 rubikitch at ruby-lang dot org までお気軽に御連絡ください。
EmacsRuby の実用的なサンプルという目的もあります. ↩
inject は慣れるまでけっこう曲者です。今は筆者の大好きなメソッドのひとつ。 ↩
筆者は C-@ C-s にしています。 ↩
当然 C-m でもよい。筆者は C-m 派。 ↩
いい名前が思い付かなかったため、パラメータの有無で動作制御しています。 ↩
%w 記法は空白を含まない文字列の配列です。空白で区切ります。 ↩
しかし Inline が入ると読み辛い。筆者もめったに Inline は使わない。 ↩
筆者は view-mode を多用します。 view-mode では w3m に似たキー割り当てをしています。そのため閲覧のみの場合は指に負担をかけずにすみます。 ↩
「(lh」という文字列で始まり行末までを色付けする仕組みから。 ↩
短いから。数学の関数 f(x) の入力である x というイメージ。 ↩
将来ほかのファイル名拡張記法を用意するかもしれない。その場合も normalize で展開しておくだろう。 ↩
あえて用意しているのは、Object#to_a は obsolete だから。 ↩
DRY 原則遵守。 ↩