Bind `C-v' to `scroll-up-command' and `M-v' to `scroll-down-command'.
[bpt/emacs.git] / lisp / emulation / cua-rect.el
CommitLineData
72cc582e
KS
1;;; cua-rect.el --- CUA unified rectangle support
2
5fd6d89f 3;; Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
114f9c96 4;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
72cc582e
KS
5
6;; Author: Kim F. Storm <storm@cua.dk>
7;; Keywords: keyboard emulations convenience CUA
8
9;; This file is part of GNU Emacs.
10
ed0f493f 11;; GNU Emacs is free software: you can redistribute it and/or modify
72cc582e 12;; it under the terms of the GNU General Public License as published by
ed0f493f
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
72cc582e
KS
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
ed0f493f 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
72cc582e
KS
23
24;;; Acknowledgements
25
26;; The rectangle handling and display code borrows from the standard
aa87aafc 27;; GNU emacs rect.el package and the rect-mark.el package by Rick
72cc582e
KS
28;; Sladkey <jrs@world.std.com>.
29
30764597
PJ
30;;; Commentary:
31
32;;; Code:
33
72cc582e 34(eval-when-compile
2c0f8564 35 (require 'cua-base))
72cc582e
KS
36
37;;; Rectangle support
38
39(require 'rect)
40
41;; If non-nil, restrict current region to this rectangle.
72797108 42;; Value is a vector [top bot left right corner ins virt select].
72cc582e
KS
43;; CORNER specifies currently active corner 0=t/l 1=t/r 2=b/l 3=b/r.
44;; INS specifies whether to insert on left(nil) or right(t) side.
72797108 45;; If VIRT is non-nil, virtual straight edges are enabled.
72cc582e
KS
46;; If SELECT is a regexp, only lines starting with that regexp are affected.")
47(defvar cua--rectangle nil)
48(make-variable-buffer-local 'cua--rectangle)
49
50;; Most recent rectangle geometry. Note: car is buffer.
51(defvar cua--last-rectangle nil)
52
53;; Rectangle restored by undo.
54(defvar cua--restored-rectangle nil)
55
56;; Last rectangle copied/killed; nil if last kill was not a rectangle.
57(defvar cua--last-killed-rectangle nil)
58
59;; List of overlays used to display current rectangle.
60(defvar cua--rectangle-overlays nil)
61(make-variable-buffer-local 'cua--rectangle-overlays)
c0e4cc19 62(put 'cua--rectangle-overlays 'permanent-local t)
72cc582e 63
1e71278b
KS
64(defvar cua--overlay-keymap
65 (let ((map (make-sparse-keymap)))
66 (define-key map "\r" 'cua-rotate-rectangle)))
67
72797108
KS
68(defvar cua--virtual-edges-debug nil)
69
e4907bbe
KS
70;; Undo rectangle commands.
71
72(defvar cua--rect-undo-set-point nil)
72cc582e 73
72cc582e
KS
74(defun cua--rectangle-undo-boundary ()
75 (when (listp buffer-undo-list)
e4907bbe
KS
76 (let ((s (cua--rect-start-position))
77 (e (cua--rect-end-position)))
78 (undo-boundary)
79 (push (list 'apply 0 s e
80 'cua--rect-undo-handler
81 (copy-sequence cua--rectangle) t s e)
82 buffer-undo-list))))
83
84(defun cua--rect-undo-handler (rect on s e)
85 (if (setq on (not on))
86 (setq cua--rect-undo-set-point s)
87 (setq cua--restored-rectangle (copy-sequence rect))
88 (setq cua--buffer-and-point-before-command nil))
89 (push (list 'apply 0 s (if on e s)
90 'cua--rect-undo-handler rect on s e)
91 buffer-undo-list))
72cc582e
KS
92
93;;; Rectangle geometry
94
95(defun cua--rectangle-top (&optional val)
96 ;; Top of CUA rectangle (buffer position on first line).
97 (if (not val)
98 (aref cua--rectangle 0)
99 (setq val (line-beginning-position))
100 (if (<= val (aref cua--rectangle 1))
101 (aset cua--rectangle 0 val)
102 (aset cua--rectangle 1 val)
103 (cua--rectangle-corner 2))))
104
105(defun cua--rectangle-bot (&optional val)
106 ;; Bot of CUA rectangle (buffer position on last line).
107 (if (not val)
108 (aref cua--rectangle 1)
109 (setq val (line-end-position))
110 (if (>= val (aref cua--rectangle 0))
111 (aset cua--rectangle 1 val)
112 (aset cua--rectangle 0 val)
113 (cua--rectangle-corner 2))))
114
115(defun cua--rectangle-left (&optional val)
116 ;; Left column of CUA rectangle.
117 (if (integerp val)
118 (if (<= val (aref cua--rectangle 3))
119 (aset cua--rectangle 2 val)
120 (aset cua--rectangle 3 val)
121 (cua--rectangle-corner (if (cua--rectangle-right-side) -1 1)))
122 (aref cua--rectangle 2)))
123
124(defun cua--rectangle-right (&optional val)
125 ;; Right column of CUA rectangle.
126 (if (integerp val)
127 (if (>= val (aref cua--rectangle 2))
128 (aset cua--rectangle 3 val)
129 (aset cua--rectangle 2 val)
130 (cua--rectangle-corner (if (cua--rectangle-right-side) -1 1)))
131 (aref cua--rectangle 3)))
132
133(defun cua--rectangle-corner (&optional advance)
134 ;; Currently active corner of rectangle.
135 (let ((c (aref cua--rectangle 4)))
136 (if (not (integerp advance))
137 c
a1506d29 138 (aset cua--rectangle 4
72cc582e
KS
139 (if (= advance 0)
140 (- 3 c) ; opposite corner
141 (mod (+ c 4 advance) 4)))
142 (aset cua--rectangle 5 0))))
143
144(defun cua--rectangle-right-side (&optional topbot)
145 ;; t if point is on right side of rectangle.
146 (if (and topbot (= (cua--rectangle-left) (cua--rectangle-right)))
147 (< (cua--rectangle-corner) 2)
148 (= (mod (cua--rectangle-corner) 2) 1)))
149
150(defun cua--rectangle-column ()
151 (if (cua--rectangle-right-side)
152 (cua--rectangle-right)
153 (cua--rectangle-left)))
154
155(defun cua--rectangle-insert-col (&optional col)
156 ;; Currently active corner of rectangle.
157 (if (integerp col)
158 (aset cua--rectangle 5 col)
159 (if (cua--rectangle-right-side t)
160 (if (= (aref cua--rectangle 5) 0)
161 (1+ (cua--rectangle-right))
162 (aref cua--rectangle 5))
163 (cua--rectangle-left))))
164
72797108
KS
165(defun cua--rectangle-virtual-edges (&optional set val)
166 ;; Current setting of rectangle virtual-edges
72cc582e
KS
167 (if set
168 (aset cua--rectangle 6 val))
72797108 169 (and ;(not buffer-read-only)
72cc582e
KS
170 (aref cua--rectangle 6)))
171
172(defun cua--rectangle-restriction (&optional val bounded negated)
173 ;; Current rectangle restriction
174 (if val
175 (aset cua--rectangle 7
176 (and (stringp val)
177 (> (length val) 0)
178 (list val bounded negated)))
179 (aref cua--rectangle 7)))
180
181(defun cua--rectangle-assert ()
182 (message "%S (%d)" cua--rectangle (point))
183 (if (< (cua--rectangle-right) (cua--rectangle-left))
184 (message "rectangle right < left"))
185 (if (< (cua--rectangle-bot) (cua--rectangle-top))
186 (message "rectangle bot < top")))
187
72797108 188(defun cua--rectangle-get-corners ()
72cc582e
KS
189 ;; Calculate the rectangular region represented by point and mark,
190 ;; putting start in the upper left corner and end in the
191 ;; bottom right corner.
192 (let ((top (point)) (bot (mark)) r l corner)
193 (save-excursion
194 (goto-char top)
195 (setq l (current-column))
196 (goto-char bot)
197 (setq r (current-column))
198 (if (<= top bot)
199 (setq corner (if (<= l r) 0 1))
200 (setq top (prog1 bot (setq bot top)))
201 (setq corner (if (<= l r) 2 3)))
202 (if (<= l r)
203 (if (< l r)
204 (setq r (1- r)))
205 (setq l (prog1 r (setq r l)))
206 (goto-char top)
72797108 207 (move-to-column l)
72cc582e
KS
208 (setq top (point))
209 (goto-char bot)
72797108 210 (move-to-column r)
72cc582e 211 (setq bot (point))))
72797108 212 (vector top bot l r corner 0 cua-virtual-rectangle-edges nil)))
72cc582e
KS
213
214(defun cua--rectangle-set-corners ()
215 ;; Set mark and point in opposite corners of current rectangle.
216 (let (pp pc mp mc (c (cua--rectangle-corner)))
217 (cond
218 ((= c 0) ; top/left -> bot/right
219 (setq pp (cua--rectangle-top) pc (cua--rectangle-left)
220 mp (cua--rectangle-bot) mc (cua--rectangle-right)))
221 ((= c 1) ; top/right -> bot/left
222 (setq pp (cua--rectangle-top) pc (cua--rectangle-right)
223 mp (cua--rectangle-bot) mc (cua--rectangle-left)))
224 ((= c 2) ; bot/left -> top/right
225 (setq pp (cua--rectangle-bot) pc (cua--rectangle-left)
226 mp (cua--rectangle-top) mc (cua--rectangle-right)))
227 ((= c 3) ; bot/right -> top/left
228 (setq pp (cua--rectangle-bot) pc (cua--rectangle-right)
229 mp (cua--rectangle-top) mc (cua--rectangle-left))))
230 (goto-char mp)
72797108 231 (move-to-column mc)
72cc582e
KS
232 (set-mark (point))
233 (goto-char pp)
1e71278b 234 ;; Move cursor inside rectangle, except if char at rigth edge is a tab.
e2ea72e9 235 (if (and (if (cua--rectangle-right-side)
1e71278b
KS
236 (and (= (move-to-column pc) (- pc tab-width))
237 (not (eolp)))
e2ea72e9
KS
238 (> (move-to-column pc) pc))
239 (not (bolp)))
240 (backward-char 1))
72797108 241 ))
72cc582e 242
e4907bbe
KS
243(defun cua--rect-start-position ()
244 ;; Return point of top left corner
245 (save-excursion
246 (goto-char (cua--rectangle-top))
247 (and (> (move-to-column (cua--rectangle-left))
248 (cua--rectangle-left))
249 (not (bolp))
250 (backward-char 1))
251 (point)))
252
253(defun cua--rect-end-position ()
254 ;; Return point of bottom right cornet
255 (save-excursion
256 (goto-char (cua--rectangle-bot))
257 (and (= (move-to-column (cua--rectangle-right))
258 (- (cua--rectangle-right) tab-width))
259 (not (eolp))
260 (not (bolp))
261 (backward-char 1))
262 (point)))
263
72cc582e
KS
264;;; Rectangle resizing
265
72797108 266(defun cua--forward-line (n)
72cc582e 267 ;; Move forward/backward one line. Returns t if movement.
1e71278b
KS
268 (let ((pt (point)))
269 (and (= (forward-line n) 0)
270 ;; Deal with end of buffer
271 (or (not (eobp))
272 (goto-char pt)))))
72cc582e
KS
273
274(defun cua--rectangle-resized ()
275 ;; Refresh state after resizing rectangle
276 (setq cua--buffer-and-point-before-command nil)
72cc582e
KS
277 (cua--rectangle-insert-col 0)
278 (cua--rectangle-set-corners)
279 (cua--keep-active))
280
281(defun cua-resize-rectangle-right (n)
282 "Resize rectangle to the right."
283 (interactive "p")
72797108 284 (let ((resized (> n 0)))
72cc582e
KS
285 (while (> n 0)
286 (setq n (1- n))
287 (cond
72cc582e 288 ((cua--rectangle-right-side)
72797108
KS
289 (cua--rectangle-right (1+ (cua--rectangle-right)))
290 (move-to-column (cua--rectangle-right)))
72cc582e 291 (t
72797108
KS
292 (cua--rectangle-left (1+ (cua--rectangle-left)))
293 (move-to-column (cua--rectangle-right)))))
72cc582e
KS
294 (if resized
295 (cua--rectangle-resized))))
296
297(defun cua-resize-rectangle-left (n)
298 "Resize rectangle to the left."
299 (interactive "p")
72797108 300 (let (resized)
72cc582e
KS
301 (while (> n 0)
302 (setq n (1- n))
303 (if (or (= (cua--rectangle-right) 0)
304 (and (not (cua--rectangle-right-side)) (= (cua--rectangle-left) 0)))
305 (setq n 0)
306 (cond
72cc582e 307 ((cua--rectangle-right-side)
72797108
KS
308 (cua--rectangle-right (1- (cua--rectangle-right)))
309 (move-to-column (cua--rectangle-right)))
72cc582e 310 (t
72797108
KS
311 (cua--rectangle-left (1- (cua--rectangle-left)))
312 (move-to-column (cua--rectangle-right))))
72cc582e
KS
313 (setq resized t)))
314 (if resized
315 (cua--rectangle-resized))))
316
317(defun cua-resize-rectangle-down (n)
318 "Resize rectangle downwards."
319 (interactive "p")
72797108 320 (let (resized)
72cc582e
KS
321 (while (> n 0)
322 (setq n (1- n))
323 (cond
324 ((>= (cua--rectangle-corner) 2)
325 (goto-char (cua--rectangle-bot))
72797108
KS
326 (when (cua--forward-line 1)
327 (move-to-column (cua--rectangle-column))
72cc582e
KS
328 (cua--rectangle-bot t)
329 (setq resized t)))
330 (t
331 (goto-char (cua--rectangle-top))
72797108
KS
332 (when (cua--forward-line 1)
333 (move-to-column (cua--rectangle-column))
72cc582e
KS
334 (cua--rectangle-top t)
335 (setq resized t)))))
336 (if resized
337 (cua--rectangle-resized))))
338
339(defun cua-resize-rectangle-up (n)
340 "Resize rectangle upwards."
341 (interactive "p")
72797108 342 (let (resized)
72cc582e
KS
343 (while (> n 0)
344 (setq n (1- n))
345 (cond
346 ((>= (cua--rectangle-corner) 2)
347 (goto-char (cua--rectangle-bot))
72797108
KS
348 (when (cua--forward-line -1)
349 (move-to-column (cua--rectangle-column))
72cc582e
KS
350 (cua--rectangle-bot t)
351 (setq resized t)))
352 (t
353 (goto-char (cua--rectangle-top))
72797108
KS
354 (when (cua--forward-line -1)
355 (move-to-column (cua--rectangle-column))
72cc582e
KS
356 (cua--rectangle-top t)
357 (setq resized t)))))
358 (if resized
359 (cua--rectangle-resized))))
360
361(defun cua-resize-rectangle-eol ()
362 "Resize rectangle to end of line."
363 (interactive)
364 (unless (eolp)
365 (end-of-line)
366 (if (> (current-column) (cua--rectangle-right))
367 (cua--rectangle-right (current-column)))
368 (if (not (cua--rectangle-right-side))
369 (cua--rectangle-corner 1))
370 (cua--rectangle-resized)))
371
372(defun cua-resize-rectangle-bol ()
373 "Resize rectangle to beginning of line."
374 (interactive)
375 (unless (bolp)
376 (beginning-of-line)
377 (cua--rectangle-left (current-column))
378 (if (cua--rectangle-right-side)
379 (cua--rectangle-corner -1))
380 (cua--rectangle-resized)))
381
382(defun cua-resize-rectangle-bot ()
383 "Resize rectangle to bottom of buffer."
384 (interactive)
385 (goto-char (point-max))
72797108 386 (move-to-column (cua--rectangle-column))
72cc582e
KS
387 (cua--rectangle-bot t)
388 (cua--rectangle-resized))
389
390(defun cua-resize-rectangle-top ()
391 "Resize rectangle to top of buffer."
392 (interactive)
393 (goto-char (point-min))
72797108 394 (move-to-column (cua--rectangle-column))
72cc582e
KS
395 (cua--rectangle-top t)
396 (cua--rectangle-resized))
397
398(defun cua-resize-rectangle-page-up ()
399 "Resize rectangle upwards by one scroll page."
400 (interactive)
72797108
KS
401 (scroll-down)
402 (move-to-column (cua--rectangle-column))
403 (if (>= (cua--rectangle-corner) 2)
404 (cua--rectangle-bot t)
405 (cua--rectangle-top t))
406 (cua--rectangle-resized))
72cc582e
KS
407
408(defun cua-resize-rectangle-page-down ()
409 "Resize rectangle downwards by one scroll page."
410 (interactive)
72797108
KS
411 (scroll-up)
412 (move-to-column (cua--rectangle-column))
413 (if (>= (cua--rectangle-corner) 2)
414 (cua--rectangle-bot t)
415 (cua--rectangle-top t))
416 (cua--rectangle-resized))
72cc582e
KS
417
418;;; Mouse support
419
420;; This is pretty simplistic, but it does the job...
421
422(defun cua-mouse-resize-rectangle (event)
423 "Set rectangle corner at mouse click position."
424 (interactive "e")
425 (mouse-set-point event)
72797108
KS
426 ;; FIX ME -- need to calculate virtual column.
427 (if (cua--rectangle-virtual-edges)
72cc582e
KS
428 (move-to-column (car (posn-col-row (event-end event))) t))
429 (if (cua--rectangle-right-side)
430 (cua--rectangle-right (current-column))
431 (cua--rectangle-left (current-column)))
432 (if (>= (cua--rectangle-corner) 2)
433 (cua--rectangle-bot t)
434 (cua--rectangle-top t))
435 (cua--rectangle-resized))
436
437(defvar cua--mouse-last-pos nil)
438
439(defun cua-mouse-set-rectangle-mark (event)
440 "Start rectangle at mouse click position."
441 (interactive "e")
442 (when cua--rectangle
443 (cua--deactivate-rectangle)
444 (cua--deactivate t))
445 (setq cua--last-rectangle nil)
446 (mouse-set-point event)
72797108 447 ;; FIX ME -- need to calculate virtual column.
72cc582e
KS
448 (cua-set-rectangle-mark)
449 (setq cua--buffer-and-point-before-command nil)
450 (setq cua--mouse-last-pos nil))
451
452(defun cua-mouse-save-then-kill-rectangle (event arg)
453 "Expand rectangle to mouse click position and copy rectangle.
454If command is repeated at same position, delete the rectangle."
455 (interactive "e\nP")
456 (if (and (eq this-command last-command)
457 (eq (point) (car-safe cua--mouse-last-pos))
458 (eq cua--last-killed-rectangle (cdr-safe cua--mouse-last-pos)))
459 (progn
460 (unless buffer-read-only
461 (cua--delete-rectangle))
462 (cua--deactivate))
463 (cua-mouse-resize-rectangle event)
464 (let ((cua-keep-region-after-copy t))
465 (cua-copy-rectangle arg)
466 (setq cua--mouse-last-pos (cons (point) cua--last-killed-rectangle)))))
72797108 467
72cc582e
KS
468(defun cua--mouse-ignore (event)
469 (interactive "e")
470 (setq this-command last-command))
471
472(defun cua--rectangle-move (dir)
72797108 473 (let ((moved t)
72cc582e
KS
474 (top (cua--rectangle-top))
475 (bot (cua--rectangle-bot))
476 (l (cua--rectangle-left))
477 (r (cua--rectangle-right)))
478 (cond
479 ((eq dir 'up)
480 (goto-char top)
72797108 481 (when (cua--forward-line -1)
72cc582e
KS
482 (cua--rectangle-top t)
483 (goto-char bot)
484 (forward-line -1)
485 (cua--rectangle-bot t)))
486 ((eq dir 'down)
487 (goto-char bot)
72797108 488 (when (cua--forward-line 1)
72cc582e
KS
489 (cua--rectangle-bot t)
490 (goto-char top)
72797108 491 (cua--forward-line 1)
72cc582e
KS
492 (cua--rectangle-top t)))
493 ((eq dir 'left)
494 (when (> l 0)
495 (cua--rectangle-left (1- l))
496 (cua--rectangle-right (1- r))))
497 ((eq dir 'right)
498 (cua--rectangle-right (1+ r))
499 (cua--rectangle-left (1+ l)))
500 (t
501 (setq moved nil)))
502 (when moved
503 (setq cua--buffer-and-point-before-command nil)
72cc582e
KS
504 (cua--rectangle-set-corners)
505 (cua--keep-active))))
506
507
508;;; Operations on current rectangle
509
72797108
KS
510(defun cua--tabify-start (start end)
511 ;; Return position where auto-tabify should start (or nil if not required).
512 (save-excursion
513 (save-restriction
514 (widen)
515 (and (not buffer-read-only)
516 cua-auto-tabify-rectangles
517 (if (or (not (integerp cua-auto-tabify-rectangles))
518 (= (point-min) (point-max))
519 (progn
520 (goto-char (max (point-min)
521 (- start cua-auto-tabify-rectangles)))
522 (search-forward "\t" (min (point-max)
523 (+ end cua-auto-tabify-rectangles)) t)))
524 start)))))
525
526(defun cua--rectangle-operation (keep-clear visible undo pad tabify &optional fct post-fct)
72cc582e
KS
527 ;; Call FCT for each line of region with 4 parameters:
528 ;; Region start, end, left-col, right-col
529 ;; Point is at start when FCT is called
72797108
KS
530 ;; Call fct with (s,e) = whole lines if VISIBLE non-nil.
531 ;; Only call fct for visible lines if VISIBLE==t.
72cc582e 532 ;; Set undo boundary if UNDO is non-nil.
72797108
KS
533 ;; Rectangle is padded if PAD = t or numeric and (cua--rectangle-virtual-edges)
534 ;; Perform auto-tabify after operation if TABIFY is non-nil.
72cc582e 535 ;; Mark is kept if keep-clear is 'keep and cleared if keep-clear is 'clear.
4e687447
KS
536 (let* ((inhibit-field-text-motion t)
537 (start (cua--rectangle-top))
72cc582e
KS
538 (end (cua--rectangle-bot))
539 (l (cua--rectangle-left))
540 (r (1+ (cua--rectangle-right)))
541 (m (make-marker))
542 (tabpad (and (integerp pad) (= pad 2)))
72797108
KS
543 (sel (cua--rectangle-restriction))
544 (tabify-start (and tabify (cua--tabify-start start end))))
72cc582e
KS
545 (if undo
546 (cua--rectangle-undo-boundary))
547 (if (integerp pad)
72797108 548 (setq pad (cua--rectangle-virtual-edges)))
72cc582e
KS
549 (save-excursion
550 (save-restriction
551 (widen)
552 (when (> (cua--rectangle-corner) 1)
553 (goto-char end)
554 (and (bolp) (not (eolp)) (not (eobp))
555 (setq end (1+ end))))
72797108 556 (when (eq visible t)
72cc582e
KS
557 (setq start (max (window-start) start))
558 (setq end (min (window-end) end)))
559 (goto-char end)
560 (setq end (line-end-position))
e2ea72e9
KS
561 (if (and visible (bolp) (not (eobp)))
562 (setq end (1+ end)))
72cc582e
KS
563 (goto-char start)
564 (setq start (line-beginning-position))
565 (narrow-to-region start end)
566 (goto-char (point-min))
567 (while (< (point) (point-max))
568 (move-to-column r pad)
569 (and (not pad) (not visible) (> (current-column) r)
570 (backward-char 1))
571 (if (and tabpad (not pad) (looking-at "\t"))
572 (forward-char 1))
573 (set-marker m (point))
574 (move-to-column l pad)
72797108 575 (if (and fct (or visible (and (>= (current-column) l) (<= (current-column) r))))
72cc582e
KS
576 (let ((v t) (p (point)))
577 (when sel
578 (if (car (cdr sel))
579 (setq v (looking-at (car sel)))
580 (setq v (re-search-forward (car sel) m t))
581 (goto-char p))
582 (if (car (cdr (cdr sel)))
583 (setq v (null v))))
584 (if visible
72797108 585 (funcall fct p m l r v)
72cc582e
KS
586 (if v
587 (funcall fct p m l r)))))
588 (set-marker m nil)
589 (forward-line 1))
590 (if (not visible)
591 (cua--rectangle-bot t))
592 (if post-fct
72797108
KS
593 (funcall post-fct l r))
594 (when tabify-start
595 (tabify tabify-start (point)))))
72cc582e
KS
596 (cond
597 ((eq keep-clear 'keep)
598 (cua--keep-active))
599 ((eq keep-clear 'clear)
600 (cua--deactivate))
601 ((eq keep-clear 'corners)
602 (cua--rectangle-set-corners)
603 (cua--keep-active)))
604 (setq cua--buffer-and-point-before-command nil)))
605
606(put 'cua--rectangle-operation 'lisp-indent-function 4)
607
72cc582e 608(defun cua--delete-rectangle ()
72797108
KS
609 (let ((lines 0))
610 (if (not (cua--rectangle-virtual-edges))
611 (cua--rectangle-operation nil nil t 2 t
612 '(lambda (s e l r v)
613 (setq lines (1+ lines))
614 (if (and (> e s) (<= e (point-max)))
615 (delete-region s e))))
616 (cua--rectangle-operation nil 1 t nil t
617 '(lambda (s e l r v)
618 (setq lines (1+ lines))
619 (when (and (> e s) (<= e (point-max)))
620 (delete-region s e)))))
621 lines))
72cc582e
KS
622
623(defun cua--extract-rectangle ()
624 (let (rect)
72797108
KS
625 (if (not (cua--rectangle-virtual-edges))
626 (cua--rectangle-operation nil nil nil nil nil ; do not tabify
627 '(lambda (s e l r)
15ac4d58 628 (setq rect (cons (filter-buffer-substring s e nil t) rect))))
72797108
KS
629 (cua--rectangle-operation nil 1 nil nil nil ; do not tabify
630 '(lambda (s e l r v)
631 (let ((copy t) (bs 0) (as 0) row)
632 (if (= s e) (setq e (1+ e)))
633 (goto-char s)
634 (move-to-column l)
635 (if (= (point) (line-end-position))
636 (setq bs (- r l)
637 copy nil)
55920229 638 (skip-chars-forward "\s\t" e)
72797108
KS
639 (setq bs (- (min r (current-column)) l)
640 s (point))
641 (move-to-column r)
55920229 642 (skip-chars-backward "\s\t" s)
72797108
KS
643 (setq as (- r (max (current-column) l))
644 e (point)))
645 (setq row (if (and copy (> e s))
15ac4d58 646 (filter-buffer-substring s e nil t)
72797108
KS
647 ""))
648 (when (> bs 0)
649 (setq row (concat (make-string bs ?\s) row)))
650 (when (> as 0)
651 (setq row (concat row (make-string as ?\s))))
652 (setq rect (cons row rect))))))
653 (nreverse rect)))
654
655(defun cua--insert-rectangle (rect &optional below paste-column line-count)
72cc582e
KS
656 ;; Insert rectangle as insert-rectangle, but don't set mark and exit with
657 ;; point at either next to top right or below bottom left corner
658 ;; Notice: In overwrite mode, the rectangle is inserted as separate text lines.
72797108 659 (if (eq below 'auto)
72cc582e
KS
660 (setq below (and (bolp)
661 (or (eolp) (eobp) (= (1+ (point)) (point-max))))))
72797108
KS
662 (unless paste-column
663 (setq paste-column (current-column)))
72cc582e 664 (let ((lines rect)
72cc582e 665 (first t)
72797108
KS
666 (tabify-start (cua--tabify-start (point) (point)))
667 last-column
72cc582e
KS
668 p)
669 (while (or lines below)
670 (or first
671 (if overwrite-mode
672 (insert ?\n)
673 (forward-line 1)
72797108
KS
674 (or (bolp) (insert ?\n))))
675 (unless overwrite-mode
676 (move-to-column paste-column t))
72cc582e
KS
677 (if (not lines)
678 (setq below nil)
679 (insert-for-yank (car lines))
72797108
KS
680 (unless last-column
681 (setq last-column (current-column)))
72cc582e
KS
682 (setq lines (cdr lines))
683 (and first (not below)
684 (setq p (point))))
72797108
KS
685 (setq first nil)
686 (if (and line-count (= (setq line-count (1- line-count)) 0))
687 (setq lines nil)))
688 (when (and line-count last-column (not overwrite-mode))
689 (while (> line-count 0)
690 (forward-line 1)
691 (or (bolp) (insert ?\n))
692 (move-to-column paste-column t)
693 (insert-char ?\s (- last-column paste-column -1))
694 (setq line-count (1- line-count))))
695 (when (and tabify-start
696 (not overwrite-mode))
697 (tabify tabify-start (point)))
72cc582e
KS
698 (and p (not overwrite-mode)
699 (goto-char p))))
700
701(defun cua--copy-rectangle-as-kill (&optional ring)
702 (if cua--register
703 (set-register cua--register (cua--extract-rectangle))
704 (setq killed-rectangle (cua--extract-rectangle))
705 (setq cua--last-killed-rectangle (cons (and kill-ring (car kill-ring)) killed-rectangle))
706 (if ring
707 (kill-new (mapconcat
708 (function (lambda (row) (concat row "\n")))
709 killed-rectangle "")))))
710
72797108 711(defun cua--activate-rectangle ()
72cc582e
KS
712 ;; Turn on rectangular marking mode by disabling transient mark mode
713 ;; and manually handling highlighting from a post command hook.
714 ;; Be careful if we are already marking a rectangle.
a1506d29
JB
715 (setq cua--rectangle
716 (if (and cua--last-rectangle
72cc582e
KS
717 (eq (car cua--last-rectangle) (current-buffer))
718 (eq (car (cdr cua--last-rectangle)) (point)))
719 (cdr (cdr cua--last-rectangle))
72797108
KS
720 (cua--rectangle-get-corners))
721 cua--status-string (if (cua--rectangle-virtual-edges) " [R]" "")
72cc582e
KS
722 cua--last-rectangle nil))
723
724;; (defvar cua-save-point nil)
725
726(defun cua--deactivate-rectangle ()
727 ;; This is used to clean up after `cua--activate-rectangle'.
026056a4 728 (mapc (function delete-overlay) cua--rectangle-overlays)
a1506d29 729 (setq cua--last-rectangle (cons (current-buffer)
72cc582e
KS
730 (cons (point) ;; cua-save-point
731 cua--rectangle))
732 cua--rectangle nil
733 cua--rectangle-overlays nil
734 cua--status-string nil
735 cua--mouse-last-pos nil))
736
737(defun cua--highlight-rectangle ()
738 ;; This function is used to highlight the rectangular region.
739 ;; We do this by putting an overlay on each line within the rectangle.
740 ;; Each overlay extends across all the columns of the rectangle.
741 ;; We try to reuse overlays where possible because this is more efficient
742 ;; and results in less flicker.
72797108 743 ;; If cua--rectangle-virtual-edges is nil and the buffer contains tabs or short lines,
72cc582e
KS
744 ;; the higlighted region may not be perfectly rectangular.
745 (let ((deactivate-mark deactivate-mark)
746 (old cua--rectangle-overlays)
747 (new nil)
748 (left (cua--rectangle-left))
749 (right (1+ (cua--rectangle-right))))
750 (when (/= left right)
751 (sit-for 0) ; make window top/bottom reliable
72797108 752 (cua--rectangle-operation nil t nil nil nil ; do not tabify
72cc582e 753 '(lambda (s e l r v)
1e98d199 754 (let ((rface (if v 'cua-rectangle 'cua-rectangle-noselect))
e2ea72e9 755 overlay bs ms as)
72797108
KS
756 (when (cua--rectangle-virtual-edges)
757 (let ((lb (line-beginning-position))
758 (le (line-end-position))
759 cl cl0 pl cr cr0 pr)
760 (goto-char s)
761 (setq cl (move-to-column l)
762 pl (point))
763 (setq cr (move-to-column r)
764 pr (point))
765 (if (= lb pl)
766 (setq cl0 0)
767 (goto-char (1- pl))
768 (setq cl0 (current-column)))
769 (if (= lb le)
770 (setq cr0 0)
771 (goto-char (1- pr))
772 (setq cr0 (current-column)))
773 (unless (and (= cl l) (= cr r))
774 (when (/= cl l)
775 (setq bs (propertize
776 (make-string
777 (- l cl0 (if (and (= le pl) (/= le lb)) 1 0))
778 (if cua--virtual-edges-debug ?. ?\s))
98faed9f 779 'face (or (get-text-property (1- s) 'face) 'default)))
72797108
KS
780 (if (/= pl le)
781 (setq s (1- s))))
782 (cond
783 ((= cr r)
e2ea72e9
KS
784 (if (and (/= pr le)
785 (/= cr0 (1- cr))
786 (or bs (/= cr0 (- cr tab-width)))
787 (/= (mod cr tab-width) 0))
72797108
KS
788 (setq e (1- e))))
789 ((= cr cl)
e2ea72e9
KS
790 (setq ms (propertize
791 (make-string
792 (- r l)
793 (if cua--virtual-edges-debug ?, ?\s))
794 'face rface))
795 (if (cua--rectangle-right-side)
b53b41ba
KS
796 (put-text-property (1- (length ms)) (length ms) 'cursor 2 ms)
797 (put-text-property 0 1 'cursor 2 ms))
e2ea72e9 798 (setq bs (concat bs ms))
72797108 799 (setq rface nil))
e2ea72e9 800 (t
72797108
KS
801 (setq as (propertize
802 (make-string
803 (- r cr0 (if (= le pr) 1 0))
804 (if cua--virtual-edges-debug ?~ ?\s))
805 'face rface))
e2ea72e9 806 (if (cua--rectangle-right-side)
b53b41ba
KS
807 (put-text-property (1- (length as)) (length as) 'cursor 2 as)
808 (put-text-property 0 1 'cursor 2 as))
72797108
KS
809 (if (/= pr le)
810 (setq e (1- e))))))))
811 ;; Trim old leading overlays.
72cc582e
KS
812 (while (and old
813 (setq overlay (car old))
814 (< (overlay-start overlay) s)
815 (/= (overlay-end overlay) e))
816 (delete-overlay overlay)
817 (setq old (cdr old)))
818 ;; Reuse an overlay if possible, otherwise create one.
819 (if (and old
820 (setq overlay (car old))
821 (or (= (overlay-start overlay) s)
822 (= (overlay-end overlay) e)))
823 (progn
824 (move-overlay overlay s e)
825 (setq old (cdr old)))
826 (setq overlay (make-overlay s e)))
e2ea72e9 827 (overlay-put overlay 'before-string bs)
72797108
KS
828 (overlay-put overlay 'after-string as)
829 (overlay-put overlay 'face rface)
1e71278b 830 (overlay-put overlay 'keymap cua--overlay-keymap)
f2856495 831 (overlay-put overlay 'window (selected-window))
72797108 832 (setq new (cons overlay new))))))
72cc582e 833 ;; Trim old trailing overlays.
026056a4 834 (mapc (function delete-overlay) old)
72cc582e
KS
835 (setq cua--rectangle-overlays (nreverse new))))
836
837(defun cua--indent-rectangle (&optional ch to-col clear)
838 ;; Indent current rectangle.
839 (let ((col (cua--rectangle-insert-col))
72797108 840 (pad (cua--rectangle-virtual-edges))
72cc582e 841 indent)
e2ea72e9 842 (cua--rectangle-operation (if clear 'clear 'corners) nil t pad nil
72cc582e
KS
843 '(lambda (s e l r)
844 (move-to-column col pad)
845 (if (and (eolp)
846 (< (current-column) col))
847 (move-to-column col t))
848 (cond
849 (to-col (indent-to to-col))
c872c51e 850 ((and ch (not (eq ch ?\t))) (insert ch))
72cc582e
KS
851 (t (tab-to-tab-stop)))
852 (if (cua--rectangle-right-side t)
853 (cua--rectangle-insert-col (current-column))
854 (setq indent (- (current-column) l))))
855 '(lambda (l r)
856 (when (and indent (> indent 0))
857 (aset cua--rectangle 2 (+ l indent))
858 (aset cua--rectangle 3 (+ r indent -1)))))))
859
860;;
861;; rectangle functions / actions
862;;
863
864(defvar cua--rectangle-initialized nil)
865
866(defun cua-set-rectangle-mark (&optional reopen)
867 "Set mark and start in CUA rectangle mode.
868With prefix argument, activate previous rectangle if possible."
869 (interactive "P")
870 (unless cua--rectangle-initialized
871 (cua--init-rectangles))
872 (when (not cua--rectangle)
873 (if (and reopen
874 cua--last-rectangle
875 (eq (car cua--last-rectangle) (current-buffer)))
876 (goto-char (car (cdr cua--last-rectangle)))
877 (if (not mark-active)
878 (push-mark nil nil t)))
879 (cua--activate-rectangle)
880 (cua--rectangle-set-corners)
881 (setq mark-active t
882 cua--explicit-region-start t)
883 (if cua-enable-rectangle-auto-help
884 (cua-help-for-rectangle t))))
885
886(defun cua-clear-rectangle-mark ()
887 "Cancel current rectangle."
888 (interactive)
889 (when cua--rectangle
890 (setq mark-active nil
891 cua--explicit-region-start nil)
892 (cua--deactivate-rectangle)))
893
894(defun cua-toggle-rectangle-mark ()
895 (interactive)
896 (if cua--rectangle
897 (cua--deactivate-rectangle)
898 (unless cua--rectangle-initialized
899 (cua--init-rectangles))
900 (cua--activate-rectangle))
901 (if cua--rectangle
902 (if cua-enable-rectangle-auto-help
903 (cua-help-for-rectangle t))
904 (if cua-enable-region-auto-help
905 (cua-help-for-region t))))
906
907(defun cua-restrict-regexp-rectangle (arg)
908 "Restrict rectangle to lines (not) matching REGEXP.
909With prefix argument, the toggle restriction."
910 (interactive "P")
911 (let ((r (cua--rectangle-restriction)) regexp)
912 (if (and r (null (car (cdr r))))
913 (if arg
914 (cua--rectangle-restriction (car r) nil (not (car (cdr (cdr r)))))
915 (cua--rectangle-restriction "" nil nil))
916 (cua--rectangle-restriction
917 (read-from-minibuffer "Restrict rectangle (regexp): "
918 nil nil nil nil) nil arg))))
919
920(defun cua-restrict-prefix-rectangle (arg)
921 "Restrict rectangle to lines (not) starting with CHAR.
922With prefix argument, the toggle restriction."
923 (interactive "P")
924 (let ((r (cua--rectangle-restriction)) regexp)
925 (if (and r (car (cdr r)))
926 (if arg
927 (cua--rectangle-restriction (car r) t (not (car (cdr (cdr r)))))
928 (cua--rectangle-restriction "" nil nil))
929 (cua--rectangle-restriction
a1506d29 930 (format "[%c]"
72cc582e
KS
931 (read-char "Restrictive rectangle (char): ")) t arg))))
932
933(defun cua-move-rectangle-up ()
934 (interactive)
935 (cua--rectangle-move 'up))
936
937(defun cua-move-rectangle-down ()
938 (interactive)
939 (cua--rectangle-move 'down))
940
941(defun cua-move-rectangle-left ()
942 (interactive)
943 (cua--rectangle-move 'left))
944
945(defun cua-move-rectangle-right ()
946 (interactive)
947 (cua--rectangle-move 'right))
948
949(defun cua-copy-rectangle (arg)
950 (interactive "P")
951 (setq arg (cua--prefix-arg arg))
952 (cua--copy-rectangle-as-kill arg)
953 (if cua-keep-region-after-copy
954 (cua--keep-active)
955 (cua--deactivate)))
956
957(defun cua-cut-rectangle (arg)
958 (interactive "P")
959 (if buffer-read-only
960 (cua-copy-rectangle arg)
961 (setq arg (cua--prefix-arg arg))
962 (goto-char (min (mark) (point)))
963 (cua--copy-rectangle-as-kill arg)
964 (cua--delete-rectangle))
965 (cua--deactivate))
966
967(defun cua-delete-rectangle ()
968 (interactive)
969 (goto-char (min (point) (mark)))
970 (if cua-delete-copy-to-register-0
971 (set-register ?0 (cua--extract-rectangle)))
972 (cua--delete-rectangle)
973 (cua--deactivate))
974
975(defun cua-rotate-rectangle ()
976 (interactive)
977 (cua--rectangle-corner (if (= (cua--rectangle-left) (cua--rectangle-right)) 0 1))
e2ea72e9
KS
978 (cua--rectangle-set-corners)
979 (if (cua--rectangle-virtual-edges)
980 (setq cua--buffer-and-point-before-command nil)))
72cc582e 981
72797108 982(defun cua-toggle-rectangle-virtual-edges ()
72cc582e 983 (interactive)
72797108
KS
984 (cua--rectangle-virtual-edges t (not (cua--rectangle-virtual-edges)))
985 (cua--rectangle-set-corners)
986 (setq cua--status-string (and (cua--rectangle-virtual-edges) " [R]"))
72cc582e
KS
987 (cua--keep-active))
988
989(defun cua-do-rectangle-padding ()
990 (interactive)
991 (if buffer-read-only
8482d727 992 (message "Cannot do padding in read-only buffer")
72797108 993 (cua--rectangle-operation nil nil t t t)
72cc582e
KS
994 (cua--rectangle-set-corners))
995 (cua--keep-active))
996
997(defun cua-open-rectangle ()
998 "Blank out CUA rectangle, shifting text right.
999The text previously in the region is not overwritten by the blanks,
1000but instead winds up to the right of the rectangle."
1001 (interactive)
72797108 1002 (cua--rectangle-operation 'corners nil t 1 nil
72cc582e
KS
1003 '(lambda (s e l r)
1004 (skip-chars-forward " \t")
1005 (let ((ws (- (current-column) l))
1006 (p (point)))
1007 (skip-chars-backward " \t")
1008 (delete-region (point) p)
1009 (indent-to (+ r ws))))))
1010
1011(defun cua-close-rectangle (arg)
1012 "Delete all whitespace starting at left edge of CUA rectangle.
1013On each line in the rectangle, all continuous whitespace starting
1014at that column is deleted.
1015With prefix arg, also delete whitespace to the left of that column."
1016 (interactive "P")
72797108 1017 (cua--rectangle-operation 'clear nil t 1 nil
72cc582e
KS
1018 '(lambda (s e l r)
1019 (when arg
1020 (skip-syntax-backward " " (line-beginning-position))
1021 (setq s (point)))
1022 (skip-syntax-forward " " (line-end-position))
1023 (delete-region s (point)))))
1024
1025(defun cua-blank-rectangle ()
1026 "Blank out CUA rectangle.
1027The text previously in the rectangle is overwritten by the blanks."
1028 (interactive)
72797108 1029 (cua--rectangle-operation 'keep nil nil 1 nil
72cc582e
KS
1030 '(lambda (s e l r)
1031 (goto-char e)
1032 (skip-syntax-forward " " (line-end-position))
1033 (setq e (point))
1034 (let ((column (current-column)))
1035 (goto-char s)
1036 (skip-syntax-backward " " (line-beginning-position))
1037 (delete-region (point) e)
1038 (indent-to column)))))
1039
1040(defun cua-align-rectangle ()
1041 "Align rectangle lines to left column."
1042 (interactive)
1043 (let (x)
72797108 1044 (cua--rectangle-operation 'clear nil t t nil
72cc582e
KS
1045 '(lambda (s e l r)
1046 (let ((b (line-beginning-position)))
1047 (skip-syntax-backward "^ " b)
1048 (skip-syntax-backward " " b)
1049 (setq s (point)))
1050 (skip-syntax-forward " " (line-end-position))
1051 (delete-region s (point))
1052 (indent-to l))
1053 '(lambda (l r)
1054 (move-to-column l)
1055 ;; (setq cua-save-point (point))
1056 ))))
1057
2c0f8564
GM
1058(declare-function cua--cut-rectangle-to-global-mark "cua-gmrk" (as-text))
1059(declare-function cua--copy-rectangle-to-global-mark "cua-gmrk" (as-text))
1060
72cc582e
KS
1061(defun cua-copy-rectangle-as-text (&optional arg delete)
1062 "Copy rectangle, but store as normal text."
1063 (interactive "P")
1064 (if cua--global-mark-active
1065 (if delete
1066 (cua--cut-rectangle-to-global-mark t)
1067 (cua--copy-rectangle-to-global-mark t))
1068 (let* ((rect (cua--extract-rectangle))
1069 (text (mapconcat
1070 (function (lambda (row) (concat row "\n")))
1071 rect "")))
1072 (setq arg (cua--prefix-arg arg))
1073 (if cua--register
1074 (set-register cua--register text)
1075 (kill-new text)))
1076 (if delete
1077 (cua--delete-rectangle))
1078 (cua--deactivate)))
1079
1080(defun cua-cut-rectangle-as-text (arg)
1081 "Kill rectangle, but store as normal text."
1082 (interactive "P")
1083 (cua-copy-rectangle-as-text arg (not buffer-read-only)))
1084
1085(defun cua-string-rectangle (string)
1086 "Replace CUA rectangle contents with STRING on each line.
1087The length of STRING need not be the same as the rectangle width."
1088 (interactive "sString rectangle: ")
72797108 1089 (cua--rectangle-operation 'keep nil t t nil
72cc582e
KS
1090 '(lambda (s e l r)
1091 (delete-region s e)
1092 (skip-chars-forward " \t")
1093 (let ((ws (- (current-column) l)))
1094 (delete-region s (point))
1095 (insert string)
1096 (indent-to (+ (current-column) ws))))
1097 (unless (cua--rectangle-restriction)
1098 '(lambda (l r)
1099 (cua--rectangle-right (max l (+ l (length string) -1)))))))
1100
8482d727 1101(defun cua-fill-char-rectangle (character)
72cc582e
KS
1102 "Replace CUA rectangle contents with CHARACTER."
1103 (interactive "cFill rectangle with character: ")
72797108 1104 (cua--rectangle-operation 'clear nil t 1 nil
72cc582e
KS
1105 '(lambda (s e l r)
1106 (delete-region s e)
1107 (move-to-column l t)
8482d727 1108 (insert-char character (- r l)))))
72cc582e
KS
1109
1110(defun cua-replace-in-rectangle (regexp newtext)
1111 "Replace REGEXP with NEWTEXT in each line of CUA rectangle."
1112 (interactive "sReplace regexp: \nsNew text: ")
1113 (if buffer-read-only
1114 (message "Cannot replace in read-only buffer")
72797108 1115 (cua--rectangle-operation 'keep nil t 1 nil
72cc582e
KS
1116 '(lambda (s e l r)
1117 (if (re-search-forward regexp e t)
1118 (replace-match newtext nil nil))))))
1119
1120(defun cua-incr-rectangle (increment)
1121 "Increment each line of CUA rectangle by prefix amount."
1122 (interactive "p")
72797108 1123 (cua--rectangle-operation 'keep nil t 1 nil
72cc582e
KS
1124 '(lambda (s e l r)
1125 (cond
1126 ((re-search-forward "0x\\([0-9a-fA-F]+\\)" e t)
15ac4d58 1127 (let* ((txt (filter-buffer-substring (match-beginning 1) (match-end 1) nil t))
72cc582e
KS
1128 (n (string-to-number txt 16))
1129 (fmt (format "0x%%0%dx" (length txt))))
1130 (replace-match (format fmt (+ n increment)))))
1131 ((re-search-forward "\\( *-?[0-9]+\\)" e t)
15ac4d58 1132 (let* ((txt (filter-buffer-substring (match-beginning 1) (match-end 1) nil t))
72cc582e
KS
1133 (prefix (if (= (aref txt 0) ?0) "0" ""))
1134 (n (string-to-number txt 10))
1135 (fmt (format "%%%s%dd" prefix (length txt))))
1136 (replace-match (format fmt (+ n increment)))))
1137 (t nil)))))
1138
1139(defvar cua--rectangle-seq-format "%d"
8482d727 1140 "Last format used by `cua-sequence-rectangle'.")
72cc582e 1141
8482d727 1142(defun cua-sequence-rectangle (first incr format)
72cc582e
KS
1143 "Resequence each line of CUA rectangle starting from FIRST.
1144The numbers are formatted according to the FORMAT string."
a1506d29 1145 (interactive
72cc582e
KS
1146 (list (if current-prefix-arg
1147 (prefix-numeric-value current-prefix-arg)
1148 (string-to-number
1149 (read-string "Start value: (0) " nil nil "0")))
1150 (string-to-number
1151 (read-string "Increment: (1) " nil nil "1"))
1152 (read-string (concat "Format: (" cua--rectangle-seq-format ") "))))
8482d727
JB
1153 (if (= (length format) 0)
1154 (setq format cua--rectangle-seq-format)
1155 (setq cua--rectangle-seq-format format))
72797108 1156 (cua--rectangle-operation 'clear nil t 1 nil
72cc582e
KS
1157 '(lambda (s e l r)
1158 (delete-region s e)
8482d727 1159 (insert (format format first))
72cc582e
KS
1160 (setq first (+ first incr)))))
1161
72797108
KS
1162(defmacro cua--convert-rectangle-as (command tabify)
1163 `(cua--rectangle-operation 'clear nil nil nil ,tabify
3b365de3
KS
1164 '(lambda (s e l r)
1165 (,command s e))))
1166
72cc582e
KS
1167(defun cua-upcase-rectangle ()
1168 "Convert the rectangle to upper case."
1169 (interactive)
72797108 1170 (cua--convert-rectangle-as upcase-region nil))
72cc582e
KS
1171
1172(defun cua-downcase-rectangle ()
1173 "Convert the rectangle to lower case."
1174 (interactive)
72797108 1175 (cua--convert-rectangle-as downcase-region nil))
3b365de3
KS
1176
1177(defun cua-upcase-initials-rectangle ()
1178 "Convert the rectangle initials to upper case."
1179 (interactive)
72797108 1180 (cua--convert-rectangle-as upcase-initials-region nil))
3b365de3
KS
1181
1182(defun cua-capitalize-rectangle ()
1183 "Convert the rectangle to proper case."
1184 (interactive)
72797108 1185 (cua--convert-rectangle-as capitalize-region nil))
72cc582e
KS
1186
1187
1188;;; Replace/rearrange text in current rectangle
1189
1190(defun cua--rectangle-aux-replace (width adjust keep replace pad format-fct &optional setup-fct)
1191 ;; Process text inserted by calling SETUP-FCT or current rectangle if nil.
1192 ;; Then call FORMAT-FCT on text (if non-nil); takes two args: start and end.
1193 ;; Fill to WIDTH characters if > 0 or fill to current width if == 0.
1194 ;; Don't fill if WIDTH < 0.
1195 ;; Replace current rectangle by filled text if REPLACE is non-nil
1196 (let ((auxbuf (get-buffer-create "*CUA temp*"))
1197 (w (if (> width 1) width
1198 (- (cua--rectangle-right) (cua--rectangle-left) -1)))
1199 (r (or setup-fct (cua--extract-rectangle)))
1200 y z (tr 0))
937e6a56 1201 (with-current-buffer auxbuf
72cc582e
KS
1202 (erase-buffer)
1203 (if setup-fct
1204 (funcall setup-fct)
1205 (cua--insert-rectangle r))
1206 (if format-fct
1207 (let ((fill-column w))
1208 (funcall format-fct (point-min) (point-max))))
1209 (when replace
1210 (goto-char (point-min))
1211 (while (not (eobp))
15ac4d58 1212 (setq z (cons (filter-buffer-substring (point) (line-end-position)) z))
72cc582e
KS
1213 (forward-line 1))))
1214 (if (not cua--debug)
1215 (kill-buffer auxbuf))
1216 (when replace
1217 (setq z (reverse z))
1218 (if cua--debug
1219 (print z auxbuf))
72797108 1220 (cua--rectangle-operation nil nil t pad nil
72cc582e
KS
1221 '(lambda (s e l r)
1222 (let (cc)
1223 (goto-char e)
1224 (skip-chars-forward " \t")
1225 (setq cc (current-column))
1226 (if cua--debug
1227 (print (list cc s e) auxbuf))
1228 (delete-region s (point))
1229 (if (not z)
1230 (setq y 0)
1231 (move-to-column l t)
1232 (insert (car z))
1233 (when (> (current-column) (+ l w))
1234 (setq y (point))
1235 (move-to-column (+ l w) t)
1236 (delete-region (point) y)
1237 (setq tr (1+ tr)))
1238 (setq z (cdr z)))
1239 (if cua--debug
1240 (print (list (current-column) cc) auxbuf))
e87aa620 1241 (just-one-space 0)
72cc582e
KS
1242 (indent-to cc))))
1243 (if (> tr 0)
1244 (message "Warning: Truncated %d row%s" tr (if (> tr 1) "s" "")))
1245 (if adjust
1246 (cua--rectangle-right (+ (cua--rectangle-left) w -1)))
1247 (if keep
1248 (cua--rectangle-resized)))))
1249
1250(put 'cua--rectangle-aux-replace 'lisp-indent-function 4)
1251
1252(defun cua--left-fill-rectangle (start end)
1253 (beginning-of-line)
1254 (while (< (point) (point-max))
1255 (delete-horizontal-space nil)
1256 (forward-line 1))
1257 (fill-region-as-paragraph (point-min) (point-max) 'left nil)
1258 (untabify (point-min) (point-max)))
1259
1260(defun cua-text-fill-rectangle (width text)
1261 "Replace rectagle with filled TEXT read from minibuffer.
1262A numeric prefix argument is used a new width for the filled rectangle."
1263 (interactive (list
1264 (prefix-numeric-value current-prefix-arg)
1265 (read-from-minibuffer "Enter text: "
1266 nil nil nil nil)))
1267 (cua--rectangle-aux-replace width t t t 1
1268 'cua--left-fill-rectangle
1269 '(lambda () (insert text))))
1270
1271(defun cua-refill-rectangle (width)
1272 "Fill contents of current rectagle.
1273A numeric prefix argument is used as new width for the filled rectangle."
1274 (interactive "P")
1275 (cua--rectangle-aux-replace
1276 (if width (prefix-numeric-value width) 0)
1277 t t t 1 'cua--left-fill-rectangle))
1278
1279(defun cua-shell-command-on-rectangle (replace command)
1280 "Run shell command on rectangle like `shell-command-on-region'.
1281With prefix arg, replace rectangle with output from command."
1282 (interactive (list
1283 current-prefix-arg
1284 (read-from-minibuffer "Shell command on rectangle: "
a1506d29 1285 nil nil nil
72cc582e
KS
1286 'shell-command-history)))
1287 (cua--rectangle-aux-replace -1 t t replace 1
1288 '(lambda (s e)
1289 (shell-command-on-region s e command
1290 replace replace nil))))
1291
1292(defun cua-reverse-rectangle ()
1293 "Reverse the lines of the rectangle."
1294 (interactive)
1295 (cua--rectangle-aux-replace 0 t t t t 'reverse-region))
1296
1297(defun cua-scroll-rectangle-up ()
1298 "Remove the first line of the rectangle and scroll remaining lines up."
1299 (interactive)
1300 (cua--rectangle-aux-replace 0 t t t t
a1506d29 1301 '(lambda (s e)
72cc582e
KS
1302 (if (= (forward-line 1) 0)
1303 (delete-region s (point))))))
1304
1305(defun cua-scroll-rectangle-down ()
1306 "Insert a blank line at the first line of the rectangle.
1307The remaining lines are scrolled down, losing the last line."
1308 (interactive)
1309 (cua--rectangle-aux-replace 0 t t t t
1310 '(lambda (s e)
1311 (goto-char s)
1312 (insert "\n"))))
1313
1314
1315;;; Insert/delete text to left or right of rectangle
1316
1317(defun cua-insert-char-rectangle (&optional ch)
1318 (interactive)
1319 (if buffer-read-only
1320 (ding)
1321 (cua--indent-rectangle (or ch (aref (this-single-command-keys) 0)))
1322 (cua--keep-active))
1323 t)
1324
1325(defun cua-indent-rectangle (column)
1326 "Indent rectangle to next tab stop.
1327With prefix arg, indent to that column."
1328 (interactive "P")
1329 (if (null column)
1330 (cua-insert-char-rectangle ?\t)
1331 (cua--indent-rectangle nil (prefix-numeric-value column))))
1332
1333(defun cua-delete-char-rectangle ()
1334 "Delete char to left or right of rectangle."
1335 (interactive)
1336 (let ((col (cua--rectangle-insert-col))
72797108 1337 (pad (cua--rectangle-virtual-edges))
72cc582e 1338 indent)
72797108 1339 (cua--rectangle-operation 'corners nil t pad nil
72cc582e 1340 '(lambda (s e l r)
a1506d29 1341 (move-to-column
72cc582e
KS
1342 (if (cua--rectangle-right-side t)
1343 (max (1+ r) col) l)
1344 pad)
1345 (if (bolp)
1346 nil
1347 (delete-backward-char 1)
1348 (if (cua--rectangle-right-side t)
1349 (cua--rectangle-insert-col (current-column))
1350 (setq indent (- l (current-column))))))
1351 '(lambda (l r)
1352 (when (and indent (> indent 0))
1353 (aset cua--rectangle 2 (- l indent))
1354 (aset cua--rectangle 3 (- r indent 1)))))))
1355
1356(defun cua-help-for-rectangle (&optional help)
1357 (interactive)
1638bf54
KS
1358 (let ((M (cond ((eq cua--rectangle-modifier-key 'hyper) " H-")
1359 ((eq cua--rectangle-modifier-key 'super) " s-")
a4520735 1360 ((eq cua--rectangle-modifier-key 'alt) " A-")
1638bf54 1361 (t " M-"))))
a1506d29 1362 (message
72cc582e 1363 (concat (if help "C-?:help" "")
a1506d29 1364 M "p:pad" M "o:open" M "c:close" M "b:blank"
72cc582e
KS
1365 M "s:string" M "f:fill" M "i:incr" M "n:seq"))))
1366
1367
1368;;; CUA-like cut & paste for rectangles
1369
1370(defun cua--cancel-rectangle ()
1371 ;; Cancel rectangle
1372 (if cua--rectangle
1373 (cua--deactivate-rectangle))
1374 (setq cua--last-rectangle nil))
1375
1376(defun cua--rectangle-post-command ()
1377 (if cua--restored-rectangle
e4907bbe
KS
1378 (progn
1379 (setq cua--rectangle cua--restored-rectangle
1380 cua--restored-rectangle nil
1381 mark-active t
1382 deactivate-mark nil)
1383 (cua--rectangle-set-corners))
72cc582e
KS
1384 (when (and cua--rectangle cua--buffer-and-point-before-command
1385 (equal (car cua--buffer-and-point-before-command) (current-buffer))
1386 (not (= (cdr cua--buffer-and-point-before-command) (point))))
1387 (if (cua--rectangle-right-side)
1388 (cua--rectangle-right (current-column))
1389 (cua--rectangle-left (current-column)))
1390 (if (>= (cua--rectangle-corner) 2)
1391 (cua--rectangle-bot t)
72797108 1392 (cua--rectangle-top t))))
72cc582e
KS
1393 (if cua--rectangle
1394 (if (and mark-active
1395 (not deactivate-mark))
1396 (cua--highlight-rectangle)
c0e4cc19
KS
1397 (cua--deactivate-rectangle))
1398 (when cua--rectangle-overlays
1399 ;; clean-up after revert-buffer
026056a4 1400 (mapc (function delete-overlay) cua--rectangle-overlays)
c0e4cc19
KS
1401 (setq cua--rectangle-overlays nil)
1402 (setq deactivate-mark t)))
e4907bbe
KS
1403 (when cua--rect-undo-set-point
1404 (goto-char cua--rect-undo-set-point)
1405 (setq cua--rect-undo-set-point nil)))
72cc582e
KS
1406
1407;;; Initialization
1408
1409(defun cua--rect-M/H-key (key cmd)
1410 (cua--M/H-key cua--rectangle-keymap key cmd))
1411
72cc582e 1412(defun cua--init-rectangles ()
27366995
KS
1413 (define-key cua--rectangle-keymap cua-rectangle-mark-key 'cua-clear-rectangle-mark)
1414 (define-key cua--region-keymap cua-rectangle-mark-key 'cua-toggle-rectangle-mark)
1638bf54
KS
1415 (unless (eq cua--rectangle-modifier-key 'meta)
1416 (cua--rect-M/H-key ?\s 'cua-clear-rectangle-mark)
1417 (cua--M/H-key cua--region-keymap ?\s 'cua-toggle-rectangle-mark))
72cc582e
KS
1418
1419 (define-key cua--rectangle-keymap [remap copy-region-as-kill] 'cua-copy-rectangle)
1420 (define-key cua--rectangle-keymap [remap kill-ring-save] 'cua-copy-rectangle)
1421 (define-key cua--rectangle-keymap [remap kill-region] 'cua-cut-rectangle)
1422 (define-key cua--rectangle-keymap [remap delete-char] 'cua-delete-rectangle)
1423 (define-key cua--rectangle-keymap [remap set-mark-command] 'cua-toggle-rectangle-mark)
1424
1425 (define-key cua--rectangle-keymap [remap forward-char] 'cua-resize-rectangle-right)
1426 (define-key cua--rectangle-keymap [remap backward-char] 'cua-resize-rectangle-left)
1427 (define-key cua--rectangle-keymap [remap next-line] 'cua-resize-rectangle-down)
1428 (define-key cua--rectangle-keymap [remap previous-line] 'cua-resize-rectangle-up)
1429 (define-key cua--rectangle-keymap [remap end-of-line] 'cua-resize-rectangle-eol)
1430 (define-key cua--rectangle-keymap [remap beginning-of-line] 'cua-resize-rectangle-bol)
1431 (define-key cua--rectangle-keymap [remap end-of-buffer] 'cua-resize-rectangle-bot)
1432 (define-key cua--rectangle-keymap [remap beginning-of-buffer] 'cua-resize-rectangle-top)
1433 (define-key cua--rectangle-keymap [remap scroll-down] 'cua-resize-rectangle-page-up)
1434 (define-key cua--rectangle-keymap [remap scroll-up] 'cua-resize-rectangle-page-down)
32129746
JL
1435 (define-key cua--rectangle-keymap [remap scroll-down-command] 'cua-resize-rectangle-page-up)
1436 (define-key cua--rectangle-keymap [remap scroll-up-command] 'cua-resize-rectangle-page-down)
72cc582e
KS
1437
1438 (define-key cua--rectangle-keymap [remap delete-backward-char] 'cua-delete-char-rectangle)
1439 (define-key cua--rectangle-keymap [remap backward-delete-char] 'cua-delete-char-rectangle)
1440 (define-key cua--rectangle-keymap [remap backward-delete-char-untabify] 'cua-delete-char-rectangle)
1441 (define-key cua--rectangle-keymap [remap self-insert-command] 'cua-insert-char-rectangle)
1442 (define-key cua--rectangle-keymap [remap self-insert-iso] 'cua-insert-char-rectangle)
a1506d29 1443
e3f01f30
KS
1444 ;; Catch self-inserting characters which are "stolen" by other modes
1445 (define-key cua--rectangle-keymap [t]
1446 '(menu-item "sic" cua-insert-char-rectangle :filter cua--self-insert-char-p))
1447
72cc582e
KS
1448 (define-key cua--rectangle-keymap "\r" 'cua-rotate-rectangle)
1449 (define-key cua--rectangle-keymap "\t" 'cua-indent-rectangle)
1450
1451 (define-key cua--rectangle-keymap [(control ??)] 'cua-help-for-rectangle)
1452
1453 (define-key cua--rectangle-keymap [mouse-1] 'cua-mouse-set-rectangle-mark)
1454 (define-key cua--rectangle-keymap [down-mouse-1] 'cua--mouse-ignore)
1455 (define-key cua--rectangle-keymap [drag-mouse-1] 'cua--mouse-ignore)
1456 (define-key cua--rectangle-keymap [mouse-3] 'cua-mouse-save-then-kill-rectangle)
1457 (define-key cua--rectangle-keymap [down-mouse-3] 'cua--mouse-ignore)
1458 (define-key cua--rectangle-keymap [drag-mouse-3] 'cua--mouse-ignore)
1459
1460 (cua--rect-M/H-key 'up 'cua-move-rectangle-up)
1461 (cua--rect-M/H-key 'down 'cua-move-rectangle-down)
1462 (cua--rect-M/H-key 'left 'cua-move-rectangle-left)
1463 (cua--rect-M/H-key 'right 'cua-move-rectangle-right)
1464
1465 (cua--rect-M/H-key '(control up) 'cua-scroll-rectangle-up)
1466 (cua--rect-M/H-key '(control down) 'cua-scroll-rectangle-down)
1467
1468 (cua--rect-M/H-key ?a 'cua-align-rectangle)
1469 (cua--rect-M/H-key ?b 'cua-blank-rectangle)
1470 (cua--rect-M/H-key ?c 'cua-close-rectangle)
1471 (cua--rect-M/H-key ?f 'cua-fill-char-rectangle)
1472 (cua--rect-M/H-key ?i 'cua-incr-rectangle)
1473 (cua--rect-M/H-key ?k 'cua-cut-rectangle-as-text)
1474 (cua--rect-M/H-key ?l 'cua-downcase-rectangle)
1475 (cua--rect-M/H-key ?m 'cua-copy-rectangle-as-text)
1476 (cua--rect-M/H-key ?n 'cua-sequence-rectangle)
1477 (cua--rect-M/H-key ?o 'cua-open-rectangle)
72797108 1478 (cua--rect-M/H-key ?p 'cua-toggle-rectangle-virtual-edges)
72cc582e
KS
1479 (cua--rect-M/H-key ?P 'cua-do-rectangle-padding)
1480 (cua--rect-M/H-key ?q 'cua-refill-rectangle)
1481 (cua--rect-M/H-key ?r 'cua-replace-in-rectangle)
1482 (cua--rect-M/H-key ?R 'cua-reverse-rectangle)
1483 (cua--rect-M/H-key ?s 'cua-string-rectangle)
1484 (cua--rect-M/H-key ?t 'cua-text-fill-rectangle)
1485 (cua--rect-M/H-key ?u 'cua-upcase-rectangle)
1486 (cua--rect-M/H-key ?| 'cua-shell-command-on-rectangle)
1487 (cua--rect-M/H-key ?' 'cua-restrict-prefix-rectangle)
1488 (cua--rect-M/H-key ?/ 'cua-restrict-regexp-rectangle)
1489
1490 (setq cua--rectangle-initialized t))
1491
2c0f8564
GM
1492(provide 'cua-rect)
1493
cbee283d 1494;; arch-tag: b730df53-17b9-4a89-bd63-4a71ec196731
72cc582e 1495;;; cua-rect.el ends here