kiwanami / emacs-window-manager

Customizable window manager for emacs
230 stars 28 forks source link

e2wm の拡張集(ne2wm)を作ってみての提案など #27

Open tkf opened 12 years ago

tkf commented 12 years ago

e2wm の拡張集(ne2wm) を作ってみて浮かんできた要望などをまとめてみます。

ここに書くべき内容かどうかは微妙ですが、 ML とかも無いようですし、機能の要望みたいなものなのでここに書かせていただきます。リンクとか楽ですし。

window の semantics

ne2wm:win-ring-pushne2wm:win-ring-rotate コマンドや history-list+ プラグイン は、"main window" (plugin window ではなくコードなどを表示する window) のリストを独自の変数で管理しています。このリストのおかげで、ある window に対しての "other window" を定義することが出来て、 "other window" を操るコマンドを書くことが出来ます。 例えば、このリストが '(left right third) で現在 left に居るとすると、 "other window" は right です。 right だと third で、 third だと一周まわって left です。

ne2wm:def-plugin-history-list+-forward/back-other-command は自分が今居る window に対する "other window" のバッファを切り替えるコマンドです。 e2wm:dp-two-right-history-forward/back-command と違い、3つ以上の "main window" をもつパースペクティブでもきちんと動作が定義できます。 また、 ne2wm:def-plugin-history-list+-forward/back-current-command は普通に使うと current window のバッファを切り替えるコマンドですが、 numeric argument (M-3 など) を与えることで、その window にフォーカスを移すことなくバッファを切り替えることができます(M-3 が与えられた場合は window list で 3番目の window を切り替える)。 ne2wm:win-ring-pushne2wm:win-ring-rotate コマンドの動作については スクリーンショット を見るのが分り易いと思います。

まとめると、 "main window list" をもつことで以下のご利益があります。

これを e2wm で導入するには、例えば :main スロットを list も取れるようにする、とか新たに :main-list スロットを導入する、みたいな方法があると思います。

さらに、 three+ パースペクティブを使ってて気づいたのですが、自分が今居る window や popup する buffer に応じて sub の位置が切り替わって欲しいと感じました。 three+ はデフォルトでは左下に sub があるのですが、一番右端の window を使っていると視線移動が大きくて辛いです。また、 sub のある column は 80 column より大分細くなっているので anything バッファとかを表示するには辛いものがあります。という訳で、動的に sub window を決めるために :sub スロットを設けてそこに window name ('sub など) または window name を返す関数を入れられるようにするのはどうでしょうか? :get-sub みたいなスロットでも良いかもしれません。そうなると、 :get-main:get-other も欲しくなります。

補足1: ne2wm:win-ring-push / ne2wm:win-ring-rotate コマンド

ne2wm:win-ring-pushne2wm:win-ring-rotate コマンド (ne2wm-utils.el) は ne2wm:win-ring 変数に定義された window を次々と巡っていくコマンドです。 ne2wm:win-ring 変数は "main" window のリストで、 three+ パースペクティブ (ne2wm-pst-three+.el) だと '(left right third) となっています。 two パースペクティブだと '(left right) とすれば使えるはずです。

補足2: history-list+ プラグイン

また、まったく同じ値を持つ変数に (ne2wm-plugin-history-list+.el) の ne2wm:def-plugin-history-list+-wname-list があります。これは、 history list に表示する window を決める変数です。また、 ne2wm:def-plugin-history-list+-pointer-list という変数も使っていて、これは history list に表示する矢印の設定です。ちなみに、これらの変数は frame local な変数ではなく :plugin-args でもつべきものですよね。書いた後に気づきました...。

これらの変数の使い方については ne2wm-pst-three+.elne2wm:dp-three+-start をご覧ください。

$pst-class にスロットが用意されていない関数の拡張

ne2wm-pst-code+.el では、次のようなコードで e2wm:dp-code-popup-sub を「拡張」しています。この「拡張法」って dirty hack な気がします。書いているうちに、もっと一般的なクラスシステムが欲しくなってきました。。。

(defun ne2wm:dp-code+-popup (buffer)
  (flet ((e2wm:dp-code-popup-sub (b) (ne2wm:popup-sub-appropriate-select b)))
    (e2wm:$pst-class-super)))

関連:

毎回以下のようなコードを書いているので、マクロが欲しくなりました。自分で作れよという話ですが、拡張集作った後に気づきました。。。

(e2wm:pst-class-register
  (make-e2wm:$pst-class ...))

(defun e2wm:dp-PST-NAME ()
  (interactive)
  (e2wm:pst-change 'PST-NAME))

ちなみに、 e2wm:pst-class-register が plist を受け取る関数で書かれていれば #22 で backward compatible な e2wm:pst-class-register を書くときに、 :extendnil の時と指定されていないときで条件が分岐出来て、よりまともな解決法になったと思いました。

popwin 対応

noselect 相当のものは e2wm:pst-buffer-setselectp 引数を使えば比較的簡単に実装出来たので作ってみました。ただ、バッファを監視して表示する必要が無くなったり C-g が押された時に sub を隠す機能は実装していません。 @kiwanami さんが popwin と組み合わせを実装してくださるということなので、大いに期待しています!!

kiwanami commented 12 years ago

使い倒された上での貴重なご意見ありがとうございます!

「window semantics」というのはe2wmがやりたかったことを一言で表したいい言葉だなと思いました。 mainがリストも取れるようにするというのは他のIDEには無い考えでこれはかなり面白そうです。普段は1つにしておけば問題ないのですぐに取り込めるのではないかと思います。

クラスシステムはeieio使えばよかったかなと思ってはいますが、自分がCLOSについての経験が乏しいため、書きなおしてしまうべきかそのままのほうがいいのか悩みどころです。もうひとつ、抽象度を上げてしまって拡張するのにいろいろ勉強しなければならないというのも出来れば避けたいので、なるべくベタでかけて、でもコードはなるべく綺麗で破綻しない感じを目指したいです。なかなか無茶ですが。。。

ちょっと本業などでまた忙しくなってしまうので速度が落ちてしまうのですが、しばらくここで提案していただいた内容について取り込む具体的方針を議論させてもらって、できるだけ取り込んで行こうかなと思っています。

tkf commented 12 years ago

お役に立ててなによりです。

window semantics をもりこんだパースペクティブ定義はこんな感じではどうかと思います:

(e2wm:pst-class-register
 (make-e2wm:$pst-class
  :name   'three+
  :main   '(left right third)    ; ← main リストを指定
  :other  '((left  . right)      ; ← :main から other を自動的に計算も
            (right . third)      ;    出来るが、マニュアルで指定も出来る。
            (third . right)      ; ← 自動計算だと left だけど right に。
            (sub-2 . right)      ; ← sub に関しても定義できる。
            (".*"  . left)       ; ← alist の key は正規表現も使えると
            )                    ;    楽かもしれません。
  :sub    '((left  . sub)        ; ← current と sub の対応表
            (right . sub-2)
            (third . sub-2)
            (".*"  . sub)
            )
  ...))

これは、 main window は左から left, right, third の順で並んでいて sub は左下、 sub-2 は右下にあるようなパースペクティブだと思ってください。

:main/:other/:sub は開くバッファも条件に使えると便利だと思います。 どんなDSL(?)が良いかはちょっとわかりません。これらのスロットが関数をとれるようにするのがてっとり早そうです。

eieio 使って欲しいなとは思ったのですが、縛りのある、WMに特化したクラスシステムで、すっきり書けるという方針も魅力的ですよね。 defstruct は派生 struct 作れるみたいなんで、それをうまく使えないかな、って思っています。

tkf commented 12 years ago

今思い出しましたが、 winfo と recipe も $pst-class の slot に(値ではなくシンボルとして)入れて良い気がします。 init で wlf:no-layout を呼び出すのは array パースペクティブみたいな特殊例をのぞけば毎回同じで base クラスに全部移動できるので。

tkf commented 12 years ago

window に数字を振るのは、 :main がリストならそれに 1, 2, 3, ... と割り当てて、残りの window は左上から順に続きの番号を割り当てていけば良いと思います。 :main がリストで無いなら :default-hide:plugin が指定されていないウィンドウから先に数字を振る、とかでしょうか。numeric argument で使うことを考えて、1 origin が良いと思います。

tkf commented 12 years ago

あ、あと dired や find-file で N番のwindowで開く、や other window で開くって出来たら良いですね。