aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorMattias EngdegÄrd2019-10-25 11:16:39 +0200
committerMattias EngdegÄrd2019-11-27 13:40:29 +0100
commit4eb7db5d4b84708912c63a77569c8adeeff6c640 (patch)
treee4f014f3b2b2407ec74e875a8ef2ab3bc37b2225 /lisp
parente7b4c248a6d2a2eca19a2a362103a7f24cfe30fc (diff)
downloademacs-4eb7db5d4b84708912c63a77569c8adeeff6c640.tar.gz
emacs-4eb7db5d4b84708912c63a77569c8adeeff6c640.zip
Mouse rectangular region selection (bug#38013)
Make it possible to select a rectangular region using the mouse. The standard binding is C-M-mouse-1. * lisp/mouse.el (mouse-scroll-subr): Add ADJUST argument. (mouse-drag-region-rectangle): New. * lisp/rect.el (rectangle--reset-point-crutches): New. (rectangle--reset-crutches): Use 'rectangle--reset-point-crutches'. * src/xdisp.c (remember_mouse_glyph, syms_of_xdisp): Add 'mouse-fine-grained-tracking'. * doc/lispref/commands.texi (Motion Events): Document 'mouse-fine-grained-tracking'. * doc/emacs/frames.texi (Mouse Commands): * doc/emacs/killing.texi (Rectangles): * etc/NEWS: Document rectangular selection with the mouse.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/mouse.el113
-rw-r--r--lisp/rect.el8
2 files changed, 118 insertions, 3 deletions
diff --git a/lisp/mouse.el b/lisp/mouse.el
index c91760a7348..f076e90bd93 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -1045,10 +1045,12 @@ the mouse has moved. However, it always scrolls at least the number
1045of lines specified by this variable." 1045of lines specified by this variable."
1046 :type 'integer) 1046 :type 'integer)
1047 1047
1048(defun mouse-scroll-subr (window jump &optional overlay start) 1048(defun mouse-scroll-subr (window jump &optional overlay start adjust)
1049 "Scroll the window WINDOW, JUMP lines at a time, until new input arrives. 1049 "Scroll the window WINDOW, JUMP lines at a time, until new input arrives.
1050If OVERLAY is an overlay, let it stretch from START to the far edge of 1050If OVERLAY is an overlay, let it stretch from START to the far edge of
1051the newly visible text. 1051the newly visible text.
1052ADJUST, if non-nil, is a function, without arguments, to call after
1053setting point.
1052Upon exit, point is at the far edge of the newly visible text." 1054Upon exit, point is at the far edge of the newly visible text."
1053 (cond 1055 (cond
1054 ((and (> jump 0) (< jump mouse-scroll-min-lines)) 1056 ((and (> jump 0) (< jump mouse-scroll-min-lines))
@@ -1077,6 +1079,8 @@ Upon exit, point is at the far edge of the newly visible text."
1077 ;; so that we don't mess up the selected window. 1079 ;; so that we don't mess up the selected window.
1078 (or (eq window (selected-window)) 1080 (or (eq window (selected-window))
1079 (goto-char opoint)) 1081 (goto-char opoint))
1082 (when adjust
1083 (funcall adjust))
1080 (sit-for mouse-scroll-delay))))) 1084 (sit-for mouse-scroll-delay)))))
1081 (or (eq window (selected-window)) 1085 (or (eq window (selected-window))
1082 (goto-char opoint)))) 1086 (goto-char opoint))))
@@ -1960,6 +1964,113 @@ When there is no region, this function does nothing."
1960 (move-overlay mouse-secondary-overlay (region-beginning) (region-end)))) 1964 (move-overlay mouse-secondary-overlay (region-beginning) (region-end))))
1961 1965
1962 1966
1967(defun mouse-drag-region-rectangle (start-event)
1968 "Set the region to the rectangle that the mouse is dragged over.
1969This must be bound to a button-down mouse event."
1970 (interactive "e")
1971 (let* ((scroll-margin 0)
1972 (start-pos (event-start start-event))
1973 (start-posn (event-start start-event))
1974 (start-point (posn-point start-posn))
1975 (start-window (posn-window start-posn))
1976 (start-hscroll (window-hscroll start-window))
1977 (start-col (+ (car (posn-col-row start-pos)) start-hscroll))
1978 (bounds (window-edges start-window))
1979 (top (nth 1 bounds))
1980 (bottom (if (window-minibuffer-p start-window)
1981 (nth 3 bounds)
1982 (1- (nth 3 bounds))))
1983 (dragged nil)
1984 (old-track-mouse track-mouse)
1985 (old-mouse-fine-grained-tracking mouse-fine-grained-tracking)
1986 ;; For right-to-left text, columns are counted from the right margin;
1987 ;; translate from mouse events, which always count from the left.
1988 (adjusted-col (lambda (col)
1989 (if (eq (current-bidi-paragraph-direction)
1990 'right-to-left)
1991 (- (frame-text-cols) col -1)
1992 col)))
1993 (map (make-sparse-keymap)))
1994 (define-key map [switch-frame] #'ignore)
1995 (define-key map [select-window] #'ignore)
1996 (define-key map [mouse-movement]
1997 (lambda (event)
1998 (interactive "e")
1999 (unless dragged
2000 ;; This is actually a drag.
2001 (setq dragged t)
2002 (mouse-minibuffer-check start-event)
2003 (deactivate-mark)
2004 (posn-set-point start-pos)
2005 (rectangle-mark-mode)
2006 ;; Only tell rectangle about the exact column if we are possibly
2007 ;; beyond end-of-line or in a tab, since the column we got from
2008 ;; the mouse position isn't necessarily accurate for use in
2009 ;; specifying a rectangle (which uses the `move-to-column'
2010 ;; measure).
2011 (when (or (eolp) (eq (following-char) ?\t))
2012 (let ((col (funcall adjusted-col start-col)))
2013 (rectangle--col-pos col 'mark)
2014 (rectangle--col-pos col 'point))))
2015
2016 (let* ((posn (event-end event))
2017 (window (posn-window posn))
2018 (hscroll (if (window-live-p window)
2019 (window-hscroll window)
2020 0))
2021 (mouse-pos (mouse-position))
2022 (mouse-col (+ (cadr mouse-pos) hscroll))
2023 (mouse-row (cddr mouse-pos))
2024 (set-col (lambda ()
2025 (if (or (eolp) (eq (following-char) ?\t))
2026 (rectangle--col-pos
2027 (funcall adjusted-col mouse-col) 'point)
2028 (rectangle--reset-point-crutches)))))
2029 (if (and (eq window start-window)
2030 mouse-row
2031 (<= top mouse-row (1- bottom)))
2032 ;; Drag inside the same window.
2033 (progn
2034 (posn-set-point posn)
2035 (funcall set-col))
2036 ;; Drag outside the window: scroll.
2037 (cond
2038 ((null mouse-row))
2039 ((< mouse-row top)
2040 (mouse-scroll-subr
2041 start-window (- mouse-row top) nil start-point
2042 set-col))
2043 ((>= mouse-row bottom)
2044 (mouse-scroll-subr
2045 start-window (1+ (- mouse-row bottom)) nil start-point
2046 set-col)))))))
2047 (condition-case err
2048 (progn
2049 (setq track-mouse t)
2050 (setq mouse-fine-grained-tracking t)
2051 (set-transient-map
2052 map t
2053 (lambda ()
2054 (setq track-mouse old-track-mouse)
2055 (setq mouse-fine-grained-tracking old-mouse-fine-grained-tracking)
2056 (when (or (not dragged)
2057 (not (mark))
2058 (equal (rectangle-dimensions (mark) (point)) '(0 . 1)))
2059 ;; No nontrivial region selected; deactivate rectangle mode.
2060 (deactivate-mark)))))
2061 ;; Clean up in case something went wrong.
2062 (error (setq track-mouse old-track-mouse)
2063 (setq mouse-fine-grained-tracking old-mouse-fine-grained-tracking)
2064 (signal (car err) (cdr err))))))
2065
2066;; The drag event must be bound to something but does not need any effect,
2067;; as everything takes place in `mouse-drag-region-rectangle'.
2068;; The click event can be anything; `mouse-set-point' is just a convenience.
2069(global-set-key [C-M-down-mouse-1] #'mouse-drag-region-rectangle)
2070(global-set-key [C-M-drag-mouse-1] #'ignore)
2071(global-set-key [C-M-mouse-1] #'mouse-set-point)
2072
2073
1963(defcustom mouse-buffer-menu-maxlen 20 2074(defcustom mouse-buffer-menu-maxlen 20
1964 "Number of buffers in one pane (submenu) of the buffer menu. 2075 "Number of buffers in one pane (submenu) of the buffer menu.
1965If we have lots of buffers, divide them into groups of 2076If we have lots of buffers, divide them into groups of
diff --git a/lisp/rect.el b/lisp/rect.el
index 4d4d6146f21..1109786fc5b 100644
--- a/lisp/rect.el
+++ b/lisp/rect.el
@@ -133,11 +133,15 @@ Point is at the end of the segment of this line within the rectangle."
133(defun rectangle--crutches () 133(defun rectangle--crutches ()
134 (cons rectangle--mark-crutches 134 (cons rectangle--mark-crutches
135 (window-parameter nil 'rectangle--point-crutches))) 135 (window-parameter nil 'rectangle--point-crutches)))
136(defun rectangle--reset-crutches () 136
137 (kill-local-variable 'rectangle--mark-crutches) 137(defun rectangle--reset-point-crutches ()
138 (if (window-parameter nil 'rectangle--point-crutches) 138 (if (window-parameter nil 'rectangle--point-crutches)
139 (setf (window-parameter nil 'rectangle--point-crutches) nil))) 139 (setf (window-parameter nil 'rectangle--point-crutches) nil)))
140 140
141(defun rectangle--reset-crutches ()
142 (kill-local-variable 'rectangle--mark-crutches)
143 (rectangle--reset-point-crutches))
144
141;;; Rectangle operations. 145;;; Rectangle operations.
142 146
143(defun apply-on-rectangle (function start end &rest args) 147(defun apply-on-rectangle (function start end &rest args)