├── .gitignore ├── .travis.yml ├── Cask ├── Makefile ├── README.ja.markdown ├── README.markdown ├── e2wm-config.el ├── e2wm-vcs.el ├── e2wm.el ├── features ├── e2wm.feature ├── frame.feature ├── history.feature ├── pst-two.feature ├── step-definitions │ └── e2wm-steps.el └── support │ ├── e2wm-testing.el │ └── env.el └── test-e2wm-pst-class.el /.gitignore: -------------------------------------------------------------------------------- 1 | elpa 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: emacs-lisp 2 | env: 3 | matrix: 4 | - EMACS=emacs24 5 | - EMACS=emacs-snapshot 6 | global: 7 | - CASK=$HOME/.cask/bin/cask 8 | before_install: 9 | - curl -fsSkL --max-time 10 --retry 10 --retry-delay 10 10 | https://raw.github.com/cask/cask/master/go | python 11 | - export PATH="$HOME/.cask/bin:$PATH" 12 | - cask 13 | - if [ "$EMACS" = "emacs24" ]; then 14 | sudo add-apt-repository -y ppa:cassou/emacs && 15 | sudo apt-get update -qq && 16 | sudo apt-get install -qq emacs24 emacs24-el; 17 | fi 18 | - if [ "$EMACS" = 'emacs-snapshot' ]; then 19 | sudo add-apt-repository -y ppa:cassou/emacs && 20 | sudo apt-get update -qq && 21 | sudo apt-get install -qq 22 | emacs-snapshot-el emacs-snapshot-gtk emacs-snapshot; 23 | fi 24 | script: 25 | make travis-ci 26 | -------------------------------------------------------------------------------- /Cask: -------------------------------------------------------------------------------- 1 | (source "melpa" "http://melpa.milkbox.net/packages/") 2 | 3 | (package "e2wm" "1.2" "simple window manager for emacs") 4 | 5 | (depends-on "window-layout") 6 | 7 | (development 8 | (depends-on "ecukes") 9 | (depends-on "espuds")) 10 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | EMACS ?= emacs 2 | CASK ?= cask 3 | ECUKES ?= $(shell find .cask/*/elpa/ecukes-*/bin/ecukes | tail -1) 4 | ECUKES_OPTS ?= --tags ~@known --no-win 5 | 6 | test: unit-tests ecukes-features 7 | 8 | unit-tests: elpa 9 | ${CASK} exec ${EMACS} -Q -batch -L . -l test-e2wm-pst-class.el \ 10 | -f ert-run-tests-batch-and-exit 11 | 12 | ecukes-features: elpa 13 | ${CASK} exec ${ECUKES} ${ECUKES_OPTS} features 14 | 15 | elpa: 16 | mkdir -p elpa 17 | ${CASK} install 2> elpa/install.log 18 | 19 | clean-elpa: 20 | rm -rf elpa 21 | 22 | clean-elc: 23 | rm -f *.elc 24 | 25 | clean: clean-elpa clean-elc 26 | 27 | print-deps: 28 | ${EMACS} --version 29 | @echo CASK=${CASK} 30 | @echo ECUKES=${ECUKES} 31 | 32 | travis-ci: print-deps test 33 | -------------------------------------------------------------------------------- /README.ja.markdown: -------------------------------------------------------------------------------- 1 | # E2WM : Equilibrium Emacs Window Managaer 2 | 3 | ## 概要 4 | 5 | Emacsのウインドウマネージャーです。ポップアップウインドウの出現場所や、 6 | ウインドウの分割などをあらかじめ設定しておいた方法で表示されるように管 7 | 理します。 8 | 9 | ウインドウの管理だけでなく、作業上便利な付加機能が付いています。 10 | 11 | ### バッファ履歴管理 12 | 13 | 編集対象のバッファについては履歴を管理していますので、行ったり来たりする 14 | 編集が多少楽になると思います。 15 | 16 | ### パースペクティブ 17 | 18 | 作業シーンによって分割表示方法を切り替えることができます。この分割表示方法 19 | をEclipseにならってパースペクティブと呼んでいます。デフォルトでは、以下の 20 | ものを用意しています。 21 | 22 | - code: 中央に1つのコードを表示してがっつり読み書きする 23 | - two: 左右2分割してコードの比較や参照をする 24 | - htwo 上下2分割してコードの比較や参照をする 25 | - doc: 長いコードやドキュメントをfollow-modeで読む 26 | - dashboard: たまに見たい、使いたいバッファを集めて置いておく 27 | - array: 開いているバッファを全部表示して全体を眺めたり、視覚的に探したりする 28 | 29 | パースペクティブはユーザー側で自由に増やしたり拡張したりできます。自分 30 | の好みにカスタマイズすると、自分でウインドウを分割するような作業がほと 31 | んど必要無くなります。 32 | 33 | ### プラグインによる拡張 34 | 35 | Eclipseの「ビュー」のような、機能を持ったウインドウを増やすことができます。 36 | ここではプラグインと呼んでいます。デフォルトでは以下のようなプラグイン 37 | を用意しています。 38 | 39 | - 編集中バッファのディレクトリ内のファイル一覧を表示 40 | - バッファ履歴一覧を表示 41 | - Imenuでアウトラインの表示・移動、現在地の表示 42 | - topコマンドの出力を表示、一定時間おきに更新 43 | - 時計の表示 44 | 45 | プラグインも自由に増やしたり設定することができます。 46 | 47 | 48 | ## インストール 49 | 50 | 必要なもの、環境 51 | 52 | ロードパスに e2wm.el, window-layout.el を置き、以下のように呼び出し用の 53 | コードを .emacsなどに追加してください。以下の例では、Altキーを押しなが 54 | ら「+」を押すとウインドウの管理を開始します。終了する場合は「C-c ; C-q」 55 | です。 56 | 57 | ;; 最小の e2wm 設定例 58 | (require 'e2wm) 59 | (global-set-key (kbd "M-+") 'e2wm:start-management) 60 | 61 | ※注意点 62 | 63 | Window周りの関数をほとんど乗っ取っていますので、お使いの環境と相性が悪 64 | いことがあるかもしれません。本気のバッファで使う前に、作業に支障が出な 65 | いかどうかご確認をお願いします。 66 | 67 | ## 使い方 68 | 69 | TODO... 70 | 71 | ### キーバインド 72 | 73 | #### パースペクティブ共通 74 | 75 | #### codeパースペクティブ 76 | 77 | #### twoパースペクティブ 78 | 79 | #### htwoパースペクティブ 80 | 81 | #### docパースペクティブ 82 | 83 | #### dashboardパースペクティブ 84 | 85 | #### arrayパースペクティブ 86 | 87 | 88 | ### 簡易的なカスタマイズなど 89 | 90 | TODO... 91 | 92 | なお、設定のひな形を e2wm-config.el としておいていますので、参考にしてみ 93 | てください。 94 | 95 | 96 | ### ウインドウ分割の詳細 97 | 98 | ### パースペクティブの作成 99 | 100 | ### プラグインの作成 101 | 102 | ### 略語、表記など 103 | 104 | - `pst` : perspective 105 | - `e2wm:c-` : カスタマイズ変数 106 | - `e2wm:$` : 構造体定義 107 | 108 | - `e2wm:history-` : 履歴管理 109 | - `e2wm:pst-` : パースペクティブフレームワーク 110 | - `e2wm:pstset-` : パースペクティブセット 111 | - `e2wm:ad-` : アドバイス(switch-to-buffer, pop-to-bufferなど) 112 | - `e2wm:plugin-` : プラグインフレームワーク 113 | - `e2wm:menu-` : メニュー 114 | - `e2wm:def-plugin-` : プラグイン定義 115 | - `e2wm:dp-` : パースペクティブ定義 116 | + `e2wm:dp-code-` : code 117 | + `e2wm:dp-doc-` : doc 118 | + `e2wm:dp-two-` : two 119 | + `e2wm:dp-dashboard-` : dashboard 120 | + `e2wm:dp-array-` : array 121 | 122 | 123 | ### 構造体 124 | 125 | #### e2wm:$pst-class 構造体 126 | 127 | この構造体でパースペクティブの定義を行う。 128 | 129 | - **name** (_symbol_, 必須): 130 | このパースペクティブの名前。 131 | 132 | - **extend** (_symbol_): 133 | このパースペクティブの継承元名。 134 | 以下のものでこのクラスの定義が `nil` だったら継承元を呼ぶ。 135 | 136 | - **init** (_function()_, 必須): 137 | このパースペクティブのコンストラクタ。 138 | 返値として `wset` 構造体を返す。 139 | 基本的に wset 構造体だけを返すようにして、レイアウトや 140 | 必要なフックなどのセットアップが必要であれば下のstartで行う。 141 | init で使える dynamic bind 変数 : `prev-selected-buffer`。 142 | 143 | - **title** (_string_, 必須): 144 | このパースペクティブのタイトル(人が読む用)。 145 | 146 | - **main** (_symbol_): 147 | wlfのウインドウレイアウトのうち、デフォルトでフォーカスを当てるべき場所の名前。 148 | nilなら適当に選ぶ。 149 | 150 | - **start** (_function(wm)_): 151 | レイアウトや必要なフックなどのセットアップを行う。引数:wm。 152 | この関数がnilなら何もしない。 153 | (leaveで一時中断して後で再度startが呼ばれることがある。) 154 | start で使える dynamic bind 変数 : `prev-selected-buffer`。 155 | 156 | - **update** (_function(wm)_): 157 | wlfの各windowを更新する際に呼ばれる関数。引数:wm。 158 | この関数がnilなら何もしない。 159 | 各Windowのプラグインの更新が行われる前に呼ばれる。 160 | ウインドウの構成の変更や履歴を戻ったりするたびに呼ばれる。 161 | 162 | - **switch** (_function(buffer)_): 163 | `switch-to-buffer` を乗っ取る関数。引数:buffer。 164 | この関数がnilなら何もしない。返値でnilを返すと本来の動作、 165 | それ以外なら動作を乗っ取ったものとみなしてそのまま終了する。 166 | プラグインの更新などが必要であれば `e2wm:pst-update-windows` を呼ぶこと。 167 | 168 | - **popup** (_function(buffer)_): 169 | `pop-to-buffer`, `special-display-func` を乗っ取る関数。引数:buffer。 170 | この関数がnilなら何もしない。返値でnilを返すと本来の動作、 171 | それ以外なら動作を乗っ取ったものとみなしてそのまま終了する。 172 | プラグインの更新などが必要であれば `e2wm:pst-update-windows` を呼ぶこと。 173 | 174 | - **leave** (_function(wm)_): 175 | このパースペクティブを終了する際に呼ばれる関数。引数:wm。 176 | この関数がnilなら何もしない。 177 | 178 | - **keymap** (_keymap_): 179 | このパースペクティブで有効にするキーマップのシンボル。nilだと何も設定しない。 180 | 181 | - **save** (_function()_): 182 | `after-save-hook` で呼ばれる。 183 | 選択されているパースペクティブだけ作用。nilだと何もしない。 184 | 185 | 関数を入れるスロットで継承元を呼ぶ場合は `(e2wm:$pst-class-super)` 186 | (dynamic bind関数)を引数無しで呼ぶ。 187 | 188 | 189 | #### e2wm:$pst(perspective) インスタンス構造体 190 | 191 | - **name** : 192 | このパースペクティブの名前、シンボル 193 | - **wm** : 194 | wlfレイアウトオブジェクト 195 | - **type** : 196 | class オブジェクトへの参照 197 | 198 | 199 | #### e2wm:$wcfg ウインドウ配置構造体 200 | 201 | - **wcfg** : 202 | 本来の `current-window-configuration` でとれるウインドウ配置オブジェクト 203 | - **pst** : 204 | パースペクティブのインスタンスのコピー 205 | - **count** : 206 | デバッグ用カウンタ 207 | 208 | 209 | #### e2wm:$plugin構造体 210 | 211 | - **name** : 212 | プラグインの symbol 213 | - **title** : 214 | 人が読む用のプラグインの名前 215 | - **update** : 216 | プラグイン本体の関数 217 | 218 | 219 | ## ライセンスなど 220 | 221 | License 222 | GPL v3 223 | 224 | Repository 225 | http://github.com/kiwanami/emacs-window-manager 226 | 227 | SAKURAI, Masashi 228 | m.sakurai atmark kiwanami.net 229 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # E2WM : Equilibrium Emacs Window Manager 2 | 3 | E2WM is a window manager for Emacs. It enables to customize the 4 | place of pop-up window, how the windows are split, how the buffers 5 | are located in the windows, keybinds to manipulate windows and 6 | buffers, etc. It also has plug-ins to help your Emacs life. 7 | 8 | ## Buffer history 9 | 10 | Buffers that you edit is recorded in a special history. It will 11 | help you to go back and forth to edit these buffers. 12 | 13 | ## Perspective 14 | 15 | Depending on the kind of your task, you can change how the windows are 16 | split. Following the term from Eclipse, it is called perspective. 17 | E2WM has the following perspectives by default. 18 | 19 | ### Code perspective 20 | 21 | ![code perspective](http://cdn-ak.f.st-hatena.com/images/fotolife/k/kiwanami/20100527/20100527231754.png) 22 | 23 | Place a buffer for reading/writing code at center and helper plug-ins 24 | around of it. 25 | 26 | ### Two / HTwo perspective 27 | 28 | ![two perspective](http://cdn-ak.f.st-hatena.com/images/fotolife/k/kiwanami/20100527/20100527231758.png) 29 | 30 | Show two buffers by splitting left and right (two) or top and bottom (htwo). 31 | 32 | ### Doc perspective 33 | 34 | ![doc perspective](http://cdn-ak.f.st-hatena.com/images/fotolife/k/kiwanami/20100527/20100527231753.png) 35 | 36 | Read long code or document in the follow-mode. 37 | 38 | ### Dashboard perspective 39 | 40 | ![dashboard](http://cdn-ak.f.st-hatena.com/images/fotolife/k/kiwanami/20100527/20100527231752.png) 41 | 42 | Put the buffers you want see occasionally. 43 | 44 | ### Array perspective 45 | 46 | ![array](http://cdn-ak.f.st-hatena.com/images/fotolife/k/kiwanami/20100527/20100527231751.png) 47 | 48 | Show all the buffers you have and help searching for the buffer you 49 | are looking for visually. 50 | 51 | ### Emacs DBI 52 | 53 | ![Emacs DBI](https://cacoo.com/diagrams/VdRPw8hjXiezJJud-23532.png?width=450) 54 | 55 | Emacs DBI (Database Interface for Emacs Lisp) has it's own perspective 56 | to manipulate database. 57 | 58 | See also [emacs-edbi](https://github.com/kiwanami/emacs-edbi). 59 | 60 | 61 | ### Customize 62 | 63 | Perspective is highly customizable. You don't need to split windows 64 | by yourself anymore; let E2WM do the job! 65 | 66 | 67 | ## Plug-ins 68 | 69 | E2WM can have windows which have a specific function, something like 70 | Eclipse's "view". It is called plug-in. E2WM has the following 71 | plug-ins by default. (Yes, you can create your own plug-ins also.) 72 | 73 | ### history-list 74 | 75 | ![history-list plug-in](http://cdn-ak.f.st-hatena.com/images/fotolife/k/kiwanami/20100527/20100527231755.png) 76 | 77 | ![history-list2 plug-in](http://cdn-ak.f.st-hatena.com/images/fotolife/k/kiwanami/20100607/20100607234419.png) 78 | 79 | Show buffer history. 80 | 81 | 82 | ### files (dired) 83 | 84 | ![files plug-in](http://cdn-ak.f.st-hatena.com/images/fotolife/k/kiwanami/20100527/20100527231759.png) 85 | 86 | A list of files in the current directory. 87 | 88 | 89 | ### imenu 90 | 91 | ![imenu plug-in](http://cdn-ak.f.st-hatena.com/images/fotolife/k/kiwanami/20100527/20100527231747.png) 92 | 93 | Show the outline of the current code and the current position on it 94 | using Imenu. 95 | 96 | 97 | ## Install 98 | 99 | Put e2wm.el and 100 | [window-layout.el](https://github.com/kiwanami/emacs-window-layout) in 101 | your load-path. This is a very simple setting example: 102 | 103 | (require 'e2wm) 104 | (global-set-key (kbd "M-+") 'e2wm:start-management) 105 | 106 | Have a look at e2wm-config.el to see how to customize E2WM. 107 | 108 | **Warning**: E2WM overrides Emacs lisp functions which is related to 109 | window manipulation. It is possible that E2WM does not work in your 110 | environment. It is recommended to test if E2WM works find before 111 | use it to serious files. 112 | 113 | 114 | ## Usage 115 | 116 | TODO... 117 | 118 | 119 | ## License 120 | 121 | License 122 | GPL v3 123 | 124 | Repository 125 | http://github.com/kiwanami/emacs-window-manager 126 | 127 | SAKURAI, Masashi 128 | m.sakurai atmark kiwanami.net 129 | -------------------------------------------------------------------------------- /e2wm-config.el: -------------------------------------------------------------------------------- 1 | ;;; e2wm-config.el --- e2wm configuration 2 | 3 | ;; Copyright (C) 2010, 2011 SAKURAI Masashi 4 | 5 | ;; Author: SAKURAI Masashi 6 | ;; Version: 1.0 7 | ;; Keywords: tools, window manager 8 | 9 | ;; This program is free software; you can redistribute it and/or modify 10 | ;; it under the terms of the GNU General Public License as published by 11 | ;; the Free Software Foundation, either version 3 of the License, or 12 | ;; (at your option) any later version. 13 | 14 | ;; This program is distributed in the hope that it will be useful, 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | ;; GNU General Public License for more details. 18 | 19 | ;; You should have received a copy of the GNU General Public License 20 | ;; along with this program. If not, see . 21 | 22 | ;;; Commentary: 23 | 24 | ;; sample configuration 25 | ;; コメントアウトされているものはデフォルトの設定 26 | 27 | ;;; Code: 28 | 29 | (setq woman-use-own-frame nil) ; womanで新規フレームを開かせない 30 | 31 | ;; (setq e2wm:prefix-key "C-c ; ") 32 | 33 | (require 'e2wm) 34 | 35 | 36 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 37 | ;;; 全体設定 38 | 39 | ;; (setq e2wm:debug nil) 40 | 41 | ;; (setq e2wm:c-max-history-num 20) ; 履歴の保存数 42 | 43 | ;; (setq e2wm:c-recordable-buffer-p ; 履歴として記録したいBuffer 44 | ;; (lambda (buf) 45 | ;; (buffer-local-value 'buffer-file-name buf))) ; ファイル名に関連ついてるもの 46 | 47 | ;; (setq e2wm:c-document-buffer-p 48 | ;; (lambda (buf) 49 | ;; (string-match "\\*\\(Help\\|info\\|w3m\\|WoMan\\)" 50 | ;; (buffer-name buf)))) ; ドキュメント的に扱いたいバッファ 51 | 52 | ;; (setq e2wm:c-blank-buffer ; 白紙バッファ 53 | ;; (let ((buf (get-buffer-create " *e2wm:blank*"))) 54 | ;; (with-current-buffer buf 55 | ;; (setq buffer-read-only nil) 56 | ;; (buffer-disable-undo buf) 57 | ;; (erase-buffer) 58 | ;; (setq buffer-read-only t)) buf)) 59 | 60 | 61 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 62 | ;;; パースペクティブカスタマイズ 63 | 64 | ;;; code 65 | 66 | ;; ;; レイアウト 67 | 68 | ;; ;; for 1440x900以上 (default) 69 | ;; (setq e2wm:c-code-recipe 70 | ;; '(| (:left-max-size 35) 71 | ;; (- (:upper-size-ratio 0.7) 72 | ;; files history) 73 | ;; (- (:upper-size-ratio 0.7) 74 | ;; (| (:right-max-size 30) 75 | ;; main imenu) 76 | ;; sub))) 77 | 78 | ;; ;; for 1280x768 79 | ;; (setq e2wm:c-code-recipe 80 | ;; '(| (:left-max-size 30) 81 | ;; (- (:upper-size-ratio 0.7) 82 | ;; files history) 83 | ;; (- (:upper-size-ratio 0.7) 84 | ;; (| (:right-max-size 25) 85 | ;; main imenu) 86 | ;; sub))) 87 | 88 | ;; ;; for 1024x768 89 | ;; (setq e2wm:c-code-recipe 90 | ;; '(| (:left-max-size 35) 91 | ;; (- (:upper-size-ratio 0.7) 92 | ;; (- (:upper-size-ratio 0.6) 93 | ;; files imenu) 94 | ;; history) 95 | ;; (- (:upper-size-ratio 0.7) 96 | ;; main sub))) 97 | 98 | ;; (setq e2wm:c-code-winfo 99 | ;; '((:name main) 100 | ;; (:name files :plugin files) 101 | ;; (:name history :plugin history-list) 102 | ;; (:name sub :buffer "*info*" :default-hide t) 103 | ;; (:name imenu :plugin imenu :default-hide nil)) 104 | ;; ) 105 | 106 | ;; ;; メインに表示していいもの(それ以外はSubに表示される) 107 | ;; (setq e2wm:c-code-show-main-regexp 108 | ;; "\\*\\(vc-diff\\)\\*") 109 | 110 | ;; キーバインド 111 | (e2wm:add-keymap 112 | e2wm:pst-minor-mode-keymap 113 | '(("" . e2wm:dp-code) ; codeへ変更 114 | ("" . e2wm:dp-two) ; twoへ変更 115 | ("" . e2wm:dp-doc) ; docへ変更 116 | ("" . e2wm:dp-dashboard) ; dashboardへ変更 117 | ("C-." . e2wm:pst-history-forward-command) ; 履歴を進む 118 | ("C-," . e2wm:pst-history-back-command) ; 履歴をもどる 119 | ("prefix L" . ielm) 120 | ("M-m" . e2wm:pst-window-select-main-command) 121 | ) e2wm:prefix-key) 122 | 123 | ;;; two 124 | 125 | ;; ;; レイアウト 126 | ;; (setq e2wm:c-two-recipe 127 | ;; '(- (:upper-size-ratio 0.8) 128 | ;; (| left 129 | ;; (- (:upper-size-ratio 0.9) 130 | ;; right history)) 131 | ;; sub)) 132 | 133 | ;; (setq e2wm:c-two-winfo 134 | ;; '((:name left ) 135 | ;; (:name right ) 136 | ;; (:name sub :buffer "*Help*" :default-hide t) 137 | ;; (:name history :plugin history-list :default-hide nil))) 138 | 139 | ;; デフォルトで右側に何を表示するかの設定。 140 | ;; * left : 左右同じバッファ 141 | ;; * prev : バッファ履歴のひとつ前 142 | ;; (setq e2wm:c-two-right-default 'left) ; left, prev 143 | 144 | ;; キーバインド 145 | (e2wm:add-keymap 146 | e2wm:dp-two-minor-mode-map 147 | '(("prefix I" . info) 148 | ("C->" . e2wm:dp-two-right-history-forward-command) ; 右側の履歴を進む 149 | ("C-<" . e2wm:dp-two-right-history-back-command) ; 右側の履歴を進む 150 | ) e2wm:prefix-key) 151 | 152 | ;;; doc 153 | 154 | ;; ;; レイアウト 155 | ;; (setq e2wm:c-doc-recipe 156 | ;; '(- (:upper-size-ratio 0.75) 157 | ;; (| left right) 158 | ;; sub)) 159 | 160 | ;; (setq e2wm:c-doc-winfo 161 | ;; '((:name left) 162 | ;; (:name right) 163 | ;; (:name sub :default-hide t))) 164 | 165 | ;; キーバインド 166 | (e2wm:add-keymap 167 | e2wm:dp-doc-minor-mode-map 168 | '(("prefix I" . info)) 169 | e2wm:prefix-key) 170 | 171 | ;;; dashboard 172 | 173 | (setq e2wm:c-dashboard-plugins 174 | '(clock top 175 | (open :plugin-args (:command eshell :buffer "*eshell*")) 176 | (open :plugin-args (:command doctor :buffer "*doctor*")) 177 | )) 178 | 179 | ;;; pstset 180 | 181 | 182 | 183 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 184 | ;;; プラグインカスタマイズ 185 | 186 | ;;; top 187 | 188 | ;; (setq e2wm:def-plugin-top-timer-interval 20 "Seconds for update.") 189 | 190 | ;;; clock 191 | 192 | ;; (defvar e2wm:def-plugin-clock-download-file "/tmp/wmclock.jpg" "[internal]") 193 | ;; (defvar e2wm:def-plugin-clock-resized-file "/tmp/wmclockt.jpg" "[internal]") 194 | ;;↑cygwin環境の場合は "C:/cygwin/tmp/wmclock.jpg" とかにすると良いかも 195 | 196 | ;; for bijin (default) 197 | ;; (setq e2wm:def-plugin-clock-url "http://www.bijint.com/jp/img/clk/%H%M.jpg") 198 | ;; (setq e2wm:def-plugin-clock-referer "http://www.bijint.com/jp/") 199 | 200 | ;; for binan 201 | ;; (setq e2wm:def-plugin-clock-url "http://www.bijint.com/binan/tokei_images/%H%M.jpg") 202 | ;; (setq e2wm:def-plugin-clock-referer "http://www.bijint.com/binan/") 203 | 204 | ;; for circuit 205 | ;; (setq e2wm:def-plugin-clock-url "http://www.bijint.com/cc/tokei_images/%H%M.jpg") 206 | ;; (setq e2wm:def-plugin-clock-referer "http://www.bijint.com/cc/") 207 | 208 | ;; for fukuoka (maybe the other places...) 209 | ;; (setq e2wm:def-plugin-clock-url "http://www.bijint.com/fukuoka/tokei_images/%H%M.jpg") 210 | ;; (setq e2wm:def-plugin-clock-referer "http://www.bijint.com/fukuoka/") 211 | ;; see the site -> http://www.bijint.com/jp/pages/tokei/ 212 | 213 | 214 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 215 | ;;; 機能干渉対応 216 | 217 | ;;; For emacsclient 218 | 219 | ;; server-start を実行した後に、follow-mode を実行すると emacsclient と 220 | ;; の通信が出来なくなる。follow-mode が emacsclient のソケットプロセス 221 | ;; の入力を捨ててしまうことが原因。 222 | 223 | ;; 対策(1) 224 | ;; follow-intercept-processes を nil にすると、 follow-mode のプロセス 225 | ;; 乗っ取りを止めることが出来るが、外部プロセスの入力によって 226 | ;; follow-modeの位置がずれていくことがあるかもしれない。 227 | 228 | (setq follow-intercept-processes nil) 229 | 230 | ;; 対策(2) 231 | ;; follow-intercept-processes を nil にしたくない場合は、以下のように 232 | ;; follow-modeの関数を乗っ取ることでうまく動く。ただし、 follow-mode の 233 | ;; 実装が今後変わった場合には、動作は保証されない。 234 | 235 | ;; (eval-after-load "follow-mode" 236 | ;; (defun follow-intercept-process-output () 237 | ;; "Intercept all active processes (Overrided by e2wm)." 238 | ;; (interactive) 239 | ;; (let ((list (process-list))) 240 | ;; (while list 241 | ;; (if (or (eq (process-filter (car list)) 'follow-generic-filter) 242 | ;; (eq (car list) server-process)) ; <- see the source at "server.el" 243 | ;; nil 244 | ;; (set-process-filter (car list) (process-filter (car list)))) 245 | ;; (setq list (cdr list)))) 246 | ;; (setq follow-intercept-processes t)) 247 | ;; ) 248 | 249 | ;;; For moccur 250 | 251 | ;; moccurの検索結果バッファでエンター(moccur-mode-goto-occurrence, moccur-grep-goto)し 252 | ;; たときの挙動を改善する。また、マッチのプレビュー表示でカーソールが移 253 | ;; 動しない問題はgoto-lineでウインドウの位置を修正するようにアドバイス。 254 | 255 | (eval-after-load "color-moccur" 256 | '(progn 257 | 258 | (defadvice moccur-mode-goto-occurrence (around e2wm:ad-override) 259 | ad-do-it 260 | (delete-window (selected-window)) ; Enterでmoccurのバッファを消す(消さない方が良ければこの行をコメント) 261 | (e2wm:pst-window-select-main)) 262 | 263 | (defadvice moccur-grep-goto (around e2wm:ad-override) 264 | ad-do-it 265 | (delete-window (selected-window)) ; Enterでmoccurのバッファを消す(消さない方が良ければこの行をコメント) 266 | (e2wm:pst-window-select-main)) 267 | 268 | (defadvice goto-line (around e2wm:ad-override) 269 | ad-do-it 270 | (let ((buf (or (ad-get-arg 2) (current-buffer)))) 271 | (when (and 272 | (e2wm:managed-p) 273 | (eq (wlf:get-window (e2wm:pst-get-wm) 'sub) (selected-window)) 274 | (not (eql (selected-window) (get-buffer-window buf)))) 275 | (set-window-point 276 | (get-buffer-window buf) 277 | (with-current-buffer buf (point)))))) 278 | 279 | (when (e2wm:managed-p) 280 | (ad-activate-regexp "^e2wm:ad-override$")) 281 | )) 282 | 283 | ;;; For widen-window.el 284 | 285 | ;; widen-window.el と e2wm を同時に使うとEmacsがエラーで入力を受け付け 286 | ;; なくなってしまう。widen-window.elがアドバイスで乗っ取る関数と e2wm 287 | ;; が乗っ取る関数がかぶっていることが原因。以下のコメントされたコードを 288 | ;; 実行すると、e2wmのフレームではwiden-window.elが動作しないように回避 289 | ;; する。 290 | 291 | ;; (eval-after-load "widen-window" 292 | ;; '(progn 293 | ;; (defun e2wm:fix-widen-window-pre-start () 294 | ;; 295 | ;; ;; widen-window でエラーを起きないようする 296 | ;; (defadvice wlf:layout-internal (around disable-ww-mode activate) 297 | ;; (ad-deactivate-regexp "widen-window") 298 | ;; (unwind-protect 299 | ;; ad-do-it 300 | ;; (ad-activate-regexp "widen-window"))) 301 | ;; 302 | ;; ;; widen-window を e2wm では全く使わない場合 303 | ;; (defadvice widen-current-window (around e2wm:disable-ww-mode activate) 304 | ;; (unless (e2wm:managed-p) 305 | ;; ad-do-it 306 | ;; ))) 307 | ;; 308 | ;; (defun e2wm:fix-widen-window-post-stop () 309 | ;; ;; e2wm が終わったら widen-window を戻す 310 | ;; (ad-deactivate-regexp "e2wm:disable-ww-mode")) 311 | ;; 312 | ;; (defun e2wm:fix-widen-window () 313 | ;; (interactive) 314 | ;; (when (featurep 'widen-window) 315 | ;; (add-hook 'e2wm:pre-start-hook 'e2wm:fix-widen-window-pre-start) 316 | ;; (add-hook 'e2wm:post-stop-hook 'e2wm:fix-widen-window-post-stop)) 317 | ;; ) 318 | ;; 319 | ;; (e2wm:fix-widen-window))) 320 | 321 | ;;; For elscreen.el 322 | 323 | ;; elscreen.el は e2wm と同じく、フレーム内のウインドウの挙動を監視し、 324 | ;; ウインドウの状態を保存、復帰している。そのため、スクリーン(タブ) 325 | ;; を作ると、e2wmはウインドウを管理できなくなる。デフォルトの状態では、 326 | ;; スクリーンを複数作らなければelscreen.el自体を動かすことについては 327 | ;; 特に問題はない。 328 | 329 | ;; 回避方法としては、elscreenの管理オブジェクトの中にe2wmの管理オブジェ 330 | ;; クトを入れてelscreenの傘下に入るという方法を行う。これにより、 331 | ;; elscreenごとに異なる異なるe2wmインスタンスを持つ頃が出来る。 332 | ;; (e2wmの所々でグローバルで値を共有しているところがあるので今後直す) 333 | 334 | (eval-after-load "elscreen" 335 | '(progn 336 | ;; overrides storages for elscreen 337 | (defadvice e2wm:frame-param-get (around e2wm:ad-override-els (name &optional frame)) 338 | ;; frame is not used... 339 | (e2wm:message "** e2wm:frame-param-get : %s " name) 340 | (let ((alst (cdr (assq 'e2wm-frame-prop 341 | (elscreen-get-screen-property 342 | (elscreen-get-current-screen)))))) 343 | (setq ad-return-value (and alst (cdr (assq name alst)))))) 344 | (defadvice e2wm:frame-param-set (around e2wm:ad-override-els (name val &optional frame)) 345 | (e2wm:message "** e2wm:frame-param-set : %s / %s" name val) 346 | (let* ((screen (elscreen-get-current-screen)) 347 | (screen-prop (elscreen-get-screen-property screen)) 348 | (alst (cdr (assq 'e2wm-frame-prop screen-prop)))) 349 | (set-alist 'alst name val) 350 | (set-alist 'screen-prop 'e2wm-frame-prop alst) 351 | (elscreen-set-screen-property screen screen-prop) 352 | (setq ad-return-value val))) 353 | ;; grab switch events 354 | (defun e2wm:elscreen-define-advice (function) 355 | (eval 356 | `(defadvice ,function (around e2wm:ad-override-els) 357 | (e2wm:message "** %s vvvv" ',function) 358 | (when (e2wm:managed-p) 359 | (e2wm:message "** e2wm:managed") 360 | (let ((it (e2wm:pst-get-instance))) 361 | (e2wm:pst-method-call e2wm:$pst-class-leave it (e2wm:$pst-wm it))) 362 | (e2wm:pst-minor-mode -1)) 363 | (e2wm:message "** ad-do-it ->") 364 | ad-do-it 365 | (e2wm:message "** ad-do-it <-") 366 | (e2wm:message "** e2wm:param %s" 367 | (cdr (assq 'e2wm-frame-prop 368 | (elscreen-get-screen-property 369 | (elscreen-get-current-screen))))) 370 | (when (e2wm:managed-p) 371 | (e2wm:message "** e2wm:managed") 372 | (let ((it (e2wm:pst-get-instance))) 373 | (e2wm:pst-method-call e2wm:$pst-class-start it (e2wm:$pst-wm it))) 374 | (e2wm:pst-minor-mode 1)) 375 | (e2wm:message "** %s ^^^^^" ',function) 376 | ))) 377 | (defadvice elscreen-create (around e2wm:ad-override-els) 378 | (let (default-wcfg) 379 | (when (e2wm:managed-p) 380 | (loop for screen in (reverse (sort (elscreen-get-screen-list) '<)) 381 | for alst = (cdr (assq 'e2wm-frame-prop 382 | (elscreen-get-screen-property screen))) 383 | for wcfg = (and alst (cdr (assq 'e2wm-save-window-configuration alst))) 384 | if wcfg 385 | do (setq default-wcfg wcfg) (return))) 386 | ad-do-it 387 | (when default-wcfg 388 | (set-window-configuration default-wcfg)))) 389 | (defadvice elscreen-run-screen-update-hook (around e2wm:ad-override-els) 390 | (flet ((e2wm:managed-p () nil)) 391 | ad-do-it 392 | )) 393 | 394 | ;; apply defadvices to some elscreen functions 395 | (loop for i in '(elscreen-goto 396 | elscreen-kill 397 | elscreen-clone 398 | elscreen-swap) 399 | do (e2wm:elscreen-define-advice i)) 400 | (defun e2wm:elscreen-override () 401 | (ad-activate-regexp "^e2wm:ad-override-els$") 402 | (setq e2wm:override-window-ext-managed t)) 403 | (defun e2wm:elscreen-revert () 404 | (ad-deactivate-regexp "^e2wm:ad-override-els$") 405 | (setq e2wm:override-window-ext-managed nil)) 406 | ;; start and exit 407 | (add-hook 'e2wm:pre-start-hook 'e2wm:elscreen-override) 408 | (add-hook 'e2wm:post-stop-hook 'e2wm:elscreen-revert) 409 | )) 410 | 411 | ;;; For Multi Term 412 | 413 | ;; Multi Term は「dedicated」なウインドウを消さないような、簡易ウインド 414 | ;; ウ管理の仕組みを持っている。実装としてはウインドウ系のアドバイスがい 415 | ;; くつか入っている。MultiTermはe2wmとそういった点でウインドウ管理の機 416 | ;; 能が重複する。そのため、共存が難しいのでウインドウ系のアドバイスにつ 417 | ;; いてはe2wm管理下では無効にする。とりあえず完全に機能が競合する 418 | ;; delete-other-windowsだけ無効にする。 419 | 420 | (eval-after-load "multi-term" 421 | '(progn 422 | 423 | (defun e2wm:mult-term-advices-disable () 424 | (ad-disable-advice 'delete-other-windows 'around 'multi-term-delete-other-window-advice)) 425 | (defun e2wm:mult-term-advices-enable () 426 | (ad-enable-advice 'delete-other-windows 'around 'multi-term-delete-other-window-advice)) 427 | 428 | (add-hook 'e2wm:pst-minor-mode-setup-hook 'e2wm:mult-term-advices-disable) 429 | (add-hook 'e2wm:pst-minor-mode-abort-hook 'e2wm:mult-term-advices-enable) 430 | )) 431 | 432 | (provide 'e2wm-config) 433 | ;;; e2wm-config.el ends here 434 | -------------------------------------------------------------------------------- /e2wm-vcs.el: -------------------------------------------------------------------------------- 1 | ;;; e2wm-vcs.el --- VCS perspectives 2 | 3 | ;; Copyright (C) 2011 SAKURAI Masashi 4 | 5 | ;; Author: SAKURAI Masashi 6 | ;; Keywords: tools 7 | 8 | ;; This program is free software; you can redistribute it and/or modify 9 | ;; it under the terms of the GNU General Public License as published by 10 | ;; the Free Software Foundation, either version 3 of the License, or 11 | ;; (at your option) any later version. 12 | 13 | ;; This program is distributed in the hope that it will be useful, 14 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | ;; GNU General Public License for more details. 17 | 18 | ;; You should have received a copy of the GNU General Public License 19 | ;; along with this program. If not, see . 20 | 21 | ;;; Commentary: 22 | 23 | ;; These are e2wm perspectives for magit and dsvn. 24 | ;; One can change the perspective by M-x e2wm:dp-magit or e2wm:dp-svn. 25 | 26 | ;; Here is a sample code to add switching perspective key bindings: 27 | ;; (e2wm:add-keymap e2wm:pst-minor-mode-keymap '(("prefix v" . e2wm:dp-magit)) e2wm:prefix-key) 28 | ;; (e2wm:add-keymap e2wm:pst-minor-mode-keymap '(("prefix v" . e2wm:dp-svn)) e2wm:prefix-key) 29 | 30 | ;;; Code: 31 | 32 | (require 'e2wm) 33 | (require 'magit nil t) 34 | (require 'monky nil t) 35 | (require 'dsvn nil t) 36 | 37 | 38 | ;;; Utilities 39 | ;;;-------------------------------------------------- 40 | 41 | (defface e2wm:face-vcs-na 42 | '((((class color) (background light)) 43 | :foreground "Chocolate" :height 1.5 :inherit variable-pitch) 44 | (((class color) (background dark)) 45 | :foreground "Chocolate3" :weight bold :height 1.5 :inherit variable-pitch) 46 | (t :height 1.5 :weight bold :inherit variable-pitch)) 47 | "Face for e2wm:vcs-na title." 48 | :group 'e2wm) 49 | 50 | (defun e2wm:def-plugin-vcs-na-buffer (title) 51 | (let ((buf (get-buffer-create " *e2wm:vcs-na*"))) 52 | (with-current-buffer buf 53 | (let (buffer-read-only) 54 | (buffer-disable-undo buf) 55 | (erase-buffer) 56 | (insert (e2wm:rt (substring title 0) 'e2wm:face-vcs-na)) 57 | buf)))) 58 | 59 | 60 | (defun e2wm:def-plugin-vcs-with-window (topdir-func body-func na-buffer-func) 61 | (let* ((buf (or e2wm:prev-selected-buffer 62 | (wlf:get-buffer (e2wm:pst-get-wm) 63 | (e2wm:$pst-main (e2wm:pst-get-instance))) 64 | (current-buffer))) 65 | (file (buffer-file-name buf)) 66 | (dir (or (and file (file-name-directory file)) 67 | (with-current-buffer buf default-directory))) 68 | (topdir (and dir (funcall topdir-func dir)))) 69 | (e2wm:with-advice 70 | (cond 71 | (topdir 72 | (with-selected-window (wlf:get-window wm (wlf:window-name winfo)) 73 | (with-current-buffer buf 74 | (funcall body-func dir topdir) 75 | (goto-char (point-min))) 76 | (wlf:set-buffer wm (wlf:window-name winfo) 77 | (window-buffer (selected-window))))) 78 | (t 79 | (wlf:set-buffer wm (wlf:window-name winfo) 80 | (funcall na-buffer-func))))))) 81 | 82 | (defvar e2wm:c-vcs-select-if-plugin t "If this variable is non-nil, the plugin window is selected during popping up the plugin buffer.") 83 | 84 | (defun e2wm:vcs-select-if-plugin (buf) 85 | (e2wm:message "#vcs-select-if-plugin") 86 | (if e2wm:c-vcs-select-if-plugin 87 | (loop with wm = (e2wm:pst-get-wm) 88 | for wname in (mapcar 'wlf:window-name (wlf:wset-winfo-list wm)) 89 | if (and (equal buf (wlf:get-buffer wm wname)) 90 | (e2wm:pst-window-plugin-get wm wname)) 91 | return (progn (wlf:select wm wname) 92 | (e2wm:message "#vcs-select-if-plugin wname: %s" wname) 93 | t)))) 94 | 95 | 96 | ;;; magit / plugins 97 | ;;;-------------------------------------------------- 98 | 99 | (defun e2wm:def-plugin-magit-branches (frame wm winfo) 100 | (e2wm:def-plugin-vcs-with-window 101 | 'magit-toplevel 102 | (if (fboundp 'magit-branch-manager) 103 | (lambda (dir topdir) (magit-branch-manager)) 104 | (lambda (dir topdir) (magit-show-refs-current))) 105 | (lambda () (e2wm:def-plugin-vcs-na-buffer "Git N/A")))) 106 | 107 | (e2wm:plugin-register 'magit-branches 108 | "Magit Branches" 109 | 'e2wm:def-plugin-magit-branches) 110 | 111 | (defun e2wm:def-plugin-magit-logs (frame wm winfo) 112 | (e2wm:def-plugin-vcs-with-window 113 | 'magit-toplevel 114 | (lambda (dir topdir) 115 | (magit-log (magit-log-read-revs t) '("--graph" "--color" "--decorate" "-n100"))) 116 | (lambda () (e2wm:def-plugin-vcs-na-buffer "Git N/A")))) 117 | 118 | (e2wm:plugin-register 'magit-logs 119 | "Magit Logs" 120 | 'e2wm:def-plugin-magit-logs) 121 | 122 | (defun e2wm:def-plugin-magit-status (frame wm winfo) 123 | (e2wm:def-plugin-vcs-with-window 124 | 'magit-toplevel 125 | (lambda (dir topdir) 126 | (magit-status topdir)) 127 | (lambda () (e2wm:history-get-main-buffer)))) 128 | 129 | (e2wm:plugin-register 'magit-status 130 | "Magit Status" 131 | 'e2wm:def-plugin-magit-status) 132 | 133 | 134 | ;;; magit / magit perspective 135 | ;;;-------------------------------------------------- 136 | 137 | (defvar e2wm:c-magit-recipe 138 | '(| (:left-max-size 35) 139 | (- (:upper-size-ratio 0.7) 140 | files history) 141 | (| (:right-max-size 45) 142 | (- status (- main sub)) 143 | (- (:upper-size-ratio 0.4) branches logs)))) 144 | 145 | (defvar e2wm:c-magit-winfo 146 | '((:name main) 147 | (:name status :plugin magit-status) 148 | (:name files :plugin files) 149 | (:name history :plugin history-list) 150 | (:name sub :buffer nil :default-hide t) 151 | (:name branches :plugin magit-branches) 152 | (:name logs :plugin magit-logs))) 153 | 154 | (defvar e2wm:c-magit-show-main-regexp 155 | "\\*\\(vc-diff\\)\\*") 156 | 157 | (e2wm:pst-class-register 158 | (make-e2wm:$pst-class 159 | :name 'magit 160 | :extend 'base 161 | :title "Magit" 162 | :init 'e2wm:dp-magit-init 163 | :main 'main 164 | :start 'e2wm:dp-magit-start 165 | :switch 'e2wm:dp-magit-switch 166 | :popup 'e2wm:dp-magit-popup 167 | :leave 'e2wm:dp-magit-leave 168 | :keymap 'e2wm:dp-magit-minor-mode-map)) 169 | 170 | (defadvice magit-log-edit-commit (after e2wm:ad-override-magit) 171 | (e2wm:pst-update-windows)) 172 | (ad-deactivate-regexp "^e2wm:ad-override-magit$") 173 | 174 | (defun e2wm:dp-magit-leave (wm) 175 | (ad-deactivate-regexp "^e2wm:ad-override-magit$") 176 | (setq e2wm:prev-selected-buffer nil)) 177 | 178 | (defun e2wm:dp-magit-start (wm) 179 | (ad-activate-regexp "^e2wm:ad-override-magit$")) 180 | 181 | (defun e2wm:dp-magit-init () 182 | (let* ((magit-wm 183 | (wlf:no-layout e2wm:c-magit-recipe e2wm:c-magit-winfo)) 184 | (buf (or e2wm:prev-selected-buffer 185 | (e2wm:history-get-main-buffer)))) 186 | (wlf:set-buffer magit-wm 'main buf) 187 | magit-wm)) 188 | 189 | (defun e2wm:dp-magit-switch (buf) 190 | (e2wm:message "#DP MAGIT switch : %s" buf) 191 | (unless (e2wm:vcs-select-if-plugin buf) 192 | (e2wm:pst-buffer-set 'main buf t t))) 193 | 194 | (defun e2wm:dp-magit-popup (buf) 195 | (let ((cb (current-buffer))) 196 | (e2wm:message "#DP MAGIT popup : %s (current %s / backup %s)" 197 | buf cb e2wm:override-window-cfg-backup)) 198 | (unless (e2wm:vcs-select-if-plugin buf) 199 | (let ((buf-name (buffer-name buf)) 200 | (wm (e2wm:pst-get-wm)) 201 | (not-minibufp (= 0 (minibuffer-depth)))) 202 | (e2wm:with-advice 203 | (cond 204 | ((string-match "^\\*magit-diff: .*$" buf-name) 205 | ;; displaying commit objects in the main window 206 | (e2wm:pst-buffer-set 'status buf t nil)) 207 | ((string-match "^\\*magit: .*$" buf-name) 208 | ;; displaying status object in the status window 209 | (e2wm:pst-buffer-set 'status buf t t)) 210 | ((buffer-file-name buf) 211 | ;; displaying file buffer in the main window 212 | (e2wm:pst-buffer-set 'main buf t t)) 213 | (t 214 | ;; displaying other objects in the sub window 215 | (e2wm:pst-buffer-set 'sub buf t not-minibufp))))))) 216 | 217 | ;; Commands / Keybindings 218 | 219 | ;;;###autoload 220 | (defun e2wm:dp-magit () 221 | (interactive) 222 | (e2wm:pst-change 'magit)) 223 | 224 | (defvar e2wm:dp-magit-minor-mode-map 225 | (e2wm:define-keymap '() e2wm:prefix-key)) 226 | 227 | ;; (e2wm:add-keymap e2wm:pst-minor-mode-keymap '(("prefix v" . e2wm:dp-magit)) e2wm:prefix-key) 228 | 229 | 230 | ;;; monky / plugins 231 | ;;;-------------------------------------------------- 232 | 233 | (defun e2wm:monky-get-root-dir (dir) 234 | (monky-get-root-dir)) 235 | 236 | (defun e2wm:def-plugin-monky-branches (frame wm winfo) 237 | (e2wm:def-plugin-vcs-with-window 238 | 'e2wm:monky-get-root-dir 239 | (lambda (dir topdir) 240 | (monky-branches)) 241 | (lambda () (e2wm:def-plugin-vcs-na-buffer "Hg N/A")))) 242 | 243 | (e2wm:plugin-register 'monky-branches 244 | "Monky Branches" 245 | 'e2wm:def-plugin-monky-branches) 246 | 247 | (defun e2wm:def-plugin-monky-logs (frame wm winfo) 248 | (e2wm:def-plugin-vcs-with-window 249 | 'e2wm:monky-get-root-dir 250 | (lambda (dir topdir) (monky-log)) 251 | (lambda () (e2wm:def-plugin-vcs-na-buffer "Hg N/A")))) 252 | 253 | (e2wm:plugin-register 'monky-logs 254 | "Monky Logs" 255 | 'e2wm:def-plugin-monky-logs) 256 | 257 | (defun e2wm:def-plugin-monky-status (frame wm winfo) 258 | (e2wm:def-plugin-vcs-with-window 259 | 'e2wm:monky-get-root-dir 260 | (lambda (dir topdir) (monky-status)) 261 | (lambda () (e2wm:history-get-main-buffer)))) 262 | 263 | (e2wm:plugin-register 'monky-status 264 | "Monky Status" 265 | 'e2wm:def-plugin-monky-status) 266 | 267 | 268 | ;;; monky / monky perspective 269 | ;;;-------------------------------------------------- 270 | 271 | (defvar e2wm:c-monky-recipe 272 | '(| (:left-max-size 35) 273 | (- (:upper-size-ratio 0.7) 274 | files history) 275 | (| (:right-max-size 45) 276 | (- status (- main sub)) 277 | (- (:upper-size-ratio 0.4) branches logs)))) 278 | 279 | (defvar e2wm:c-monky-winfo 280 | '((:name main) 281 | (:name status :plugin monky-status) 282 | (:name files :plugin files) 283 | (:name history :plugin history-list) 284 | (:name sub :buffer nil :default-hide t) 285 | (:name branches :plugin monky-branches) 286 | (:name logs :plugin monky-logs))) 287 | 288 | (defvar e2wm:c-monky-show-main-regexp 289 | "\\*\\(vc-diff\\)\\*") 290 | 291 | (e2wm:pst-class-register 292 | (make-e2wm:$pst-class 293 | :name 'monky 294 | :extend 'base 295 | :title "Monky" 296 | :init 'e2wm:dp-monky-init 297 | :main 'main 298 | :start 'e2wm:dp-monky-start 299 | :update 'e2wm:dp-monky-update 300 | :switch 'e2wm:dp-monky-switch 301 | :popup 'e2wm:dp-monky-popup 302 | :leave 'e2wm:dp-vcs-monky 303 | :keymap 'e2wm:dp-monky-minor-mode-map)) 304 | 305 | (defadvice monky-log-edit-commit (after e2wm:ad-override-monky) 306 | (e2wm:pst-update-windows)) 307 | (ad-deactivate-regexp "^e2wm:ad-override-monky$") 308 | 309 | (defun e2wm:dp-vcs-monky (wm) 310 | (ad-deactivate-regexp "^e2wm:ad-override-monky$") 311 | (setq e2wm:prev-selected-buffer nil)) 312 | 313 | (defun e2wm:dp-monky-start (wm) 314 | (ad-activate-regexp "^e2wm:ad-override-monky$")) 315 | 316 | (defun e2wm:dp-monky-init () 317 | (let* ((monky-wm 318 | (wlf:no-layout e2wm:c-monky-recipe e2wm:c-monky-winfo)) 319 | (buf (or e2wm:prev-selected-buffer 320 | (e2wm:history-get-main-buffer)))) 321 | (wlf:set-buffer monky-wm 'main buf) 322 | monky-wm)) 323 | 324 | (defun e2wm:dp-monky-update (wm) 325 | (monky-with-refresh 326 | (e2wm:$pst-class-super))) 327 | 328 | (defun e2wm:dp-monky-switch (buf) 329 | (e2wm:message "#DP MONKY switch : %s" buf) 330 | (e2wm:vcs-select-if-plugin buf)) 331 | 332 | (defun e2wm:dp-monky-popup (buf) 333 | (let ((cb (current-buffer))) 334 | (e2wm:message "#DP MONKY popup : %s (current %s / backup %s)" 335 | buf cb e2wm:override-window-cfg-backup)) 336 | (unless (e2wm:vcs-select-if-plugin buf) 337 | (let ((buf-name (buffer-name buf)) 338 | (wm (e2wm:pst-get-wm)) 339 | (not-minibufp (= 0 (minibuffer-depth)))) 340 | (e2wm:with-advice 341 | (cond 342 | ((equal buf-name monky-commit-buffer-name) 343 | ;; displaying commit objects in the main window 344 | (e2wm:pst-buffer-set 'main buf t nil)) 345 | ((string-match "^\\*monky: .*\\*$" buf-name) 346 | ;; displaying status object in the status window 347 | (e2wm:pst-buffer-set 'status buf t t)) 348 | ((equal buf-name monky-queue-buffer-name) 349 | ;; displaying queue objects in the status window 350 | (e2wm:pst-buffer-set 'status buf t t)) 351 | ((buffer-file-name buf) 352 | ;; displaying file buffer in the main window 353 | (e2wm:pst-buffer-set 'main buf t t)) 354 | (t 355 | ;; displaying other objects in the sub window 356 | (e2wm:pst-buffer-set 'sub buf t not-minibufp))))))) 357 | 358 | ;; Commands / Keybindings 359 | 360 | ;;;###autoload 361 | (defun e2wm:dp-monky () 362 | (interactive) 363 | (e2wm:pst-change 'monky)) 364 | 365 | (defvar e2wm:dp-monky-minor-mode-map 366 | (e2wm:define-keymap '() e2wm:prefix-key)) 367 | 368 | ;; (e2wm:add-keymap e2wm:pst-minor-mode-keymap '(("prefix v" . e2wm:dp-monky)) e2wm:prefix-key) 369 | 370 | 371 | ;;; Subversion / plugins 372 | ;;;-------------------------------------------------- 373 | 374 | (defvar e2wm:def-plugin-svn-log-arg "-l 4 -v") 375 | 376 | (defun e2wm:def-plugin-svn-top-dir (dir) 377 | (let* ((expanded-dir (expand-file-name dir)) 378 | (svndir (member ".svn" (directory-files expanded-dir)))) 379 | (cond 380 | (svndir expanded-dir) 381 | ((or 382 | (string= expanded-dir "/") 383 | (string= expanded-dir (expand-file-name "~/"))) nil) 384 | (t (let ((updir (e2wm:def-plugin-svn-top-dir 385 | (concat (file-name-as-directory dir) "..")))) 386 | (if (null updir) expanded-dir updir)))))) 387 | 388 | (defvar e2wm:def-plugin-svn-logs-buffer-name " *WM:dsvn-logs*" "[internal]") 389 | 390 | (defun e2wm:def-plugin-svn-logs (frame wm winfo) 391 | (e2wm:def-plugin-vcs-with-window 392 | 'e2wm:def-plugin-svn-top-dir 393 | (lambda (dir topdir) 394 | (let ((default-directory (file-name-as-directory topdir))) 395 | (svn-log e2wm:def-plugin-svn-log-arg)) 396 | (let ((dbuf (get-buffer-create e2wm:def-plugin-svn-logs-buffer-name))) 397 | (with-current-buffer dbuf 398 | (setq buffer-read-only nil) 399 | (buffer-disable-undo dbuf) 400 | (erase-buffer) 401 | (insert (with-current-buffer (get-buffer "*svn output*") 402 | (buffer-string))) 403 | (setq default-directory dir) 404 | (setq buffer-read-only t) 405 | (goto-char (point-min)) 406 | (svn-log-mode)) 407 | (set-window-buffer (selected-window) dbuf))) 408 | (lambda () (e2wm:def-plugin-vcs-na-buffer "Subversion N/A")))) 409 | 410 | (e2wm:plugin-register 'svn-logs 411 | "Svn Logs" 412 | 'e2wm:def-plugin-svn-logs) 413 | 414 | (defun e2wm:def-plugin-svn-status (frame wm winfo) 415 | (e2wm:def-plugin-vcs-with-window 416 | 'e2wm:def-plugin-svn-top-dir 417 | (lambda (dir topdir) 418 | (svn-status (file-name-as-directory topdir))) 419 | (lambda () (e2wm:history-get-main-buffer)))) 420 | 421 | (e2wm:plugin-register 'svn-status 422 | "Svn Status" 423 | 'e2wm:def-plugin-svn-status) 424 | 425 | 426 | ;;; Subversion status perspective 427 | ;;;-------------------------------------------------- 428 | 429 | (defvar e2wm:c-svn-recipe 430 | '(| (:left-max-size 35) 431 | (- (:upper-size-ratio 0.7) 432 | files history) 433 | (| (:right-max-size 45) 434 | (- status (- main sub)) 435 | logs))) 436 | 437 | (defvar e2wm:c-svn-winfo 438 | '((:name main) 439 | (:name status :plugin svn-status) 440 | (:name files :plugin files) 441 | (:name history :plugin history-list) 442 | (:name sub :buffer nil :default-hide t) 443 | (:name logs :plugin svn-logs :default-hide t))) 444 | 445 | (defvar e2wm:c-svn-focus-buffer-regexp "\\*\\(svn commit\\)\\*") 446 | 447 | (e2wm:pst-class-register 448 | (make-e2wm:$pst-class 449 | :name 'svn 450 | :extend 'base 451 | :title "Svn" 452 | :init 'e2wm:dp-svn-init 453 | :main 'main 454 | :switch 'e2wm:dp-svn-switch 455 | :popup 'e2wm:dp-svn-popup 456 | :leave 'e2wm:dp-svn-leave 457 | :keymap 'e2wm:dp-svn-minor-mode-map)) 458 | 459 | (defun e2wm:dp-svn-leave (wm) 460 | (setq e2wm:prev-selected-buffer nil)) 461 | 462 | (defun e2wm:dp-svn-init () 463 | (let* ((svn-wm 464 | (wlf:no-layout e2wm:c-svn-recipe e2wm:c-svn-winfo)) 465 | (buf (or e2wm:prev-selected-buffer 466 | (e2wm:history-get-main-buffer)))) 467 | (wlf:set-buffer svn-wm 'main buf) 468 | svn-wm)) 469 | 470 | (defun e2wm:dp-svn-switch (buf) 471 | (e2wm:message "#DP SVN switch : %s" buf) 472 | (e2wm:vcs-select-if-plugin buf)) 473 | 474 | (defun e2wm:dp-svn-popup (buf) 475 | (let ((cb (current-buffer))) 476 | (e2wm:message "#DP SVN popup : %s (current %s / backup %s)" 477 | buf cb e2wm:override-window-cfg-backup)) 478 | (let* ((wm (e2wm:pst-get-wm)) 479 | (bufname (buffer-name buf)) 480 | (focus-set (and (= 0 (minibuffer-depth)) 481 | (string-match e2wm:c-svn-focus-buffer-regexp bufname)))) 482 | (e2wm:with-advice 483 | (e2wm:pst-buffer-set 'sub buf t focus-set)))) 484 | 485 | ;; Commands / Keybindings 486 | 487 | ;;;###autoload 488 | (defun e2wm:dp-svn () 489 | (interactive) 490 | (e2wm:pst-change 'svn)) 491 | 492 | (defvar e2wm:dp-svn-minor-mode-map 493 | (e2wm:define-keymap '() e2wm:prefix-key)) 494 | 495 | ;; (e2wm:add-keymap e2wm:pst-minor-mode-keymap '(("prefix v" . e2wm:dp-svn)) e2wm:prefix-key) 496 | 497 | 498 | (provide 'e2wm-vcs) 499 | ;;; e2wm-vcs.el ends here 500 | -------------------------------------------------------------------------------- /features/e2wm.feature: -------------------------------------------------------------------------------- 1 | Feature: Simple window management 2 | In order to have a happy Emacs life 3 | As a user 4 | I want to manage Emacs windows 5 | 6 | Scenario: Toggle imenu window 7 | Given I enabled e2wm 8 | When I switch to "code" perspective 9 | Then I should see window "imenu" 10 | When I press "C-c ; I" 11 | Then I should not see window "imenu" 12 | 13 | Scenario: Pop to help buffer 14 | Given I enabled e2wm 15 | When I switch to "code" perspective 16 | Then I should be in window "main" 17 | When I have a popup buffer "*Help*" 18 | Then I should be in window "sub" 19 | And I should be in buffer "*Help*" 20 | 21 | Scenario: Toggle maximize 22 | Given I enabled e2wm 23 | When I switch to "code" perspective 24 | Then I should see these windows: 25 | | Window names | 26 | | main | 27 | | files | 28 | | history | 29 | | imenu | 30 | And I press "C-c ; M" 31 | Then I should see these windows: 32 | | Window names | 33 | | main | 34 | And I press "C-c ; M" 35 | Then I should see these windows: 36 | | Window names | 37 | | main | 38 | | files | 39 | | history | 40 | | imenu | 41 | 42 | Scenario: When in left window, open buffer in right window 43 | Given I enabled e2wm 44 | When I switch to "stwo" perspective 45 | Then I should be in window "left" 46 | And I switch to a buffer "recordable-1" 47 | When I have a popup buffer "recordable-2" 48 | Then I should be in window "right" 49 | And I should be in buffer "recordable-2" 50 | When I switch to window "left" 51 | Then I should be in buffer "recordable-1" 52 | 53 | Scenario: When in right window, open buffer in left window 54 | Given I enabled e2wm 55 | When I switch to "stwo" perspective 56 | And I switch to window "right" 57 | And I switch to a buffer "recordable-1" 58 | When I have a popup buffer "recordable-2" 59 | Then I should be in window "left" 60 | And I should be in buffer "recordable-2" 61 | When I switch to window "right" 62 | Then I should be in buffer "recordable-1" 63 | 64 | Scenario: Do not show blank buffer when opening a file in VC (#46) 65 | Given I enabled e2wm 66 | When I switch to "stwo" perspective 67 | Then I should be in window "left" 68 | And I switch to a buffer "recordable-1" 69 | And I execute a command that reopens buffer "recordable-2" in other window 70 | Then I should be in window "right" 71 | And I should be in buffer "recordable-2" 72 | When I switch to window "left" 73 | And I should be in buffer "recordable-1" 74 | 75 | Scenario: Killing the blank buffer should not cause a problem (#42) 76 | Given I enabled e2wm 77 | When I switch to "code" perspective 78 | And I switch to a buffer " *e2wm:blank*" 79 | And I press "C-x k RET" 80 | And I switch to buffer "recordable" 81 | And I press "C-x k RET" 82 | 83 | Scenario: Completing window should not move focused window 84 | Given I enabled e2wm 85 | When I switch to "stwo" perspective 86 | And I switch to window "right" 87 | And I press "C-x C-f ~ / TAB TAB" 88 | Then I should see buffer "*Completions*" in window "sub" 89 | And I quit 90 | Then I should not see window "sub" 91 | Then I should be in window "right" 92 | 93 | Scenario: Original display-buffer-function should be restored 94 | Given I have custom display-buffer-function 95 | And I enabled e2wm 96 | Then my custom display-buffer-function should not be enabled 97 | When I disabled e2wm 98 | Then my custom display-buffer-function should be enabled 99 | 100 | Scenario: Display method should work even windows were distorted (#58) 101 | Given I enabled e2wm 102 | And I switch to "code" perspective 103 | And windows are distorted due to manual rearrangement 104 | When I display buffer "*test*" 105 | Then I should be in window "sub" 106 | -------------------------------------------------------------------------------- /features/frame.feature: -------------------------------------------------------------------------------- 1 | Feature: Multiple frame support 2 | In order to manage windows in multiple frames 3 | As a user 4 | I want to use E2WM with multiple frames 5 | 6 | Scenario: Comeback from unmanaged frame 7 | Given I enabled e2wm 8 | Then I should be in perspective "code" 9 | When I press "C-x 5 2" 10 | Then I should not be in e2wm-managed frame 11 | When I press "C-x 5 o" 12 | Then I should be in e2wm-managed frame 13 | And I should be in perspective "code" 14 | 15 | Scenario: Frame local keymap 16 | Given I enabled e2wm 17 | Then "e2wm:stop-management" should be called when I type "C-c ; Q" 18 | When I press "C-x 5 2" 19 | Then I should not be in e2wm-managed frame 20 | And key-binding "C-c ;" is undefined 21 | When I press "C-x 5 o" 22 | Then I should be in e2wm-managed frame 23 | And "e2wm:stop-management" should be called when I type "C-c ; Q" 24 | 25 | Scenario: Frame/perspective local keymap 26 | Given I enabled e2wm 27 | When I switch to "two" perspective 28 | And I switch to window "left" and open buffer "recordable-left" 29 | And I switch to window "right" and open buffer "recordable-right" 30 | When I press "C-x 5 2" 31 | Then I should not be in e2wm-managed frame 32 | When I press "C-x 5 o" 33 | Then I should be in e2wm-managed frame 34 | And I should be in perspective "two" 35 | And I should be in buffer "recordable-right" 36 | When I press "C-c ; -" 37 | Then I should be in buffer "recordable-left" 38 | When I press "C-c ; -" 39 | Then I should be in buffer "recordable-right" 40 | 41 | Scenario: Manage windows in two frames 42 | Given I enabled e2wm 43 | When I press "C-x 5 2" 44 | Then I should not be in e2wm-managed frame 45 | Given I enabled e2wm 46 | Then I should be in e2wm-managed frame 47 | When I press "C-x 5 o" 48 | Then I should be in e2wm-managed frame 49 | 50 | Scenario: Stopping window management of already dead frame 51 | Given I enabled e2wm 52 | When I press "C-x 5 2" 53 | And I press "C-x 5 1" 54 | And I disabled e2wm 55 | Then I should not be in e2wm-managed frame 56 | 57 | Scenario: Different perspective on different frame 58 | Given I enabled e2wm 59 | And I press "C-x 5 2" 60 | And I enabled e2wm 61 | Then I should be in perspective "code" 62 | When I press "C-x 5 o" 63 | And I switch to "two" perspective 64 | And I press "C-x 5 o" 65 | Then I should be in perspective "code" 66 | And "e2wm:dp-code-imenu-toggle-command" should be called when I type "C-c ; I" 67 | And I press "C-x 5 o" 68 | Then I should be in perspective "two" 69 | And "e2wm:dp-two-swap-buffers-command" should be called when I type "C-c ; -" 70 | 71 | Scenario: Stop one of managed frame 72 | Given I enabled e2wm 73 | And I press "C-x 5 2" 74 | And I enabled e2wm 75 | When I disabled e2wm 76 | Then I should not be in e2wm-managed frame 77 | When I press "C-x 5 o" 78 | Then I should be in e2wm-managed frame 79 | And "e2wm:dp-code-imenu-toggle-command" should be called when I type "C-c ; I" 80 | 81 | Scenario: Stop all managed frames 82 | Given I enabled e2wm 83 | And I press "C-x 5 2" 84 | And I enabled e2wm 85 | When I disabled e2wm 86 | And I press "C-x 5 o" 87 | And I disabled e2wm 88 | Then I should not be in e2wm-managed frame 89 | And key-binding "C-c ;" is undefined 90 | And I press "C-x 5 o" 91 | And I should not be in e2wm-managed frame 92 | And key-binding "C-c ;" is undefined 93 | 94 | Scenario: Restart one of managed frame 95 | Given I enabled e2wm 96 | And I press "C-x 5 2" 97 | And I enabled e2wm 98 | And I press "C-x 5 o" 99 | And I disabled e2wm 100 | And I press "C-x 5 o" 101 | And I disabled e2wm 102 | And I press "C-x 5 o" 103 | And I enabled e2wm 104 | Then I should be in e2wm-managed frame 105 | And "e2wm:dp-code-imenu-toggle-command" should be called when I type "C-c ; I" 106 | When I press "C-x 5 o" 107 | Then I should not be in e2wm-managed frame 108 | And key-binding "C-c ;" is undefined 109 | 110 | Scenario: Original display-buffer-function should be used in unmanaged frame 111 | Given I have custom display-buffer-function 112 | And I enabled e2wm 113 | Then my custom display-buffer-function should not be enabled 114 | When I press "C-x 5 2" 115 | Then my custom display-buffer-function should be enabled 116 | When I press "C-x 5 o" 117 | Then my custom display-buffer-function should not be enabled 118 | 119 | Scenario: Forcefully disable multiple frames 120 | Given I enabled e2wm 121 | And I press "C-x 5 2" 122 | And I enabled e2wm 123 | And I press "C-x 5 2" 124 | And I enabled e2wm 125 | Then "e2wm:pst-minor-mode" is on 126 | When I disabled e2wm forcefully 127 | Then "e2wm:pst-minor-mode" is off 128 | Then I should not be in e2wm-managed frame 129 | When I press "C-x 5 0" 130 | Then I should not be in e2wm-managed frame 131 | When I press "C-x 5 0" 132 | Then I should not be in e2wm-managed frame 133 | -------------------------------------------------------------------------------- /features/history.feature: -------------------------------------------------------------------------------- 1 | Feature: History management 2 | In order to organize buffers 3 | As a user 4 | I want to manage history of opened buffers 5 | 6 | Scenario: Open three recordable buffers 7 | Given I enabled e2wm 8 | When I switch to "code" perspective 9 | And I switch to a buffer "recordable-buffer-a" 10 | And I switch to a buffer "recordable-buffer-b" 11 | And I switch to a buffer "recordable-buffer-c" 12 | Then I should have these buffers in history: 13 | | Pointer | Buffer Name | 14 | | -> | recordable-buffer-c | 15 | | | recordable-buffer-b | 16 | | | recordable-buffer-a | 17 | 18 | Scenario: Ignore unrecordable buffers 19 | Given I enabled e2wm 20 | When I switch to "code" perspective 21 | And I switch to a buffer "unrecordable-buffer-1" 22 | And I switch to a buffer "recordable-buffer-a" 23 | And I switch to a buffer "unrecordable-buffer-2" 24 | And I switch to a buffer "recordable-buffer-b" 25 | And I switch to a buffer "unrecordable-buffer-3" 26 | And I switch to a buffer "recordable-buffer-c" 27 | Then I should have these buffers in history: 28 | | Pointer | Buffer Name | 29 | | -> | recordable-buffer-c | 30 | | | recordable-buffer-b | 31 | | | recordable-buffer-a | 32 | 33 | Scenario: Go back and forth 34 | Given I enabled e2wm 35 | When I switch to "code" perspective 36 | And I switch to a buffer "recordable-buffer-a" 37 | And I switch to a buffer "recordable-buffer-b" 38 | And I switch to a buffer "recordable-buffer-c" 39 | Then I should have these buffers in history: 40 | | Pointer | Buffer Name | 41 | | -> | recordable-buffer-c | 42 | | | recordable-buffer-b | 43 | | | recordable-buffer-a | 44 | And I go back history 45 | Then I should have these buffers in history: 46 | | Pointer | Buffer Name | 47 | | | recordable-buffer-c | 48 | | -> | recordable-buffer-b | 49 | | | recordable-buffer-a | 50 | And I go back history 51 | Then I should have these buffers in history: 52 | | Pointer | Buffer Name | 53 | | | recordable-buffer-c | 54 | | | recordable-buffer-b | 55 | | -> | recordable-buffer-a | 56 | And I go forward history 57 | Then I should have these buffers in history: 58 | | Pointer | Buffer Name | 59 | | | recordable-buffer-c | 60 | | -> | recordable-buffer-b | 61 | | | recordable-buffer-a | 62 | 63 | Scenario: Open and then kill three recordable buffers 64 | Given I enabled e2wm 65 | When I switch to "code" perspective 66 | And I switch to a buffer "recordable-buffer-a" 67 | And I switch to a buffer "recordable-buffer-b" 68 | And I switch to a buffer "recordable-buffer-c" 69 | Then I should have these buffers in history: 70 | | Pointer | Buffer Name | 71 | | -> | recordable-buffer-c | 72 | | | recordable-buffer-b | 73 | | | recordable-buffer-a | 74 | And I press "C-x k RET" 75 | Then I should have these buffers in history: 76 | | Pointer | Buffer Name | 77 | | -> | recordable-buffer-b | 78 | | | recordable-buffer-a | 79 | And I press "C-x k RET" 80 | Then I should have these buffers in history: 81 | | Pointer | Buffer Name | 82 | | -> | recordable-buffer-a | 83 | And I press "C-x k RET" 84 | Then I should have these buffers in history: 85 | | Pointer | Buffer Name | 86 | -------------------------------------------------------------------------------- /features/pst-two.feature: -------------------------------------------------------------------------------- 1 | Feature: Perspective "two" 2 | In order to work with two buffers side-by-side 3 | As a user 4 | I want to use built-in "two" perspective 5 | 6 | Scenario: Swap buffer when in left window 7 | Given I enabled e2wm 8 | When I switch to "two" perspective 9 | And I switch to window "left" and open buffer "recordable-left" 10 | And I switch to window "right" and open buffer "recordable-right" 11 | And I switch to window "left" 12 | Then I should be in buffer "recordable-left" 13 | When I press "C-c ; -" 14 | Then I should be in buffer "recordable-right" 15 | When I press "C-c ; -" 16 | Then I should be in buffer "recordable-left" 17 | 18 | Scenario: Swap buffer when in right window 19 | Given I enabled e2wm 20 | When I switch to "two" perspective 21 | And I switch to window "left" and open buffer "recordable-left" 22 | And I switch to window "right" and open buffer "recordable-right" 23 | Then I should be in buffer "recordable-right" 24 | When I press "C-c ; -" 25 | Then I should be in buffer "recordable-left" 26 | When I press "C-c ; -" 27 | Then I should be in buffer "recordable-right" 28 | -------------------------------------------------------------------------------- /features/step-definitions/e2wm-steps.el: -------------------------------------------------------------------------------- 1 | ;; This file contains your project specific step definitions. All 2 | ;; files in this directory whose names end with "-steps.el" will be 3 | ;; loaded automatically by Ecukes. 4 | 5 | (Given "^I enabled e2wm\\( forcefully\\|\\)$" 6 | (lambda (forcefully) 7 | (e2wm:start-management (equal " forcefully" forcefully)))) 8 | 9 | (Given "^I disabled e2wm\\( forcefully\\|\\)$" 10 | (lambda (forcefully) 11 | (e2wm:stop-management (equal " forcefully" forcefully)))) 12 | 13 | (Then "^I should\\( not\\|\\) be in e2wm-managed frame$" 14 | (lambda (not) 15 | (let ((not-p (equal not " not")) 16 | (pst (e2wm:pst-get-instance))) 17 | (assert (eq not-p (not pst)) nil 18 | "I have frame-local e2wm:pst instance: %S." 19 | pst)))) 20 | 21 | (Then "^\"\\(.+\\)\" is \\(on\\|off\\)$" 22 | (lambda (mode-str on) 23 | (let ((mode-val (eval (intern mode-str))) 24 | (on-p (equal on "on"))) 25 | (assert (eq on-p mode-val) nil "%s is %S." mode-str mode-val)))) 26 | 27 | (Then "^I should\\( not\\|\\) be in perspective \"\\(.+\\)\"$" 28 | (lambda (not desired) 29 | (let ((not-p (equal not " not")) 30 | (actual (format "%s" (e2wm:$pst-name (e2wm:pst-get-instance))))) 31 | (assert (eq (not not-p) (equal actual desired)) nil 32 | "Expected%s in perspective %S but in %S." 33 | (if not-p " not" "") desired actual)))) 34 | 35 | (When "^I switch to \"\\(.+\\)\" perspective$" 36 | (lambda (pst) 37 | (e2wm:pst-change (intern pst)))) 38 | 39 | (Then "^I should\\( not\\|\\) see window \"\\(.+\\)\"$" 40 | (lambda (not window) 41 | (let ((not-p (equal not " not")) 42 | (has-window-p 43 | (ignore-errors (wlf:get-window (e2wm:pst-get-wm) 44 | (intern window))))) 45 | (assert 46 | (if not-p (not has-window-p) has-window-p) 47 | nil 48 | "There should be%s window named %s" 49 | (if not-p " no" "") 50 | window)))) 51 | 52 | (Then "^I should\\( not\\|\\) be in window \"\\(.+\\)\"$" 53 | (lambda (not window) 54 | (let* ((not-p (equal not " not")) 55 | (given-wname (intern window)) 56 | (cur-wname (wlf:get-window-name (e2wm:pst-get-wm) 57 | (selected-window))) 58 | (same-window-p (eq given-wname cur-wname))) 59 | (assert 60 | (if not-p (not same-window-p) same-window-p) 61 | nil 62 | "I should%s be in window named %s, but in %s." 63 | not given-wname cur-wname)))) 64 | 65 | (Then "^I should see buffer \"\\(.+\\)\" in window \"\\(.+\\)\"$" 66 | (lambda (buffer-name window-name) 67 | (let* ((wm (e2wm:pst-get-wm)) 68 | (actual-buffer (wlf:get-buffer wm (intern window-name)))) 69 | (assert 70 | (equal buffer-name (buffer-name actual-buffer)) 71 | nil 72 | "Expected to see buffer %S in window %S but got %S." 73 | buffer-name window-name (buffer-name actual-buffer))))) 74 | 75 | (Then "^I should see these windows:$" 76 | (lambda (table) 77 | (let* ((wm (e2wm:pst-get-wm)) 78 | (header (car table)) 79 | (desired-names (sort (mapcar #'car (cdr table)) 80 | #'string-lessp)) 81 | (actual-names 82 | (sort (mapcar 83 | (lambda (w) (symbol-name (wlf:get-window-name wm w))) 84 | (window-list)) 85 | #'string-lessp))) 86 | (assert 87 | (equal actual-names desired-names) 88 | nil 89 | "I have different set of windows: %S" 90 | actual-names)))) 91 | 92 | (And "^I have a popup buffer \"\\(.+\\)\"$" 93 | (lambda (buffer-name) 94 | (pop-to-buffer (get-buffer-create buffer-name)))) 95 | 96 | (And "^I switch to a buffer \"\\(.+\\)\"$" 97 | (lambda (buffer-name) 98 | (switch-to-buffer (get-buffer-create buffer-name)))) 99 | 100 | (When "^I display buffer \"\\(.+\\)\"$" 101 | (lambda (buffer-name) 102 | (display-buffer (get-buffer-create buffer-name)))) 103 | 104 | (And "^I switch to window \"\\(.+\\)\"$" 105 | (lambda (window-name) 106 | (e2wm:pst-window-select (intern window-name)))) 107 | 108 | (When "^I switch to window \"\\(.+\\)\" and open buffer \"\\(.+\\)\"$" 109 | (lambda (window-name buffer-name) 110 | (When "I switch to window \"%s\"" window-name) 111 | (And "I switch to a buffer \"%s\"" buffer-name))) 112 | 113 | (When "^windows are distorted due to manual rearrangement$" 114 | "Simulate manual rearrangement of window." 115 | (lambda () 116 | (When "I press \"C-x +\""))) 117 | 118 | (defun e2wm:testing-separate-table (rows) 119 | (let ((backup-p t) 120 | history-backup history) 121 | (mapc (lambda (row) 122 | (when (not (equal (car row) "")) 123 | (setq backup-p nil)) 124 | (if backup-p 125 | (push (cadr row) history-backup) 126 | (push (cadr row) history))) 127 | rows) 128 | (list history-backup 129 | (nreverse history)))) 130 | 131 | (Then "^I should have these buffers in history:$" 132 | (lambda (table) 133 | (let* ((header (car table)) 134 | (packed (e2wm:testing-separate-table (cdr table))) 135 | (given-backup (car packed)) 136 | (given-history (cadr packed)) 137 | (actual-backup (mapcar #'buffer-name (e2wm:history-get-backup))) 138 | (actual-history (mapcar #'buffer-name (e2wm:history-get)))) 139 | (assert 140 | (equal given-history actual-history) 141 | nil 142 | "I have different history: %S" 143 | actual-history) 144 | (assert 145 | (equal given-backup actual-backup) 146 | nil 147 | "I have different history-backup: %S" 148 | actual-backup)))) 149 | 150 | (And "^I go forward history$" 151 | 'e2wm:pst-history-forward-command) 152 | 153 | (And "^I go back history$" 154 | 'e2wm:pst-history-back-command) 155 | 156 | (And "^I execute a command that reopens buffer \"\\(.+\\)\" in other window$" 157 | (lambda (buffer-name) 158 | ;; This emulates `vc-follow-link': 159 | (let ((this-command 'dummy-command)) 160 | (kill-buffer (get-buffer-create buffer-name)) 161 | (switch-to-buffer-other-window (get-buffer-create buffer-name))))) 162 | 163 | (Then "^key-binding \"\\(.+\\)\" is undefined$" 164 | (lambda (key) 165 | (let ((command (key-binding (edmacro-parse-keys key)))) 166 | (assert (not command) nil 167 | "There should be no binding but %s was found." 168 | command)))) 169 | 170 | (Then "^\"\\(.+\\)\" should be called when I type \"\\(.+\\)\"$" 171 | (lambda (command key) 172 | (let ((actual (key-binding (edmacro-parse-keys key))) 173 | (desired (intern command))) 174 | (assert (eq actual desired) nil 175 | "Command %s was bound instead of %s." 176 | actual desired)))) 177 | 178 | (defun e2wm:testing-dummy-display-buffer (buffer &optional action) 179 | "Just call plain `display-buffer'" 180 | (let (display-buffer-function) 181 | (display-buffer buffer action))) 182 | 183 | (Given "^I have custom display-buffer-function$" 184 | (lambda () 185 | (setq display-buffer-function 'e2wm:testing-dummy-display-buffer))) 186 | 187 | (Then "^my custom display-buffer-function should\\( not\\|\\) be enabled$" 188 | (lambda (not) 189 | (let* ((not-p (equal not " not")) 190 | (customized (eq display-buffer-function 191 | 'e2wm:testing-dummy-display-buffer))) 192 | (assert (equal (not not-p) customized) nil 193 | "display-buffer-function is %S" 194 | display-buffer-function)))) 195 | -------------------------------------------------------------------------------- /features/support/e2wm-testing.el: -------------------------------------------------------------------------------- 1 | (require 'e2wm) 2 | 3 | 4 | ;;; Symmetric two column perspective 5 | ;; A variant of TWO perspective that has lesser asymmetric behavior. 6 | 7 | (e2wm:pst-class-register 8 | (make-e2wm:$pst-class 9 | :name 'stwo 10 | :extend 'two 11 | :title "Symmetric Two Columns" 12 | :switch 'e2wm:dp-stwo-switch 13 | :popup 'e2wm:dp-stwo-popup)) 14 | 15 | (defun e2wm:dp-stwo-switch (buf) 16 | (e2wm:message "#DP STWO switch : %s" buf) 17 | (let ((wname (wlf:get-window-name (e2wm:pst-get-wm) (selected-window)))) 18 | (cond 19 | ((memq wname '(left right)) 20 | (e2wm:pst-buffer-set wname buf) 21 | (e2wm:pst-update-windows) 22 | t) 23 | (t nil)))) 24 | 25 | (defun e2wm:dp-stwo-popup (buf) 26 | (e2wm:message "#DP STWO popup : %s" buf) 27 | (cond 28 | ((e2wm:document-buffer-p buf) ; document goes to sub 29 | (e2wm:dp-two-popup-sub buf)) 30 | ((e2wm:history-recordable-p buf) ; recordable goes to left or sub 31 | (case (wlf:get-window-name (e2wm:pst-get-wm) 32 | (selected-window)) 33 | (left (e2wm:pst-buffer-set 'right buf t t)) 34 | (t (e2wm:pst-buffer-set 'left buf t t))) 35 | (e2wm:pst-update-windows)) 36 | (t (e2wm:dp-two-popup-sub buf))) 37 | t) 38 | -------------------------------------------------------------------------------- /features/support/env.el: -------------------------------------------------------------------------------- 1 | ;; This is an example of how you could set up this file. This setup 2 | ;; requires a directory called util in the project root and that the 3 | ;; util directory contains the testing tools ert and espuds. 4 | 5 | (let* ((features-directory 6 | (file-name-directory 7 | (directory-file-name (file-name-directory load-file-name)))) 8 | (project-directory 9 | (file-name-directory 10 | (directory-file-name features-directory)))) 11 | (setq e2wm-root-path project-directory) 12 | (setq e2wm-util-path (expand-file-name "util" e2wm-root-path))) 13 | 14 | (add-to-list 'load-path e2wm-root-path) 15 | (add-to-list 'load-path (expand-file-name "espuds" e2wm-util-path)) 16 | (add-to-list 'load-path (expand-file-name "ert" e2wm-util-path)) 17 | 18 | (require 'e2wm) 19 | (require 'espuds) 20 | (require 'ert) 21 | 22 | (defvar e2wm:message-orig (symbol-function 'e2wm:message)) 23 | (defalias 'e2wm:message 'message) 24 | 25 | (Setup 26 | ;; Before anything has run 27 | (setq e2wm:debug t) 28 | (setq e2wm:c-recordable-buffer-p 29 | (lambda (buf) 30 | (e2wm:aand (buffer-name buf) 31 | (string-prefix-p "recordable" it t))))) 32 | 33 | (Before 34 | ;; Before each scenario is run 35 | ;; Remove recordable buffers: 36 | (mapc (lambda (buf) 37 | (when (e2wm:history-recordable-p buf) 38 | (kill-buffer buf))) 39 | (buffer-list)) 40 | ;; Clear history: 41 | (e2wm:history-save nil) 42 | (e2wm:history-save-backup nil)) 43 | 44 | (After 45 | ;; After each scenario is run 46 | ;; Exit from e2wm management: 47 | (e2wm:stop-management t) 48 | ;; Stopping management when e2wm has live frame kills Emacs. This is 49 | ;; another bug needed to be solved, but let's play on the safer side 50 | ;; now: 51 | (delete-other-frames) 52 | (setq display-buffer-function nil)) 53 | 54 | (Teardown 55 | ;; After when everything has been run 56 | (fset 'e2wm:message e2wm:message-orig)) 57 | -------------------------------------------------------------------------------- /test-e2wm-pst-class.el: -------------------------------------------------------------------------------- 1 | ;; How to run: 2 | ;; emacs -batch \ 3 | ;; -L PATH/TO/E2WM/ \ 4 | ;; -L PATH/TO/WINDOW-LAYOUT/ \ 5 | ;; -l PATH/TO/test-e2wm-pst-class.el \ 6 | ;; -f ert-run-tests-batch-and-exit 7 | 8 | 9 | (require 'ert) 10 | (require 'e2wm) 11 | 12 | 13 | (ert-deftest e2wm-pst-class-simple-inheritance () 14 | (let* ((expected-result 1) 15 | (super-class 16 | (make-e2wm:$pst-class :init (lambda () expected-result))) 17 | (class 18 | (make-e2wm:$pst-class 19 | :extend super-class 20 | :init (lambda () (e2wm:$pst-class-super)))) 21 | (result (e2wm:method-call 22 | #'e2wm:$pst-class-init class nil))) 23 | (should (equal result expected-result)))) 24 | 25 | 26 | (ert-deftest e2wm-pst-class-grandchild () 27 | (let* ((expected-result 1) 28 | (grand-class 29 | (make-e2wm:$pst-class :init (lambda () expected-result))) 30 | (super-class 31 | (make-e2wm:$pst-class 32 | :extend grand-class 33 | :init (lambda () (e2wm:$pst-class-super)))) 34 | (class 35 | (make-e2wm:$pst-class 36 | :extend super-class 37 | :init (lambda () (e2wm:$pst-class-super)))) 38 | (result (e2wm:method-call 39 | #'e2wm:$pst-class-init class nil))) 40 | (should (equal result expected-result)))) 41 | --------------------------------------------------------------------------------