Commit | Line | Data |
---|---|---|
72c0ae01 ER |
1 | ;;; two-column.el --- minor mode for editing of two-column text |
2 | ||
3731a850 TTN |
3 | ;; Copyright (C) 1992, 1993, 1994, 1995, 2002, 2003, 2004, |
4 | ;; 2005 Free Software Foundation, Inc. | |
e6b72410 | 5 | |
3e910376 | 6 | ;; Author: Daniel Pfeiffer <occitan@esperanto.org> |
e6b72410 | 7 | ;; Adapted-By: ESR, Daniel Pfeiffer |
6228c05b | 8 | ;; Keywords: wp |
e6b72410 | 9 | |
e8af40ee PJ |
10 | ;; This file is part of GNU Emacs. |
11 | ||
e6b72410 KH |
12 | ;; Esperanto: English: |
13 | ||
14 | ;; ^Ci dosiero estas ero de GNU Emacs. This file is part of GNU Emacs. | |
15 | ||
16 | ;; GNU Emacs estas libera programaro; GNU Emacs is free software; you can | |
17 | ;; vi povas disdoni ^gin kaj/a^u modifi redistribute it and/or modify it | |
18 | ;; ^gin sub la kondi^coj de la GNU under the terms of the GNU General | |
19 | ;; ^Generala Publika Licenco kiel pub- Public License as published by the | |
20 | ;; likigita far la Liberprogramara Fon- Free Software Foundation; either | |
21 | ;; da^jo; a^u eldono 2a, a^u (la^u via version 2, or (at your option) any | |
22 | ;; elekto) ajna posta eldono. later version. | |
23 | ||
24 | ;; GNU Emacs estas disdonata en la GNU Emacs is distributed in the hope | |
25 | ;; espero ke ^gi estos utila, sed SEN that it will be useful, but WITHOUT | |
26 | ;; IA GARANTIO; sen e^c la implicita ANY WARRANTY; without even the | |
27 | ;; garantio de VENDEBLECO a^u PRETECO implied warranty of MERCHANTABILITY | |
28 | ;; POR DETERMINITA CELO. Vidu la GNU or FITNESS FOR A PARTICULAR PURPOSE. | |
29 | ;; ^Generala Publika Licenco por plenaj See the GNU General Public License | |
30 | ;; detaloj. for more details. | |
31 | ||
32 | ;; Vi devus ricevinti kopion de la GNU You should have received a copy of | |
33 | ;; ^Generala Publika Licenco kune kun the GNU General Public License along | |
34 | ;; GNU Emacs; vidu la dosieron COPYING. with GNU Emacs; see the file | |
35 | ;; Alikaze skribu al la COPYING. If not, write to the | |
36 | ||
4fc5845f LK |
37 | ;; Free Software Foundation, 51 Franklin Street, Fifth Floor |
38 | ;; Boston, MA 02110-1301, USA. | |
e6b72410 | 39 | |
e8af40ee | 40 | ;;; Commentary: |
e6b72410 KH |
41 | |
42 | ;;; Komentario: Commentary: | |
43 | ||
44 | ;; Tiu programaro ebligas vin redakti This package gives you the ability | |
45 | ;; dukolumnan tekston. to edit text in a two-column format. | |
46 | ||
47 | ||
48 | ;; Vi havas tri eblecojn por eki tiun You have three ways to start up this | |
49 | ;; mal^cefan modalon. ^Ciu donas al vi minor mode. Each gives you a | |
50 | ;; horizontale disigatan fenestron, si- horizontally split window similar to | |
51 | ;; milan al fina apareco de via teksto: the final outcome of your text: | |
52 | ||
53 | ||
54 | ;; f2 2 asocias novan bufron nomatan associates a new buffer called | |
55 | ;; C-x 6 2 same, sed kun 2C/ anta^u. the same, but with 2C/ | |
56 | ;; prepended. | |
57 | ||
58 | ;; f2 b asocias alian bufron. Vi povas associates another buffer. | |
59 | ;; C-x 6 b anka^u asocii dataron, se vi This can be used to associate a | |
60 | ;; ^jus anta^ue faris C-x C-f. file if you just did C-x C-f. | |
61 | ||
62 | ;; f2 s disigas jam dukolumnan tekston splits a two-column text into | |
63 | ;; C-x 6 s en du bufroj ekde la nuna two buffers from the current | |
64 | ;; linio, kaj je la nuna kolumno. line and at the current column. | |
65 | ;; La anta^uaj signoj (ofte The preceding characters (often | |
66 | ;; tabeligilo a^u |) estas la tab or |) are the column | |
67 | ;; kolumna disiganto. Linioj kiuj separator. Lines that don't | |
68 | ;; ne enhavas ilin ne estas have them won't be separated. | |
69 | ;; disigitaj. Kiel la kvara kaj Like the fourth and fifth line | |
70 | ;; la kvina linio se vi disigas if you split this file from | |
71 | ;; ^ci dataron ekde la unua angla the first english word. | |
72 | ;; vorto. | |
73 | ||
74 | ;; Se vi volas meti longajn liniojn If you include long lines, i.e which | |
75 | ;; (ekz. programerojn) en la kunigotan will span both columns (eg. source | |
76 | ;; tekston, ili devas esti en la code), they should be in what will | |
77 | ;; estonte unua kolumno. La alia devas be the first column, with the | |
78 | ;; havi vakajn linion apud ili. associated buffer having empty lines | |
79 | ;; next to them. | |
80 | ||
81 | ;; Averto: en Emacs kiam vi ^san^gas la Attention: in Emacs when you change | |
82 | ;; ^cefan modalon, la mal^cefaj modaloj the major mode, the minor modes are | |
83 | ;; estas anka^u elmemorigitaj. Tiu- also purged from memory. In that | |
84 | ;; okaze vi devas religi la du bufrojn case you must reassociate the two | |
85 | ;; per iu C-x 6-ordono, ekz. C-x 6 b. buffers with any C-x 6-command, e.g. | |
86 | ;; C-x 6 b. | |
87 | ||
88 | ;; Kiam vi estos kontenta de la When you have edited both buffers to | |
89 | ;; rezulto, vi kunmetos la du kolumnojn your content, you merge them with | |
90 | ;; per C-x 6 1. Se vi poste vidas C-x 6 1. If you then see a problem, | |
91 | ;; problemon, vi neniigu la kunmeton you undo the merge with C-x u and | |
92 | ;; per C-x u kaj plue modifu la du continue to edit the two buffers. | |
93 | ;; bufrojn. Kiam vi ne plu volas tajpi When you no longer want to edit in | |
94 | ;; dukolumne, vi eliru el la mal^cefa two columns, you turn off the minor | |
95 | ;; modalo per C-x 6 d. mode with C-x 6 d. | |
96 | ||
97 | ||
98 | ;; Aldone al dukolumna redaktado, ek- In addition to two-column editing of | |
99 | ;; zemple por skribi dulingvan tekston text, for example for writing a | |
100 | ;; flank-al-flanke kiel ^ci tiu, aliaj bilingual text side-by-side as shown | |
101 | ;; interesaj uzoj trovitas por tiu mal- here, other interesting uses have | |
102 | ;; ^cefa modalo: been found for this minor mode: | |
103 | ||
104 | ;; Vi povas disigi la kolumnojn per {+} You can separate the columns with | |
105 | ;; ajna pla^ca ^ceno starigante {+} any string that pleases you, by | |
106 | ;; `2C-separator'. Ekzemple "{+} " {+} setting `2C-separator'. For example | |
107 | ;; por amuzi^gi. f2 s a^u C-x 6 s {+} "{+} " if you'd like to have fun. | |
108 | ;; traktas tiujn kun prefiksa {+} f2 s or C-x 6 s handles these with a | |
109 | ;; argumento kiu signifas la longon {+} prefix argument that means the | |
110 | ;; de tia ^ceno. {+} desired length of such a string. | |
111 | ||
112 | ||
113 | ;; Programistoj eble ^satus la eblecon Programmers might like the ability | |
114 | ;; forspliti la komentarian kolumnon de to split off the comment column of a | |
115 | ;; dosiero kiel la sekvanta. Vi povas file that looks like the following. | |
116 | ;; rearan^gigi la paragrafon. La pro- You can fill-paragraph the comment. | |
117 | ;; blemo estas ke koda^jo tuj lar- The problem is, code quickly gets | |
118 | ;; ^gi^gas, tiel ke vi bezonas pli rather wide, so you need to use a | |
119 | ;; mallar^gan komentarian kolumnon. narrower comment column. Code lines | |
120 | ;; Koda^jaj linioj tra `comment-column' that reach beyond `comment-column' | |
121 | ;; ne problemas, krom ke vi ne vidos are no problem, except that you | |
122 | ;; iliajn finojn dum redaktado. won't see their end during editing. | |
123 | ||
124 | ||
72c0ae01 ER |
125 | ;; BEGIN -- This is just some meaningless |
126 | ;; FOR i IN 1..10 LOOP -- code in Ada, that runs foobar | |
e6b72410 | 127 | ;; foobar( i ); -- once for each argument from one |
72c0ae01 ER |
128 | ;; END LOOP; -- to ten, and then we're already |
129 | ;; END; -- through with it. | |
e6b72410 KH |
130 | |
131 | ;; Pli bone ankora^u, vi povas pozici- Better yet, you can put the point | |
132 | ;; i^gi anta^u "This", tajpi M-3 f2 s before "This", type M-3 f2 s | |
133 | ;; kiu igas "-- " la separigilon inter which makes "-- " the separator | |
134 | ;; senkomentaria Ada bufro kaj nur- between a no-comments Ada buffer, | |
135 | ;; teksta komentaria bufro. Kiam vi and a plain text comment buffer. | |
136 | ;; denove kuni^gos ilin, ^ciu nevaka When you put them back together, | |
137 | ;; linio de l' dua kolumno denove every non-empty line of the 2nd | |
138 | ;; anta^uhavos "-- ". column will again be preceded by | |
139 | ;; "-- ". | |
140 | ||
72c0ae01 ER |
141 | |
142 | ;;; Code: | |
143 | \f | |
e6b72410 KH |
144 | |
145 | ;; Lucid patch | |
146 | (or (fboundp 'frame-width) | |
147 | (fset 'frame-width 'screen-width)) | |
148 | ||
149 | ||
3bcbd523 | 150 | ;;;;; Set up keymap ;;;;; |
72c0ae01 | 151 | |
e6b72410 KH |
152 | (defvar 2C-mode-map |
153 | (let ((map (make-sparse-keymap))) | |
154 | (define-key map "2" '2C-two-columns) | |
155 | (define-key map [f2] '2C-two-columns) | |
156 | (define-key map "b" '2C-associate-buffer) | |
157 | (define-key map "s" '2C-split) | |
e6b72410 KH |
158 | map) |
159 | "Keymap for commands for setting up two-column mode.") | |
160 | ||
161 | ||
162 | ||
163 | ;;;###autoload (autoload '2C-command "two-column" () t 'keymap) | |
164 | (fset '2C-command 2C-mode-map) | |
72c0ae01 | 165 | |
e6b72410 KH |
166 | ;; This one is for historical reasons and simple keyboards, it is not |
167 | ;; at all mnemonic. All usual sequences containing 2 were used, and | |
168 | ;; f2 could not be set up in a standard way under Emacs 18. | |
2c02e313 | 169 | ;;;###autoload (global-set-key "\C-x6" '2C-command) |
e6b72410 | 170 | |
2c02e313 | 171 | ;;;###autoload (global-set-key [f2] '2C-command) |
e6b72410 KH |
172 | |
173 | ||
174 | (defvar 2C-minor-mode-map | |
175 | (let ((map (make-sparse-keymap))) | |
176 | (define-key map "1" '2C-merge) | |
177 | (define-key map "d" '2C-dissociate) | |
178 | (define-key map "o" '2C-associated-buffer) | |
8fe9ecef | 179 | (define-key map "\^m" '2C-newline) |
e6b72410 | 180 | (define-key map "|" '2C-toggle-autoscroll) |
30a7d33c KH |
181 | (define-key map "{" '2C-shrink-window-horizontally) |
182 | (define-key map "}" '2C-enlarge-window-horizontally) | |
e6b72410 KH |
183 | map) |
184 | "Keymap for commands for use in two-column mode.") | |
185 | ||
186 | ||
187 | (setq minor-mode-map-alist | |
188 | (cons (cons '2C-mode | |
189 | (let ((map (make-sparse-keymap))) | |
190 | (substitute-key-definition '2C-command 2C-minor-mode-map | |
191 | map (current-global-map)) | |
30a7d33c KH |
192 | (substitute-key-definition 'enlarge-window-horizontally |
193 | '2C-enlarge-window-horizontally | |
194 | map (current-global-map)) | |
195 | (substitute-key-definition 'shrink-window-horizontally | |
196 | '2C-shrink-window-horizontally | |
197 | map (current-global-map)) | |
e6b72410 KH |
198 | map)) |
199 | minor-mode-map-alist)) | |
3bcbd523 RS |
200 | \f |
201 | ;;;;; variable declarations ;;;;; | |
72c0ae01 | 202 | |
ded3e3d8 | 203 | (defgroup two-column nil |
5cbebcab | 204 | "Minor mode for editing of two-column text." |
ded3e3d8 RS |
205 | :prefix "2C-" |
206 | :group 'frames) | |
207 | ||
208 | ||
e6b72410 KH |
209 | ;; Markers seem to be the only buffer-id not affected by renaming a buffer. |
210 | ;; This nevertheless loses when a buffer is killed. The variable-name is | |
211 | ;; required by `describe-mode'. | |
212 | (defvar 2C-mode nil | |
72c0ae01 | 213 | "Marker to the associated buffer, if non-nil.") |
e6b72410 KH |
214 | (make-variable-buffer-local '2C-mode) |
215 | (put '2C-mode 'permanent-local t) | |
216 | ||
217 | ||
218 | ||
219 | (setq minor-mode-alist (cons '(2C-mode " 2C") minor-mode-alist)) | |
220 | ||
72c0ae01 | 221 | |
72c0ae01 ER |
222 | |
223 | ;; rearranged, so that the pertinent info will show in 40 columns | |
ded3e3d8 | 224 | (defcustom 2C-mode-line-format |
72c0ae01 | 225 | '("-%*- %15b --" (-3 . "%p") "--%[(" mode-name |
e6b72410 | 226 | minor-mode-alist "%n" mode-line-process ")%]%-") |
431328cc | 227 | "*Value of `mode-line-format' for a buffer in two-column minor mode." |
ded3e3d8 RS |
228 | :type 'sexp |
229 | :group 'two-column) | |
72c0ae01 | 230 | |
e6b72410 | 231 | |
ded3e3d8 RS |
232 | (defcustom 2C-other-buffer-hook 'text-mode |
233 | "*Hook run in new buffer when it is associated with current one." | |
234 | :type 'function | |
235 | :group 'two-column) | |
e6b72410 KH |
236 | |
237 | ||
ded3e3d8 | 238 | (defcustom 2C-separator "" |
72c0ae01 | 239 | "*A string inserted between the two columns when merging. |
ded3e3d8 RS |
240 | This gets set locally by \\[2C-split]." |
241 | :type 'string | |
242 | :group 'two-column) | |
e6b72410 KH |
243 | (put '2C-separator 'permanent-local t) |
244 | ||
245 | ||
72c0ae01 | 246 | |
ded3e3d8 | 247 | (defcustom 2C-window-width 40 |
72c0ae01 | 248 | "*The width of the first column. (Must be at least `window-min-width') |
ded3e3d8 RS |
249 | This value is local for every buffer that sets it." |
250 | :type 'integer | |
251 | :group 'two-column) | |
e6b72410 KH |
252 | (make-variable-buffer-local '2C-window-width) |
253 | (put '2C-window-width 'permanent-local t) | |
72c0ae01 | 254 | |
e6b72410 KH |
255 | |
256 | ||
ded3e3d8 | 257 | (defcustom 2C-beyond-fill-column 4 |
72c0ae01 | 258 | "*Base for calculating `fill-column' for a buffer in two-column minor mode. |
e6b72410 | 259 | The value of `fill-column' becomes `2C-window-width' for this buffer |
ded3e3d8 RS |
260 | minus this value." |
261 | :type 'integer | |
262 | :group 'two-column) | |
72c0ae01 | 263 | |
e6b72410 KH |
264 | |
265 | ||
ded3e3d8 RS |
266 | (defcustom 2C-autoscroll t |
267 | "If non-nil, Emacs attempts to keep the two column's buffers aligned." | |
268 | :type 'boolean | |
269 | :group 'two-column) | |
e6b72410 KH |
270 | |
271 | ||
272 | ||
273 | (defvar 2C-autoscroll-start nil) | |
274 | (make-variable-buffer-local '2C-autoscroll-start) | |
72c0ae01 ER |
275 | \f |
276 | ;;;;; base functions ;;;;; | |
277 | ||
e6b72410 | 278 | ;; The access method for the other buffer. This tries to remedy against |
72c0ae01 | 279 | ;; lost local variables and lost buffers. |
8fe9ecef KH |
280 | (defun 2C-other (&optional req) |
281 | (or (if 2C-mode | |
282 | (or (prog1 | |
283 | (marker-buffer 2C-mode) | |
284 | (setq mode-line-format 2C-mode-line-format)) | |
285 | ;; The associated buffer somehow got killed. | |
286 | (progn | |
287 | ;; The other variables may later be useful if the user | |
288 | ;; reestablishes the association. | |
289 | (kill-local-variable '2C-mode) | |
290 | (kill-local-variable 'mode-line-format) | |
291 | nil))) | |
e8af40ee | 292 | (if req (error "You must first set two-column minor mode")))) |
72c0ae01 | 293 | |
72c0ae01 | 294 | |
72c0ae01 | 295 | |
e6b72410 KH |
296 | ;; function for setting up two-column minor mode in a buffer associated |
297 | ;; with the buffer pointed to by the marker other. | |
298 | (defun 2C-mode (other) | |
299 | "Minor mode for independently editing two columns. | |
300 | This is set up for two associated buffers by the three commands bound | |
301 | to \\[2C-two-columns] , \\[2C-associate-buffer] and \\[2C-split]. | |
302 | Turning on two-column mode calls the value of the variable `2C-mode-hook', | |
303 | if that value is non-nil. | |
304 | ||
305 | These buffers can be edited separately, for example with `fill-paragraph'. | |
306 | If you want to disable parallel scrolling temporarily, use \\[2C-toggle-autoscroll] . | |
72c0ae01 ER |
307 | |
308 | If you include long lines, i.e which will span both columns (eg. | |
309 | source code), they should be in what will be the first column, with | |
310 | the associated buffer having empty lines next to them. | |
311 | ||
e6b72410 KH |
312 | Potential uses are writing bilingual texts, or editing the comments of a |
313 | source code. See the file lisp/two-column.el for detailed examples. | |
314 | ||
72c0ae01 ER |
315 | You have the following commands at your disposal: |
316 | ||
e6b72410 KH |
317 | \\[2C-two-columns] Rearrange screen with current buffer first |
318 | \\[2C-associate-buffer] Reassociate buffer after changing major mode | |
72c0ae01 | 319 | \\[shrink-window-horizontally], \\[enlarge-window-horizontally] Shrink, enlarge current column |
8fe9ecef KH |
320 | \\[2C-associated-buffer] Switch to associated buffer at same point |
321 | \\[2C-newline] Insert newline(s) in both buffers at same point | |
e6b72410 KH |
322 | \\[2C-merge] Merge both buffers |
323 | \\[2C-dissociate] Dissociate the two buffers | |
72c0ae01 | 324 | |
e6b72410 KH |
325 | These keybindings can be customized in your ~/.emacs by `2C-mode-map', |
326 | `2C-minor-mode-map' and by binding `2C-command' to some prefix. | |
72c0ae01 ER |
327 | |
328 | The appearance of the screen can be customized by the variables | |
e6b72410 KH |
329 | `2C-window-width', `2C-beyond-fill-column', `2C-mode-line-format' and |
330 | `truncate-partial-width-windows'." | |
5181be3a | 331 | (add-hook 'post-command-hook '2C-autoscroll nil t) |
e6b72410 KH |
332 | (setq fill-column (- 2C-window-width |
333 | 2C-beyond-fill-column) | |
e6b72410 KH |
334 | mode-line-format 2C-mode-line-format |
335 | 2C-mode other) | |
336 | (run-hooks '2C-mode-hook)) | |
337 | ||
338 | ||
72c0ae01 | 339 | |
e6b72410 KH |
340 | ;;;###autoload |
341 | (defun 2C-two-columns (&optional buffer) | |
342 | "Split current window vertically for two-column editing. | |
343 | When called the first time, associates a buffer with the current | |
344 | buffer in two-column minor mode (see \\[describe-mode] ). | |
345 | Runs `2C-other-buffer-hook' in the new buffer. | |
346 | When called again, restores the screen layout with the current buffer | |
17c3470e | 347 | first and the associated buffer to its right." |
72c0ae01 | 348 | (interactive "P") |
e6b72410 | 349 | ;; first go to full width, so that we can certainly split into two windows |
3bcbd523 | 350 | (if (< (window-width) (frame-width)) |
72c0ae01 ER |
351 | (enlarge-window 99999 t)) |
352 | (split-window-horizontally | |
e6b72410 | 353 | (max window-min-width (min 2C-window-width |
3bcbd523 | 354 | (- (frame-width) window-min-width)))) |
e6b72410 | 355 | (if (2C-other) |
72c0ae01 ER |
356 | (progn |
357 | (other-window 1) | |
e6b72410 | 358 | (switch-to-buffer (2C-other)) |
72c0ae01 | 359 | (other-window -1) |
e6b72410 KH |
360 | (if 2C-autoscroll |
361 | (2C-toggle-autoscroll t))) | |
362 | ||
363 | (2C-mode (prog1 (point-marker) | |
364 | (other-window 1) | |
365 | (switch-to-buffer | |
366 | (or buffer | |
8fe9ecef | 367 | (generate-new-buffer (concat "2C/" (buffer-name))))) |
e6b72410 KH |
368 | (or buffer |
369 | (run-hooks '2C-other-buffer-hook)))) | |
eaae8106 | 370 | |
e6b72410 KH |
371 | (2C-mode (prog1 (point-marker) |
372 | (other-window -1))))) | |
373 | ||
374 | ||
72c0ae01 | 375 | |
6f5191a2 | 376 | ;;;###autoload |
e6b72410 | 377 | (defun 2C-associate-buffer () |
72c0ae01 ER |
378 | "Associate another buffer with this one in two-column minor mode. |
379 | Can also be used to associate a just previously visited file, by | |
380 | accepting the proposed default buffer. | |
381 | ||
e6b72410 | 382 | \(See \\[describe-mode] .)" |
72c0ae01 ER |
383 | (interactive) |
384 | (let ((b1 (current-buffer)) | |
e6b72410 | 385 | (b2 (or (2C-other) |
72c0ae01 ER |
386 | (read-buffer "Associate buffer: " (other-buffer))))) |
387 | (save-excursion | |
e6b72410 | 388 | (setq 2C-mode nil) |
72c0ae01 | 389 | (set-buffer b2) |
e6b72410 KH |
390 | (and (2C-other) |
391 | (not (eq b1 (2C-other))) | |
e8af40ee | 392 | (error "Buffer already associated with buffer `%s'" |
e6b72410 KH |
393 | (buffer-name (2C-other)))) |
394 | (setq b1 (and (assq '2C-window-width (buffer-local-variables)) | |
395 | 2C-window-width))) | |
72c0ae01 | 396 | ; if other buffer has a local width, adjust here too |
e6b72410 KH |
397 | (if b1 (setq 2C-window-width (- (frame-width) b1))) |
398 | (2C-two-columns b2))) | |
399 | ||
400 | ||
72c0ae01 | 401 | |
6f5191a2 | 402 | ;;;###autoload |
e6b72410 KH |
403 | (defun 2C-split (arg) |
404 | "Split a two-column text at point, into two buffers in two-column minor mode. | |
405 | Point becomes the local value of `2C-window-width'. Only lines that | |
406 | have the ARG same preceding characters at that column get split. The | |
407 | ARG preceding characters without any leading whitespace become the local | |
408 | value for `2C-separator'. This way lines that continue across both | |
72c0ae01 ER |
409 | columns remain untouched in the first buffer. |
410 | ||
e6b72410 KH |
411 | This function can be used with a prototype line, to set up things. You |
412 | write the first line of each column and then split that line. E.g.: | |
72c0ae01 | 413 | |
e6b72410 | 414 | First column's text sSs Second column's text |
72c0ae01 ER |
415 | \\___/\\ |
416 | / \\ | |
e6b72410 | 417 | 5 character Separator You type M-5 \\[2C-split] with the point here. |
72c0ae01 | 418 | |
e6b72410 KH |
419 | \(See \\[describe-mode] .)" |
420 | (interactive "*p") | |
421 | (and (2C-other) | |
72c0ae01 | 422 | (if (y-or-n-p (concat "Overwrite associated buffer `" |
e6b72410 | 423 | (buffer-name (2C-other)) |
72c0ae01 ER |
424 | "'? ")) |
425 | (save-excursion | |
e6b72410 | 426 | (set-buffer (2C-other)) |
72c0ae01 ER |
427 | (erase-buffer)) |
428 | (signal 'quit nil))) | |
429 | (let ((point (point)) | |
430 | ; make next-line always come back to same column | |
431 | (goal-column (current-column)) | |
432 | ; a counter for empty lines in other buffer | |
433 | (n (1- (count-lines (point-min) (point)))) | |
434 | chars other) | |
435 | (save-excursion | |
436 | (backward-char arg) | |
437 | (setq chars (buffer-substring (point) point)) | |
438 | (skip-chars-forward " \t" point) | |
e6b72410 KH |
439 | (make-local-variable '2C-separator) |
440 | (setq 2C-separator (buffer-substring (point) point) | |
441 | 2C-window-width (current-column))) | |
442 | (2C-two-columns) | |
443 | (setq other (2C-other)) | |
444 | ; now we're ready to actually split | |
72c0ae01 ER |
445 | (save-excursion |
446 | (while (not (eobp)) | |
447 | (if (not (and (= (current-column) goal-column) | |
448 | (string= chars | |
449 | (buffer-substring (point) | |
450 | (save-excursion | |
451 | (backward-char arg) | |
452 | (point)))))) | |
453 | (setq n (1+ n)) | |
454 | (setq point (point)) | |
455 | (backward-char arg) | |
456 | (skip-chars-backward " \t") | |
457 | (delete-region point (point)) | |
458 | (setq point (point)) | |
459 | (insert-char ?\n n) | |
460 | (append-to-buffer other point (progn (end-of-line) | |
461 | (if (eobp) | |
462 | (point) | |
463 | (1+ (point))))) | |
464 | (delete-region point (point)) | |
465 | (setq n 0)) | |
466 | (next-line 1))))) | |
467 | ||
e6b72410 KH |
468 | |
469 | ||
470 | ||
471 | (defun 2C-dissociate () | |
72c0ae01 ER |
472 | "Turn off two-column minor mode in current and associated buffer. |
473 | If the associated buffer is unmodified and empty, it is killed." | |
474 | (interactive) | |
475 | (let ((buffer (current-buffer))) | |
476 | (save-excursion | |
e6b72410 KH |
477 | (and (2C-other) |
478 | (set-buffer (2C-other)) | |
479 | (or (not (2C-other)) | |
480 | (eq buffer (2C-other))) | |
72c0ae01 ER |
481 | (if (and (not (buffer-modified-p)) |
482 | (eobp) (bobp)) | |
483 | (kill-buffer nil) | |
e6b72410 KH |
484 | (kill-local-variable '2C-mode) |
485 | (kill-local-variable '2C-window-width) | |
486 | (kill-local-variable '2C-separator) | |
72c0ae01 ER |
487 | (kill-local-variable 'mode-line-format) |
488 | (kill-local-variable 'fill-column)))) | |
e6b72410 KH |
489 | (kill-local-variable '2C-mode) |
490 | (kill-local-variable '2C-window-width) | |
491 | (kill-local-variable '2C-separator) | |
72c0ae01 ER |
492 | (kill-local-variable 'mode-line-format) |
493 | (kill-local-variable 'fill-column))) | |
494 | ||
495 | ||
e6b72410 | 496 | |
72c0ae01 ER |
497 | ;; this doesn't use yank-rectangle, so that the first column can |
498 | ;; contain long lines | |
e6b72410 | 499 | (defun 2C-merge () |
72c0ae01 | 500 | "Merges the associated buffer with the current buffer. |
e6b72410 KH |
501 | They get merged at the column, which is the value of `2C-window-width', |
502 | i.e. usually at the vertical window separator. This separator gets | |
503 | replaced with white space. Beyond that the value of `2C-separator' gets | |
504 | inserted on merged lines. The two columns are thus pasted side by side, | |
505 | in a single text. If the other buffer is not displayed to the left of | |
506 | this one, then this one becomes the left column. | |
507 | ||
508 | If you want `2C-separator' on empty lines in the second column, | |
72c0ae01 | 509 | you should put just one space in them. In the final result, you can strip |
eaae8106 | 510 | off trailing spaces with \\[delete-trailing-whitespace]." |
72c0ae01 | 511 | (interactive) |
72c0ae01 ER |
512 | (and (> (car (window-edges)) 0) ; not touching left edge of screen |
513 | (eq (window-buffer (previous-window)) | |
8fe9ecef | 514 | (2C-other t)) |
72c0ae01 ER |
515 | (other-window -1)) |
516 | (save-excursion | |
517 | (let ((b1 (current-buffer)) | |
8fe9ecef | 518 | (b2 (2C-other t)) |
72c0ae01 ER |
519 | string) |
520 | (goto-char (point-min)) | |
521 | (set-buffer b2) | |
522 | (goto-char (point-min)) | |
523 | (while (not (eobp)) | |
524 | (setq string (buffer-substring (point) | |
525 | (progn (end-of-line) (point)))) | |
526 | (or (eobp) | |
527 | (forward-char)) ; next line | |
528 | (set-buffer b1) | |
529 | (if (string= string "") | |
530 | () | |
531 | (end-of-line) | |
e6b72410 KH |
532 | (indent-to-column 2C-window-width) |
533 | (insert 2C-separator string)) | |
72c0ae01 ER |
534 | (next-line 1) ; add one if necessary |
535 | (set-buffer b2)))) | |
3bcbd523 | 536 | (if (< (window-width) (frame-width)) |
72c0ae01 ER |
537 | (enlarge-window 99999 t))) |
538 | \f | |
539 | ;;;;; utility functions ;;;;; | |
540 | ||
e6b72410 | 541 | (defun 2C-associated-buffer () |
72c0ae01 ER |
542 | "Switch to associated buffer." |
543 | (interactive) | |
8fe9ecef KH |
544 | (let ((line (+ (count-lines (point-min) (point)) |
545 | (if (bolp) 1 0))) | |
546 | (col (if (eolp) (if (bolp) 0) (current-column)))) | |
547 | (if (get-buffer-window (2C-other t)) | |
548 | (select-window (get-buffer-window (2C-other))) | |
549 | (switch-to-buffer (2C-other))) | |
550 | (newline (goto-line line)) | |
551 | (if col | |
552 | (move-to-column col) | |
553 | (end-of-line 1)))) | |
554 | ||
555 | (defun 2C-newline (arg) | |
556 | "Insert ARG newlines in both buffers." | |
557 | (interactive "P") | |
558 | (save-window-excursion | |
559 | (2C-associated-buffer) | |
560 | (newline arg)) | |
561 | (newline arg)) | |
72c0ae01 | 562 | |
e6b72410 KH |
563 | (defun 2C-toggle-autoscroll (arg) |
564 | "Toggle autoscrolling, or set it iff prefix ARG is non-nil and positive. | |
565 | When autoscrolling is turned on, this also realigns the two buffers." | |
72c0ae01 | 566 | (interactive "P") |
8fe9ecef | 567 | ;(sit-for 0) |
e6b72410 KH |
568 | (setq 2C-autoscroll-start (window-start)) |
569 | (if (setq 2C-autoscroll (if arg | |
570 | (>= (prefix-numeric-value arg) 0) | |
571 | (not 2C-autoscroll))) | |
572 | (select-window | |
573 | (prog1 (selected-window) | |
574 | (message "Autoscrolling is on.") | |
e6b72410 | 575 | (setq arg (count-lines (point-min) (window-start))) |
8fe9ecef | 576 | (if (get-buffer-window (2C-other t)) |
e6b72410 KH |
577 | (progn |
578 | (select-window (get-buffer-window (2C-other))) | |
579 | (setq arg (- arg (count-lines (point-min) (window-start)))) | |
580 | ;; make sure that other buffer has enough lines | |
581 | (save-excursion | |
582 | (insert-char ?\n | |
583 | (- arg (count-lines (window-start) | |
584 | (goto-char (point-max))) | |
585 | -1))) | |
586 | (scroll-up arg))))) | |
587 | (message "Autoscrolling is off."))) | |
588 | ||
589 | ||
590 | ||
591 | (defun 2C-autoscroll () | |
592 | (if 2C-autoscroll | |
593 | ;; catch a mouse scroll on non-selected scrollbar | |
594 | (select-window | |
595 | (prog1 (selected-window) | |
596 | (and (consp last-command-char) | |
597 | (not (eq (selected-window) | |
598 | (car (car (cdr last-command-char))))) | |
599 | (select-window (car (car (cdr last-command-char))))) | |
600 | ;; In some cases scrolling causes an error, but post-command-hook | |
601 | ;; shouldn't, and should always stay in the original window | |
602 | (condition-case () | |
603 | (and (or 2C-autoscroll-start (2C-toggle-autoscroll t) nil) | |
604 | (/= (window-start) 2C-autoscroll-start) | |
605 | (2C-other) | |
606 | (get-buffer-window (2C-other)) | |
607 | (let ((lines (count-lines (window-start) | |
608 | 2C-autoscroll-start))) | |
609 | (if (< (window-start) 2C-autoscroll-start) | |
610 | (setq lines (- lines))) | |
611 | (setq 2C-autoscroll-start (window-start)) | |
612 | (select-window (get-buffer-window (2C-other))) | |
613 | ;; make sure that other buffer has enough lines | |
614 | (save-excursion | |
615 | (insert-char | |
616 | ?\n (- lines (count-lines (window-start) | |
617 | (goto-char (point-max))) | |
618 | -1))) | |
619 | (scroll-up lines) | |
620 | (setq 2C-autoscroll-start (window-start)))) | |
621 | (error)))))) | |
622 | ||
623 | ||
72c0ae01 | 624 | |
30a7d33c | 625 | (defun 2C-enlarge-window-horizontally (arg) |
72c0ae01 ER |
626 | "Make current window ARG columns wider." |
627 | (interactive "p") | |
628 | (enlarge-window arg t) | |
e6b72410 KH |
629 | (and (2C-other) |
630 | (setq 2C-window-width (+ 2C-window-width arg)) | |
631 | (set-buffer (2C-other)) | |
632 | (setq 2C-window-width (- 2C-window-width arg)))) | |
72c0ae01 | 633 | |
30a7d33c | 634 | (defun 2C-shrink-window-horizontally (arg) |
72c0ae01 ER |
635 | "Make current window ARG columns narrower." |
636 | (interactive "p") | |
30a7d33c | 637 | (2C-enlarge-window-horizontally (- arg))) |
72c0ae01 | 638 | |
e6b72410 KH |
639 | |
640 | ||
3bcbd523 RS |
641 | (provide 'two-column) |
642 | ||
ab5796a9 | 643 | ;;; arch-tag: 2021b5ab-d3a4-4a8c-a21c-1936b0f9e6b1 |
72c0ae01 | 644 | ;;; two-column.el ends here |