Mercurial > emacs
comparison lisp/mouse-sel.el @ 11490:01f5b6e9c234
Downcase function parameters.
Doc fixes.
Rewrite to support secondary selection.
(mouse-sel-maintainer-address): New constant.
(mouse-sel-submit-bug-report): New function.
Rename mouse-sel-selection-type to mouse-sel-primary-thing.
(mouse-sel-secondary-thing): New variable.
(mouse-sel-selection-alist): New constant.
(mouse-sel-set-selection-function): Semantics changed. Value
should now be a function taking two arguments.
(mouse-sel-get-selection-function): Semantics changed. Value
should now be a function taking one argument.
(mouse-sel-selection-owner-p-function): New variable.
Removed variable mouse-sel-check-selection-function.
Rename mouse-sel-determine-selection-type to
mouse-sel-determine-selection-thing.
(mouse-sel-set-selection): New function.
(mouse-sel-get-selection): New function.
(mouse-sel-selection-owner-p): New function.
(mouse-sel-selection-overlay): New function.
(mouse-sel-selection-thing): New function.
(mouse-sel-region-to-primary): New function.
(mouse-sel-primary-to-region): New function.
(mouse-sel-eval-at-event-end): New macro.
(mouse-sel-determine-selection-thing): Quad-click selects paragraphs.
Removed variable mouse-sel-retain-highlight; use inverse of
transient-mark-mode instead.
(mouse-select-internal): New function.
(mouse-select): Re-written using mouse-select-internal and
mouse-sel-primary-to-region.
(mouse-select-secondary): New function.
(mouse-extend-internal): New function.
(mouse-extend): Re-written using mouse-extend-internal,
mouse-sel-region-to-primary and mouse-sel-primary-to-region.
(mouse-extend-secondary): New function.
(mouse-insert-selection-internal): New function.
(mouse-insert-selection): Re-written using
mouse-insert-selection-internal.
(mouse-insert-secondary): New function.
(mouse-sel-validate-selection): Check all selections in
mouse-sel-selection-alist.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Wed, 19 Apr 1995 04:35:22 +0000 |
parents | 3181c9270f40 |
children | efb59db39da7 |
comparison
equal
deleted
inserted
replaced
11489:cfb899623032 | 11490:01f5b6e9c234 |
---|---|
1 ;;; mouse-sel.el --- Multi-click selection support for Emacs 19 | 1 ;;; mouse-sel.el --- Multi-click selection support for Emacs 19 |
2 | 2 |
3 ;; Copyright (C) 1993, 1994 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc. |
4 | 4 |
5 ;; Author: Mike Williams <mikew@gopher.dosli.govt.nz> | 5 ;; Author: Mike Williams <mikew@gopher.dosli.govt.nz> |
6 ;; Keywords: mouse | 6 ;; Keywords: mouse |
7 ;; Version: 2.1 | |
8 | 7 |
9 ;; This file is part of GNU Emacs. | 8 ;; This file is part of GNU Emacs. |
10 | 9 |
11 ;; GNU Emacs is free software; you can redistribute it and/or modify | 10 ;; 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 | 11 ;; it under the terms of the GNU General Public License as published by |
32 ;; * Double-clicking on word constituents selects words. | 31 ;; * Double-clicking on word constituents selects words. |
33 ;; Double-clicking on symbol constituents selects symbols. | 32 ;; Double-clicking on symbol constituents selects symbols. |
34 ;; Double-clicking on quotes or parentheses selects sexps. | 33 ;; Double-clicking on quotes or parentheses selects sexps. |
35 ;; Double-clicking on whitespace selects whitespace. | 34 ;; Double-clicking on whitespace selects whitespace. |
36 ;; Triple-clicking selects lines. | 35 ;; Triple-clicking selects lines. |
36 ;; Quad-clicking selects paragraphs. | |
37 ;; | 37 ;; |
38 ;; * Selecting sets the region & X primary selection, but does NOT affect | 38 ;; * Selecting sets the region & X primary selection, but does NOT affect |
39 ;; the kill-ring. Because the mouse handlers set the primary selection | 39 ;; the kill-ring. Because the mouse handlers set the primary selection |
40 ;; directly, mouse-sel sets the variables interprogram-cut-function | 40 ;; directly, mouse-sel sets the variables interprogram-cut-function |
41 ;; and interprogram-paste-function to nil. | 41 ;; and interprogram-paste-function to nil. |
42 ;; | 42 ;; |
43 ;; * Clicking mouse-2 pastes contents of primary selection at the mouse | 43 ;; * Clicking mouse-2 inserts the contents of the primary selection at |
44 ;; position. | 44 ;; the mouse position (or point, if mouse-yank-at-point is non-nil). |
45 ;; | 45 ;; |
46 ;; * Pressing mouse-2 while selecting or extending copies selection | 46 ;; * Pressing mouse-2 while selecting or extending copies selection |
47 ;; to the kill ring. Pressing mouse-1 or mouse-3 kills it. | 47 ;; to the kill ring. Pressing mouse-1 or mouse-3 kills it. |
48 ;; | 48 ;; |
49 ;; * Double-clicking mouse-3 also kills selection. | 49 ;; * Double-clicking mouse-3 also kills selection. |
50 ;; | |
51 ;; * M-mouse-1, M-mouse-2 & M-mouse-3 work similarly to mouse-1, mouse-2 | |
52 ;; & mouse-3, but operate on the X secondary selection rather than the | |
53 ;; primary selection and region. | |
50 ;; | 54 ;; |
51 ;; This module requires my thingatpt.el module, which it uses to find the | 55 ;; This module requires my thingatpt.el module, which it uses to find the |
52 ;; bounds of words, lines, sexps, etc. | 56 ;; bounds of words, lines, sexps, etc. |
53 ;; | 57 ;; |
54 ;; Thanks to KevinB@bartley.demon.co.uk for his useful input. | 58 ;; Thanks to KevinB@bartley.demon.co.uk for his useful input. |
69 ;; * You can control the way mouse-sel binds its keys by setting the value | 73 ;; * You can control the way mouse-sel binds its keys by setting the value |
70 ;; of mouse-sel-default-bindings before loading mouse-sel. | 74 ;; of mouse-sel-default-bindings before loading mouse-sel. |
71 ;; | 75 ;; |
72 ;; (a) If mouse-sel-default-bindings = t (the default) | 76 ;; (a) If mouse-sel-default-bindings = t (the default) |
73 ;; | 77 ;; |
74 ;; Mouse sets and pastes selection | 78 ;; Mouse sets and insert selection |
75 ;; mouse-1 mouse-select | 79 ;; mouse-1 mouse-select |
76 ;; mouse-2 mouse-insert-selection | 80 ;; mouse-2 mouse-insert-selection |
77 ;; mouse-3 mouse-extend | 81 ;; mouse-3 mouse-extend |
78 ;; | 82 ;; |
79 ;; Selection/kill-ring interaction is disabled | 83 ;; Selection/kill-ring interaction is disabled |
80 ;; interprogram-cut-function = nil | 84 ;; interprogram-cut-function = nil |
81 ;; interprogram-paste-function = nil | 85 ;; interprogram-paste-function = nil |
82 ;; | 86 ;; |
83 ;; (b) If mouse-sel-default-bindings = 'interprogram-cut-paste | 87 ;; (b) If mouse-sel-default-bindings = 'interprogram-cut-paste |
84 ;; | 88 ;; |
85 ;; Mouse sets selection, and pastes from kill-ring | 89 ;; Mouse sets selection, and pastes from kill-ring |
86 ;; mouse-1 mouse-select | 90 ;; mouse-1 mouse-select |
87 ;; mouse-2 mouse-yank-at-click | 91 ;; mouse-2 mouse-yank-at-click |
88 ;; mouse-3 mouse-extend | 92 ;; mouse-3 mouse-extend |
89 ;; | 93 ;; |
90 ;; Selection/kill-ring interaction is retained | 94 ;; Selection/kill-ring interaction is retained |
91 ;; interprogram-cut-function = x-select-text | 95 ;; interprogram-cut-function = x-select-text |
92 ;; interprogram-paste-function = x-cut-buffer-or-selection-value | 96 ;; interprogram-paste-function = x-cut-buffer-or-selection-value |
93 ;; | 97 ;; |
106 ;; cursor makes it look like one extra character is selected). You can | 110 ;; cursor makes it look like one extra character is selected). You can |
107 ;; disable this behaviour with: | 111 ;; disable this behaviour with: |
108 ;; | 112 ;; |
109 ;; (setq mouse-sel-leave-point-near-mouse nil) | 113 ;; (setq mouse-sel-leave-point-near-mouse nil) |
110 ;; | 114 ;; |
111 ;; * Normally, the selection highlight will be removed when the mouse is | 115 ;; * By default, mouse-select cycles the click count after 4 clicks. That |
112 ;; lifted. You can tell mouse-sel to retain the selection highlight | 116 ;; is, clicking mouse-1 five times has the same effect as clicking it |
113 ;; (useful if you don't use transient-mark-mode) with: | 117 ;; once, clicking six times has the same effect as clicking twice, etc. |
114 ;; | |
115 ;; (setq mouse-sel-retain-highlight t) | |
116 ;; | |
117 ;; * By default, mouse-select cycles the click count after 3 clicks. That | |
118 ;; is, clicking mouse-1 four times has the same effect as clicking it | |
119 ;; once, clicking five times has the same effect as clicking twice, etc. | |
120 ;; Disable this behaviour with: | 118 ;; Disable this behaviour with: |
121 ;; | 119 ;; |
122 ;; (setq mouse-sel-cycle-clicks nil) | 120 ;; (setq mouse-sel-cycle-clicks nil) |
123 ;; | 121 ;; |
124 ;; * The variables mouse-sel-{set,get,check}-selection-function control how | 122 ;; * The variables mouse-sel-{set,get}-selection-function control how the |
125 ;; the selection is handled. Under X Windows, these variables default so | 123 ;; selection is handled. Under X Windows, these variables default so |
126 ;; that the X primary selection is used. Under other windowing systems, | 124 ;; that the X primary selection is used. Under other windowing systems, |
127 ;; alternate functions are used, which simply store the selection value | 125 ;; alternate functions are used, which simply store the selection value |
128 ;; in a variable. | 126 ;; in a variable. |
129 ;; | 127 ;; |
130 ;;--- Hints --------------------------------------------------------------- | |
131 ;; | |
132 ;; * You can change the selection highlight face by altering the properties | 128 ;; * You can change the selection highlight face by altering the properties |
133 ;; of mouse-drag-overlay, eg. | 129 ;; of mouse-drag-overlay, eg. |
134 ;; | 130 ;; |
135 ;; (overlay-put mouse-drag-overlay 'face 'bold) | 131 ;; (overlay-put mouse-drag-overlay 'face 'bold) |
136 ;; | |
137 ;; * Pasting from the primary selection under emacs 19.19 is SLOW (there's | |
138 ;; a two second delay). The following code will cause mouse-sel to use | |
139 ;; the cut buffer rather than the primary selection. However, be aware | |
140 ;; that cut buffers are OBSOLETE, and some X applications may not support | |
141 ;; them. | |
142 ;; | |
143 ;; (setq mouse-sel-set-selection-function 'x-select-text | |
144 ;; mouse-sel-get-selection-function 'x-get-cut-buffer) | |
145 ;; | |
146 ;;--- Warnings ------------------------------------------------------------ | |
147 ;; | |
148 ;; * When selecting sexps, the selection extends by sexps at the same | |
149 ;; nesting level. This also means the selection cannot be extended out | |
150 ;; of the enclosing nesting level. This is INTENTIONAL. | |
151 | 132 |
152 ;;; Code: ================================================================= | 133 ;;; Code: ================================================================= |
153 | 134 |
154 (provide 'mouse-sel) | 135 (provide 'mouse-sel) |
155 | 136 |
156 (require 'mouse) | 137 (require 'mouse) |
157 (require 'thingatpt) | 138 (require 'thingatpt) |
158 | 139 (require 'backquote) |
159 ;;=== Version ============================================================= | |
160 | |
161 (defconst mouse-sel-version "2.1" | |
162 "The version number of mouse-sel (as string).") | |
163 | 140 |
164 ;;=== User Variables ====================================================== | 141 ;;=== User Variables ====================================================== |
165 | 142 |
166 (defvar mouse-sel-leave-point-near-mouse t | 143 (defvar mouse-sel-leave-point-near-mouse t |
167 "*Leave point near last mouse position. | 144 "*Leave point near last mouse position. |
168 If non-nil, \\[mouse-select] and \\[mouse-extend] leave point at the end | 145 If non-nil, \\[mouse-select] and \\[mouse-extend] will leave point at the end |
169 of the region nearest to where the mouse last was. | 146 of the region nearest to where the mouse last was. |
170 If nil, point is always placed at the beginning of the region.") | 147 If nil, point will always be placed at the beginning of the region.") |
171 | |
172 (defvar mouse-sel-retain-highlight nil | |
173 "*Retain highlight after dragging is finished. | |
174 If non-nil, regions selected using \\[mouse-select] and \\[mouse-extend] will | |
175 remain highlighted. | |
176 If nil, highlighting turns off when you release the mouse button.") | |
177 | 148 |
178 (defvar mouse-sel-cycle-clicks t | 149 (defvar mouse-sel-cycle-clicks t |
179 "*If non-nil, \\[mouse-select] cycles the click-counts after 3 clicks. | 150 "*If non-nil, \\[mouse-select] cycles the click-counts after 4 clicks.") |
180 Ie. 4 clicks = 1 click, 5 clicks = 2 clicks, etc.") | |
181 | 151 |
182 (defvar mouse-sel-default-bindings t | 152 (defvar mouse-sel-default-bindings t |
183 "Set to nil before loading `mouse-sel' to prevent default mouse bindings.") | 153 "Set to nil before loading `mouse-sel' to prevent default mouse bindings.") |
184 | 154 |
185 ;;=== Selection =========================================================== | 155 ;;=== Internal Variables/Constants ======================================== |
186 | 156 |
187 (defvar mouse-sel-selection-type nil "Type of current selection") | 157 (defvar mouse-sel-primary-thing nil |
188 (make-variable-buffer-local 'mouse-sel-selection-type) | 158 "Type of PRIMARY selection in current buffer.") |
189 | 159 (make-variable-buffer-local 'mouse-sel-primary-thing) |
190 (defvar mouse-sel-selection "" | 160 |
191 "Store the selection value when using a window systems other than X.") | 161 (defvar mouse-sel-secondary-thing nil |
192 | 162 "Type of SECONDARY selection in current buffer.") |
163 (make-variable-buffer-local 'mouse-sel-secondary-thing) | |
164 | |
165 ;; Ensure that secondary overlay is defined | |
166 (if (overlayp mouse-secondary-overlay) nil | |
167 (setq mouse-secondary-overlay (make-overlay 1 1)) | |
168 (overlay-put mouse-secondary-overlay 'face 'secondary-selection)) | |
169 | |
170 (defconst mouse-sel-selection-alist | |
171 '((PRIMARY mouse-drag-overlay mouse-sel-primary-thing) | |
172 (SECONDARY mouse-secondary-overlay mouse-sel-secondary-thing)) | |
173 "Alist associating selections with variables. Each element is of | |
174 the form: | |
175 | |
176 (SELECTION-NAME OVERLAY-SYMBOL SELECTION-THING-SYMBOL) | |
177 | |
178 where SELECTION-NAME = name of selection | |
179 OVERLAY-SYMBOL = name of variable containing overlay to use | |
180 SELECTION-THING-SYMBOL = name of variable where the current selection | |
181 type for this selection should be stored.") | |
182 | |
193 (defvar mouse-sel-set-selection-function | 183 (defvar mouse-sel-set-selection-function |
194 (if (fboundp 'x-set-selection) | 184 (if (fboundp 'x-set-selection) |
195 (function (lambda (s) (x-set-selection 'PRIMARY s))) | 185 'x-set-selection) |
196 (function (lambda (s) (setq mouse-sel-selection s)))) | |
197 "Function to call to set selection. | 186 "Function to call to set selection. |
198 Called with one argument, the text to select.") | 187 Called with two arguments: |
188 | |
189 SELECTION, the name of the selection concerned, and | |
190 VALUE, the text to store.") | |
199 | 191 |
200 (defvar mouse-sel-get-selection-function | 192 (defvar mouse-sel-get-selection-function |
201 (if (fboundp 'x-get-selection) | 193 (if (fboundp 'x-get-selection) |
202 'x-get-selection | 194 'x-get-selection) |
203 (function (lambda () mouse-sel-selection))) | |
204 "Function to call to get the selection. | 195 "Function to call to get the selection. |
205 Called with no argument.") | 196 Called with one argument: |
206 | 197 |
207 (defvar mouse-sel-check-selection-function | 198 SELECTION: the name of the selection concerned.") |
199 | |
200 (defvar mouse-sel-selection-owner-p-function | |
208 (if (fboundp 'x-selection-owner-p) | 201 (if (fboundp 'x-selection-owner-p) |
209 'x-selection-owner-p | 202 'x-selection-owner-p) |
210 nil) | |
211 "Function to check whether Emacs still owns the selection. | 203 "Function to check whether Emacs still owns the selection. |
212 Called with no arguments.") | 204 Called with one argument: |
213 | 205 |
214 (defun mouse-sel-determine-selection-type (NCLICKS) | 206 SELECTION: the name of the selection concerned.") |
215 "Determine what \"thing\" `mouse-sel' should operate on. | 207 |
216 The first argument, NCLICKS, is the number of consecutive | 208 ;;=== Support/access functions ============================================ |
217 mouse clicks at the same position." | 209 |
218 (let* ((next-char (char-after (point))) | 210 (defun mouse-sel-determine-selection-thing (nclicks) |
219 (char-syntax (if next-char (char-syntax next-char))) | 211 "Determine what `thing' `mouse-sel' should operate on. |
220 (nclicks (if mouse-sel-cycle-clicks (1+ (% (1- NCLICKS) 3)) NCLICKS))) | 212 The first argument is NCLICKS, is the number of consecutive |
221 (cond | 213 mouse clicks at the same position. |
222 ((= nclicks 1) nil) | |
223 ((>= nclicks 3) 'line) | |
224 ((memq char-syntax '(?\( ?\) ?\" ?')) 'sexp) | |
225 ((memq next-char '(? ?\t ?\n)) 'whitespace) | |
226 ((eq char-syntax ?_) 'symbol) | |
227 ((eq char-syntax ?w) 'word)))) | |
228 | |
229 (defun mouse-select (EVENT) | |
230 "Set region/selection using the mouse. | |
231 | |
232 Clicking sets point to click position, and deactivates the mark | |
233 if you are in Transient Mark mode. | |
234 Dragging extends region/selection. | |
235 | 214 |
236 Double-clicking on word constituents selects words. | 215 Double-clicking on word constituents selects words. |
237 Double-clicking on symbol constituents selects symbols. | 216 Double-clicking on symbol constituents selects symbols. |
238 Double-clicking on quotes or parentheses selects sexps. | 217 Double-clicking on quotes or parentheses selects sexps. |
239 Double-clicking on whitespace selects whitespace. | 218 Double-clicking on whitespace selects whitespace. |
240 Triple-clicking selects lines. | 219 Triple-clicking selects lines. |
241 | 220 Quad-clicking selects paragraphs. |
242 Clicking mouse-2 while selecting copies the region to the kill-ring. | 221 |
243 Clicking mouse-1 or mouse-3 kills the region. | 222 Feel free to re-define this function to support your own desired |
223 multi-click semantics." | |
224 (let* ((next-char (char-after (point))) | |
225 (char-syntax (if next-char (char-syntax next-char)))) | |
226 (if mouse-sel-cycle-clicks | |
227 (setq nclicks (1+ (% (1- nclicks) 4)))) | |
228 (cond | |
229 ((= nclicks 1) nil) | |
230 ((= nclicks 3) 'line) | |
231 ((>= nclicks 4) 'paragraph) | |
232 ((memq char-syntax '(?\( ?\) ?\" ?')) 'sexp) | |
233 ((memq next-char '(? ?\t ?\n)) 'whitespace) | |
234 ((eq char-syntax ?_) 'symbol) | |
235 ((eq char-syntax ?w) 'word)))) | |
236 | |
237 (defun mouse-sel-set-selection (selection value) | |
238 "Set the specified SELECTION to VALUE." | |
239 (if mouse-sel-set-selection-function | |
240 (funcall mouse-sel-set-selection-function selection value) | |
241 (put 'mouse-sel-internal-selection selection value))) | |
242 | |
243 (defun mouse-sel-get-selection (selection) | |
244 "Get the value of the specified SELECTION." | |
245 (if mouse-sel-get-selection-function | |
246 (funcall mouse-sel-get-selection-function selection) | |
247 (get 'mouse-sel-internal-selection selection))) | |
248 | |
249 (defun mouse-sel-selection-owner-p (selection) | |
250 "Determine whether Emacs owns the specified SELECTION." | |
251 (if mouse-sel-selection-owner-p-function | |
252 (funcall mouse-sel-selection-owner-p-function selection) | |
253 t)) | |
254 | |
255 (defun mouse-sel-selection-overlay (selection) | |
256 "Return overlay corresponding to SELECTION." | |
257 (let ((symbol (nth 1 (assoc selection mouse-sel-selection-alist)))) | |
258 (or symbol (error "No overlay corresponding to %s selection" selection)) | |
259 (symbol-value symbol))) | |
260 | |
261 (defun mouse-sel-selection-thing (selection) | |
262 "Return overlay corresponding to SELECTION." | |
263 (let ((symbol (nth 2 (assoc selection mouse-sel-selection-alist)))) | |
264 (or symbol (error "No symbol corresponding to %s selection" selection)) | |
265 symbol)) | |
266 | |
267 (defun mouse-sel-region-to-primary (orig-window) | |
268 "Convert region to PRIMARY overlay and deactivate region. | |
269 Argument ORIG-WINDOW specifies the window the cursor was in when the | |
270 originating command was issued, and is used to determine whether the | |
271 region was visible or not." | |
272 (if transient-mark-mode | |
273 (let ((overlay (mouse-sel-selection-overlay 'PRIMARY))) | |
274 (cond | |
275 ((and mark-active | |
276 (or highlight-nonselected-windows | |
277 (eq orig-window (selected-window)))) | |
278 ;; Region was visible, so convert region to overlay | |
279 (move-overlay overlay (region-beginning) (region-end) | |
280 (current-buffer))) | |
281 ((eq orig-window (selected-window)) | |
282 ;; Point was visible, so set overlay at point | |
283 (move-overlay overlay (point) (point) (current-buffer))) | |
284 (t | |
285 ;; Nothing was visible, so remove overlay | |
286 (delete-overlay overlay))) | |
287 (setq mark-active nil)))) | |
288 | |
289 (defun mouse-sel-primary-to-region (&optional direction) | |
290 "Convert PRIMARY overlay to region. | |
291 Optional argument DIRECTION specifies the mouse drag direction: a value of | |
292 1 indicates that the mouse was dragged left-to-right, otherwise it was | |
293 dragged right-to-left." | |
294 (let* ((overlay (mouse-sel-selection-overlay 'PRIMARY)) | |
295 (start (overlay-start overlay)) | |
296 (end (overlay-end overlay))) | |
297 (if (eq start end) | |
298 (progn | |
299 (if start (goto-char start)) | |
300 (deactivate-mark)) | |
301 (if (and mouse-sel-leave-point-near-mouse (eq direction 1)) | |
302 (progn | |
303 (goto-char end) | |
304 (push-mark start 'nomsg 'active)) | |
305 (goto-char start) | |
306 (push-mark end 'nomsg 'active))) | |
307 (if transient-mark-mode (delete-overlay overlay)))) | |
308 | |
309 (defmacro mouse-sel-eval-at-event-end (event &rest forms) | |
310 "Evaluate forms at mouse position. | |
311 Move to the end position of EVENT, execute FORMS, and restore original | |
312 point and window." | |
313 (` | |
314 (let ((posn (event-end (, event)))) | |
315 (if posn (mouse-minibuffer-check (, event))) | |
316 (if (and posn (not (windowp (posn-window posn)))) | |
317 (error "Cursor not in text area of window")) | |
318 (let (orig-window orig-point-marker) | |
319 (setq orig-window (selected-window)) | |
320 (if posn (select-window (posn-window posn))) | |
321 (setq orig-point-marker (point-marker)) | |
322 (if (and posn (numberp (posn-point posn))) | |
323 (goto-char (posn-point posn))) | |
324 (unwind-protect | |
325 (progn | |
326 (,@ forms)) | |
327 (goto-char (marker-position orig-point-marker)) | |
328 (move-marker orig-point-marker nil) | |
329 (select-window orig-window) | |
330 ))))) | |
331 | |
332 (put 'mouse-sel-eval-at-event-end 'lisp-indent-hook 1) | |
333 | |
334 ;;=== Select ============================================================== | |
335 | |
336 (defun mouse-select (event) | |
337 "Set region/selection using the mouse. | |
338 | |
339 Click sets point & mark to click position. | |
340 Dragging extends region/selection. | |
341 | |
342 Multi-clicking selects word/lines/paragraphs, as determined by | |
343 'mouse-sel-determine-selection-thing. | |
344 | |
345 Clicking mouse-2 while selecting copies selected text to the kill-ring. | |
346 Clicking mouse-1 or mouse-3 kills the selected text. | |
244 | 347 |
245 This should be bound to a down-mouse event." | 348 This should be bound to a down-mouse event." |
349 (interactive "@e") | |
350 (let (direction) | |
351 (unwind-protect | |
352 (setq direction (mouse-select-internal 'PRIMARY event)) | |
353 (mouse-sel-primary-to-region direction)))) | |
354 | |
355 (defun mouse-select-secondary (event) | |
356 "Set secondary selection using the mouse. | |
357 | |
358 Click sets the start of the secondary selection to click position. | |
359 Dragging extends the secondary selection. | |
360 | |
361 Multi-clicking selects word/lines/paragraphs, as determined by | |
362 'mouse-sel-determine-selection-thing. | |
363 | |
364 Clicking mouse-2 while selecting copies selected text to the kill-ring. | |
365 Clicking mouse-1 or mouse-3 kills the selected text. | |
366 | |
367 This should be bound to a down-mouse event." | |
368 (interactive "e") | |
369 (mouse-select-internal 'SECONDARY event)) | |
370 | |
371 (defun mouse-select-internal (selection event) | |
372 "Set SELECTION using the mouse." | |
373 (mouse-sel-eval-at-event-end event | |
374 (let ((thing-symbol (mouse-sel-selection-thing selection)) | |
375 (overlay (mouse-sel-selection-overlay selection))) | |
376 (set thing-symbol | |
377 (mouse-sel-determine-selection-thing (event-click-count event))) | |
378 (let ((object-bounds (bounds-of-thing-at-point | |
379 (symbol-value thing-symbol)))) | |
380 (if object-bounds | |
381 (progn | |
382 (move-overlay overlay | |
383 (car object-bounds) (cdr object-bounds) | |
384 (current-buffer))) | |
385 (move-overlay overlay (point) (point) (current-buffer))))) | |
386 (mouse-extend-internal selection))) | |
387 | |
388 ;;=== Extend ============================================================== | |
389 | |
390 (defun mouse-extend (event) | |
391 "Extend region/selection using the mouse." | |
246 (interactive "e") | 392 (interactive "e") |
247 (mouse-set-point EVENT) | 393 (let ((orig-window (selected-window)) |
248 (setq mouse-sel-selection-type | 394 direction) |
249 (mouse-sel-determine-selection-type (event-click-count EVENT))) | 395 (select-window (posn-window (event-end event))) |
250 (let ((object-bounds (bounds-of-thing-at-point mouse-sel-selection-type))) | 396 (unwind-protect |
251 (if object-bounds | |
252 (progn | 397 (progn |
253 (setq mark-active t) | 398 (mouse-sel-region-to-primary orig-window) |
254 (goto-char (car object-bounds)) | 399 (setq direction (mouse-extend-internal 'PRIMARY event))) |
255 (set-mark (cdr object-bounds))) | 400 (mouse-sel-primary-to-region direction)))) |
256 (deactivate-mark))) | 401 |
257 (mouse-extend (if mouse-sel-selection-type EVENT))) | 402 (defun mouse-extend-secondary (event) |
258 | 403 "Extend secondary selection using the mouse." |
259 (defun mouse-extend (&optional EVENT) | |
260 "Extend region/selection using the mouse. | |
261 | |
262 See documentation for mouse-select for more details. | |
263 | |
264 This should be bound to a down-mouse event." | |
265 (interactive "e") | 404 (interactive "e") |
266 (if EVENT (select-window (posn-window (event-end EVENT)))) | 405 (save-window-excursion |
267 (let* ((use-region (and (or EVENT transient-mark-mode) mark-active)) | 406 (mouse-extend-internal 'SECONDARY event))) |
268 (min (if use-region (region-beginning) (point))) | 407 |
269 (max (if use-region (region-end) (point))) | 408 (defun mouse-extend-internal (selection &optional initial-event) |
270 (orig-window (selected-window)) | 409 "Extend specified SELECTION using the mouse. |
271 (orig-window-frame (window-frame orig-window)) | 410 Track mouse-motion events, adjusting the SELECTION appropriately. |
272 (top (nth 1 (window-edges orig-window))) | 411 Optional argument INITIAL-EVENT specifies an initial down-mouse event to |
273 (bottom (nth 3 (window-edges orig-window))) | 412 process. |
274 (orig-cursor-type | 413 |
275 (cdr (assoc 'cursor-type (frame-parameters (selected-frame))))) | 414 See documentation for mouse-select-internal for more details." |
276 direction | 415 (mouse-sel-eval-at-event-end initial-event |
277 event) | 416 (let ((orig-cursor-type |
278 | 417 (cdr (assoc 'cursor-type (frame-parameters (selected-frame)))))) |
279 ;; Inhibit normal region highlight | 418 (unwind-protect |
280 (setq mark-active nil) | 419 |
281 | 420 (let* ((thing-symbol (mouse-sel-selection-thing selection)) |
282 ;; Highlight region (forcing re-highlight) | 421 (overlay (mouse-sel-selection-overlay selection)) |
283 (move-overlay mouse-drag-overlay min max (current-buffer)) | 422 (orig-window (selected-window)) |
284 (overlay-put mouse-drag-overlay 'face | 423 (orig-window-frame (window-frame orig-window)) |
285 (overlay-get mouse-drag-overlay 'face)) | 424 (top (nth 1 (window-edges orig-window))) |
286 | 425 (bottom (nth 3 (window-edges orig-window))) |
287 ;; Bar cursor | 426 (mark-active nil) ; inhibit normal region highlight |
288 (if (fboundp 'modify-frame-parameters) | 427 (echo-keystrokes 0) ; don't echo mouse events |
289 (modify-frame-parameters (selected-frame) '((cursor-type . bar)))) | 428 min max |
290 | 429 direction |
291 ;; Handle dragging | 430 event) |
292 (unwind-protect | 431 |
293 (progn | 432 ;; Get current bounds of overlay |
294 (track-mouse | 433 (if (eq (overlay-buffer overlay) (current-buffer)) |
434 (setq min (overlay-start overlay) | |
435 max (overlay-end overlay)) | |
436 (setq min (point) | |
437 max min) | |
438 (set thing-symbol nil)) | |
439 | |
440 | |
441 ;; Bar cursor | |
442 (if (fboundp 'modify-frame-parameters) | |
443 (modify-frame-parameters (selected-frame) | |
444 '((cursor-type . bar)))) | |
295 | 445 |
296 (while (if EVENT ; Use initial event | 446 ;; Handle dragging |
297 (prog1 | 447 (track-mouse |
298 (setq event EVENT) | 448 |
299 (setq EVENT nil)) | 449 (while (if initial-event ; Use initial event |
300 (setq event (read-event)) | 450 (prog1 |
301 (and (consp event) | 451 (setq event initial-event) |
302 (memq (car event) '(mouse-movement switch-frame)))) | 452 (setq initial-event nil)) |
453 (setq event (read-event)) | |
454 (and (consp event) | |
455 (memq (car event) '(mouse-movement switch-frame)))) | |
456 | |
457 (let ((selection-thing (symbol-value thing-symbol)) | |
458 (end (event-end event))) | |
459 | |
460 (cond | |
461 | |
462 ;; Ignore any movement outside the frame | |
463 ((eq (car-safe event) 'switch-frame) nil) | |
464 ((and (posn-window end) | |
465 (not (eq (let ((posn-w (posn-window end))) | |
466 (if (windowp posn-w) | |
467 (window-frame posn-w) | |
468 posn-w)) | |
469 (window-frame orig-window)))) nil) | |
470 | |
471 ;; Different window, same frame | |
472 ((not (eq (posn-window end) orig-window)) | |
473 (let ((end-row (cdr (cdr (mouse-position))))) | |
474 (cond | |
475 ((and end-row (not (bobp)) (< end-row top)) | |
476 (mouse-scroll-subr orig-window (- end-row top) | |
477 overlay max)) | |
478 ((and end-row (not (eobp)) (>= end-row bottom)) | |
479 (mouse-scroll-subr orig-window (1+ (- end-row bottom)) | |
480 overlay min)) | |
481 ))) | |
482 | |
483 ;; On the mode line | |
484 ((eq (posn-point end) 'mode-line) | |
485 (mouse-scroll-subr orig-window 1 overlay min)) | |
486 | |
487 ;; In original window | |
488 (t (goto-char (posn-point end))) | |
489 | |
490 ) | |
303 | 491 |
304 (let ((end (event-end event))) | 492 ;; Determine direction of drag |
493 (cond | |
494 ((and (not direction) (not (eq min max))) | |
495 (setq direction (if (< (point) (/ (+ min max) 2)) -1 1))) | |
496 ((and (not (eq direction -1)) (<= (point) min)) | |
497 (setq direction -1)) | |
498 ((and (not (eq direction 1)) (>= (point) max)) | |
499 (setq direction 1))) | |
500 | |
501 (if (not selection-thing) nil | |
305 | 502 |
503 ;; If dragging forward, goal is next character | |
504 (if (and (eq direction 1) (not (eobp))) (forward-char 1)) | |
505 | |
506 ;; Move to start/end of selected thing | |
507 (let ((goal (point)) | |
508 last) | |
509 (goto-char (if (eq 1 direction) min max)) | |
510 (condition-case nil | |
511 (progn | |
512 (while (> (* direction (- goal (point))) 0) | |
513 (setq last (point)) | |
514 (forward-thing selection-thing direction)) | |
515 (let ((end (point))) | |
516 (forward-thing selection-thing (- direction)) | |
517 (goto-char | |
518 (if (> (* direction (- goal (point))) 0) | |
519 end last)))) | |
520 (error)))) | |
521 | |
522 ;; Move overlay | |
523 (move-overlay overlay | |
524 (if (eq 1 direction) min (point)) | |
525 (if (eq -1 direction) max (point)) | |
526 (current-buffer)) | |
527 | |
528 ))) ; end track-mouse | |
529 | |
530 ;; Finish up after dragging | |
531 (let ((overlay-start (overlay-start overlay)) | |
532 (overlay-end (overlay-end overlay))) | |
533 | |
534 ;; Set selection | |
535 (if (not (eq overlay-start overlay-end)) | |
536 (mouse-sel-set-selection | |
537 selection | |
538 (buffer-substring overlay-start overlay-end))) | |
539 | |
540 ;; Handle copy/kill | |
541 (let (this-command) | |
306 (cond | 542 (cond |
307 | 543 ((eq (event-basic-type last-input-event) 'mouse-2) |
308 ;; Ignore any movement outside the frame | 544 (copy-region-as-kill overlay-start overlay-end) |
309 ((eq (car-safe event) 'switch-frame) nil) | 545 (read-event) (read-event)) |
310 ((and (posn-window end) | 546 ((and (memq (event-basic-type last-input-event) |
311 (not (eq (let ((posn-w (posn-window end))) | 547 '(mouse-1 mouse-3)) |
312 (if (windowp posn-w) | 548 (memq 'down (event-modifiers last-input-event))) |
313 (window-frame posn-w) | 549 (kill-region overlay-start overlay-end) |
314 posn-w)) | 550 (move-overlay overlay overlay-start overlay-start) |
315 (window-frame orig-window)))) nil) | 551 (read-event) (read-event)) |
316 | 552 ((and (eq (event-basic-type last-input-event) 'mouse-3) |
317 ;; Different window, same frame | 553 (memq 'double (event-modifiers last-input-event))) |
318 ((not (eq (posn-window end) orig-window)) | 554 (kill-region overlay-start overlay-end) |
319 (let ((end-row (cdr (cdr (mouse-position))))) | 555 (move-overlay overlay overlay-start overlay-start))))) |
320 (cond | 556 |
321 ((and end-row (not (bobp)) (< end-row top)) | 557 direction) |
322 (mouse-scroll-subr orig-window (- end-row top) | 558 |
323 mouse-drag-overlay max)) | 559 ;; Restore cursor |
324 ((and end-row (not (eobp)) (>= end-row bottom)) | 560 (if (fboundp 'modify-frame-parameters) |
325 (mouse-scroll-subr orig-window (1+ (- end-row bottom)) | 561 (modify-frame-parameters |
326 mouse-drag-overlay min)) | 562 (selected-frame) (list (cons 'cursor-type orig-cursor-type)))) |
327 ))) | 563 |
328 | 564 )))) |
329 ;; On the mode line | 565 |
330 ((eq (posn-point end) 'mode-line) | 566 ;;=== Paste =============================================================== |
331 (mouse-scroll-subr orig-window 1 mouse-drag-overlay min)) | 567 |
332 | 568 (defun mouse-insert-selection (event) |
333 ;; In original window | 569 "Insert the contents of the PRIMARY selection at mouse click. |
334 (t (goto-char (posn-point end))) | |
335 | |
336 ) | |
337 ;; Determine direction of drag | |
338 (cond | |
339 ((and (not direction) (not (eq min max))) | |
340 (setq direction (if (< (point) (/ (+ min max) 2)) -1 1))) | |
341 ((and (not (eq direction -1)) (<= (point) min)) | |
342 (setq direction -1)) | |
343 ((and (not (eq direction 1)) (>= (point) max)) | |
344 (setq direction 1))) | |
345 | |
346 (if (not mouse-sel-selection-type) nil | |
347 | |
348 ;; If dragging forward, goal is next character | |
349 (if (and (eq direction 1) (not (eobp))) (forward-char 1)) | |
350 | |
351 ;; Move to start/end of selected thing | |
352 (let ((goal (point)) | |
353 last) | |
354 (goto-char (if (eq 1 direction) min max)) | |
355 (condition-case nil | |
356 (progn | |
357 (while (> (* direction (- goal (point))) 0) | |
358 (setq last (point)) | |
359 (forward-thing mouse-sel-selection-type | |
360 direction)) | |
361 (let ((end (point))) | |
362 (forward-thing mouse-sel-selection-type | |
363 (- direction)) | |
364 (goto-char | |
365 (if (> (* direction (- goal (point))) 0) | |
366 end last)))) | |
367 (error)))) | |
368 | |
369 ;; Move overlay | |
370 (move-overlay mouse-drag-overlay | |
371 (if (eq 1 direction) min (point)) | |
372 (if (eq -1 direction) max (point)) | |
373 (current-buffer)) | |
374 | |
375 ))) ; end track-mouse | |
376 | |
377 (let ((overlay-start (overlay-start mouse-drag-overlay)) | |
378 (overlay-end (overlay-end mouse-drag-overlay))) | |
379 | |
380 ;; Set region | |
381 (if (eq overlay-start overlay-end) | |
382 (deactivate-mark) | |
383 (if (and mouse-sel-leave-point-near-mouse (eq direction 1)) | |
384 (progn | |
385 (set-mark overlay-start) | |
386 (goto-char overlay-end)) | |
387 (set-mark overlay-end) | |
388 (goto-char overlay-start))) | |
389 | |
390 ;; Set selection | |
391 (if (and mark-active mouse-sel-set-selection-function) | |
392 (funcall mouse-sel-set-selection-function | |
393 (buffer-substring overlay-start overlay-end))) | |
394 | |
395 ;; Handle copy/kill | |
396 (cond | |
397 ((eq (car-safe last-input-event) 'down-mouse-2) | |
398 (copy-region-as-kill overlay-start overlay-end) | |
399 (read-event) (read-event)) | |
400 ((memq (car-safe last-input-event) '(down-mouse-1 down-mouse-3)) | |
401 (kill-region overlay-start overlay-end) | |
402 (deactivate-mark) | |
403 (read-event) (read-event)) | |
404 ((eq (car-safe last-input-event) 'double-mouse-3) | |
405 (kill-region overlay-start overlay-end) | |
406 (deactivate-mark))))) | |
407 | |
408 ;; Restore cursor | |
409 (if (fboundp 'modify-frame-parameters) | |
410 (modify-frame-parameters | |
411 (selected-frame) (list (cons 'cursor-type orig-cursor-type)))) | |
412 | |
413 ;; Remove overlay | |
414 (or mouse-sel-retain-highlight | |
415 (delete-overlay mouse-drag-overlay))))) | |
416 | |
417 (defun mouse-insert-selection (click) | |
418 "Insert the contents of the selection at mouse click. | |
419 If `mouse-yank-at-point' is non-nil, insert at point instead." | 570 If `mouse-yank-at-point' is non-nil, insert at point instead." |
420 (interactive "e") | 571 (interactive "e") |
572 (mouse-insert-selection-internal 'PRIMARY event)) | |
573 | |
574 (defun mouse-insert-secondary (event) | |
575 "Insert the contents of the SECONDARY selection at mouse click. | |
576 If `mouse-yank-at-point' is non-nil, insert at point instead." | |
577 (interactive "e") | |
578 (mouse-insert-selection-internal 'SECONDARY event)) | |
579 | |
580 (defun mouse-insert-selection-internal (selection event) | |
581 "Insert the contents of the named SELECTION at mouse click. | |
582 If `mouse-yank-at-point' is non-nil, insert at point instead." | |
421 (or mouse-yank-at-point | 583 (or mouse-yank-at-point |
422 (mouse-set-point click)) | 584 (mouse-set-point event)) |
423 (deactivate-mark) | |
424 (if mouse-sel-get-selection-function | 585 (if mouse-sel-get-selection-function |
425 (insert (or (funcall mouse-sel-get-selection-function) "")))) | 586 (progn |
587 (push-mark (point) 'nomsg) | |
588 (insert (or (funcall mouse-sel-get-selection-function selection) ""))))) | |
589 | |
590 ;;=== Validate selection ================================================== | |
426 | 591 |
427 (defun mouse-sel-validate-selection () | 592 (defun mouse-sel-validate-selection () |
428 "Remove selection highlight if emacs no longer owns the primary selection." | 593 "Validate selections in mouse-sel-selection-alist. |
429 (or (not mouse-sel-check-selection-function) | 594 For each listed selection, remove the selection overlay if Emacs no longer |
430 (funcall mouse-sel-check-selection-function) | 595 owns the selection." |
431 (delete-overlay mouse-drag-overlay))) | 596 (let ((owner-p-function mouse-sel-selection-owner-p-function) |
597 (alist mouse-sel-selection-alist) | |
598 selection overlay) | |
599 (if owner-p-function | |
600 (while alist | |
601 (setq selection (car (car alist)) | |
602 overlay (symbol-value (nth 1 (car alist))) | |
603 alist (cdr alist)) | |
604 (or (funcall owner-p-function selection) | |
605 (delete-overlay overlay)))))) | |
432 | 606 |
433 (add-hook 'pre-command-hook 'mouse-sel-validate-selection) | 607 (add-hook 'pre-command-hook 'mouse-sel-validate-selection) |
434 | 608 |
435 ;;=== Key bindings ======================================================== | 609 ;;=== Key bindings ======================================================== |
436 | 610 |
440 (global-unset-key [drag-mouse-1]) | 614 (global-unset-key [drag-mouse-1]) |
441 (global-unset-key [mouse-3]) | 615 (global-unset-key [mouse-3]) |
442 | 616 |
443 (global-set-key [down-mouse-1] 'mouse-select) | 617 (global-set-key [down-mouse-1] 'mouse-select) |
444 (global-set-key [down-mouse-3] 'mouse-extend) | 618 (global-set-key [down-mouse-3] 'mouse-extend) |
619 | |
620 (global-unset-key [M-mouse-1]) | |
621 (global-unset-key [M-drag-mouse-1]) | |
622 (global-unset-key [M-mouse-3]) | |
445 | 623 |
624 (global-set-key [M-down-mouse-1] 'mouse-select-secondary) | |
625 (global-set-key [M-down-mouse-3] 'mouse-extend-secondary) | |
626 | |
446 (if (eq mouse-sel-default-bindings 'interprogram-cut-paste) nil | 627 (if (eq mouse-sel-default-bindings 'interprogram-cut-paste) nil |
447 | 628 |
448 (global-set-key [mouse-2] 'mouse-insert-selection) | 629 (global-set-key [mouse-2] 'mouse-insert-selection) |
630 | |
449 (setq interprogram-cut-function nil | 631 (setq interprogram-cut-function nil |
450 interprogram-paste-function nil)) | 632 interprogram-paste-function nil)) |
451 | 633 |
634 (global-set-key [M-mouse-2] 'mouse-insert-secondary) | |
635 | |
452 ) | 636 ) |
453 | 637 |
638 ;;=== Bug reporting ======================================================= | |
639 | |
640 (defconst mouse-sel-maintainer-address "mikew@gopher.dosli.govt.nz") | |
641 | |
642 (defun mouse-sel-submit-bug-report () | |
643 "Submit a bug report on mouse-sel.el via mail." | |
644 (interactive) | |
645 (require 'reporter) | |
646 (reporter-submit-bug-report | |
647 mouse-sel-maintainer-address | |
648 (concat "mouse-sel.el " | |
649 (or (condition-case nil mouse-sel-version (error)) | |
650 "(distributed with Emacs)")) | |
651 (list 'transient-mark-mode | |
652 'delete-selection-mode | |
653 'mouse-sel-default-bindings | |
654 'mouse-sel-leave-point-near-mouse | |
655 'mouse-sel-cycle-clicks | |
656 'mouse-sel-selection-alist | |
657 'mouse-sel-set-selection-function | |
658 'mouse-sel-get-selection-function | |
659 'mouse-sel-selection-owner-p-function | |
660 'mouse-yank-at-point))) | |
661 | |
454 ;; mouse-sel.el ends here. | 662 ;; mouse-sel.el ends here. |