-
-
Notifications
You must be signed in to change notification settings - Fork 102
/
better-registers.el
321 lines (277 loc) · 13.4 KB
/
better-registers.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
;;; better-registers.el --- facilities for more powerful registers
;; Version: 20220325.1356
;; X-Original-Version: 20140812.1546
;; -*- emacs-lisp -*-
;; Copyright (C) 2005 Sigurd Meldgaard
;; Author: Sigurd Meldgaard <yogurth @ gmail>
;; Keywords: register macro
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; This package provides a row of commands, and keyboard shortcuts to
;; make the powerful concept of registers even more powerful (most
;; important it lets you save macros there), and to save them to a
;; file. It is collected as a minor mode.
;; The code requires the cl.el (common-lisp-wannabe extensions) package
;; It is not tested under xemacs
;;; Installation:
;; dump this file somwhere on your load path. Then insert the
;; following into your .emacs (or other file loaded at startup) (of
;; course removing the ;;'s
;; ;;;Better registers!
;; (require 'better-registers)
;; (better-registers-install-save-registers-hook)
;; (load better-registers-save-file)
;; The last two line are unnecessary if you do not want to have your
;; registers contents saved across sessions.
;; Note that this package is pretty harsh to your std shortcuts you
;; probably should edit them (or at least see them through this file
;; to suit your needs. I e.g. personally never used backwards searches,
;; so C-r was doomed in my hands. I use only enter for indented
;; linebreaks, so C-j also seemed as a nice candidate for something
;; more useful - you might want to bind:
;; (global-set-key "\r" 'newline-and-indent)
;;; Use:
;; Macros: record a macro as usual and then press C-r m to save the
;; macro in a register. You now can play the macro with C-j
;; Markers: (as usual) Place point a place you want to remember C-r
;; space will put the marker in a register. When the buffer is closed
;; or the register is saved and reloaded it is turned into a
;; file-query that is a question about whether to reopen the file. C-j
;; will bring you back to the marker.
;; Window/Frame-configurations: C-rw and C-rf will save the current
;; configuration in the given register. To recall use C-j
;; Remark: these will not be saved for next session :(
;; Other stuff: for rectangles and numbers see through the list of
;; key-shortcuts and get good ideas.
;; In modes which overwrite C-j C-xj should still be bound to the same.
(eval-when-compile (require 'cl-lib))
(defvar better-registers-version "0.61"
"The version of the package better-registers.
Revision history:
from 0.60 to 0.61 register-read-with-preview works for Emacs 25 and newer
from 0.59 to 0.60 User can choose to use C-r or not optionally
from 0.58 to 0.59 Add support for both Emacs 24.4 and older
from 0.57 to 0.58 Improved interactive argument handling of better-registers-save-registers.
from 0.57 to 0.57 Can now correctly save fontified strings, added convenient macro key (f1)
from 0.55 to 0.56 No longer blocks enter in the minibuffer
from 0.5 to 0.55 changed it to a minor mode
instead of having global keys - much nicer! Thanks to Lennart Borgman
for the advice.")
(defgroup better-registers nil
"Some convenience and power for using registers and macros"
:group 'convenience)
(defcustom better-registers-save-file "~/.emacsregisters.el"
"The place where the contents of the registers should be saved."
:group 'better-registers
:type '(file))
(defvar better-registers-map (make-keymap)
"Keymap for better-registers minor-mode")
(defvar better-registers-r-map (make-sparse-keymap)
"Keymap for combinations with C-r first")
(defcustom better-registers-use-C-r t
"Use C-r if enable"
:group 'better-registers
)
(define-key better-registers-map [f1] 'better-registers-play-macro-if-not-playing)
(define-key better-registers-map [S-f1] 'better-registers-toggle-macro-recording)
(define-key better-registers-map "\C-j" 'better-registers-jump-to-register)
(define-key better-registers-map "\C-xj" 'better-registers-jump-to-register)
(if better-registers-use-C-r
(progn
(define-key better-registers-map "\C-xr" 'isearch-backward) ;free C-r
(define-key better-registers-map "\C-r" ;Shadow C-r global
better-registers-r-map))
(define-key better-registers-map "\C-xr" ;Shadow C-r global
better-registers-r-map))
(define-key better-registers-r-map "n" 'number-to-register)
(define-key better-registers-r-map "+" 'increment-register)
(define-key better-registers-r-map "-" 'better-registers-decrement-register)
(define-key better-registers-r-map "w" 'window-configuration-to-register)
(define-key better-registers-r-map "f" (if (and (>= emacs-major-version 24)
(>= emacs-minor-version 4))
'frameset-to-register
'frame-configuration-to-register
))
(define-key better-registers-r-map "r" 'copy-rectangle-to-register)
(define-key better-registers-r-map "i" 'better-registers-jump-to-register)
(define-key better-registers-r-map "s" 'copy-to-register)
(define-key better-registers-r-map " " 'point-to-register)
(define-key better-registers-r-map "k" 'kill-rectangle)
(define-key better-registers-r-map "m"
'better-registers-put-keyboard-macro-in-register)
(define-key better-registers-r-map "p"
'better-registers-put-buffer-filename-in-register)
(define-key better-registers-r-map "b"
'better-registers-put-buffer-in-register)
;(define-key better-registers-r-map "k" 'kill-rectangle)
;(define-key better-registers-r-map "d" 'delete-rectangle)
;(define-key better-registers-r-map "y" 'yank-rectangle)
;(define-key better-registers-r-map "o" 'open-rectangle)
;(define-key better-registers-r-map "t" 'string-rectangle)
(define-minor-mode better-registers
"A minor mode for easier and more powerful register commands"
t
nil
better-registers-map
())
(defun better-registers-install-save-registers-hook ()
(add-hook 'kill-emacs-hook
'(lambda ()
(better-registers-save-registers))))
(defun better-registers-save-registers (&optional filename queryp)
"Print the contents of all registers to a file as loadable data.
Cannot save window/frame configuration.
But it works with keyboard macros, text, buffernames,
filenames and rectangles.
If filename is non-nil and queryp is nil, use that, otherwise
use the default filename. If queryp is non-nil (a prefix
argument is given), query interactively for the file-name."
(interactive "i\nP")
(when queryp
(setq filename (read-file-name nil better-registers-save-file)))
(let ((fn (or filename better-registers-save-file))
(print-level nil) ;Let us write anything
(print-length nil)
(b (generate-new-buffer "*registers*")))
(set-buffer b)
(dolist (i register-alist)
(let ((char (car i))
(contents (cdr i)))
(cond
((stringp contents)
(insert (format "%S\n"
`(set-register
,char
,contents))))
((numberp contents) ;numbers are printed non-quotes
(insert (format "%S\n" `(set-register ,char ,contents))))
((markerp contents)
(insert (format
"%S\n"
`(set-register
,char
'(file-query
,(buffer-file-name (marker-buffer contents))
,(marker-position contents))))))
((bufferp (cdr contents))
(insert (format "%s\n"
`(set-register ,char
',(buffer-name (cdr contents))))))
(t (when (and contents ; different from nil
(not (or (window-configuration-p (car contents))
(frame-configuration-p (car contents)))))
(insert (format "%S\n"
`(set-register ,char (quote ,contents)))))))))
(write-file fn)
(kill-buffer b)))
(defun better-registers-put-buffer-in-register (register &optional delete)
"Put current buffername in register - this would also work for
just buffers, as switch-to-buffer can use both, but it
facilitates for easier saving/restoring of registers."
(interactive "cPut current buffername in register: \nP.")
(set-register register (cons 'buffer (buffer-name (current-buffer)))))
(defun better-registers-put-buffer-filename-in-register
(register &optional delete)
"This is better than put-buffer-in-register for file-buffers, because a closed
file can be opened again, but does not work for no-file-buffers."
(interactive "cPut the filename of current buffer in register: \nP")
(set-register register (cons 'file (buffer-file-name (current-buffer)))))
(defun better-registers-put-keyboard-macro-in-register
(register &optional delete)
"Save the contents of the last keyboard macro to the given register.
can be played again by jump-to-register."
(interactive "cPut last keyboard-macro in register: \nP")
(set-register register (cons 'macro last-kbd-macro)))
(if (or
(and (>= emacs-major-version 24)
(>= emacs-minor-version 4))
(>= emacs-major-version 25))
(defun better-registers-jump-to-register (register &optional delete)
(interactive (list (register-read-with-preview "Jump to register: ")
current-prefix-arg))
(better-registers-jump-to-register-action register delete))
(defun better-registers-jump-to-register (register &optional delete)
(interactive "cJump to register: \nP")
(better-registers-jump-to-register-action register delete)))
(defun better-registers-jump-to-register-action (register &optional delete)
"Do what is the most sane thing to do for the thing stored in
register Either insert text (evt. a rectangle), move point to
location stored in a register, a buffer stored in a register,
a file stored in register, or run a macro saved in a register.
If the register contains a file name, find that file. Or
restore a saved window/frame configuration."
(let ((val (get-register register)))
(cond
((registerv-p val)
(cl-assert (registerv-jump-func val) nil
"Don't know how to jump to register %s"
(single-key-description register))
(funcall (registerv-jump-func val) (registerv-data val)))
((and (consp val) (frame-configuration-p (car val)))
(set-frame-configuration (car val) (not delete))
(goto-char (cadr val)))
((and (consp val) (window-configuration-p (car val)))
(set-window-configuration (car val))
(goto-char (cadr val)))
((markerp val)
(or (marker-buffer val)
(error "That register's buffer no longer exists"))
(switch-to-buffer (marker-buffer val))
(goto-char val))
((and (consp val) (eq (car val) 'file))
(find-file (cdr val)))
((and (consp val) (eq (car val) 'buffer))
(switch-to-buffer (cdr val)))
((and (consp val) (eq (car val) 'macro))
;appearently the only way to run a macro is by putting them in
;last-kbd-macro (named keyboard macros can only (as far as I
;know) be called interactively, but this works quite
;unproblematically).
(let ((old-macro last-kbd-macro))
(setq last-kbd-macro (cdr val))
(call-last-kbd-macro)
(setq last-kbd-macro old-macro)))
((and (consp val) (eq (car val) 'file-query))
(or (find-buffer-visiting (nth 1 val))
(y-or-n-p (format "Visit file %s again? " (nth 1 val)))
(error "Register access aborted"))
(find-file (nth 1 val))
(goto-char (nth 2 val)))
((or (stringp val)
(consp val)
(numberp val)
(and (markerp val)
(marker-position val)))
(insert-register register))
(t
(error "Register doesn't contain a buffer, buffer position, macro, file, text, rectangle or configuration")))))
;;Just call increment-register with the negative arg.
(defun better-registers-decrement-register (number register)
"Subtract NUMBER from the contents of register REGISTER.
Interactively, NUMBER is the prefix arg."
(interactive "p\ncDecrement register: ")
(increment-register (- number) register))
(defun better-registers-toggle-macro-recording ()
(interactive)
(message "hej")
(if defining-kbd-macro
(end-kbd-macro)
(start-kbd-macro nil)))
(defun better-registers-play-macro-if-not-playing ()
(interactive)
(if defining-kbd-macro
(end-kbd-macro)
(call-last-kbd-macro)))
(provide 'better-registers)
;;; better-registers.el ends here.