diff options
| author | Stefan Monnier | 2014-06-11 17:51:44 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2014-06-11 17:51:44 -0400 |
| commit | 7e74ad023826cfe89604b09b605ef74679b375e2 (patch) | |
| tree | b60095b9e15c1177ff6d30e6db571bd509690c5b | |
| parent | b83db3b9439b36e84cf8dfb253b8a6006f726c4d (diff) | |
| download | emacs-7e74ad023826cfe89604b09b605ef74679b375e2.tar.gz emacs-7e74ad023826cfe89604b09b605ef74679b375e2.zip | |
* lisp/rect.el: Make it possible to move bounds past EOL or into TABs.
(operate-on-rectangle): Use apply-on-rectangle.
(rectangle--mark-crutches): New var.
(rectangle--pos-cols, rectangle--col-pos, rectangle--point-col)
(rectangle--crutches, rectangle--reset-crutches): New functions.
(apply-on-rectangle): Obey crutches. Avoid setq.
Fix missing final iteration if end is at EOB&BOL.
(rectangle-mark-mode-map): Add remap bindings for
exchange-point-and-mark and char/line movements.
(rectangle--*-char): New function.
(rectangle-exchange-point-and-mark, rectangle-right-char)
(rectangle-left-char, rectangle-forward-char)
(rectangle-backward-char, rectangle-next-line)
(rectangle-previous-line): New commands.
(rectangle--place-cursor): New function.
(rectangle--highlight-for-redisplay): Use it. Use apply-on-rectangle.
| -rw-r--r-- | etc/NEWS | 3 | ||||
| -rw-r--r-- | lisp/ChangeLog | 19 | ||||
| -rw-r--r-- | lisp/rect.el | 412 |
3 files changed, 303 insertions, 131 deletions
| @@ -72,6 +72,9 @@ performance improvements when pasting large amounts of text. | |||
| 72 | 72 | ||
| 73 | * Changes in Specialized Modes and Packages in Emacs 24.5 | 73 | * Changes in Specialized Modes and Packages in Emacs 24.5 |
| 74 | 74 | ||
| 75 | ** rectangle-mark-mode can now have corners past EOL or in the middle of a TAB | ||
| 76 | Also C-x C-x in rectangle-mark-mode now cycles through the four corners. | ||
| 77 | |||
| 75 | ** font-lock | 78 | ** font-lock |
| 76 | *** New functions font-lock-ensure and font-lock-flush that should be used | 79 | *** New functions font-lock-ensure and font-lock-flush that should be used |
| 77 | instead of font-lock-fontify-buffer when called from Elisp. | 80 | instead of font-lock-fontify-buffer when called from Elisp. |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 2ce06f6ba54..3df94a73929 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,22 @@ | |||
| 1 | 2014-06-11 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * rect.el: Make it possible to move bounds past EOL or into TABs. | ||
| 4 | (operate-on-rectangle): Use apply-on-rectangle. | ||
| 5 | (rectangle--mark-crutches): New var. | ||
| 6 | (rectangle--pos-cols, rectangle--col-pos, rectangle--point-col) | ||
| 7 | (rectangle--crutches, rectangle--reset-crutches): New functions. | ||
| 8 | (apply-on-rectangle): Obey crutches. Avoid setq. | ||
| 9 | Fix missing final iteration if end is at EOB&BOL. | ||
| 10 | (rectangle-mark-mode-map): Add remap bindings for | ||
| 11 | exchange-point-and-mark and char/line movements. | ||
| 12 | (rectangle--*-char): New function. | ||
| 13 | (rectangle-exchange-point-and-mark, rectangle-right-char) | ||
| 14 | (rectangle-left-char, rectangle-forward-char) | ||
| 15 | (rectangle-backward-char, rectangle-next-line) | ||
| 16 | (rectangle-previous-line): New commands. | ||
| 17 | (rectangle--place-cursor): New function. | ||
| 18 | (rectangle--highlight-for-redisplay): Use it. Use apply-on-rectangle. | ||
| 19 | |||
| 1 | 2014-06-08 Glenn Morris <rgm@gnu.org> | 20 | 2014-06-08 Glenn Morris <rgm@gnu.org> |
| 2 | 21 | ||
| 3 | * startup.el (initial-buffer-choice): Doc fix. | 22 | * startup.el (initial-buffer-choice): Doc fix. |
diff --git a/lisp/rect.el b/lisp/rect.el index e798b07b556..603ed8c95d1 100644 --- a/lisp/rect.el +++ b/lisp/rect.el | |||
| @@ -31,6 +31,8 @@ | |||
| 31 | 31 | ||
| 32 | ;;; Code: | 32 | ;;; Code: |
| 33 | 33 | ||
| 34 | (eval-when-compile (require 'cl-lib)) | ||
| 35 | |||
| 34 | ;; FIXME: this function should be replaced by `apply-on-rectangle' | 36 | ;; FIXME: this function should be replaced by `apply-on-rectangle' |
| 35 | (defun operate-on-rectangle (function start end coerce-tabs) | 37 | (defun operate-on-rectangle (function start end coerce-tabs) |
| 36 | "Call FUNCTION for each line of rectangle with corners at START, END. | 38 | "Call FUNCTION for each line of rectangle with corners at START, END. |
| @@ -42,42 +44,95 @@ FUNCTION is called with three arguments: | |||
| 42 | number of columns that belong to rectangle but are before that position, | 44 | number of columns that belong to rectangle but are before that position, |
| 43 | number of columns that belong to rectangle but are after point. | 45 | number of columns that belong to rectangle but are after point. |
| 44 | Point is at the end of the segment of this line within the rectangle." | 46 | Point is at the end of the segment of this line within the rectangle." |
| 45 | (let (startcol startlinepos endcol endlinepos) | 47 | (apply-on-rectangle |
| 46 | (save-excursion | 48 | (lambda (startcol endcol) |
| 47 | (goto-char start) | 49 | (let (startpos begextra endextra) |
| 48 | (setq startcol (current-column)) | 50 | (move-to-column startcol coerce-tabs) |
| 49 | (beginning-of-line) | 51 | (setq begextra (- (current-column) startcol)) |
| 50 | (setq startlinepos (point))) | 52 | (setq startpos (point)) |
| 51 | (save-excursion | 53 | (move-to-column endcol coerce-tabs) |
| 52 | (goto-char end) | 54 | ;; If we overshot, move back one character |
| 53 | (setq endcol (current-column)) | 55 | ;; so that endextra will be positive. |
| 54 | (forward-line 1) | 56 | (if (and (not coerce-tabs) (> (current-column) endcol)) |
| 55 | (setq endlinepos (point-marker))) | 57 | (backward-char 1)) |
| 56 | (if (< endcol startcol) | 58 | (setq endextra (- endcol (current-column))) |
| 57 | (setq startcol (prog1 endcol (setq endcol startcol)))) | 59 | (if (< begextra 0) |
| 58 | (save-excursion | 60 | (setq endextra (+ endextra begextra) |
| 59 | (goto-char startlinepos) | 61 | begextra 0)) |
| 60 | (while (< (point) endlinepos) | 62 | (funcall function startpos begextra endextra))) |
| 61 | (let (startpos begextra endextra) | 63 | start end)) |
| 62 | (if coerce-tabs | 64 | |
| 63 | (move-to-column startcol t) | 65 | ;;; Crutches to let rectangle's corners be where point can't be |
| 64 | (move-to-column startcol)) | 66 | ;; (e.g. in the middle of a TAB, or past the EOL). |
| 65 | (setq begextra (- (current-column) startcol)) | 67 | |
| 66 | (setq startpos (point)) | 68 | (defvar-local rectangle--mark-crutches nil |
| 67 | (if coerce-tabs | 69 | "(POS . COL) to override the column to use for the mark.") |
| 68 | (move-to-column endcol t) | 70 | |
| 69 | (move-to-column endcol)) | 71 | (defun rectangle--pos-cols (start end) |
| 70 | ;; If we overshot, move back one character | 72 | ;; At this stage, we don't know which of start/end is point/mark :-( |
| 71 | ;; so that endextra will be positive. | 73 | ;; And in case start=end, it might still be that point and mark have |
| 72 | (if (and (not coerce-tabs) (> (current-column) endcol)) | 74 | ;; different crutches! |
| 73 | (backward-char 1)) | 75 | (let ((cw (window-parameter nil 'rectangle--point-crutches))) |
| 74 | (setq endextra (- endcol (current-column))) | 76 | (cond |
| 75 | (if (< begextra 0) | 77 | ((eq start (car cw)) |
| 76 | (setq endextra (+ endextra begextra) | 78 | (let ((sc (cdr cw)) |
| 77 | begextra 0)) | 79 | (ec (if (eq end (car rectangle--mark-crutches)) |
| 78 | (funcall function startpos begextra endextra)) | 80 | (cdr rectangle--mark-crutches) |
| 79 | (forward-line 1))) | 81 | (if rectangle--mark-crutches |
| 80 | (- endcol startcol))) | 82 | (setq rectangle--mark-crutches nil)) |
| 83 | (goto-char end) (current-column)))) | ||
| 84 | (if (eq start end) (cons (min sc ec) (max sc ec)) (cons sc ec)))) | ||
| 85 | ((eq end (car cw)) | ||
| 86 | (if (eq start (car rectangle--mark-crutches)) | ||
| 87 | (cons (cdr rectangle--mark-crutches) (cdr cw)) | ||
| 88 | (if rectangle--mark-crutches (setq rectangle--mark-crutches nil)) | ||
| 89 | (cons (progn (goto-char start) (current-column)) (cdr cw)))) | ||
| 90 | ((progn | ||
| 91 | (if cw (setf (window-parameter nil 'rectangle--point-crutches) nil)) | ||
| 92 | (eq start (car rectangle--mark-crutches))) | ||
| 93 | (let ((sc (cdr rectangle--mark-crutches)) | ||
| 94 | (ec (progn (goto-char end) (current-column)))) | ||
| 95 | (if (eq start end) (cons (min sc ec) (max sc ec)) (cons sc ec)))) | ||
| 96 | ((eq end (car rectangle--mark-crutches)) | ||
| 97 | (cons (progn (goto-char start) (current-column)) | ||
| 98 | (cdr rectangle--mark-crutches))) | ||
| 99 | (t | ||
| 100 | (if rectangle--mark-crutches (setq rectangle--mark-crutches nil)) | ||
| 101 | (cons (progn (goto-char start) (current-column)) | ||
| 102 | (progn (goto-char end) (current-column))))))) | ||
| 103 | |||
| 104 | (defun rectangle--col-pos (col kind) | ||
| 105 | (let ((c (move-to-column col))) | ||
| 106 | (if (= c col) | ||
| 107 | (if (eq kind 'point) | ||
| 108 | (if (window-parameter nil 'rectangle--point-crutches) | ||
| 109 | (setf (window-parameter nil 'rectangle--point-crutches) nil)) | ||
| 110 | (if rectangle--mark-crutches (setq rectangle--mark-crutches nil))) | ||
| 111 | ;; If move-to-column over-shooted, move back one char so we're | ||
| 112 | ;; at the position where rectangle--highlight-for-redisplay | ||
| 113 | ;; will add the overlay (so that the cursor can be drawn at the | ||
| 114 | ;; right place). | ||
| 115 | (when (> c col) (forward-char -1)) | ||
| 116 | (setf (if (eq kind 'point) | ||
| 117 | (window-parameter nil 'rectangle--point-crutches) | ||
| 118 | rectangle--mark-crutches) | ||
| 119 | (cons (point) col))))) | ||
| 120 | |||
| 121 | (defun rectangle--point-col (pos) | ||
| 122 | (let ((pc (window-parameter nil 'rectangle--point-crutches))) | ||
| 123 | (if (eq pos (car pc)) (cdr pc) | ||
| 124 | (goto-char pos) | ||
| 125 | (current-column)))) | ||
| 126 | |||
| 127 | (defun rectangle--crutches () | ||
| 128 | (cons rectangle--mark-crutches | ||
| 129 | (window-parameter nil 'rectangle--point-crutches))) | ||
| 130 | (defun rectangle--reset-crutches () | ||
| 131 | (kill-local-variable 'rectangle--mark-crutches) | ||
| 132 | (if (window-parameter nil 'rectangle--point-crutches) | ||
| 133 | (setf (window-parameter nil 'rectangle--point-crutches) nil))) | ||
| 134 | |||
| 135 | ;;; Rectangle operations. | ||
| 81 | 136 | ||
| 82 | (defun apply-on-rectangle (function start end &rest args) | 137 | (defun apply-on-rectangle (function start end &rest args) |
| 83 | "Call FUNCTION for each line of rectangle with corners at START, END. | 138 | "Call FUNCTION for each line of rectangle with corners at START, END. |
| @@ -85,27 +140,27 @@ FUNCTION is called with two arguments: the start and end columns of the | |||
| 85 | rectangle, plus ARGS extra arguments. Point is at the beginning of line when | 140 | rectangle, plus ARGS extra arguments. Point is at the beginning of line when |
| 86 | the function is called. | 141 | the function is called. |
| 87 | The final point after the last operation will be returned." | 142 | The final point after the last operation will be returned." |
| 88 | (let (startcol startpt endcol endpt final-point) | 143 | (save-excursion |
| 89 | (save-excursion | 144 | (let* ((cols (rectangle--pos-cols start end)) |
| 90 | (goto-char start) | 145 | (startcol (car cols)) |
| 91 | (setq startcol (current-column)) | 146 | (endcol (cdr cols)) |
| 92 | (beginning-of-line) | 147 | (startpt (progn (goto-char start) (line-beginning-position))) |
| 93 | (setq startpt (point)) | 148 | (endpt (progn (goto-char end) |
| 94 | (goto-char end) | 149 | (copy-marker (line-end-position)))) |
| 95 | (setq endcol (current-column)) | 150 | final-point) |
| 96 | (forward-line 1) | 151 | ;; Ensure the start column is the left one. |
| 97 | (setq endpt (point-marker)) | ||
| 98 | ;; ensure the start column is the left one. | ||
| 99 | (if (< endcol startcol) | 152 | (if (< endcol startcol) |
| 100 | (let ((col startcol)) | 153 | (let ((col startcol)) |
| 101 | (setq startcol endcol endcol col))) | 154 | (setq startcol endcol endcol col))) |
| 102 | ;; start looping over lines | 155 | ;; Start looping over lines. |
| 103 | (goto-char startpt) | 156 | (goto-char startpt) |
| 104 | (while (< (point) endpt) | 157 | (while |
| 105 | (apply function startcol endcol args) | 158 | (progn |
| 106 | (setq final-point (point)) | 159 | (apply function startcol endcol args) |
| 107 | (forward-line 1))) | 160 | (setq final-point (point)) |
| 108 | final-point)) | 161 | (and (zerop (forward-line 1)) |
| 162 | (<= (point) endpt)))) | ||
| 163 | final-point))) | ||
| 109 | 164 | ||
| 110 | (defun delete-rectangle-line (startcol endcol fill) | 165 | (defun delete-rectangle-line (startcol endcol fill) |
| 111 | (when (= (move-to-column startcol (if fill t 'coerce)) startcol) | 166 | (when (= (move-to-column startcol (if fill t 'coerce)) startcol) |
| @@ -429,8 +484,12 @@ with a prefix argument, prompt for START-AT and FORMAT." | |||
| 429 | (let ((map (make-sparse-keymap))) | 484 | (let ((map (make-sparse-keymap))) |
| 430 | (define-key map [?\C-o] 'open-rectangle) | 485 | (define-key map [?\C-o] 'open-rectangle) |
| 431 | (define-key map [?\C-t] 'string-rectangle) | 486 | (define-key map [?\C-t] 'string-rectangle) |
| 432 | ;; (define-key map [remap open-line] 'open-rectangle) | 487 | (define-key map [remap exchange-point-and-mark] |
| 433 | ;; (define-key map [remap transpose-chars] 'string-rectangle) | 488 | 'rectangle-exchange-point-and-mark) |
| 489 | (dolist (cmd '(right-char left-char forward-char backward-char | ||
| 490 | next-line previous-line)) | ||
| 491 | (define-key map (vector 'remap cmd) | ||
| 492 | (intern (format "rectangle-%s" cmd)))) | ||
| 434 | map) | 493 | map) |
| 435 | "Keymap used while marking a rectangular region.") | 494 | "Keymap used while marking a rectangular region.") |
| 436 | 495 | ||
| @@ -439,6 +498,7 @@ with a prefix argument, prompt for START-AT and FORMAT." | |||
| 439 | "Toggle the region as rectangular. | 498 | "Toggle the region as rectangular. |
| 440 | Activates the region if needed. Only lasts until the region is deactivated." | 499 | Activates the region if needed. Only lasts until the region is deactivated." |
| 441 | nil nil nil | 500 | nil nil nil |
| 501 | (rectangle--reset-crutches) | ||
| 442 | (when rectangle-mark-mode | 502 | (when rectangle-mark-mode |
| 443 | (add-hook 'deactivate-mark-hook | 503 | (add-hook 'deactivate-mark-hook |
| 444 | (lambda () (rectangle-mark-mode -1))) | 504 | (lambda () (rectangle-mark-mode -1))) |
| @@ -447,6 +507,96 @@ Activates the region if needed. Only lasts until the region is deactivated." | |||
| 447 | (activate-mark) | 507 | (activate-mark) |
| 448 | (message "Mark set (rectangle mode)")))) | 508 | (message "Mark set (rectangle mode)")))) |
| 449 | 509 | ||
| 510 | (defun rectangle-exchange-point-and-mark (&optional arg) | ||
| 511 | "Like `exchange-point-and-mark' but cycles through the rectangle's corners." | ||
| 512 | (interactive "P") | ||
| 513 | (if arg | ||
| 514 | (progn | ||
| 515 | (setq this-command 'exchange-point-and-mark) | ||
| 516 | (exchange-point-and-mark arg)) | ||
| 517 | (let* ((p (point)) | ||
| 518 | (repeat (eq this-command last-command)) | ||
| 519 | (m (mark)) | ||
| 520 | (p<m (< p m)) | ||
| 521 | (cols (if p<m (rectangle--pos-cols p m) (rectangle--pos-cols m p))) | ||
| 522 | (cp (if p<m (car cols) (cdr cols))) | ||
| 523 | (cm (if p<m (cdr cols) (car cols)))) | ||
| 524 | (if repeat (setq this-command 'exchange-point-and-mark)) | ||
| 525 | (rectangle--reset-crutches) | ||
| 526 | (goto-char p) | ||
| 527 | (rectangle--col-pos (if repeat cm cp) 'mark) | ||
| 528 | (set-mark (point)) | ||
| 529 | (goto-char m) | ||
| 530 | (rectangle--col-pos (if repeat cp cm) 'point)))) | ||
| 531 | |||
| 532 | (defun rectangle--*-char (cmd n &optional other-cmd) | ||
| 533 | ;; Part of the complexity here is that I'm trying to avoid making assumptions | ||
| 534 | ;; about the L2R/R2L direction of text around point, but this is largely | ||
| 535 | ;; useless since the rectangles implemented in this file are "logical | ||
| 536 | ;; rectangles" and not "visual rectangles", so in the presence of | ||
| 537 | ;; bidirectional text things won't work well anyway. | ||
| 538 | (if (< n 0) (rectangle--*-char other-cmd (- n)) | ||
| 539 | (let ((col (rectangle--point-col (point)))) | ||
| 540 | (while (> n 0) | ||
| 541 | (let* ((bol (line-beginning-position)) | ||
| 542 | (eol (line-end-position)) | ||
| 543 | (curcol (current-column)) | ||
| 544 | (nextcol | ||
| 545 | (condition-case nil | ||
| 546 | (save-excursion | ||
| 547 | (funcall cmd 1) | ||
| 548 | (cond | ||
| 549 | ((> bol (point)) (- curcol 1)) | ||
| 550 | ((< eol (point)) (+ col (1+ n))) | ||
| 551 | (t (current-column)))) | ||
| 552 | (end-of-buffer (+ col (1+ n))) | ||
| 553 | (beginning-of-buffer (- curcol 1)))) | ||
| 554 | (diff (abs (- nextcol col)))) | ||
| 555 | (cond | ||
| 556 | ((and (< nextcol curcol) (< curcol col)) | ||
| 557 | (let ((curdiff (- col curcol))) | ||
| 558 | (if (<= curdiff n) | ||
| 559 | (progn (cl-decf n curdiff) (setq col curcol)) | ||
| 560 | (setq col (- col n) n 0)))) | ||
| 561 | ((< nextcol 0) (ding) (setq n 0 col 0)) ;Bumping into BOL! | ||
| 562 | ((= nextcol curcol) (funcall cmd 1)) | ||
| 563 | (t ;; (> nextcol curcol) | ||
| 564 | (if (<= diff n) | ||
| 565 | (progn (cl-decf n diff) (setq col nextcol)) | ||
| 566 | (setq col (if (< col nextcol) (+ col n) (- col n)) n 0)))))) | ||
| 567 | ;; FIXME: This rectangle--col-pos's move-to-column is wasted! | ||
| 568 | (rectangle--col-pos col 'point)))) | ||
| 569 | |||
| 570 | (defun rectangle-right-char (&optional n) | ||
| 571 | "Like `right-char' but steps into wide chars and moves past EOL." | ||
| 572 | (interactive "p") (rectangle--*-char #'right-char n #'left-char)) | ||
| 573 | (defun rectangle-left-char (&optional n) | ||
| 574 | "Like `left-char' but steps into wide chars and moves past EOL." | ||
| 575 | (interactive "p") (rectangle--*-char #'left-char n #'right-char)) | ||
| 576 | |||
| 577 | (defun rectangle-forward-char (&optional n) | ||
| 578 | "Like `forward-char' but steps into wide chars and moves past EOL." | ||
| 579 | (interactive "p") (rectangle--*-char #'forward-char n #'backward-char)) | ||
| 580 | (defun rectangle-backward-char (&optional n) | ||
| 581 | "Like `backward-char' but steps into wide chars and moves past EOL." | ||
| 582 | (interactive "p") (rectangle--*-char #'backward-char n #'forward-char)) | ||
| 583 | |||
| 584 | (defun rectangle-next-line (&optional n) | ||
| 585 | "Like `next-line' but steps into wide chars and moves past EOL. | ||
| 586 | Ignores `line-move-visual'." | ||
| 587 | (interactive "p") | ||
| 588 | (let ((col (rectangle--point-col (point)))) | ||
| 589 | (forward-line n) | ||
| 590 | (rectangle--col-pos col 'point))) | ||
| 591 | (defun rectangle-previous-line (&optional n) | ||
| 592 | "Like `previous-line' but steps into wide chars and moves past EOL. | ||
| 593 | Ignores `line-move-visual'." | ||
| 594 | (interactive "p") | ||
| 595 | (let ((col (rectangle--point-col (point)))) | ||
| 596 | (forward-line (- n)) | ||
| 597 | (rectangle--col-pos col 'point))) | ||
| 598 | |||
| 599 | |||
| 450 | (defun rectangle--extract-region (orig &optional delete) | 600 | (defun rectangle--extract-region (orig &optional delete) |
| 451 | (if (not rectangle-mark-mode) | 601 | (if (not rectangle-mark-mode) |
| 452 | (funcall orig delete) | 602 | (funcall orig delete) |
| @@ -476,6 +626,11 @@ Activates the region if needed. Only lasts until the region is deactivated." | |||
| 476 | (while (not (eq pending-undo-list (cdr undo-at-start))) | 626 | (while (not (eq pending-undo-list (cdr undo-at-start))) |
| 477 | (undo-more 1)))))) | 627 | (undo-more 1)))))) |
| 478 | 628 | ||
| 629 | (defun rectangle--place-cursor (leftcol left str) | ||
| 630 | (let ((pc (window-parameter nil 'rectangle--point-crutches))) | ||
| 631 | (if (and (eq left (car pc)) (eq leftcol (cdr pc))) | ||
| 632 | (put-text-property 0 1 'cursor 1 str)))) | ||
| 633 | |||
| 479 | (defun rectangle--highlight-for-redisplay (orig start end window rol) | 634 | (defun rectangle--highlight-for-redisplay (orig start end window rol) |
| 480 | (cond | 635 | (cond |
| 481 | ((not rectangle-mark-mode) | 636 | ((not rectangle-mark-mode) |
| @@ -483,93 +638,88 @@ Activates the region if needed. Only lasts until the region is deactivated." | |||
| 483 | ((and (eq 'rectangle (car-safe rol)) | 638 | ((and (eq 'rectangle (car-safe rol)) |
| 484 | (eq (nth 1 rol) (buffer-chars-modified-tick)) | 639 | (eq (nth 1 rol) (buffer-chars-modified-tick)) |
| 485 | (eq start (nth 2 rol)) | 640 | (eq start (nth 2 rol)) |
| 486 | (eq end (nth 3 rol))) | 641 | (eq end (nth 3 rol)) |
| 642 | (equal (rectangle--crutches) (nth 4 rol))) | ||
| 487 | rol) | 643 | rol) |
| 488 | (t | 644 | (t |
| 489 | (save-excursion | 645 | (save-excursion |
| 490 | (let* ((nrol nil) | 646 | (let* ((nrol nil) |
| 491 | (old (if (eq 'rectangle (car-safe rol)) | 647 | (old (if (eq 'rectangle (car-safe rol)) |
| 492 | (nthcdr 4 rol) | 648 | (nthcdr 5 rol) |
| 493 | (funcall redisplay-unhighlight-region-function rol) | 649 | (funcall redisplay-unhighlight-region-function rol) |
| 494 | nil)) | 650 | nil))) |
| 495 | (ptcol (progn (goto-char start) (current-column))) | 651 | (apply-on-rectangle |
| 496 | (markcol (progn (goto-char end) (current-column))) | 652 | (lambda (leftcol rightcol) |
| 497 | (leftcol (min ptcol markcol)) | 653 | (let* ((mleft (move-to-column leftcol)) |
| 498 | (rightcol (max ptcol markcol))) | 654 | (left (point)) |
| 499 | (goto-char start) | 655 | (mright (move-to-column rightcol)) |
| 500 | (while | 656 | (right (point)) |
| 501 | (let* ((mleft (move-to-column leftcol)) | 657 | (ol |
| 502 | (left (point)) | 658 | (if (not old) |
| 503 | (mright (move-to-column rightcol)) | 659 | (let ((ol (make-overlay left right))) |
| 504 | (right (point)) | 660 | (overlay-put ol 'window window) |
| 505 | (ol | 661 | (overlay-put ol 'face 'region) |
| 506 | (if (not old) | 662 | ol) |
| 507 | (let ((ol (make-overlay left right))) | 663 | (let ((ol (pop old))) |
| 508 | (overlay-put ol 'window window) | 664 | (move-overlay ol left right (current-buffer)) |
| 509 | (overlay-put ol 'face 'region) | 665 | ol)))) |
| 510 | ol) | 666 | ;; `move-to-column' may stop before the column (if bumping into |
| 511 | (let ((ol (pop old))) | 667 | ;; EOL) or overshoot it a little, when column is in the middle |
| 512 | (move-overlay ol left right (current-buffer)) | 668 | ;; of a char. |
| 513 | ol)))) | 669 | (cond |
| 514 | ;; `move-to-column' may stop before the column (if bumping into | 670 | ((< mleft leftcol) ;`leftcol' is past EOL. |
| 515 | ;; EOL) or overshoot it a little, when column is in the middle | 671 | (overlay-put ol 'before-string |
| 516 | ;; of a char. | 672 | (spaces-string (- leftcol mleft))) |
| 517 | (cond | 673 | (setq mright (max mright leftcol))) |
| 518 | ((< mleft leftcol) ;`leftcol' is past EOL. | 674 | ((and (> mleft leftcol) ;`leftcol' is in the middle of a char. |
| 519 | (overlay-put ol 'before-string | 675 | (eq (char-before left) ?\t)) |
| 520 | (spaces-string (- leftcol mleft))) | 676 | (setq left (1- left)) |
| 521 | (setq mright (max mright leftcol))) | 677 | (move-overlay ol left right) |
| 522 | ((and (> mleft leftcol) ;`leftcol' is in the middle of a char. | 678 | (goto-char left) |
| 523 | (eq (char-before left) ?\t)) | 679 | (overlay-put ol 'before-string |
| 524 | (setq left (1- left)) | 680 | (spaces-string (- leftcol (current-column))))) |
| 525 | (move-overlay ol left right) | 681 | ((overlay-get ol 'before-string) |
| 526 | (goto-char left) | 682 | (overlay-put ol 'before-string nil))) |
| 527 | (overlay-put ol 'before-string | 683 | (cond |
| 528 | (spaces-string (- leftcol (current-column))))) | 684 | ((< mright rightcol) ;`rightcol' is past EOL. |
| 529 | ((overlay-get ol 'before-string) | 685 | (let ((str (make-string (- rightcol mright) ?\s))) |
| 530 | (overlay-put ol 'before-string nil))) | 686 | (put-text-property 0 (length str) 'face 'region str) |
| 531 | (cond | 687 | ;; If cursor happens to be here, draw it at the right place. |
| 532 | ((< mright rightcol) ;`rightcol' is past EOL. | 688 | (rectangle--place-cursor leftcol left str) |
| 533 | (let ((str (make-string (- rightcol mright) ?\s))) | 689 | (overlay-put ol 'after-string str))) |
| 534 | (put-text-property 0 (length str) 'face 'region str) | 690 | ((and (> mright rightcol) ;`rightcol's in the middle of a char. |
| 535 | ;; If cursor happens to be here, draw it *before* rather than | 691 | (eq (char-before right) ?\t)) |
| 536 | ;; after this highlighted pseudo-text. | 692 | (setq right (1- right)) |
| 537 | (put-text-property 0 1 'cursor t str) | 693 | (move-overlay ol left right) |
| 538 | (overlay-put ol 'after-string str))) | 694 | (if (= rightcol leftcol) |
| 539 | ((and (> mright rightcol) ;`rightcol's in the middle of a char. | 695 | (overlay-put ol 'after-string nil) |
| 540 | (eq (char-before right) ?\t)) | 696 | (goto-char right) |
| 541 | (setq right (1- right)) | 697 | (let ((str (make-string |
| 542 | (move-overlay ol left right) | 698 | (- rightcol (max leftcol (current-column))) |
| 543 | (if (= rightcol leftcol) | 699 | ?\s))) |
| 544 | (overlay-put ol 'after-string nil) | 700 | (put-text-property 0 (length str) 'face 'region str) |
| 545 | (goto-char right) | 701 | (when (= left right) |
| 546 | (let ((str (make-string | 702 | (rectangle--place-cursor leftcol left str)) |
| 547 | (- rightcol (max leftcol (current-column))) | 703 | (overlay-put ol 'after-string str)))) |
| 548 | ?\s))) | 704 | ((overlay-get ol 'after-string) |
| 549 | (put-text-property 0 (length str) 'face 'region str) | 705 | (overlay-put ol 'after-string nil))) |
| 550 | (when (= left right) | 706 | (when (and (= leftcol rightcol) (display-graphic-p)) |
| 551 | ;; If cursor happens to be here, draw it *before* rather | 707 | ;; Make zero-width rectangles visible! |
| 552 | ;; than after this highlighted pseudo-text. | 708 | (overlay-put ol 'after-string |
| 553 | (put-text-property 0 1 'cursor 1 str)) | 709 | (concat (propertize " " |
| 554 | (overlay-put ol 'after-string str)))) | 710 | 'face '(region (:height 0.2))) |
| 555 | ((overlay-get ol 'after-string) | 711 | (overlay-get ol 'after-string)))) |
| 556 | (overlay-put ol 'after-string nil))) | 712 | (push ol nrol))) |
| 557 | (when (and (= leftcol rightcol) (display-graphic-p)) | 713 | start end) |
| 558 | ;; Make zero-width rectangles visible! | ||
| 559 | (overlay-put ol 'after-string | ||
| 560 | (concat (propertize " " | ||
| 561 | 'face '(region (:height 0.2))) | ||
| 562 | (overlay-get ol 'after-string)))) | ||
| 563 | (push ol nrol) | ||
| 564 | (and (zerop (forward-line 1)) | ||
| 565 | (<= (point) end)))) | ||
| 566 | (mapc #'delete-overlay old) | 714 | (mapc #'delete-overlay old) |
| 567 | `(rectangle ,(buffer-chars-modified-tick) ,start ,end ,@nrol)))))) | 715 | `(rectangle ,(buffer-chars-modified-tick) |
| 716 | ,start ,end ,(rectangle--crutches) | ||
| 717 | ,@nrol)))))) | ||
| 568 | 718 | ||
| 569 | (defun rectangle--unhighlight-for-redisplay (orig rol) | 719 | (defun rectangle--unhighlight-for-redisplay (orig rol) |
| 570 | (if (not (eq 'rectangle (car-safe rol))) | 720 | (if (not (eq 'rectangle (car-safe rol))) |
| 571 | (funcall orig rol) | 721 | (funcall orig rol) |
| 572 | (mapc #'delete-overlay (nthcdr 4 rol)) | 722 | (mapc #'delete-overlay (nthcdr 5 rol)) |
| 573 | (setcar (cdr rol) nil))) | 723 | (setcar (cdr rol) nil))) |
| 574 | 724 | ||
| 575 | (provide 'rect) | 725 | (provide 'rect) |