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