* doc.c (Fsnarf_documentation): Use memmove instead of memcpy as
[bpt/emacs.git] / lisp / register.el
CommitLineData
55535639 1;;; register.el --- register commands for Emacs
c88ab9ce 2
c90f2757 3;; Copyright (C) 1985, 1993, 1994, 2001, 2002, 2003, 2004,
114f9c96 4;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
9750e079 5
4821e2af 6;; Maintainer: FSF
d7b4d18f 7;; Keywords: internal
bd78fa1d 8;; Package: emacs
4821e2af 9
efeae993
RS
10;; This file is part of GNU Emacs.
11
eb3fa2cf 12;; GNU Emacs is free software: you can redistribute it and/or modify
efeae993 13;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
14;; the Free Software Foundation, either version 3 of the License, or
15;; (at your option) any later version.
efeae993
RS
16
17;; GNU Emacs is distributed in the hope that it will be useful,
18;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20;; GNU General Public License for more details.
21
22;; You should have received a copy of the GNU General Public License
eb3fa2cf 23;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
efeae993 24
d9ecc911
ER
25;;; Commentary:
26
27;; This package of functions emulates and somewhat extends the venerable
28;; TECO's `register' feature, which permits you to save various useful
29;; pieces of buffer state to named variables. The entry points are
30;; documented in the Emacs user's manual.
31
4cf1d7e3
CY
32(declare-function semantic-insert-foreign-tag "semantic/tag" (foreign-tag))
33(declare-function semantic-tag-buffer "semantic/tag" (tag))
34(declare-function semantic-tag-start "semantic/tag" (tag))
35
8daffab7
JL
36;;; Global key bindings
37
09c01323
DN
38(define-key ctl-x-r-map "\C-@" 'point-to-register)
39(define-key ctl-x-r-map [?\C-\ ] 'point-to-register)
40(define-key ctl-x-r-map " " 'point-to-register)
41(define-key ctl-x-r-map "j" 'jump-to-register)
42(define-key ctl-x-r-map "s" 'copy-to-register)
43(define-key ctl-x-r-map "x" 'copy-to-register)
44(define-key ctl-x-r-map "i" 'insert-register)
45(define-key ctl-x-r-map "g" 'insert-register)
46(define-key ctl-x-r-map "r" 'copy-rectangle-to-register)
47(define-key ctl-x-r-map "n" 'number-to-register)
48(define-key ctl-x-r-map "+" 'increment-register)
49(define-key ctl-x-r-map "w" 'window-configuration-to-register)
50(define-key ctl-x-r-map "f" 'frame-configuration-to-register)
8daffab7 51
4821e2af 52;;; Code:
efeae993
RS
53
54(defvar register-alist nil
55 "Alist of elements (NAME . CONTENTS), one for each Emacs register.
070c2506 56NAME is a character (a number). CONTENTS is a string, number, marker or list.
22073dda 57A list of strings represents a rectangle.
5858bcc4
CY
58A list of the form (file . FILE-NAME) represents the file named FILE-NAME.
59A list of the form (file-query FILE-NAME POSITION) represents
60 position POSITION in the file named FILE-NAME, but query before
61 visiting it.
070c2506
KH
62A list of the form (WINDOW-CONFIGURATION POSITION)
63 represents a saved window configuration plus a saved value of point.
64A list of the form (FRAME-CONFIGURATION POSITION)
65 represents a saved frame configuration plus a saved value of point.")
efeae993 66
1a86cc81
JB
67(defun get-register (register)
68 "Return contents of Emacs register named REGISTER, or nil if none."
69 (cdr (assq register register-alist)))
efeae993 70
1b8cac5d
RS
71(defun set-register (register value)
72 "Set contents of Emacs register named REGISTER to VALUE. Returns VALUE.
1a86cc81 73See the documentation of the variable `register-alist' for possible VALUEs."
1b8cac5d 74 (let ((aelt (assq register register-alist)))
efeae993
RS
75 (if aelt
76 (setcdr aelt value)
ddbb3cc7 77 (push (cons register value) register-alist))
efeae993
RS
78 value))
79
1b8cac5d 80(defun point-to-register (register &optional arg)
b42e6156 81 "Store current location of point in register REGISTER.
0cc89026 82With prefix argument, store current frame configuration.
b42e6156 83Use \\[jump-to-register] to go to that location or restore that configuration.
efeae993 84Argument is a character, naming the register."
b42e6156 85 (interactive "cPoint to register: \nP")
ddbb3cc7
SM
86 ;; Turn the marker into a file-ref if the buffer is killed.
87 (add-hook 'kill-buffer-hook 'register-swap-out nil t)
1b8cac5d 88 (set-register register
070c2506
KH
89 (if arg (list (current-frame-configuration) (point-marker))
90 (point-marker))))
efeae993 91
1b8cac5d 92(defun window-configuration-to-register (register &optional arg)
83b5d757
RS
93 "Store the window configuration of the selected frame in register REGISTER.
94Use \\[jump-to-register] to restore the configuration.
95Argument is a character, naming the register."
5f517806 96 (interactive "cWindow configuration to register: \nP")
b4a91f43
KH
97 ;; current-window-configuration does not include the value
98 ;; of point in the current buffer, so record that separately.
070c2506 99 (set-register register (list (current-window-configuration) (point-marker))))
83b5d757 100
1b8cac5d 101(defun frame-configuration-to-register (register &optional arg)
83b5d757
RS
102 "Store the window configuration of all frames in register REGISTER.
103Use \\[jump-to-register] to restore the configuration.
104Argument is a character, naming the register."
5f517806 105 (interactive "cFrame configuration to register: \nP")
b4a91f43
KH
106 ;; current-frame-configuration does not include the value
107 ;; of point in the current buffer, so record that separately.
070c2506 108 (set-register register (list (current-frame-configuration) (point-marker))))
83b5d757 109
31e1d920 110(defalias 'register-to-point 'jump-to-register)
1b8cac5d 111(defun jump-to-register (register &optional delete)
efeae993 112 "Move point to location stored in a register.
22073dda 113If the register contains a file name, find that file.
1a86cc81 114\(To put a file name in a register, you must use `set-register'.)
83b5d757
RS
115If the register contains a window configuration (one frame) or a frame
116configuration (all frames), restore that frame or all frames accordingly.
e7683fff 117First argument is a character, naming the register.
1542ad37
RS
118Optional second arg non-nil (interactively, prefix argument) says to
119delete any existing frames that the frame configuration doesn't mention.
a21d94f9 120\(Otherwise, these frames are iconified.)"
e7683fff 121 (interactive "cJump to register: \nP")
1b8cac5d 122 (let ((val (get-register register)))
376a7584 123 (cond
b4a91f43
KH
124 ((and (consp val) (frame-configuration-p (car val)))
125 (set-frame-configuration (car val) (not delete))
126 (goto-char (cadr val)))
127 ((and (consp val) (window-configuration-p (car val)))
128 (set-window-configuration (car val))
129 (goto-char (cadr val)))
376a7584 130 ((markerp val)
8c4ca60c
KH
131 (or (marker-buffer val)
132 (error "That register's buffer no longer exists"))
376a7584
JB
133 (switch-to-buffer (marker-buffer val))
134 (goto-char val))
22073dda
RS
135 ((and (consp val) (eq (car val) 'file))
136 (find-file (cdr val)))
28cbd14d
RS
137 ((and (consp val) (eq (car val) 'file-query))
138 (or (find-buffer-visiting (nth 1 val))
139 (y-or-n-p (format "Visit file %s again? " (nth 1 val)))
140 (error "Register access aborted"))
141 (find-file (nth 1 val))
142 (goto-char (nth 2 val)))
4cf1d7e3
CY
143 ((and (fboundp 'semantic-foreign-tag-p)
144 semantic-mode
145 (semantic-foreign-tag-p val))
146 (switch-to-buffer (semantic-tag-buffer val))
147 (goto-char (semantic-tag-start val)))
376a7584
JB
148 (t
149 (error "Register doesn't contain a buffer position or configuration")))))
efeae993 150
28cbd14d 151(defun register-swap-out ()
ddbb3cc7 152 "Turn markers into file-query references when a buffer is killed."
28cbd14d 153 (and buffer-file-name
ddbb3cc7
SM
154 (dolist (elem register-alist)
155 (and (markerp (cdr elem))
156 (eq (marker-buffer (cdr elem)) (current-buffer))
157 (setcdr elem
158 (list 'file-query
159 buffer-file-name
160 (marker-position (cdr elem))))))))
28cbd14d 161
0e07a458 162(defun number-to-register (number register)
070c2506
KH
163 "Store a number in a register.
164Two args, NUMBER and REGISTER (a character, naming the register).
4d2caa07
KH
165If NUMBER is nil, a decimal number is read from the buffer starting
166at point, and point moves to the end of that number.
070c2506
KH
167Interactively, NUMBER is the prefix arg (none means nil)."
168 (interactive "P\ncNumber to register: ")
4f23d31c 169 (set-register register
0e07a458
KH
170 (if number
171 (prefix-numeric-value number)
4d2caa07
KH
172 (if (looking-at "\\s-*-?[0-9]+")
173 (progn
174 (goto-char (match-end 0))
fe22eed0 175 (string-to-number (match-string 0)))
070c2506
KH
176 0))))
177
0e07a458 178(defun increment-register (number register)
070c2506 179 "Add NUMBER to the contents of register REGISTER.
0e07a458 180Interactively, NUMBER is the prefix arg."
070c2506 181 (interactive "p\ncIncrement register: ")
0e07a458 182 (or (numberp (get-register register))
070c2506 183 (error "Register does not contain a number"))
0e07a458 184 (set-register register (+ number (get-register register))))
efeae993 185
1b8cac5d 186(defun view-register (register)
efeae993 187 "Display what is contained in register named REGISTER.
1b8cac5d 188The Lisp value REGISTER is a character."
efeae993 189 (interactive "cView register: ")
1b8cac5d 190 (let ((val (get-register register)))
efeae993 191 (if (null val)
1b8cac5d 192 (message "Register %s is empty" (single-key-description register))
efeae993 193 (with-output-to-temp-buffer "*Output*"
92840a31
RS
194 (describe-register-1 register t)))))
195
196(defun list-registers ()
197 "Display a list of nonempty registers saying briefly what they contain."
198 (interactive)
199 (let ((list (copy-sequence register-alist)))
200 (setq list (sort list (lambda (a b) (< (car a) (car b)))))
201 (with-output-to-temp-buffer "*Output*"
202 (dolist (elt list)
203 (when (get-register (car elt))
204 (describe-register-1 (car elt))
205 (terpri))))))
206
207(defun describe-register-1 (register &optional verbose)
208 (princ "Register ")
209 (princ (single-key-description register))
210 (princ " contains ")
6ed21409
RS
211 (let ((val (get-register register)))
212 (cond
213 ((numberp val)
214 (princ val))
215
216 ((markerp val)
217 (let ((buf (marker-buffer val)))
218 (if (null buf)
219 (princ "a marker in no buffer")
220 (princ "a buffer position:\n buffer ")
221 (princ (buffer-name buf))
222 (princ ", position ")
223 (princ (marker-position val)))))
224
225 ((and (consp val) (window-configuration-p (car val)))
226 (princ "a window configuration."))
227
228 ((and (consp val) (frame-configuration-p (car val)))
229 (princ "a frame configuration."))
230
231 ((and (consp val) (eq (car val) 'file))
232 (princ "the file ")
233 (prin1 (cdr val))
234 (princ "."))
235
236 ((and (consp val) (eq (car val) 'file-query))
237 (princ "a file-query reference:\n file ")
238 (prin1 (car (cdr val)))
239 (princ ",\n position ")
240 (princ (car (cdr (cdr val))))
241 (princ "."))
242
243 ((consp val)
244 (if verbose
245 (progn
246 (princ "the rectangle:\n")
247 (while val
248 (princ " ")
249 (princ (car val))
250 (terpri)
251 (setq val (cdr val))))
252 (princ "a rectangle starting with ")
253 (princ (car val))))
254
255 ((stringp val)
9c7cc04b
RS
256 (if (eq yank-excluded-properties t)
257 (set-text-properties 0 (length val) nil val)
258 (remove-list-of-text-properties 0 (length val)
259 yank-excluded-properties val))
6ed21409
RS
260 (if verbose
261 (progn
262 (princ "the text:\n")
263 (princ val))
f1180544 264 (cond
13d6f302
RS
265 ;; Extract first N characters starting with first non-whitespace.
266 ((string-match (format "[^ \t\n].\\{,%d\\}"
267 ;; Deduct 6 for the spaces inserted below.
268 (min 20 (max 0 (- (window-width) 6))))
269 val)
270 (princ "text starting with\n ")
271 (princ (match-string 0 val)))
272 ((string-match "^[ \t\n]+$" val)
273 (princ "whitespace"))
274 (t
275 (princ "the empty string")))))
6ed21409
RS
276 (t
277 (princ "Garbage:\n")
278 (if verbose (prin1 val))))))
efeae993 279
1b8cac5d
RS
280(defun insert-register (register &optional arg)
281 "Insert contents of register REGISTER. (REGISTER is a character.)
efeae993
RS
282Normally puts point before and mark after the inserted text.
283If optional second arg is non-nil, puts mark before and point after.
284Interactively, second arg is non-nil if prefix arg is supplied."
ecfc7eb3 285 (interactive "*cInsert register: \nP")
efeae993 286 (push-mark)
1b8cac5d 287 (let ((val (get-register register)))
cbd4993c
KH
288 (cond
289 ((consp val)
290 (insert-rectangle val))
291 ((stringp val)
e7c765c3 292 (insert-for-yank val))
070c2506 293 ((numberp val)
cbd4993c
KH
294 (princ val (current-buffer)))
295 ((and (markerp val) (marker-position val))
296 (princ (marker-position val) (current-buffer)))
4cf1d7e3
CY
297 ((and (fboundp 'semantic-foreign-tag-p)
298 semantic-mode
299 (semantic-foreign-tag-p val))
300 (semantic-insert-foreign-tag val))
cbd4993c
KH
301 (t
302 (error "Register does not contain text"))))
efeae993
RS
303 (if (not arg) (exchange-point-and-mark)))
304
1b8cac5d 305(defun copy-to-register (register start end &optional delete-flag)
1a86cc81
JB
306 "Copy region into register REGISTER.
307With prefix arg, delete as well.
1b8cac5d 308Called from program, takes four args: REGISTER, START, END and DELETE-FLAG.
efeae993
RS
309START and END are buffer positions indicating what to copy."
310 (interactive "cCopy to register: \nr\nP")
13191e32 311 (set-register register (filter-buffer-substring start end))
efeae993
RS
312 (if delete-flag (delete-region start end)))
313
1b8cac5d
RS
314(defun append-to-register (register start end &optional delete-flag)
315 "Append region to text in register REGISTER.
316With prefix arg, delete as well.
317Called from program, takes four args: REGISTER, START, END and DELETE-FLAG.
efeae993
RS
318START and END are buffer positions indicating what to append."
319 (interactive "cAppend to register: \nr\nP")
c81f72ce
TTN
320 (let ((reg (get-register register))
321 (text (filter-buffer-substring start end)))
322 (set-register
323 register (cond ((not reg) text)
324 ((stringp reg) (concat reg text))
325 (t (error "Register does not contain text")))))
efeae993
RS
326 (if delete-flag (delete-region start end)))
327
1b8cac5d
RS
328(defun prepend-to-register (register start end &optional delete-flag)
329 "Prepend region to text in register REGISTER.
330With prefix arg, delete as well.
331Called from program, takes four args: REGISTER, START, END and DELETE-FLAG.
efeae993
RS
332START and END are buffer positions indicating what to prepend."
333 (interactive "cPrepend to register: \nr\nP")
c81f72ce
TTN
334 (let ((reg (get-register register))
335 (text (filter-buffer-substring start end)))
336 (set-register
337 register (cond ((not reg) text)
338 ((stringp reg) (concat text reg))
339 (t (error "Register does not contain text")))))
efeae993
RS
340 (if delete-flag (delete-region start end)))
341
1b8cac5d
RS
342(defun copy-rectangle-to-register (register start end &optional delete-flag)
343 "Copy rectangular region into register REGISTER.
1a86cc81
JB
344With prefix arg, delete as well.
345To insert this register in the buffer, use \\[insert-register].
5ef5d6ce
RS
346
347Called from a program, takes four args: REGISTER, START, END and DELETE-FLAG.
efeae993
RS
348START and END are buffer positions giving two corners of rectangle."
349 (interactive "cCopy rectangle to register: \nr\nP")
1b8cac5d 350 (set-register register
efeae993
RS
351 (if delete-flag
352 (delete-extract-rectangle start end)
353 (extract-rectangle start end))))
c88ab9ce 354
0f214cdf 355(provide 'register)
cbee283d 356;; arch-tag: ce14dd68-8265-475f-9341-5d4ec5a53035
c88ab9ce 357;;; register.el ends here