Typo.
[bpt/emacs.git] / lisp / emulation / pc-select.el
CommitLineData
b50c87ee
KH
1;;; pc-select.el --- emulate mark, cut, copy and paste from Motif
2;;; (or MAC GUI or MS-windoze (bah)) look-and-feel
3;;; including key bindings.
215e89e5 4
5fd6d89f 5;; Copyright (C) 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2004,
8b72699e 6;; 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
215e89e5
RS
7
8;; Author: Michael Staats <michael@thp.Uni-Duisburg.DE>
de986953 9;; Keywords: convenience emulation
215e89e5
RS
10;; Created: 26 Sep 1995
11
12;; This file is part of GNU Emacs.
13
14;; GNU Emacs is free software; you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
e0085d62 16;; the Free Software Foundation; either version 3, or (at your option)
215e89e5
RS
17;; any later version.
18
19;; GNU Emacs is distributed in the hope that it will be useful,
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
b578f267 25;; along with GNU Emacs; see the file COPYING. If not, write to the
3a35cf56
LK
26;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27;; Boston, MA 02110-1301, USA.
215e89e5
RS
28
29;;; Commentary:
b578f267 30
215e89e5
RS
31;; This package emulates the mark, copy, cut and paste look-and-feel of motif
32;; programs (which is the same as the MAC gui and (sorry for that) MS-Windows).
33;; It modifies the keybindings of the cursor keys and the next, prior,
34;; home and end keys. They will modify mark-active.
35;; You can still get the old behaviour of cursor moving with the
36;; control sequences C-f, C-b, etc.
37;; This package uses transient-mark-mode and
38;; delete-selection-mode.
39;;
13f5a20e 40;; In addition to that all key-bindings from the pc-mode are
215e89e5
RS
41;; done here too (as suggested by RMS).
42;;
43;; As I found out after I finished the first version, s-region.el tries
44;; to do the same.... But my code is a little more complete and using
45;; delete-selection-mode is very important for the look-and-feel.
46;; Pete Forman <pete.forman@airgun.wg.waii.com> provided some motif
47;; compliant keybindings which I added. I had to modify them a little
48;; to add the -mark and -nomark functionality of cursor moving.
49;;
50;; Credits:
51;; Many thanks to all who made comments.
52;; Thanks to RMS and Ralf Muschall <prm@rz.uni-jena.de> for criticism.
53;; Kevin Cutts <cutts@ukraine.corp.mot.com> added the beginning-of-buffer
54;; and end-of-buffer functions which I modified a little.
55;; David Biesack <sasdjb@unx.sas.com> suggested some more cleanup.
56;; Thanks to Pete Forman <pete.forman@airgun.wg.waii.com>
57;; for additional motif keybindings.
14dacacd
RS
58;; Thanks to jvromans@squirrel.nl (Johan Vromans) for a bug report
59;; concerning setting of this-command.
83d1d58c 60;; Dan Nicolaescu <done@ece.arizona.ro> suggested suppressing the
20c5a87d 61;; scroll-up/scroll-down error.
b50c87ee 62;; Eli Barzilay (eli@cs.bgu.ac.il) suggested the sexps functions and
13f5a20e 63;; keybindings.
215e89e5 64;;
e873bbf9 65;; Ok, some details about the idea of PC Selection mode:
215e89e5
RS
66;;
67;; o The standard keys for moving around (right, left, up, down, home, end,
68;; prior, next, called "move-keys" from now on) will always de-activate
69;; the mark.
70;; o If you press "Shift" together with the "move-keys", the region
71;; you pass along is activated
72;; o You have the copy, cut and paste functions (as in many other programs)
73;; which will operate on the active region
74;; It was not possible to bind them to C-v, C-x and C-c for obvious
75;; emacs reasons.
76;; They will be bound according to the "old" behaviour to S-delete (cut),
77;; S-insert (paste) and C-insert (copy). These keys do the same in many
78;; other programs.
20c5a87d 79;;
215e89e5 80
e8af40ee
PJ
81;;; Code:
82
fd4e5923 83;; Customization:
83d1d58c
RS
84(defgroup pc-select nil
85 "Emulate pc bindings."
86 :prefix "pc-select"
f5f727f8
DN
87 :group 'editing-basics
88 :group 'convenience)
20c5a87d 89
83d1d58c 90(defcustom pc-select-override-scroll-error t
20c5a87d
RS
91 "*Non-nil means don't generate error on scrolling past edge of buffer.
92This variable applies in PC Selection mode only.
93The scroll commands normally generate an error if you try to scroll
94past the top or bottom of the buffer. This is annoying when selecting
95text with these commands. If you set this variable to non-nil, these
83d1d58c
RS
96errors are suppressed."
97 :type 'boolean
98 :group 'pc-select)
215e89e5 99
83d1d58c 100(defcustom pc-select-selection-keys-only nil
b50c87ee
KH
101 "*Non-nil means only bind the basic selection keys when started.
102Other keys that emulate pc-behavior will be untouched.
ca088b04 103This gives mostly Emacs-like behavior with only the selection keys enabled."
83d1d58c
RS
104 :type 'boolean
105 :group 'pc-select)
b50c87ee 106
83d1d58c
RS
107(defcustom pc-select-meta-moves-sexps nil
108 "*Non-nil means move sexp-wise with Meta key, otherwise move word-wise."
109 :type 'boolean
110 :group 'pc-select)
b50c87ee 111
cb96f094
RS
112(defcustom pc-selection-mode-hook nil
113 "The hook to run when pc-selection-mode is toggled."
114 :type 'hook
115 :group 'pc-select)
116
117(defvar pc-select-saved-settings-alist nil
e873bbf9
RS
118 "The values of the variables before PC Selection mode was toggled on.
119When PC Selection mode is toggled on, it sets quite a few variables
cb96f094 120for its own purposes. This alist holds the original values of the
e873bbf9
RS
121variables PC Selection mode had set, so that these variables can be
122restored to their original values when PC Selection mode is toggled off.")
cb96f094
RS
123
124(defvar pc-select-map nil
e873bbf9 125 "The keymap used as the global map when PC Selection mode is on." )
cb96f094
RS
126
127(defvar pc-select-saved-global-map nil
e873bbf9 128 "The global map that was in effect when PC Selection mode was toggled on.")
cb96f094
RS
129
130(defvar pc-select-key-bindings-alist nil
e873bbf9 131 "This alist holds all the key bindings PC Selection mode sets.")
cb96f094
RS
132
133(defvar pc-select-default-key-bindings nil
e873bbf9 134 "These key bindings always get set by PC Selection mode.")
cb96f094
RS
135
136(unless pc-select-default-key-bindings
137 (let ((lst
de299ed7
SM
138 ;; This is to avoid confusion with the delete-selection-mode.
139 ;; On simple displays you can't see that a region is active and
cb96f094
RS
140 ;; will be deleted on the next keypress IMHO especially for
141 ;; copy-region-as-kill this is confusing.
142 ;; The same goes for exchange-point-and-mark
143 '(("\M-w" . copy-region-as-kill-nomark)
144 ("\C-x\C-x" . exchange-point-and-mark-nomark)
145 ([S-right] . forward-char-mark)
146 ([right] . forward-char-nomark)
147 ([C-S-right] . forward-word-mark)
148 ([C-right] . forward-word-nomark)
149 ([S-left] . backward-char-mark)
150 ([left] . backward-char-nomark)
151 ([C-S-left] . backward-word-mark)
152 ([C-left] . backward-word-nomark)
153 ([S-down] . next-line-mark)
154 ([down] . next-line-nomark)
155
156 ([S-end] . end-of-line-mark)
157 ([end] . end-of-line-nomark)
158 ([S-C-end] . end-of-buffer-mark)
159 ([C-end] . end-of-buffer-nomark)
160 ([S-M-end] . end-of-buffer-mark)
161 ([M-end] . end-of-buffer-nomark)
162
163 ([S-next] . scroll-up-mark)
164 ([next] . scroll-up-nomark)
165
166 ([S-up] . previous-line-mark)
167 ([up] . previous-line-nomark)
168
169 ([S-home] . beginning-of-line-mark)
170 ([home] . beginning-of-line-nomark)
171 ([S-C-home] . beginning-of-buffer-mark)
172 ([C-home] . beginning-of-buffer-nomark)
173 ([S-M-home] . beginning-of-buffer-mark)
174 ([M-home] . beginning-of-buffer-nomark)
175
176 ([M-S-down] . forward-line-mark)
177 ([M-down] . forward-line-nomark)
178 ([M-S-up] . backward-line-mark)
179 ([M-up] . backward-line-nomark)
180
181 ([S-prior] . scroll-down-mark)
182 ([prior] . scroll-down-nomark)
183
184 ;; Next four lines are from Pete Forman.
de299ed7 185 ([C-down] . forward-paragraph-nomark) ; KNextPara cDn
cb96f094
RS
186 ([C-up] . backward-paragraph-nomark) ; KPrevPara cUp
187 ([S-C-down] . forward-paragraph-mark)
188 ([S-C-up] . backward-paragraph-mark))))
a1506d29 189
cb96f094
RS
190 (setq pc-select-default-key-bindings lst)))
191
192(defvar pc-select-extra-key-bindings nil
193 "Key bindings to set only if `pc-select-selection-keys-only' is nil.")
194
195;; The following keybindings are for standard ISO keyboards
196;; as they are used with IBM compatible PCs, IBM RS/6000,
197;; MACs, many X-Stations and probably more
198(unless pc-select-extra-key-bindings
199 (let ((lst
200 '(([S-insert] . yank)
201 ([C-insert] . copy-region-as-kill)
202 ([S-delete] . kill-region)
203
204 ;; The following bindings are useful on Sun Type 3 keyboards
205 ;; They implement the Get-Delete-Put (copy-cut-paste)
206 ;; functions from sunview on the L6, L8 and L10 keys
207 ;; Sam Steingold <sds@gnu.org> says that f16 is copy and f18 is paste.
208 ([f16] . copy-region-as-kill)
209 ([f18] . yank)
210 ([f20] . kill-region)
211
212 ;; The following bindings are from Pete Forman.
213 ([f6] . other-window) ; KNextPane F6
214 ([C-delete] . kill-line) ; KEraseEndLine cDel
215 ("\M-\d" . undo) ; KUndo aBS
216
217 ;; The following binding is taken from pc-mode.el
218 ;; as suggested by RMS.
219 ;; I only used the one that is not covered above.
220 ([C-M-delete] . kill-sexp)
221 ;; Next line proposed by Eli Barzilay
222 ([C-escape] . electric-buffer-list))))
a1506d29 223
cb96f094
RS
224 (setq pc-select-extra-key-bindings lst)))
225
226(defvar pc-select-meta-moves-sexps-key-bindings
227 '((([M-S-right] . forward-sexp-mark)
228 ([M-right] . forward-sexp-nomark)
229 ([M-S-left] . backward-sexp-mark)
230 ([M-left] . backward-sexp-nomark))
231 (([M-S-right] . forward-word-mark)
232 ([M-right] . forward-word-nomark)
233 ([M-S-left] . backward-word-mark)
234 ([M-left] . backward-word-nomark)))
235 "The list of key bindings controlled by `pc-select-meta-moves-sexp'.
236The bindings in the car of this list get installed if
237`pc-select-meta-moves-sexp' is t, the bindings in the cadr of this
238list get installed otherwise.")
239
240;; This is for tty. We don't turn on normal-erase-is-backspace,
241;; but bind keys as pc-selection-mode did before
242;; normal-erase-is-backspace was invented, to keep us back
243;; compatible.
244(defvar pc-select-tty-key-bindings
245 '(([delete] . delete-char) ; KDelete Del
246 ([C-backspace] . backward-kill-word))
247 "The list of key bindings controlled by `pc-select-selection-keys-only'.
248These key bindings get installed when running in a tty, but only if
249`pc-select-selection-keys-only' is nil.")
250
251(defvar pc-select-old-M-delete-binding nil
252 "Holds the old mapping of [M-delete] in the `function-key-map'.
253This variable holds the value associated with [M-delete] in the
e873bbf9 254`function-key-map' before PC Selection mode had changed that
cb96f094
RS
255association.")
256
215e89e5
RS
257;;;;
258;; misc
259;;;;
260
261(provide 'pc-select)
262
263(defun copy-region-as-kill-nomark (beg end)
264 "Save the region as if killed; but don't kill it; deactivate mark.
265If `interprogram-cut-function' is non-nil, also save the text for a window
20c5a87d
RS
266system cut and paste.
267
fd4e5923
SM
268Deactivating mark is to avoid confusion with `delete-selection-mode'
269and `transient-mark-mode'."
215e89e5
RS
270 (interactive "r")
271 (copy-region-as-kill beg end)
272 (setq mark-active nil)
273 (message "Region saved"))
274
b50c87ee 275(defun exchange-point-and-mark-nomark ()
fd4e5923 276 "Like `exchange-point-and-mark' but without activating the mark."
b50c87ee
KH
277 (interactive)
278 (exchange-point-and-mark)
279 (setq mark-active nil))
280
215e89e5
RS
281;;;;
282;; non-interactive
283;;;;
e85c6b7c 284(defun pc-select-ensure-mark ()
215e89e5
RS
285 ;; make sure mark is active
286 ;; test if it is active, if it isn't, set it and activate it
de299ed7 287 (or mark-active (set-mark-command nil))
e85c6b7c
SM
288 ;; Remember who activated the mark.
289 (setq mark-active 'pc-select))
de299ed7 290
e85c6b7c 291(defun pc-select-maybe-deactivate-mark ()
de299ed7 292 ;; maybe switch off mark (only if *we* switched it on)
e85c6b7c
SM
293 (when (eq mark-active 'pc-select)
294 (deactivate-mark)))
215e89e5
RS
295
296;;;;;;;;;;;;;;;;;;;;;;;;;;;
297;;;;; forward and mark
298;;;;;;;;;;;;;;;;;;;;;;;;;;;
299
300(defun forward-char-mark (&optional arg)
301 "Ensure mark is active; move point right ARG characters (left if ARG negative).
302On reaching end of buffer, stop and signal error."
303 (interactive "p")
e85c6b7c 304 (pc-select-ensure-mark)
215e89e5
RS
305 (forward-char arg))
306
307(defun forward-word-mark (&optional arg)
308 "Ensure mark is active; move point right ARG words (backward if ARG is negative).
309Normally returns t.
310If an edge of the buffer is reached, point is left there
311and nil is returned."
312 (interactive "p")
e85c6b7c 313 (pc-select-ensure-mark)
215e89e5
RS
314 (forward-word arg))
315
20c5a87d
RS
316(defun forward-line-mark (&optional arg)
317 "Ensure mark is active; move cursor vertically down ARG lines."
318 (interactive "p")
e85c6b7c 319 (pc-select-ensure-mark)
20c5a87d
RS
320 (forward-line arg)
321 (setq this-command 'forward-line)
322)
323
b50c87ee
KH
324(defun forward-sexp-mark (&optional arg)
325 "Ensure mark is active; move forward across one balanced expression (sexp).
326With argument, do it that many times. Negative arg -N means
327move backward across N balanced expressions."
328 (interactive "p")
e85c6b7c 329 (pc-select-ensure-mark)
b50c87ee
KH
330 (forward-sexp arg))
331
215e89e5
RS
332(defun forward-paragraph-mark (&optional arg)
333 "Ensure mark is active; move forward to end of paragraph.
20c5a87d
RS
334With arg N, do it N times; negative arg -N means move backward N paragraphs.
335
215e89e5 336A line which `paragraph-start' matches either separates paragraphs
14dacacd 337\(if `paragraph-separate' matches it also) or is the first line of a paragraph.
215e89e5
RS
338A paragraph end is the beginning of a line which is not part of the paragraph
339to which the end of the previous line belongs, or the end of the buffer."
340 (interactive "p")
e85c6b7c 341 (pc-select-ensure-mark)
215e89e5 342 (forward-paragraph arg))
20c5a87d 343
215e89e5
RS
344(defun next-line-mark (&optional arg)
345 "Ensure mark is active; move cursor vertically down ARG lines.
346If there is no character in the target line exactly under the current column,
347the cursor is positioned after the character in that line which spans this
348column, or at the end of the line if it is not long enough.
349If there is no line in the buffer after this one, behavior depends on the
350value of `next-line-add-newlines'. If non-nil, it inserts a newline character
351to create a line, and moves the cursor to that line. Otherwise it moves the
352cursor to the end of the buffer \(if already at the end of the buffer, an error
20c5a87d
RS
353is signaled).
354
fd4e5923 355The command \\[set-goal-column] can be used to create
215e89e5
RS
356a semipermanent goal column to which this command always moves.
357Then it does not try to move vertically. This goal column is stored
358in `goal-column', which is nil when there is none."
359 (interactive "p")
e85c6b7c 360 (pc-select-ensure-mark)
3fe5c37a 361 (with-no-warnings (next-line arg))
14dacacd 362 (setq this-command 'next-line))
215e89e5
RS
363
364(defun end-of-line-mark (&optional arg)
365 "Ensure mark is active; move point to end of current line.
366With argument ARG not nil or 1, move forward ARG - 1 lines first.
367If scan reaches end of buffer, stop there without error."
368 (interactive "p")
e85c6b7c 369 (pc-select-ensure-mark)
14dacacd
RS
370 (end-of-line arg)
371 (setq this-command 'end-of-line))
215e89e5 372
20c5a87d
RS
373(defun backward-line-mark (&optional arg)
374 "Ensure mark is active; move cursor vertically up ARG lines."
375 (interactive "p")
e85c6b7c 376 (pc-select-ensure-mark)
20c5a87d
RS
377 (if (null arg)
378 (setq arg 1))
379 (forward-line (- arg))
380 (setq this-command 'forward-line)
381)
382
215e89e5
RS
383(defun scroll-down-mark (&optional arg)
384 "Ensure mark is active; scroll down ARG lines; or near full screen if no ARG.
385A near full screen is `next-screen-context-lines' less than a full screen.
386Negative ARG means scroll upward.
387When calling from a program, supply a number as argument or nil."
13f5a20e 388 (interactive "P")
e85c6b7c 389 (pc-select-ensure-mark)
2a811501
RS
390 (cond (pc-select-override-scroll-error
391 (condition-case nil (scroll-down arg)
392 (beginning-of-buffer (goto-char (point-min)))))
393 (t (scroll-down arg))))
215e89e5
RS
394
395(defun end-of-buffer-mark (&optional arg)
396 "Ensure mark is active; move point to the end of the buffer.
20c5a87d
RS
397With arg N, put point N/10 of the way from the end.
398
215e89e5 399If the buffer is narrowed, this command uses the beginning and size
20c5a87d
RS
400of the accessible part of the buffer.
401
215e89e5
RS
402Don't use this command in Lisp programs!
403\(goto-char \(point-max)) is faster and avoids clobbering the mark."
404 (interactive "P")
e85c6b7c 405 (pc-select-ensure-mark)
215e89e5
RS
406 (let ((size (- (point-max) (point-min))))
407 (goto-char (if arg
408 (- (point-max)
409 (if (> size 10000)
410 ;; Avoid overflow for large buffer sizes!
411 (* (prefix-numeric-value arg)
412 (/ size 10))
413 (/ (* size (prefix-numeric-value arg)) 10)))
414 (point-max))))
415 ;; If we went to a place in the middle of the buffer,
416 ;; adjust it to the beginning of a line.
417 (if arg (forward-line 1)
418 ;; If the end of the buffer is not already on the screen,
419 ;; then scroll specially to put it near, but not at, the bottom.
420 (if (let ((old-point (point)))
421 (save-excursion
422 (goto-char (window-start))
423 (vertical-motion (window-height))
424 (< (point) old-point)))
425 (progn
426 (overlay-recenter (point))
427 (recenter -3)))))
428
429;;;;;;;;;
430;;;;; no mark
431;;;;;;;;;
432
433(defun forward-char-nomark (&optional arg)
434 "Deactivate mark; move point right ARG characters \(left if ARG negative).
435On reaching end of buffer, stop and signal error."
436 (interactive "p")
e85c6b7c 437 (pc-select-maybe-deactivate-mark)
215e89e5
RS
438 (forward-char arg))
439
440(defun forward-word-nomark (&optional arg)
441 "Deactivate mark; move point right ARG words \(backward if ARG is negative).
442Normally returns t.
443If an edge of the buffer is reached, point is left there
444and nil is returned."
445 (interactive "p")
e85c6b7c 446 (pc-select-maybe-deactivate-mark)
215e89e5
RS
447 (forward-word arg))
448
20c5a87d
RS
449(defun forward-line-nomark (&optional arg)
450 "Deactivate mark; move cursor vertically down ARG lines."
451 (interactive "p")
e85c6b7c 452 (pc-select-maybe-deactivate-mark)
20c5a87d
RS
453 (forward-line arg)
454 (setq this-command 'forward-line)
455)
456
b50c87ee
KH
457(defun forward-sexp-nomark (&optional arg)
458 "Deactivate mark; move forward across one balanced expression (sexp).
459With argument, do it that many times. Negative arg -N means
460move backward across N balanced expressions."
461 (interactive "p")
e85c6b7c 462 (pc-select-maybe-deactivate-mark)
b50c87ee
KH
463 (forward-sexp arg))
464
215e89e5
RS
465(defun forward-paragraph-nomark (&optional arg)
466 "Deactivate mark; move forward to end of paragraph.
20c5a87d
RS
467With arg N, do it N times; negative arg -N means move backward N paragraphs.
468
215e89e5 469A line which `paragraph-start' matches either separates paragraphs
14dacacd 470\(if `paragraph-separate' matches it also) or is the first line of a paragraph.
215e89e5
RS
471A paragraph end is the beginning of a line which is not part of the paragraph
472to which the end of the previous line belongs, or the end of the buffer."
473 (interactive "p")
e85c6b7c 474 (pc-select-maybe-deactivate-mark)
215e89e5
RS
475 (forward-paragraph arg))
476
477(defun next-line-nomark (&optional arg)
478 "Deactivate mark; move cursor vertically down ARG lines.
479If there is no character in the target line exactly under the current column,
480the cursor is positioned after the character in that line which spans this
481column, or at the end of the line if it is not long enough.
482If there is no line in the buffer after this one, behavior depends on the
483value of `next-line-add-newlines'. If non-nil, it inserts a newline character
484to create a line, and moves the cursor to that line. Otherwise it moves the
485cursor to the end of the buffer (if already at the end of the buffer, an error
20c5a87d
RS
486is signaled).
487
fd4e5923 488The command \\[set-goal-column] can be used to create
215e89e5
RS
489a semipermanent goal column to which this command always moves.
490Then it does not try to move vertically. This goal column is stored
491in `goal-column', which is nil when there is none."
492 (interactive "p")
e85c6b7c 493 (pc-select-maybe-deactivate-mark)
3fe5c37a 494 (with-no-warnings (next-line arg))
14dacacd 495 (setq this-command 'next-line))
215e89e5
RS
496
497(defun end-of-line-nomark (&optional arg)
498 "Deactivate mark; move point to end of current line.
499With argument ARG not nil or 1, move forward ARG - 1 lines first.
500If scan reaches end of buffer, stop there without error."
501 (interactive "p")
e85c6b7c 502 (pc-select-maybe-deactivate-mark)
14dacacd
RS
503 (end-of-line arg)
504 (setq this-command 'end-of-line))
215e89e5 505
20c5a87d
RS
506(defun backward-line-nomark (&optional arg)
507 "Deactivate mark; move cursor vertically up ARG lines."
508 (interactive "p")
e85c6b7c 509 (pc-select-maybe-deactivate-mark)
20c5a87d
RS
510 (if (null arg)
511 (setq arg 1))
512 (forward-line (- arg))
513 (setq this-command 'forward-line)
514)
515
215e89e5
RS
516(defun scroll-down-nomark (&optional arg)
517 "Deactivate mark; scroll down ARG lines; or near full screen if no ARG.
518A near full screen is `next-screen-context-lines' less than a full screen.
519Negative ARG means scroll upward.
520When calling from a program, supply a number as argument or nil."
521 (interactive "P")
e85c6b7c 522 (pc-select-maybe-deactivate-mark)
2a811501
RS
523 (cond (pc-select-override-scroll-error
524 (condition-case nil (scroll-down arg)
525 (beginning-of-buffer (goto-char (point-min)))))
526 (t (scroll-down arg))))
215e89e5
RS
527
528(defun end-of-buffer-nomark (&optional arg)
529 "Deactivate mark; move point to the end of the buffer.
20c5a87d
RS
530With arg N, put point N/10 of the way from the end.
531
215e89e5 532If the buffer is narrowed, this command uses the beginning and size
20c5a87d
RS
533of the accessible part of the buffer.
534
215e89e5 535Don't use this command in Lisp programs!
14dacacd 536\(goto-char (point-max)) is faster and avoids clobbering the mark."
215e89e5 537 (interactive "P")
e85c6b7c 538 (pc-select-maybe-deactivate-mark)
215e89e5
RS
539 (let ((size (- (point-max) (point-min))))
540 (goto-char (if arg
541 (- (point-max)
542 (if (> size 10000)
543 ;; Avoid overflow for large buffer sizes!
544 (* (prefix-numeric-value arg)
545 (/ size 10))
546 (/ (* size (prefix-numeric-value arg)) 10)))
547 (point-max))))
548 ;; If we went to a place in the middle of the buffer,
549 ;; adjust it to the beginning of a line.
550 (if arg (forward-line 1)
551 ;; If the end of the buffer is not already on the screen,
552 ;; then scroll specially to put it near, but not at, the bottom.
553 (if (let ((old-point (point)))
554 (save-excursion
555 (goto-char (window-start))
556 (vertical-motion (window-height))
557 (< (point) old-point)))
558 (progn
559 (overlay-recenter (point))
560 (recenter -3)))))
561
562
563;;;;;;;;;;;;;;;;;;;;
564;;;;;; backwards and mark
565;;;;;;;;;;;;;;;;;;;;
566
567(defun backward-char-mark (&optional arg)
568"Ensure mark is active; move point left ARG characters (right if ARG negative).
569On attempt to pass beginning or end of buffer, stop and signal error."
570 (interactive "p")
e85c6b7c 571 (pc-select-ensure-mark)
215e89e5
RS
572 (backward-char arg))
573
574(defun backward-word-mark (&optional arg)
575 "Ensure mark is active; move backward until encountering the end of a word.
576With argument, do this that many times."
577 (interactive "p")
e85c6b7c 578 (pc-select-ensure-mark)
215e89e5
RS
579 (backward-word arg))
580
b50c87ee
KH
581(defun backward-sexp-mark (&optional arg)
582 "Ensure mark is active; move backward across one balanced expression (sexp).
583With argument, do it that many times. Negative arg -N means
584move forward across N balanced expressions."
585 (interactive "p")
e85c6b7c 586 (pc-select-ensure-mark)
b50c87ee
KH
587 (backward-sexp arg))
588
215e89e5
RS
589(defun backward-paragraph-mark (&optional arg)
590 "Ensure mark is active; move backward to start of paragraph.
20c5a87d
RS
591With arg N, do it N times; negative arg -N means move forward N paragraphs.
592
215e89e5
RS
593A paragraph start is the beginning of a line which is a
594`first-line-of-paragraph' or which is ordinary text and follows a
595paragraph-separating line; except: if the first real line of a
596paragraph is preceded by a blank line, the paragraph starts at that
20c5a87d
RS
597blank line.
598
215e89e5
RS
599See `forward-paragraph' for more information."
600 (interactive "p")
e85c6b7c 601 (pc-select-ensure-mark)
215e89e5
RS
602 (backward-paragraph arg))
603
604(defun previous-line-mark (&optional arg)
605 "Ensure mark is active; move cursor vertically up ARG lines.
606If there is no character in the target line exactly over the current column,
607the cursor is positioned after the character in that line which spans this
20c5a87d
RS
608column, or at the end of the line if it is not long enough.
609
fd4e5923 610The command \\[set-goal-column] can be used to create
215e89e5 611a semipermanent goal column to which this command always moves.
20c5a87d
RS
612Then it does not try to move vertically.
613
215e89e5
RS
614If you are thinking of using this in a Lisp program, consider using
615`forward-line' with a negative argument instead. It is usually easier
616to use and more reliable (no dependence on goal column, etc.)."
617 (interactive "p")
e85c6b7c 618 (pc-select-ensure-mark)
3fe5c37a 619 (with-no-warnings (previous-line arg))
14dacacd 620 (setq this-command 'previous-line))
215e89e5
RS
621
622(defun beginning-of-line-mark (&optional arg)
623 "Ensure mark is active; move point to beginning of current line.
624With argument ARG not nil or 1, move forward ARG - 1 lines first.
625If scan reaches end of buffer, stop there without error."
626 (interactive "p")
e85c6b7c 627 (pc-select-ensure-mark)
215e89e5
RS
628 (beginning-of-line arg))
629
630
631(defun scroll-up-mark (&optional arg)
632"Ensure mark is active; scroll upward ARG lines; or near full screen if no ARG.
633A near full screen is `next-screen-context-lines' less than a full screen.
634Negative ARG means scroll downward.
635When calling from a program, supply a number as argument or nil."
636 (interactive "P")
e85c6b7c 637 (pc-select-ensure-mark)
2a811501
RS
638 (cond (pc-select-override-scroll-error
639 (condition-case nil (scroll-up arg)
640 (end-of-buffer (goto-char (point-max)))))
641 (t (scroll-up arg))))
215e89e5
RS
642
643(defun beginning-of-buffer-mark (&optional arg)
644 "Ensure mark is active; move point to the beginning of the buffer.
20c5a87d
RS
645With arg N, put point N/10 of the way from the beginning.
646
215e89e5 647If the buffer is narrowed, this command uses the beginning and size
20c5a87d
RS
648of the accessible part of the buffer.
649
215e89e5
RS
650Don't use this command in Lisp programs!
651\(goto-char (p\oint-min)) is faster and avoids clobbering the mark."
652 (interactive "P")
e85c6b7c 653 (pc-select-ensure-mark)
215e89e5
RS
654 (let ((size (- (point-max) (point-min))))
655 (goto-char (if arg
656 (+ (point-min)
657 (if (> size 10000)
658 ;; Avoid overflow for large buffer sizes!
659 (* (prefix-numeric-value arg)
660 (/ size 10))
661 (/ (+ 10 (* size (prefix-numeric-value arg))) 10)))
662 (point-min))))
663 (if arg (forward-line 1)))
664
665;;;;;;;;
666;;; no mark
667;;;;;;;;
668
669(defun backward-char-nomark (&optional arg)
670 "Deactivate mark; move point left ARG characters (right if ARG negative).
671On attempt to pass beginning or end of buffer, stop and signal error."
672 (interactive "p")
e85c6b7c 673 (pc-select-maybe-deactivate-mark)
215e89e5
RS
674 (backward-char arg))
675
676(defun backward-word-nomark (&optional arg)
677 "Deactivate mark; move backward until encountering the end of a word.
678With argument, do this that many times."
679 (interactive "p")
e85c6b7c 680 (pc-select-maybe-deactivate-mark)
215e89e5
RS
681 (backward-word arg))
682
b50c87ee
KH
683(defun backward-sexp-nomark (&optional arg)
684 "Deactivate mark; move backward across one balanced expression (sexp).
685With argument, do it that many times. Negative arg -N means
686move forward across N balanced expressions."
687 (interactive "p")
e85c6b7c 688 (pc-select-maybe-deactivate-mark)
b50c87ee
KH
689 (backward-sexp arg))
690
215e89e5
RS
691(defun backward-paragraph-nomark (&optional arg)
692 "Deactivate mark; move backward to start of paragraph.
20c5a87d
RS
693With arg N, do it N times; negative arg -N means move forward N paragraphs.
694
215e89e5
RS
695A paragraph start is the beginning of a line which is a
696`first-line-of-paragraph' or which is ordinary text and follows a
697paragraph-separating line; except: if the first real line of a
698paragraph is preceded by a blank line, the paragraph starts at that
20c5a87d
RS
699blank line.
700
215e89e5
RS
701See `forward-paragraph' for more information."
702 (interactive "p")
e85c6b7c 703 (pc-select-maybe-deactivate-mark)
215e89e5
RS
704 (backward-paragraph arg))
705
706(defun previous-line-nomark (&optional arg)
707 "Deactivate mark; move cursor vertically up ARG lines.
708If there is no character in the target line exactly over the current column,
709the cursor is positioned after the character in that line which spans this
20c5a87d
RS
710column, or at the end of the line if it is not long enough.
711
fd4e5923 712The command \\[set-goal-column] can be used to create
215e89e5
RS
713a semipermanent goal column to which this command always moves.
714Then it does not try to move vertically."
715 (interactive "p")
e85c6b7c 716 (pc-select-maybe-deactivate-mark)
3fe5c37a 717 (with-no-warnings (previous-line arg))
14dacacd 718 (setq this-command 'previous-line))
215e89e5
RS
719
720(defun beginning-of-line-nomark (&optional arg)
721 "Deactivate mark; move point to beginning of current line.
722With argument ARG not nil or 1, move forward ARG - 1 lines first.
723If scan reaches end of buffer, stop there without error."
724 (interactive "p")
e85c6b7c 725 (pc-select-maybe-deactivate-mark)
215e89e5
RS
726 (beginning-of-line arg))
727
728(defun scroll-up-nomark (&optional arg)
729 "Deactivate mark; scroll upward ARG lines; or near full screen if no ARG.
730A near full screen is `next-screen-context-lines' less than a full screen.
731Negative ARG means scroll downward.
732When calling from a program, supply a number as argument or nil."
733 (interactive "P")
e85c6b7c 734 (pc-select-maybe-deactivate-mark)
2a811501
RS
735 (cond (pc-select-override-scroll-error
736 (condition-case nil (scroll-up arg)
737 (end-of-buffer (goto-char (point-max)))))
738 (t (scroll-up arg))))
215e89e5
RS
739
740(defun beginning-of-buffer-nomark (&optional arg)
741 "Deactivate mark; move point to the beginning of the buffer.
20c5a87d
RS
742With arg N, put point N/10 of the way from the beginning.
743
215e89e5 744If the buffer is narrowed, this command uses the beginning and size
20c5a87d
RS
745of the accessible part of the buffer.
746
215e89e5 747Don't use this command in Lisp programs!
14dacacd 748\(goto-char (point-min)) is faster and avoids clobbering the mark."
215e89e5 749 (interactive "P")
e85c6b7c 750 (pc-select-maybe-deactivate-mark)
215e89e5
RS
751 (let ((size (- (point-max) (point-min))))
752 (goto-char (if arg
753 (+ (point-min)
754 (if (> size 10000)
755 ;; Avoid overflow for large buffer sizes!
756 (* (prefix-numeric-value arg)
757 (/ size 10))
758 (/ (+ 10 (* size (prefix-numeric-value arg))) 10)))
759 (point-min))))
760 (if arg (forward-line 1)))
761
cb96f094
RS
762
763(defun pc-select-define-keys (alist keymap)
764 "Make KEYMAP have the key bindings specified in ALIST."
765 (let ((lst alist))
766 (while lst
767 (define-key keymap (caar lst) (cdar lst))
768 (setq lst (cdr lst)))))
769
770(defun pc-select-restore-keys (alist keymap saved-map)
771 "Use ALIST to restore key bindings from SAVED-MAP into KEYMAP.
772Go through all the key bindings in ALIST, and, for each key
773binding, if KEYMAP and ALIST still agree on the key binding,
774restore the previous value of that key binding from SAVED-MAP."
775 (let ((lst alist))
776 (while lst
777 (when (equal (lookup-key keymap (caar lst)) (cdar lst))
778 (define-key keymap (caar lst) (lookup-key saved-map (caar lst))))
779 (setq lst (cdr lst)))))
780
781(defmacro pc-select-add-to-alist (alist var val)
782 "Ensure that ALIST contains the cons cell (VAR . VAL).
783If a cons cell whose car is VAR is already on the ALIST, update the
a1506d29 784cdr of that cell with VAL. Otherwise, make a new cons cell
cb96f094
RS
785\(VAR . VAL), and prepend it onto ALIST."
786 (let ((elt (make-symbol "elt")))
787 `(let ((,elt (assq ',var ,alist)))
788 (if ,elt
789 (setcdr ,elt ,val)
790 (setq ,alist (cons (cons ',var ,val) ,alist))))))
791
792(defmacro pc-select-save-and-set-var (var newval)
793 "Set VAR to NEWVAL; save the old value.
794The old value is saved on the `pc-select-saved-settings-alist'."
795 `(when (boundp ',var)
024ab5b5
RS
796 (pc-select-add-to-alist pc-select-saved-settings-alist ,var ,var)
797 (setq ,var ,newval)))
cb96f094
RS
798
799(defmacro pc-select-save-and-set-mode (mode &optional arg mode-var)
800 "Call the function MODE; save the old value of the variable MODE.
801MODE is presumed to be a function which turns on a minor mode. First,
802save the value of the variable MODE on `pc-select-saved-settings-alist'.
803Then, if ARG is specified, call MODE with ARG, otherwise call it with
804nil as an argument. If MODE-VAR is specified, save the value of the
805variable MODE-VAR (instead of the value of the variable MODE) on
806`pc-select-saved-settings-alist'."
024ab5b5
RS
807 (unless mode-var (setq mode-var mode))
808 `(when (fboundp ',mode)
809 (pc-select-add-to-alist pc-select-saved-settings-alist
810 ,mode-var ,mode-var)
811 (,mode ,arg)))
cb96f094
RS
812
813(defmacro pc-select-restore-var (var)
a1506d29 814 "Restore the previous value of the variable VAR.
cb96f094
RS
815Look up VAR's previous value in `pc-select-saved-settings-alist', and,
816if the value is found, set VAR to that value."
817 (let ((elt (make-symbol "elt")))
818 `(let ((,elt (assq ',var pc-select-saved-settings-alist)))
819 (unless (null ,elt)
820 (setq ,var (cdr ,elt))))))
821
822(defmacro pc-select-restore-mode (mode)
823 "Restore the previous state (either on or off) of the minor mode MODE.
824Look up the value of the variable MODE on `pc-select-saved-settings-alist'.
825If the value is non-nil, call the function MODE with an argument of
8261, otherwise call it with an argument of -1."
827 (let ((elt (make-symbol "elt")))
828 `(when (fboundp ',mode)
829 (let ((,elt (assq ',mode pc-select-saved-settings-alist)))
830 (unless (null ,elt)
024ab5b5 831 (,mode (if (cdr ,elt) 1 -1)))))))
cb96f094
RS
832
833
3eeb7b9f 834;;;###autoload
cb96f094 835(define-minor-mode pc-selection-mode
ca088b04 836 "Change mark behavior to emulate Motif, MAC or MS-Windows cut and paste style.
20c5a87d
RS
837
838This mode enables Delete Selection mode and Transient Mark mode.
839
840The arrow keys (and others) are bound to new functions
841which modify the status of the mark.
842
843The ordinary arrow keys disable the mark.
844The shift-arrow keys move, leaving the mark behind.
845
846C-LEFT and C-RIGHT move back or forward one word, disabling the mark.
847S-C-LEFT and S-C-RIGHT move back or forward one word, leaving the mark behind.
848
b50c87ee
KH
849M-LEFT and M-RIGHT move back or forward one word or sexp, disabling the mark.
850S-M-LEFT and S-M-RIGHT move back or forward one word or sexp, leaving the mark
fd4e5923
SM
851behind. To control whether these keys move word-wise or sexp-wise set the
852variable `pc-select-meta-moves-sexps' after loading pc-select.el but before
e873bbf9 853turning PC Selection mode on.
b50c87ee 854
20c5a87d
RS
855C-DOWN and C-UP move back or forward a paragraph, disabling the mark.
856S-C-DOWN and S-C-UP move back or forward a paragraph, leaving the mark behind.
857
858HOME moves to beginning of line, disabling the mark.
859S-HOME moves to beginning of line, leaving the mark behind.
860With Ctrl or Meta, these keys move to beginning of buffer instead.
861
862END moves to end of line, disabling the mark.
863S-END moves to end of line, leaving the mark behind.
864With Ctrl or Meta, these keys move to end of buffer instead.
865
866PRIOR or PAGE-UP scrolls and disables the mark.
867S-PRIOR or S-PAGE-UP scrolls and leaves the mark behind.
868
869S-DELETE kills the region (`kill-region').
870S-INSERT yanks text from the kill ring (`yank').
871C-INSERT copies the region into the kill ring (`copy-region-as-kill').
872
b50c87ee 873In addition, certain other PC bindings are imitated (to avoid this, set
fd4e5923 874the variable `pc-select-selection-keys-only' to t after loading pc-select.el
e873bbf9 875but before calling PC Selection mode):
fd4e5923 876
cb96f094
RS
877 F6 other-window
878 DELETE delete-char
879 C-DELETE kill-line
880 M-DELETE kill-word
881 C-M-DELETE kill-sexp
882 C-BACKSPACE backward-kill-word
883 M-BACKSPACE undo"
fd4e5923 884 ;; FIXME: bring pc-bindings-mode here ?
cb96f094
RS
885 nil nil nil
886
887 :group 'pc-select
888 :global t
889
890 (if pc-selection-mode
891 (if (null pc-select-key-bindings-alist)
892 (progn
93e92186 893 (setq pc-select-saved-global-map (copy-keymap (current-global-map)))
cb96f094
RS
894 (setq pc-select-key-bindings-alist
895 (append pc-select-default-key-bindings
896 (if pc-select-selection-keys-only
897 nil
898 pc-select-extra-key-bindings)
899 (if pc-select-meta-moves-sexps
900 (car pc-select-meta-moves-sexps-key-bindings)
901 (cadr pc-select-meta-moves-sexps-key-bindings))
902 (if (or pc-select-selection-keys-only
903 (eq window-system 'x)
904 (memq system-name '(ms-dos windows-nt)))
905 nil
906 pc-select-tty-key-bindings)))
907
93e92186
RS
908 (pc-select-define-keys pc-select-key-bindings-alist
909 (current-global-map))
cb96f094
RS
910
911 (unless (or pc-select-selection-keys-only
912 (eq window-system 'x)
913 (memq system-name '(ms-dos windows-nt)))
914 ;; it is not clear that we need the following line
93e92186 915 ;; I hope it doesn't do too much harm to leave it in, though...
cb96f094
RS
916 (setq pc-select-old-M-delete-binding
917 (lookup-key function-key-map [M-delete]))
918 (define-key function-key-map [M-delete] [?\M-d]))
919
920 (when (and (not pc-select-selection-keys-only)
921 (or (eq window-system 'x)
922 (memq system-name '(ms-dos windows-nt)))
923 (fboundp 'normal-erase-is-backspace-mode))
924 (pc-select-save-and-set-mode normal-erase-is-backspace-mode 1
925 normal-erase-is-backspace))
926 ;; the original author also had this above:
927 ;; (setq-default normal-erase-is-backspace t)
928 ;; However, the documentation for the variable says that
93e92186 929 ;; "setting it with setq has no effect", so I'm removing it.
a1506d29 930
cb96f094
RS
931 (pc-select-save-and-set-var highlight-nonselected-windows nil)
932 (pc-select-save-and-set-var transient-mark-mode t)
933 (pc-select-save-and-set-var mark-even-if-inactive t)
934 (pc-select-save-and-set-mode delete-selection-mode 1))
935 ;;else
936 ;; If the user turned on pc-selection-mode a second time
937 ;; do not clobber the values of the variables that were
938 ;; saved from before pc-selection mode was activated --
939 ;; just make sure the values are the way we like them.
93e92186
RS
940 (pc-select-define-keys pc-select-key-bindings-alist
941 (current-global-map))
cb96f094
RS
942 (unless (or pc-select-selection-keys-only
943 (eq window-system 'x)
944 (memq system-name '(ms-dos windows-nt)))
945 ;; it is not clear that we need the following line
93e92186 946 ;; I hope it doesn't do too much harm to leave it in, though...
cb96f094
RS
947 (define-key function-key-map [M-delete] [?\M-d]))
948 (when (and (not pc-select-selection-keys-only)
949 (or (eq window-system 'x)
950 (memq system-name '(ms-dos windows-nt)))
951 (fboundp 'normal-erase-is-backspace-mode))
fd4e5923 952 (normal-erase-is-backspace-mode 1))
cb96f094
RS
953 (setq highlight-nonselected-windows nil)
954 (setq transient-mark-mode t)
955 (setq mark-even-if-inactive t)
956 (delete-selection-mode 1))
957 ;;else
958 (when pc-select-key-bindings-alist
959 (when (and (not pc-select-selection-keys-only)
960 (or (eq window-system 'x)
961 (memq system-name '(ms-dos windows-nt))))
962 (pc-select-restore-mode normal-erase-is-backspace-mode))
963
cb96f094 964 (pc-select-restore-keys
93e92186
RS
965 pc-select-key-bindings-alist (current-global-map)
966 pc-select-saved-global-map)
cb96f094
RS
967
968 (pc-select-restore-var highlight-nonselected-windows)
969 (pc-select-restore-var transient-mark-mode)
970 (pc-select-restore-var mark-even-if-inactive)
971 (pc-select-restore-mode delete-selection-mode)
972 (and pc-select-old-M-delete-binding
973 (define-key function-key-map [M-delete]
974 pc-select-old-M-delete-binding))
975 (setq pc-select-key-bindings-alist nil
976 pc-select-saved-settings-alist nil))))
a1506d29 977
de299ed7 978;; arch-tag: 10697b70-ae07-4f3e-ad23-7814a3f418c2
215e89e5 979;;; pc-select.el ends here