-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsplit-root.el
186 lines (167 loc) · 7.07 KB
/
split-root.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
;;; split-root.el --- root window splitter
;; Copyright (C) 2006 Nikolaj Schumacher <bugs * nschum , de>
;;; License
;; This program is free software; you can redistribute it and/or
;; modify it under the terms of the GNU General Public License
;; as published by the Free Software Foundation; either version 2
;; of the License, or (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;;; Usage
;; Use `split-root-window' to split the root window. This creates a pair of
;; windows, a new one, and one containing your previous window configuration
;; (as long as it fits).
;;; Known Issues
;; Splitting the root window actually destroys all windows and recreates them.
;; Therefore all windows will be considered dead after splitting.
(require 'cl)
(defun window-settings (window)
"Stores WINDOW's buffer, point and window-start in a list"
(list (window-buffer window) (window-point window) ;;(window-start window)
(eq (selected-window) window)))
(defun set-window-settings (conf &optional window)
"Sets buffer, point and window-start to conf, given by ``window-settings''."
(set-window-buffer window (car conf))
;; (set-window-start window ( conf))
;; set point last, so its guaranteed to stay the same
(set-window-point window (cadr conf))
(when (caddr conf) (select-window window t)))
(defun calculate-window-tree (tree)
"Calculate a version of `window-tree' for use by `split-root-window'."
(if (windowp tree)
(let ((edges (window-edges tree)))
`(,(window-settings tree)
,(- (nth 2 edges) (nth 0 edges))
,(- (nth 3 edges) (nth 1 edges))))
(let* (;;(width 0) (height 0)
(pos (cadr tree))
(width (- (nth 2 pos) (nth 0 pos)))
(height (- (nth 3 pos) (nth 1 pos)))
(horflag (not (car tree)))
(children (mapcar '(lambda (child)
(let ((size (calculate-window-tree child)))
size)) (cddr tree))))
`(,horflag ,width ,height ,@children))))
(defun build-window-tree (tree window)
"Restore window settings from a tree created by `calculate-window-tree'."
(if (atom (car tree))
;; tree
(let ((horflag (car tree))
(children (cdddr tree)))
;; create windows for children
(while (cdr children)
;; recursive descent
(let* ((child (car children))
(child-width (cadr child))
(child-height (caddr child))
(next-window
(split-window window
(if horflag child-width child-height)
horflag)))
(build-window-tree child window)
(setq window next-window)
(pop children)))
(build-window-tree (car children) window))
;; single window
(set-window-settings (car tree) window)))
(defun split-root-scale-window-tree (tree width height)
"Scale a result of `calculate-window-tree' to fit into smaller space."
(if (atom (car tree))
;; tree
(let* ((horflag (car tree))
(w (cadr tree))
(h (caddr tree))
(children (cdddr tree)))
(if (car tree)
(split-root-scale-window-tree-h tree width height)
(split-root-scale-window-tree-v tree width height)))
;; single window
`(,(car tree) ,width ,height)))
(defun split-root-scale-window-tree-h (tree width height)
"`split-root-scale-window-tree' for horizontally split tree nodes."
(let* ((w (cadr tree))
(children (cdddr tree))
result)
(assert (not (eq w 0)))
(assert (not (eq width 0)))
(assert (not (eq h 0)))
(assert (not (eq height 0)))
(while children
(let ((child (car children)))
(pop children)
(let* ((child-width (cadr child))
(new-child-width
(if (null children)
;; last child
width
(round (/ (float (* child-width width))
w)))))
(message "width %s" new-child-width)
;; and resize the child, if big enough
(unless (< new-child-width window-min-width)
;; subtract what we used up
(setq w (- w child-width))
(setq width (- width new-child-width))
(push (split-root-scale-window-tree child new-child-width height)
result)))))
`(t ,width ,height ,@(nreverse result))))
(defun split-root-scale-window-tree-v (tree width height)
"`split-root-scale-window-tree' for vertically split tree nodes."
(let* ((h (caddr tree))
(children (cdddr tree))
result)
(assert (not (eq w 0)))
(assert (not (eq width 0)))
(assert (not (eq h 0)))
(assert (not (eq height 0)))
(while children
(let ((child (car children)))
(pop children)
(let* ((child-height (caddr child))
(new-child-height
(if (null children)
;; last child
height
(round (/ (float (* child-height height))
h)))))
;; and resize the child, if big enough
(message "height %s" new-child-height)
(unless (< new-child-height window-min-height)
;; subtract what we used up
(setq h (- h child-height))
(setq height (- height new-child-height))
(push (split-root-scale-window-tree child width new-child-height)
result)))))
`(nil ,width ,height ,@(nreverse result))))
;;;###autoload
(defun split-root-window (&optional size horflag top-left)
"Split a window of SIZE lines/columns from the root window.
If optional argument horflag is non-nil, split side by side and put size
columns in the new window.
If optional argument TOP-LEFT is non-nil the window will appear at the
top/left, otherwise of the bottom/right."
(interactive)
(let ((tree (calculate-window-tree (car (window-tree)))))
(delete-other-windows)
(let* ((edges (window-edges))
(width (- (nth 2 edges) (nth 0 edges)))
(height (- (nth 3 edges) (nth 1 edges)))
(sz (or size (/ (if horflag width height) 2)))
(remaining (- (if horflag width height) sz))
(old-window (selected-window))
(new-window old-window))
(if top-left
(setq new-window (split-window new-window sz horflag))
(setq old-window (split-window new-window remaining horflag)))
(build-window-tree
(if horflag
(split-root-scale-window-tree tree remaining height)
(split-root-scale-window-tree tree width remaining)) new-window)
old-window
)))
(provide 'split-root)