diff options
| author | Federico Tedin | 2018-10-17 08:34:51 +0200 |
|---|---|---|
| committer | Martin Rudalics | 2018-10-17 08:34:51 +0200 |
| commit | 134ba45bf0c11048c44a46c11d5dc8da12ca4d3e (patch) | |
| tree | f53bdbe0caa4343fd7fbecdb6f2c09db39984079 | |
| parent | e64065bbbd21b7136a7a4efb4b0f2f39a65905dd (diff) | |
| download | emacs-134ba45bf0c11048c44a46c11d5dc8da12ca4d3e.tar.gz emacs-134ba45bf0c11048c44a46c11d5dc8da12ca4d3e.zip | |
Allow two mouse functions to work with Rectangle Mark mode
* lisp/mouse.el (mouse-save-then-kill): Make
mouse-save-then-kill work with rectangular regions, including
when mouse-drag-copy-region is set to t. (Bug#31240)
(mouse-drag-and-drop-region): Allow dragging and dropping
rectangular regions. (Bug#31240)
* rect.el (rectangle-intersect-p)
(rectangle-position-as-coordinates): New functions.
| -rw-r--r-- | lisp/mouse.el | 106 | ||||
| -rw-r--r-- | lisp/rect.el | 31 |
2 files changed, 111 insertions, 26 deletions
diff --git a/lisp/mouse.el b/lisp/mouse.el index cb63ca51c54..44cca4c868a 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | 29 | ||
| 30 | ;;; Code: | 30 | ;;; Code: |
| 31 | 31 | ||
| 32 | (eval-when-compile (require 'rect)) | ||
| 33 | |||
| 32 | ;;; Utility functions. | 34 | ;;; Utility functions. |
| 33 | 35 | ||
| 34 | ;; Indent track-mouse like progn. | 36 | ;; Indent track-mouse like progn. |
| @@ -1606,8 +1608,8 @@ if `mouse-drag-copy-region' is non-nil)" | |||
| 1606 | (if mouse-drag-copy-region | 1608 | (if mouse-drag-copy-region |
| 1607 | ;; Region already saved in the previous click; | 1609 | ;; Region already saved in the previous click; |
| 1608 | ;; don't make a duplicate entry, just delete. | 1610 | ;; don't make a duplicate entry, just delete. |
| 1609 | (delete-region (mark t) (point)) | 1611 | (funcall region-extract-function 'delete-only) |
| 1610 | (kill-region (mark t) (point))) | 1612 | (kill-region (mark t) (point) 'region)) |
| 1611 | (setq mouse-selection-click-count 0) | 1613 | (setq mouse-selection-click-count 0) |
| 1612 | (setq mouse-save-then-kill-posn nil)) | 1614 | (setq mouse-save-then-kill-posn nil)) |
| 1613 | 1615 | ||
| @@ -1632,7 +1634,7 @@ if `mouse-drag-copy-region' is non-nil)" | |||
| 1632 | (mouse-set-region-1) | 1634 | (mouse-set-region-1) |
| 1633 | (when mouse-drag-copy-region | 1635 | (when mouse-drag-copy-region |
| 1634 | ;; Region already copied to kill-ring once, so replace. | 1636 | ;; Region already copied to kill-ring once, so replace. |
| 1635 | (kill-new (filter-buffer-substring (mark t) (point)) t)) | 1637 | (kill-new (funcall region-extract-function nil) t)) |
| 1636 | ;; Arrange for a repeated mouse-3 to kill the region. | 1638 | ;; Arrange for a repeated mouse-3 to kill the region. |
| 1637 | (setq mouse-save-then-kill-posn click-pt))) | 1639 | (setq mouse-save-then-kill-posn click-pt))) |
| 1638 | 1640 | ||
| @@ -2411,7 +2413,16 @@ is copied instead of being cut." | |||
| 2411 | (buffer (current-buffer)) | 2413 | (buffer (current-buffer)) |
| 2412 | (window (selected-window)) | 2414 | (window (selected-window)) |
| 2413 | (text-from-read-only buffer-read-only) | 2415 | (text-from-read-only buffer-read-only) |
| 2414 | (mouse-drag-and-drop-overlay (make-overlay start end)) | 2416 | ;; Use multiple overlays to cover cases where the region is |
| 2417 | ;; rectangular. | ||
| 2418 | (mouse-drag-and-drop-overlays (mapcar (lambda (bounds) | ||
| 2419 | (make-overlay (car bounds) | ||
| 2420 | (cdr bounds))) | ||
| 2421 | (region-bounds))) | ||
| 2422 | (region-noncontiguous (region-noncontiguous-p)) | ||
| 2423 | (region-width (- (overlay-end (car mouse-drag-and-drop-overlays)) | ||
| 2424 | (overlay-start (car mouse-drag-and-drop-overlays)))) | ||
| 2425 | (region-height (length mouse-drag-and-drop-overlays)) | ||
| 2415 | point-to-paste | 2426 | point-to-paste |
| 2416 | point-to-paste-read-only | 2427 | point-to-paste-read-only |
| 2417 | window-to-paste | 2428 | window-to-paste |
| @@ -2455,7 +2466,11 @@ is copied instead of being cut." | |||
| 2455 | ;; Obtain the dragged text in region. When the loop was | 2466 | ;; Obtain the dragged text in region. When the loop was |
| 2456 | ;; skipped, value-selection remains nil. | 2467 | ;; skipped, value-selection remains nil. |
| 2457 | (unless value-selection | 2468 | (unless value-selection |
| 2458 | (setq value-selection (buffer-substring start end)) | 2469 | (setq value-selection (funcall region-extract-function nil)) |
| 2470 | ;; Remove yank-handler property in order to re-insert text using | ||
| 2471 | ;; the `insert-rectangle' function later on. | ||
| 2472 | (remove-text-properties 0 (length value-selection) | ||
| 2473 | '(yank-handler) value-selection) | ||
| 2459 | (when mouse-drag-and-drop-region-show-tooltip | 2474 | (when mouse-drag-and-drop-region-show-tooltip |
| 2460 | (let ((text-size mouse-drag-and-drop-region-show-tooltip)) | 2475 | (let ((text-size mouse-drag-and-drop-region-show-tooltip)) |
| 2461 | (setq text-tooltip | 2476 | (setq text-tooltip |
| @@ -2468,12 +2483,18 @@ is copied instead of being cut." | |||
| 2468 | value-selection)))) | 2483 | value-selection)))) |
| 2469 | 2484 | ||
| 2470 | ;; Check if selected text is read-only. | 2485 | ;; Check if selected text is read-only. |
| 2471 | (setq text-from-read-only (or text-from-read-only | 2486 | (setq text-from-read-only |
| 2472 | (get-text-property start 'read-only) | 2487 | (or text-from-read-only |
| 2473 | (not (equal | 2488 | (get-text-property start 'read-only) |
| 2474 | (next-single-char-property-change | 2489 | (get-text-property end 'read-only) |
| 2475 | start 'read-only nil end) | 2490 | (catch 'loop |
| 2476 | end))))) | 2491 | (dolist (bound (region-bounds)) |
| 2492 | (unless (equal | ||
| 2493 | (next-single-char-property-change | ||
| 2494 | (car bound) 'read-only nil (cdr bound)) | ||
| 2495 | (cdr bound)) | ||
| 2496 | (throw 'loop t))))))) | ||
| 2497 | |||
| 2477 | (setq window-to-paste (posn-window (event-end event))) | 2498 | (setq window-to-paste (posn-window (event-end event))) |
| 2478 | (setq point-to-paste (posn-point (event-end event))) | 2499 | (setq point-to-paste (posn-point (event-end event))) |
| 2479 | ;; Set nil when target buffer is minibuffer. | 2500 | ;; Set nil when target buffer is minibuffer. |
| @@ -2499,13 +2520,34 @@ is copied instead of being cut." | |||
| 2499 | ;; the original region. When modifier is pressed, the | 2520 | ;; the original region. When modifier is pressed, the |
| 2500 | ;; text will be inserted to inside of the original | 2521 | ;; text will be inserted to inside of the original |
| 2501 | ;; region. | 2522 | ;; region. |
| 2523 | ;; | ||
| 2524 | ;; If the region is rectangular, check if the newly inserted | ||
| 2525 | ;; rectangular text would intersect the already selected | ||
| 2526 | ;; region. If it would, then set "drag-but-negligible" to t. | ||
| 2527 | ;; As a special case, allow dragging the region freely anywhere | ||
| 2528 | ;; to the left, as this will never trigger its contents to be | ||
| 2529 | ;; inserted into the overlays tracking it. | ||
| 2502 | (setq drag-but-negligible | 2530 | (setq drag-but-negligible |
| 2503 | (and (eq (overlay-buffer mouse-drag-and-drop-overlay) | 2531 | (and (eq (overlay-buffer (car mouse-drag-and-drop-overlays)) |
| 2504 | buffer-to-paste) | 2532 | buffer-to-paste) |
| 2505 | (<= (overlay-start mouse-drag-and-drop-overlay) | 2533 | (if region-noncontiguous |
| 2506 | point-to-paste) | 2534 | (let ((size (cons region-width region-height)) |
| 2507 | (<= point-to-paste | 2535 | (start-coordinates |
| 2508 | (overlay-end mouse-drag-and-drop-overlay))))) | 2536 | (rectangle-position-as-coordinates start)) |
| 2537 | (point-to-paste-coordinates | ||
| 2538 | (rectangle-position-as-coordinates | ||
| 2539 | point-to-paste))) | ||
| 2540 | (and (rectangle-intersect-p | ||
| 2541 | start-coordinates size | ||
| 2542 | point-to-paste-coordinates size) | ||
| 2543 | (not (<= (car point-to-paste-coordinates) | ||
| 2544 | (car start-coordinates))))) | ||
| 2545 | (and (<= (overlay-start | ||
| 2546 | (car mouse-drag-and-drop-overlays)) | ||
| 2547 | point-to-paste) | ||
| 2548 | (<= point-to-paste | ||
| 2549 | (overlay-end | ||
| 2550 | (car mouse-drag-and-drop-overlays)))))))) | ||
| 2509 | 2551 | ||
| 2510 | ;; Show a tooltip. | 2552 | ;; Show a tooltip. |
| 2511 | (if mouse-drag-and-drop-region-show-tooltip | 2553 | (if mouse-drag-and-drop-region-show-tooltip |
| @@ -2524,8 +2566,9 @@ is copied instead of being cut." | |||
| 2524 | (t | 2566 | (t |
| 2525 | 'bar))) | 2567 | 'bar))) |
| 2526 | (when cursor-in-text-area | 2568 | (when cursor-in-text-area |
| 2527 | (overlay-put mouse-drag-and-drop-overlay | 2569 | (dolist (overlay mouse-drag-and-drop-overlays) |
| 2528 | 'face 'mouse-drag-and-drop-region) | 2570 | (overlay-put overlay |
| 2571 | 'face 'mouse-drag-and-drop-region)) | ||
| 2529 | (deactivate-mark) ; Maintain region in other window. | 2572 | (deactivate-mark) ; Maintain region in other window. |
| 2530 | (mouse-set-point event))))) | 2573 | (mouse-set-point event))))) |
| 2531 | 2574 | ||
| @@ -2581,7 +2624,9 @@ is copied instead of being cut." | |||
| 2581 | (select-window window) | 2624 | (select-window window) |
| 2582 | (goto-char point) | 2625 | (goto-char point) |
| 2583 | (setq deactivate-mark nil) | 2626 | (setq deactivate-mark nil) |
| 2584 | (activate-mark)) | 2627 | (activate-mark) |
| 2628 | (when region-noncontiguous | ||
| 2629 | (rectangle-mark-mode))) | ||
| 2585 | ;; Modify buffers. | 2630 | ;; Modify buffers. |
| 2586 | (t | 2631 | (t |
| 2587 | ;; * DESTINATION BUFFER:: | 2632 | ;; * DESTINATION BUFFER:: |
| @@ -2590,11 +2635,17 @@ is copied instead of being cut." | |||
| 2590 | (setq window-exempt window-to-paste) | 2635 | (setq window-exempt window-to-paste) |
| 2591 | (goto-char point-to-paste) | 2636 | (goto-char point-to-paste) |
| 2592 | (push-mark) | 2637 | (push-mark) |
| 2593 | (insert value-selection) | 2638 | |
| 2639 | (if region-noncontiguous | ||
| 2640 | (insert-rectangle (split-string value-selection "\n")) | ||
| 2641 | (insert value-selection)) | ||
| 2642 | |||
| 2594 | ;; On success, set the text as region on destination buffer. | 2643 | ;; On success, set the text as region on destination buffer. |
| 2595 | (when (not (equal (mark) (point))) | 2644 | (when (not (equal (mark) (point))) |
| 2596 | (setq deactivate-mark nil) | 2645 | (setq deactivate-mark nil) |
| 2597 | (activate-mark)) | 2646 | (activate-mark) |
| 2647 | (when region-noncontiguous | ||
| 2648 | (rectangle-mark-mode))) | ||
| 2598 | 2649 | ||
| 2599 | ;; * SOURCE BUFFER:: | 2650 | ;; * SOURCE BUFFER:: |
| 2600 | ;; Set back the original text as region or delete the original | 2651 | ;; Set back the original text as region or delete the original |
| @@ -2604,8 +2655,9 @@ is copied instead of being cut." | |||
| 2604 | ;; remove the original text. | 2655 | ;; remove the original text. |
| 2605 | (when no-modifier-on-drop | 2656 | (when no-modifier-on-drop |
| 2606 | (let (deactivate-mark) | 2657 | (let (deactivate-mark) |
| 2607 | (delete-region (overlay-start mouse-drag-and-drop-overlay) | 2658 | (dolist (overlay mouse-drag-and-drop-overlays) |
| 2608 | (overlay-end mouse-drag-and-drop-overlay)))) | 2659 | (delete-region (overlay-start overlay) |
| 2660 | (overlay-end overlay))))) | ||
| 2609 | ;; When source buffer and destination buffer are different, | 2661 | ;; When source buffer and destination buffer are different, |
| 2610 | ;; keep (set back the original text as region) or remove the | 2662 | ;; keep (set back the original text as region) or remove the |
| 2611 | ;; original text. | 2663 | ;; original text. |
| @@ -2615,15 +2667,17 @@ is copied instead of being cut." | |||
| 2615 | (if mouse-drag-and-drop-region-cut-when-buffers-differ | 2667 | (if mouse-drag-and-drop-region-cut-when-buffers-differ |
| 2616 | ;; Remove the dragged text from source buffer like | 2668 | ;; Remove the dragged text from source buffer like |
| 2617 | ;; operation `cut'. | 2669 | ;; operation `cut'. |
| 2618 | (delete-region (overlay-start mouse-drag-and-drop-overlay) | 2670 | (dolist (overlay mouse-drag-and-drop-overlays) |
| 2619 | (overlay-end mouse-drag-and-drop-overlay)) | 2671 | (delete-region (overlay-start overlay) |
| 2672 | (overlay-end overlay))) | ||
| 2620 | ;; Set back the dragged text as region on source buffer | 2673 | ;; Set back the dragged text as region on source buffer |
| 2621 | ;; like operation `copy'. | 2674 | ;; like operation `copy'. |
| 2622 | (activate-mark)) | 2675 | (activate-mark)) |
| 2623 | (select-window window-to-paste)))))) | 2676 | (select-window window-to-paste)))))) |
| 2624 | 2677 | ||
| 2625 | ;; Clean up. | 2678 | ;; Clean up. |
| 2626 | (delete-overlay mouse-drag-and-drop-overlay) | 2679 | (dolist (overlay mouse-drag-and-drop-overlays) |
| 2680 | (delete-overlay overlay)) | ||
| 2627 | 2681 | ||
| 2628 | ;; Restore old states but for the window where the drop | 2682 | ;; Restore old states but for the window where the drop |
| 2629 | ;; occurred. Restore cursor types for all windows. | 2683 | ;; occurred. Restore cursor types for all windows. |
diff --git a/lisp/rect.el b/lisp/rect.el index 8ccf051ee18..48db4ffd8f4 100644 --- a/lisp/rect.el +++ b/lisp/rect.el | |||
| @@ -167,6 +167,37 @@ The final point after the last operation will be returned." | |||
| 167 | (<= (point) endpt)))) | 167 | (<= (point) endpt)))) |
| 168 | final-point))) | 168 | final-point))) |
| 169 | 169 | ||
| 170 | (defun rectangle-position-as-coordinates (position) | ||
| 171 | "Return cons of the column and line values of POSITION. | ||
| 172 | POSITION specifies a position of the current buffer. The value | ||
| 173 | returned is a cons of the current column of POSITION and its line | ||
| 174 | number." | ||
| 175 | (save-excursion | ||
| 176 | (goto-char position) | ||
| 177 | (let ((col (current-column)) | ||
| 178 | (line (1- (line-number-at-pos)))) | ||
| 179 | (cons col line)))) | ||
| 180 | |||
| 181 | (defun rectangle-intersect-p (pos1 size1 pos2 size2) | ||
| 182 | "Return non-nil if two rectangles intersect. | ||
| 183 | POS1 and POS2 specify the positions of the upper-left corners of | ||
| 184 | the first and second rectangle as conses of their column and line | ||
| 185 | values. SIZE1 and SIZE2 specify the dimensions of the first and | ||
| 186 | second rectangle, as conses of their width and height measured in | ||
| 187 | columns and lines." | ||
| 188 | (let ((x1 (car pos1)) | ||
| 189 | (y1 (cdr pos1)) | ||
| 190 | (x2 (car pos2)) | ||
| 191 | (y2 (cdr pos2)) | ||
| 192 | (w1 (car size1)) | ||
| 193 | (h1 (cdr size1)) | ||
| 194 | (w2 (car size2)) | ||
| 195 | (h2 (cdr size2))) | ||
| 196 | (not (or (<= (+ x1 w1) x2) | ||
| 197 | (<= (+ x2 w2) x1) | ||
| 198 | (<= (+ y1 h1) y2) | ||
| 199 | (<= (+ y2 h2) y1))))) | ||
| 200 | |||
| 170 | (defun delete-rectangle-line (startcol endcol fill) | 201 | (defun delete-rectangle-line (startcol endcol fill) |
| 171 | (when (= (move-to-column startcol (if fill t 'coerce)) startcol) | 202 | (when (= (move-to-column startcol (if fill t 'coerce)) startcol) |
| 172 | (delete-region (point) | 203 | (delete-region (point) |