2011年12月26日月曜日

popwin.elと相性が良いシンプルなディレクトリ・エクスプローラ、direx.elを作りました

振り返ってみれば、今年は、人に与えるということをあまりしてなかった気がします。ブログもろくに書きませんでしたし、ソフトウェアの開発も、本やら論文を読んでばかりで、あまり進みませんでした。このような状況を反省しつつ、また、気持ちの良い新年を迎えるために、ここは一つ、皆様にクリスマスプレゼントを提供する形で、タイトルにあるようなEmacs拡張を作ってみました。

diredの問題点

direxは、popwin.el同様、私の長年の不満を解消するために開発された拡張です。Emacsにおけるディレクトリ操作には、基本的にdiredを利用しますが(少なくとも私は)、このdired(DIRectory EDitor)というのは、その名の通り、ディレクトリを編集(ファイルのコピーや移動など)するのに特化した拡張で、ディレクトリをフラットにしか表示できないため、閲覧性が悪く、構造的な操作が難しいという欠点を持っています。

スクリーンショットを見ていただければ分かると思いますが、その表示領域のほとんどが、パーミションやファイルサイズなどの、基本的に不要な情報によって占められているのが分かると思います。また、 dired-maybe-insert-subdirによって挿入されたサブディレクトリが、ツリー状にではなく、バッファの末尾にフラットに展開されて表示されるため、ディレクトリの構造を把握しづらいというのも分かると思います。もちろんこのような表示が、ディレクトリ・エディタたることの要求であることは分かりますが、もう少し何とかならんのかと思います。

では、diredではなく他の拡張を使えばよいだろうと思われるでしょうが、実際のところdired以上に(ディレクトリ・エクスプローラとして)使いやすい拡張は今のところ知りません。ディレクトリ編集に特化したdiredに、閲覧性や操作性で負ける拡張がほとんどだというのが現実です。

direxの特徴

そこで開発したのがdirex(DIRectory EXplorer)で、その名の通り、ディレクトリを探索するのに特化しています。もちろんファイルの削除やコピーといった基本的な操作も可能ですが、現時点ではまだ実装していません。

diredとの最も大きな違いは、やはりその表示形式です。diredはディレクトリをフラットに表示するのに対して、direxはディレクトリを可能な限りコンパクトにツリー状に表示します。

また、ツリーをあまり強調せずに自然な操作で移動できるのも特徴です。ちなみに私はdiredユーザーなので、diredの操作性をある程度模倣しています。

direxの設計

先述したように私は、かなり長い間diredを使っていますが、基本的にdiredバッファを意識しておらず、ファイルの編集中に、そのファイルのディレクトリを開きたくなった際、適宜C-x C-j (dired-jump)を呼び出す、という使い方をしています。ですから、dired-jumpの機能性が、(私の)パフォーマンスを上げる上で最大のポイントとなります。

そこで用意したコマンドが、direx:jump-to-directoryで、このコマンドは dired-jumpと同様の機能を持ちながら、diredが抱える次の二つの問題を見事に解決してくれます。

  1. diredはディレクトリをフラットに表示するためdired-jumpしたときに直近 のサブディレクトリが別バッファで表示されてしまう。
  2. diredの表示は幅をとるため、popwinと組み合わせて利用するのが難しい。

(1)に関しては特に、ディレクトリ構造の深いプロジェクトで開発する際に問題になります。diredのようにサブディレトリを一つ一つ別バッファで表示するのではなく、プロジェクトルートからツリーを展開した状態のバッファを表示するのが理想でしょう。

(2)に関しては、直接的な問題ではないですが、私にとっては重大です。過去に一度、diredバッファをpopwinで表示する設定を行ったことがありますが、横幅の関係から、Windows Explorerのようにウィンドウの左辺にディレクトリの内容を表示するといったことが出来ませんでした。下辺に表示しても、今度は縦幅が小さすぎて一覧性が悪くなってしまいました。

結局のところ、私としては、あるファイルでC-x C-jなどとすると、そのファイルのディレクトリを含むプロジェクトツリーを、ウィンドウ左辺に表示することが理想となります。

スクリーンショットで示すと次のようになります。

操作前

操作後

このような設計になっていることから、direxのパワーを最大限発揮するには、 popwinの存在が不可欠であると言えます。

インストール方法

クリスマスに間に合わせたかったので、必要最低限の機能しか実装していません。また、Emacs 22,23,24で少し動かしてぐらいであまりテストしていません。今後少しづつ開発を進める予定です。

インストールするには、以下のURLからdirex.elをダウンロードしてきて、ロードパスの通ったディレクトリに配置します。

https://github.com/m2ym/direx-el

install-elispがある方は次の式を評価することでインストールできます。

(install-elisp "https://raw.github.com/m2ym/direx-el/master/direx.el")

続いて、.emacsに次のようなコードを記述すればインストール完了です。

(require 'direx)

また、popwin.elと一緒に利用する場合(推奨)、popwin.elを開発版を利用する必要があります(現在v0.4を開発中)。以下のURLからインストールをしてください。

https://github.com/m2ym/popwin-el

popwin.el自体のインストール方法や使い方は、少し古いですが以下の記事を参照してください。

http://d.hatena.ne.jp/m2ym/20110120/1295524932

使い方

「direxの設計」で示した機能の使い方を紹介します。それ以外の機能は、今のところかなりどうでもよいものばかりです。

それで、その肝心な機能がdirex:jump-to-directoryで、このコマンドは、現在開いているファイルのディレクトリをツリー状に表示して、バッファを選択します。もし、開こうとしているディレクトリを子孫に持つディレクトリがすでにdirexで表示されている場合、そのツリーを展開した状態でバッファを選択します

このコマンドを次のようにC-x C-jに割り当てて利用するだけでも価値がありますが、

(global-set-key (kbd "C-x C-j") 'direx:jump-to-directory)

是非ともpopwinと一緒に利用しましょう。popwinの設定は以下のようになります。

;; direx:direx-modeのバッファをウィンドウ左辺に幅25でポップアップ
;; :dedicatedにtを指定することで、direxウィンドウ内でのバッファの切り替えが
;; ポップアップ前のウィンドウに移譲される
(push '(direx:direx-mode :position left :width 25 :dedicated t)
      popwin:special-display-config)

試しにM-x direx:jump-to-directory-other-windowを実行してみてください。ウィンドウ左辺にdirexバッファがポップアップされれば成功です。ウィンドウを閉じるにはqあるいはC-gを押します。

最後に、このコマンドを次のようにC-x C-jに割り当てましょう。

(global-set-key (kbd "C-x C-j") 'direx:jump-to-directory-other-window)

これで、どのファイルにいてもC-x C-jするだけでそのファイルを含むディレクトリをポップアップウィンドウにツリー状に表示することができます。

また、ツリーの表示で使われる罫線の形状も、ある程度設定可能になっています。私の設定は次のようになります(TextMate風)。

(setq direx:leaf-icon "  "
      direx:open-icon "▾ "
      direx:closed-icon "▸ ")

なお、direxバッファでのキーバインドは次のようになります。

キー コマンド 説明
n, C-n, <down> direx:next-node 次のノードを選択する
p, C-p, <up> direx:previous-node 前のノードを選択する
C-M-n, C-M-<down> direx:next-sibling 次の兄弟ノードを選択する
C-M-p, C-M-<up> direx:previous-sibling 前の兄弟ノードを選択する
^, C-M-u, C-M-<left> direx:up-node 親ノードを選択する
C-M-d, C-M-<right> direx:down-node 最初の子ノードを選択する
f direx:find-node そのノードを現在のウィンドウに開く
o direx:find-node-other-window そのノードを別のウィンドウに開く
RET direx:maybe-find-node そのノードをトグルする
q quit-window ウィンドウを閉じる

以下で、現時点で実装されているコマンドをいくつか紹介します。

direx:find-directory

指定されたディレクトリをdirexで表示します。

direx:find-directory-other-window

direx:find-directoryと同じですが、別ウィンドウで表示される点が異なります。

今後の課題

diredを本格的に置き換えるにはまだまだ機能が足りません。しばらくはdired とdirexの使い分ける必要があるでしょう。今後、実装する予定の機能としては、

  • ファイル操作(コピーや移動、マーク)
  • フィルタや検索機能
  • Tramp対応
  • imenuをdirexで表示
  • 高速化

などが挙げられます。

direxはディレクトリに限らずツリーのようなものは何でも表示・操作できるように抽象化された設計になっています。こういうものをdirexで表示すると面白いのでは、といったアイデアがあれば是非教えてください。また、direxや popwinに何か問題があれば私に連絡していただけると助かります。連絡先は @m2ymあるいはです。

それでは、良いお年を。

3 件のコメント:

  1. なんと。。。まさに時代が変わりそうなものですね。
    これでまたemacsが進化する。。。

    UIもかっこいいですね!

    アウトラインなんかもこれで表示できるとすごいですね!

    返信削除
  2. すごいです!これが欲しかった

    返信削除
  3. 素晴らしいtoolを感謝します。
    質問なのですが、表示をディレクトリファーストになるような設定法はありますでしょうか? ビギナーなのでコードを見ても自力では対応できず頓挫しています。

    返信削除