Don't use png_jmpbuf, it doesn't work with dynamic loading.
[bpt/emacs.git] / lisp / emulation / viper-macs.el
CommitLineData
be010748
RS
1;;; viper-macs.el --- functions implementing keyboard macros for Viper
2
5fd6d89f 3;; Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001, 2002, 2003, 2004,
5df4f04c 4;; 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
d6fd318f 5
50a07e18 6;; Author: Michael Kifer <kifer@cs.stonybrook.edu>
02f34c70 7
6c2e12f4
KH
8;; This file is part of GNU Emacs.
9
ed0f493f 10;; GNU Emacs is free software: you can redistribute it and/or modify
6c2e12f4 11;; it under the terms of the GNU General Public License as published by
ed0f493f
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
6c2e12f4
KH
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
ed0f493f 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
6c2e12f4 22
60370d40
PJ
23;;; Commentary:
24
25;;; Code:
03fc1246 26
9b70a748
MK
27(provide 'viper-macs)
28
29;; compiler pacifier
8626cfa2
MK
30(defvar viper-ex-work-buf)
31(defvar viper-custom-file-name)
32(defvar viper-current-state)
33(defvar viper-fast-keyseq-timeout)
9b70a748 34
726e270f
MK
35;; loading happens only in non-interactive compilation
36;; in order to spare non-viperized emacs from being viperized
37(if noninteractive
38 (eval-when-compile
2ee00512
MK
39 (require 'viper-cmd)
40 ))
9b70a748
MK
41;; end pacifier
42
6c2e12f4 43(require 'viper-util)
03fc1246
MK
44(require 'viper-keym)
45
6c2e12f4
KH
46
47;;; Variables
48
49;; Register holding last macro.
8626cfa2 50(defvar viper-last-macro-reg nil)
6c2e12f4 51
a1506d29 52;; format of the elements of kbd alists:
6c2e12f4
KH
53;; (name ((buf . macr)...(buf . macr)) ((maj-mode . macr)...) (t . macr))
54;; kbd macro alist for Vi state
8626cfa2 55(defvar viper-vi-kbd-macro-alist nil)
6c2e12f4 56;; same for insert/replace state
8626cfa2 57(defvar viper-insert-kbd-macro-alist nil)
6c2e12f4 58;; same for emacs state
8626cfa2 59(defvar viper-emacs-kbd-macro-alist nil)
6c2e12f4
KH
60
61;; Internal var that passes info between start-kbd-macro and end-kbd-macro
62;; in :map and :map!
8626cfa2 63(defvar viper-kbd-macro-parameters nil)
6c2e12f4 64
8626cfa2 65(defvar viper-this-kbd-macro nil
6c2e12f4 66 "Vector of keys representing the name of currently running Viper kbd macro.")
8626cfa2 67(defvar viper-last-kbd-macro nil
6c2e12f4
KH
68 "Vector of keys representing the name of last Viper keyboard macro.")
69
8626cfa2 70(defcustom viper-repeat-from-history-key 'f12
1e70790f 71 "Prefix key for accessing previously typed Vi commands.
6c2e12f4 72
3af0304a 73The previous command is accessible, as usual, via `.'. The command before this
1e70790f
MK
74can be invoked as `<this key> 1', and the command before that, and the command
75before that one is accessible as `<this key> 2'.
3af0304a 76The notation for these keys is borrowed from XEmacs. Basically,
6c2e12f4 77a key is a symbol, e.g., `a', `\\1', `f2', etc., or a list, e.g.,
1e70790f 78`(meta control f1)'."
eabbaad8 79 :type 'sexp
1e70790f 80 :group 'viper)
6c2e12f4
KH
81
82
83\f
84;;; Code
85
546fe085 86;; Ex map command
6c2e12f4 87(defun ex-map ()
6c2e12f4
KH
88 (let ((mod-char "")
89 macro-name macro-body map-args ins)
90 (save-window-excursion
8626cfa2 91 (set-buffer viper-ex-work-buf)
6c2e12f4
KH
92 (if (looking-at "!")
93 (progn
94 (setq ins t
95 mod-char "!")
96 (forward-char 1))))
97 (setq map-args (ex-map-read-args mod-char)
98 macro-name (car map-args)
99 macro-body (cdr map-args))
8626cfa2 100 (setq viper-kbd-macro-parameters (list ins mod-char macro-name macro-body))
6c2e12f4 101 (if macro-body
8626cfa2 102 (viper-end-mapping-kbd-macro 'ignore)
6c2e12f4 103 (ex-fixup-history (format "map%s %S" mod-char
8626cfa2 104 (viper-display-macro macro-name)))
6c2e12f4 105 ;; if defining macro for insert, switch there for authentic WYSIWYG
8626cfa2 106 (if ins (viper-change-state-to-insert))
6c2e12f4 107 (start-kbd-macro nil)
8626cfa2
MK
108 (define-key viper-vi-intercept-map "\C-x)" 'viper-end-mapping-kbd-macro)
109 (define-key viper-insert-intercept-map "\C-x)" 'viper-end-mapping-kbd-macro)
110 (define-key viper-emacs-intercept-map "\C-x)" 'viper-end-mapping-kbd-macro)
15c77b9e 111 (message "Mapping %S in %s state. Type macro definition followed by `C-x )'"
8626cfa2 112 (viper-display-macro macro-name)
6c2e12f4
KH
113 (if ins "Insert" "Vi")))
114 ))
a1506d29 115
6c2e12f4 116
546fe085 117;; Ex unmap
6c2e12f4 118(defun ex-unmap ()
6c2e12f4
KH
119 (let ((mod-char "")
120 temp macro-name ins)
121 (save-window-excursion
8626cfa2 122 (set-buffer viper-ex-work-buf)
6c2e12f4
KH
123 (if (looking-at "!")
124 (progn
125 (setq ins t
126 mod-char "!")
127 (forward-char 1))))
128
129 (setq macro-name (ex-unmap-read-args mod-char))
8626cfa2 130 (setq temp (viper-fixup-macro (vconcat macro-name))) ;; copy and fixup
6c2e12f4 131 (ex-fixup-history (format "unmap%s %S" mod-char
8626cfa2
MK
132 (viper-display-macro temp)))
133 (viper-unrecord-kbd-macro macro-name (if ins 'insert-state 'vi-state))
6c2e12f4 134 ))
a1506d29 135
6c2e12f4
KH
136
137;; read arguments for ex-map
138(defun ex-map-read-args (variant)
139 (let ((cursor-in-echo-area t)
140 (key-seq [])
141 temp key event message
142 macro-name macro-body args)
a1506d29 143
6c2e12f4
KH
144 (condition-case nil
145 (setq args (concat (ex-get-inline-cmd-args ".*map[!]*[ \t]?" "\n\C-m")
146 " nil nil ")
147 temp (read-from-string args)
148 macro-name (car temp)
149 macro-body (car (read-from-string args (cdr temp))))
150 (error
151 (signal
a1506d29 152 'error
6c2e12f4 153 '("map: Macro name and body must be a quoted string or a vector"))))
a1506d29 154
6c2e12f4
KH
155 ;; We expect macro-name to be a vector, a string, or a quoted string.
156 ;; In the second case, it will emerge as a symbol when read from
3af0304a 157 ;; the above read-from-string. So we need to convert it into a string
6c2e12f4
KH
158 (if macro-name
159 (cond ((vectorp macro-name) nil)
a1506d29 160 ((stringp macro-name)
6c2e12f4
KH
161 (setq macro-name (vconcat macro-name)))
162 (t (setq macro-name (vconcat (prin1-to-string macro-name)))))
15c77b9e 163 (message ":map%s <Macro Name>" variant)(sit-for 2)
6c2e12f4
KH
164 (while
165 (not (member key
166 '(?\C-m ?\n (control m) (control j) return linefeed)))
167 (setq key-seq (vconcat key-seq (if key (vector key) [])))
168 ;; the only keys available for editing are these-- no help while there
169 (if (member
170 key
171 '(?\b ?\d '^? '^H (control h) (control \?) backspace delete))
8ea74b0e 172 (setq key-seq (viper-subseq key-seq 0 (- (length key-seq) 2))))
6c2e12f4 173 (setq message
edff961b
MK
174 (format
175 ":map%s %s"
176 variant (if (> (length key-seq) 0)
8626cfa2 177 (prin1-to-string (viper-display-macro key-seq))
edff961b 178 "")))
7b8a295e 179 (message "%s" message)
8626cfa2
MK
180 (setq event (viper-read-key))
181 ;;(setq event (viper-read-event))
6c2e12f4 182 (setq key
8626cfa2 183 (if (viper-mouse-event-p event)
6c2e12f4
KH
184 (progn
185 (message "%s (No mouse---only keyboard keys, please)"
186 message)
187 (sit-for 2)
188 nil)
8626cfa2 189 (viper-event-key event)))
6c2e12f4
KH
190 )
191 (setq macro-name key-seq))
a1506d29 192
6c2e12f4
KH
193 (if (= (length macro-name) 0)
194 (error "Can't map an empty macro name"))
8626cfa2
MK
195 (setq macro-name (viper-fixup-macro macro-name))
196 (if (viper-char-array-p macro-name)
197 (setq macro-name (viper-char-array-to-macro macro-name)))
a1506d29 198
6c2e12f4 199 (if macro-body
8626cfa2
MK
200 (cond ((viper-char-array-p macro-body)
201 (setq macro-body (viper-char-array-to-macro macro-body)))
6c2e12f4
KH
202 ((vectorp macro-body) nil)
203 (t (error "map: Invalid syntax in macro definition"))))
546fe085
KH
204 (setq cursor-in-echo-area nil)(sit-for 0) ; this overcomes xemacs tty bug
205 (cons macro-name macro-body)))
a1506d29 206
6c2e12f4
KH
207
208
209;; read arguments for ex-unmap
210(defun ex-unmap-read-args (variant)
211 (let ((cursor-in-echo-area t)
212 (macro-alist (if (string= variant "!")
8626cfa2
MK
213 viper-insert-kbd-macro-alist
214 viper-vi-kbd-macro-alist))
6c2e12f4
KH
215 ;; these are disabled just in case, to avoid surprises when doing
216 ;; completing-read
8626cfa2
MK
217 viper-vi-kbd-minor-mode viper-insert-kbd-minor-mode
218 viper-emacs-kbd-minor-mode
219 viper-vi-intercept-minor-mode viper-insert-intercept-minor-mode
220 viper-emacs-intercept-minor-mode
6c2e12f4
KH
221 event message
222 key key-seq macro-name)
223 (setq macro-name (ex-get-inline-cmd-args ".*unma?p?[!]*[ \t]*"))
a1506d29 224
6c2e12f4
KH
225 (if (> (length macro-name) 0)
226 ()
227 (message ":unmap%s <Name>" variant) (sit-for 2)
228 (while
229 (not
230 (member key '(?\C-m ?\n (control m) (control j) return linefeed)))
231 (setq key-seq (vconcat key-seq (if key (vector key) [])))
232 ;; the only keys available for editing are these-- no help while there
233 (cond ((member
234 key
235 '(?\b ?\d '^? '^H (control h) (control \?) backspace delete))
8ea74b0e 236 (setq key-seq (viper-subseq key-seq 0 (- (length key-seq) 2))))
6c2e12f4 237 ((member key '(tab (control i) ?\t))
8ea74b0e 238 (setq key-seq (viper-subseq key-seq 0 (1- (length key-seq))))
a1506d29 239 (setq message
edff961b
MK
240 (format
241 ":unmap%s %s"
242 variant (if (> (length key-seq) 0)
243 (prin1-to-string
8626cfa2 244 (viper-display-macro key-seq))
edff961b 245 "")))
6c2e12f4 246 (setq key-seq
8626cfa2 247 (viper-do-sequence-completion key-seq macro-alist message))
6c2e12f4 248 ))
a1506d29 249 (setq message
edff961b
MK
250 (format
251 ":unmap%s %s"
252 variant (if (> (length key-seq) 0)
253 (prin1-to-string
8626cfa2 254 (viper-display-macro key-seq))
edff961b 255 "")))
7b8a295e 256 (message "%s" message)
8626cfa2
MK
257 (setq event (viper-read-key))
258 ;;(setq event (viper-read-event))
6c2e12f4 259 (setq key
8626cfa2 260 (if (viper-mouse-event-p event)
6c2e12f4
KH
261 (progn
262 (message "%s (No mouse---only keyboard keys, please)"
263 message)
264 (sit-for 2)
265 nil)
8626cfa2 266 (viper-event-key event)))
6c2e12f4
KH
267 )
268 (setq macro-name key-seq))
269
270 (if (= (length macro-name) 0)
271 (error "Can't unmap an empty macro name"))
a1506d29 272
6c2e12f4
KH
273 ;; convert macro names into vector, if starts with a `['
274 (if (memq (elt macro-name 0) '(?\[ ?\"))
275 (car (read-from-string macro-name))
276 (vconcat macro-name))
277 ))
a1506d29
JB
278
279
edff961b
MK
280;; Terminate a Vi kbd macro.
281;; optional argument IGNORE, if t, indicates that we are dealing with an
282;; existing macro that needs to be registered, but there is no need to
283;; terminate a kbd macro.
8626cfa2 284(defun viper-end-mapping-kbd-macro (&optional ignore)
6c2e12f4 285 (interactive)
8626cfa2
MK
286 (define-key viper-vi-intercept-map "\C-x)" nil)
287 (define-key viper-insert-intercept-map "\C-x)" nil)
288 (define-key viper-emacs-intercept-map "\C-x)" nil)
6c2e12f4 289 (if (and (not ignore)
8626cfa2 290 (or (not viper-kbd-macro-parameters)
6c2e12f4
KH
291 (not defining-kbd-macro)))
292 (error "Not mapping a kbd-macro"))
8626cfa2
MK
293 (let ((mod-char (nth 1 viper-kbd-macro-parameters))
294 (ins (nth 0 viper-kbd-macro-parameters))
295 (macro-name (nth 2 viper-kbd-macro-parameters))
296 (macro-body (nth 3 viper-kbd-macro-parameters)))
297 (setq viper-kbd-macro-parameters nil)
6c2e12f4
KH
298 (or ignore
299 (progn
300 (end-kbd-macro nil)
8626cfa2 301 (setq macro-body (viper-events-to-macro last-kbd-macro))
6c2e12f4
KH
302 ;; always go back to Vi, since this is where we started
303 ;; defining macro
8626cfa2 304 (viper-change-state-to-vi)))
a1506d29 305
8626cfa2 306 (viper-record-kbd-macro macro-name
6c2e12f4 307 (if ins 'insert-state 'vi-state)
8626cfa2 308 (viper-display-macro macro-body))
a1506d29 309
6c2e12f4 310 (ex-fixup-history (format "map%s %S %S" mod-char
8626cfa2
MK
311 (viper-display-macro macro-name)
312 (viper-display-macro macro-body)))
6c2e12f4
KH
313 ))
314
315
316
6c2e12f4
KH
317\f
318;;; Recording, unrecording, executing
319
3af0304a 320;; Accepts as macro names: strings and vectors.
6c2e12f4 321;; strings must be strings of characters; vectors must be vectors of keys
3af0304a 322;; in canonic form. The canonic form is essentially the form used in XEmacs
3f9526a3
MK
323;; More general definitions are inherited by more specific scopes:
324;; global->major mode->buffer. More specific definitions override more general
8626cfa2 325(defun viper-record-kbd-macro (macro-name state macro-body &optional scope)
3af0304a
MK
326 "Record a Vi macro. Can be used in `.viper' file to define permanent macros.
327MACRO-NAME is a string of characters or a vector of keys. STATE is
328either `vi-state' or `insert-state'. It specifies the Viper state in which to
329define the macro. MACRO-BODY is a string that represents the keyboard macro.
6c2e12f4
KH
330Optional SCOPE says whether the macro should be global \(t\), mode-specific
331\(a major-mode symbol\), or buffer-specific \(buffer name, a string\).
332If SCOPE is nil, the user is asked to specify the scope."
a1506d29 333 (let* (state-name keymap
6c2e12f4
KH
334 (macro-alist-var
335 (cond ((eq state 'vi-state)
336 (setq state-name "Vi state"
8626cfa2
MK
337 keymap viper-vi-kbd-map)
338 'viper-vi-kbd-macro-alist)
6c2e12f4
KH
339 ((memq state '(insert-state replace-state))
340 (setq state-name "Insert state"
8626cfa2
MK
341 keymap viper-insert-kbd-map)
342 'viper-insert-kbd-macro-alist)
6c2e12f4
KH
343 (t
344 (setq state-name "Emacs state"
8626cfa2
MK
345 keymap viper-emacs-kbd-map)
346 'viper-emacs-kbd-macro-alist)
6c2e12f4
KH
347 ))
348 new-elt old-elt old-sub-elt msg
349 temp lis lis2)
a1506d29 350
6c2e12f4
KH
351 (if (= (length macro-name) 0)
352 (error "Can't map an empty macro name"))
a1506d29 353
3af0304a
MK
354 ;; Macro-name is usually a vector. However, command history or macros
355 ;; recorded in ~/.viper may be recorded as strings. So, convert to
a1506d29 356 ;; vectors.
8626cfa2
MK
357 (setq macro-name (viper-fixup-macro macro-name))
358 (if (viper-char-array-p macro-name)
359 (setq macro-name (viper-char-array-to-macro macro-name)))
360 (setq macro-body (viper-fixup-macro macro-body))
361 (if (viper-char-array-p macro-body)
362 (setq macro-body (viper-char-array-to-macro macro-body)))
a1506d29 363
6c2e12f4
KH
364 ;; don't ask if scope is given and is of the right type
365 (or (eq scope t)
366 (stringp scope)
367 (and scope (symbolp scope))
368 (progn
369 (setq scope
370 (cond
371 ((y-or-n-p
372 (format
373 "Map this macro for buffer `%s' only? "
374 (buffer-name)))
375 (setq msg
376 (format
377 "%S is mapped to %s for %s in `%s'"
8626cfa2
MK
378 (viper-display-macro macro-name)
379 (viper-abbreviate-string
6c2e12f4
KH
380 (format
381 "%S"
8626cfa2 382 (setq temp (viper-display-macro macro-body)))
6c2e12f4
KH
383 14 "" ""
384 (if (stringp temp) " ....\"" " ....]"))
385 state-name (buffer-name)))
386 (buffer-name))
387 ((y-or-n-p
388 (format
389 "Map this macro for the major mode `%S' only? "
390 major-mode))
391 (setq msg
392 (format
393 "%S is mapped to %s for %s in `%S'"
8626cfa2
MK
394 (viper-display-macro macro-name)
395 (viper-abbreviate-string
6c2e12f4
KH
396 (format
397 "%S"
8626cfa2 398 (setq temp (viper-display-macro macro-body)))
6c2e12f4
KH
399 14 "" ""
400 (if (stringp macro-body) " ....\"" " ....]"))
401 state-name major-mode))
402 major-mode)
403 (t
404 (setq msg
405 (format
406 "%S is globally mapped to %s in %s"
8626cfa2
MK
407 (viper-display-macro macro-name)
408 (viper-abbreviate-string
6c2e12f4
KH
409 (format
410 "%S"
8626cfa2 411 (setq temp (viper-display-macro macro-body)))
6c2e12f4
KH
412 14 "" ""
413 (if (stringp macro-body) " ....\"" " ....]"))
414 state-name))
415 t)))
c992e211
MK
416 (if (y-or-n-p
417 (format "Save this macro in %s? "
8626cfa2 418 (viper-abbreviate-file-name viper-custom-file-name)))
a1506d29 419 (viper-save-string-in-file
8626cfa2
MK
420 (format "\n(viper-record-kbd-macro %S '%S %s '%S)"
421 (viper-display-macro macro-name)
f90edb57
MK
422 state
423 ;; if we don't let vector macro-body through %S,
424 ;; the symbols `\.' `\[' etc will be converted into
425 ;; characters, causing invalid read error on recorded
8626cfa2 426 ;; macros in .viper.
f90edb57
MK
427 ;; I am not sure is macro-body can still be a string at
428 ;; this point, but I am preserving this option anyway.
429 (if (vectorp macro-body)
430 (format "%S" macro-body)
431 macro-body)
a1506d29 432 scope)
8626cfa2 433 viper-custom-file-name))
a1506d29 434
7b8a295e 435 (message "%s" msg)
6c2e12f4 436 ))
a1506d29 437
6c2e12f4
KH
438 (setq new-elt
439 (cons macro-name
440 (cond ((eq scope t) (list nil nil (cons t nil)))
441 ((symbolp scope)
442 (list nil (list (cons scope nil)) (cons t nil)))
443 ((stringp scope)
444 (list (list (cons scope nil)) nil (cons t nil))))))
445 (setq old-elt (assoc macro-name (eval macro-alist-var)))
446
3f9526a3
MK
447 (if (null old-elt)
448 (progn
449 ;; insert new-elt in macro-alist-var and keep the list sorted
450 (define-key
451 keymap
452 (vector (viper-key-to-emacs-key (aref macro-name 0)))
453 'viper-exec-mapped-kbd-macro)
454 (setq lis (eval macro-alist-var))
455 (while (and lis (string< (viper-array-to-string (car (car lis)))
456 (viper-array-to-string macro-name)))
457 (setq lis2 (cons (car lis) lis2))
458 (setq lis (cdr lis)))
1ca2d34b 459
3f9526a3
MK
460 (setq lis2 (reverse lis2))
461 (set macro-alist-var (append lis2 (cons new-elt lis)))
462 (setq old-elt new-elt)))
6c2e12f4 463 (setq old-sub-elt
8626cfa2
MK
464 (cond ((eq scope t) (viper-kbd-global-pair old-elt))
465 ((symbolp scope) (assoc scope (viper-kbd-mode-alist old-elt)))
466 ((stringp scope) (assoc scope (viper-kbd-buf-alist old-elt)))))
a1506d29 467 (if old-sub-elt
6c2e12f4
KH
468 (setcdr old-sub-elt macro-body)
469 (cond ((symbolp scope) (setcar (cdr (cdr old-elt))
470 (cons (cons scope macro-body)
8626cfa2 471 (viper-kbd-mode-alist old-elt))))
6c2e12f4
KH
472 ((stringp scope) (setcar (cdr old-elt)
473 (cons (cons scope macro-body)
8626cfa2 474 (viper-kbd-buf-alist old-elt))))))
6c2e12f4 475 ))
6c2e12f4 476
a1506d29
JB
477
478
8626cfa2 479;; macro name must be a vector of viper-style keys
3f9526a3
MK
480;; viper-unrecord-kbd-macro doesn't have scope. Macro definitions are inherited
481;; from global -> major mode -> buffer
482;; More specific definition overrides more general
483;; Can't unrecord definition for more specific, if a more general definition is
484;; in effect
8626cfa2 485(defun viper-unrecord-kbd-macro (macro-name state)
546fe085 486 "Delete macro MACRO-NAME from Viper STATE.
3af0304a 487MACRO-NAME must be a vector of viper-style keys. This command is used by Viper
8626cfa2 488internally, but the user can also use it in ~/.viper to delete pre-defined
3af0304a
MK
489macros supplied with Viper. The best way to avoid mistakes in macro names to
490be passed to this function is to use viper-describe-kbd-macros and copy the
491name from there."
a1506d29 492 (let* (state-name keymap
6c2e12f4
KH
493 (macro-alist-var
494 (cond ((eq state 'vi-state)
495 (setq state-name "Vi state"
8626cfa2
MK
496 keymap viper-vi-kbd-map)
497 'viper-vi-kbd-macro-alist)
6c2e12f4
KH
498 ((memq state '(insert-state replace-state))
499 (setq state-name "Insert state"
8626cfa2
MK
500 keymap viper-insert-kbd-map)
501 'viper-insert-kbd-macro-alist)
6c2e12f4
KH
502 (t
503 (setq state-name "Emacs state"
8626cfa2
MK
504 keymap viper-emacs-kbd-map)
505 'viper-emacs-kbd-macro-alist)
6c2e12f4
KH
506 ))
507 buf-mapping mode-mapping global-mapping
508 macro-pair macro-entry)
a1506d29 509
3af0304a
MK
510 ;; Macro-name is usually a vector. However, command history or macros
511 ;; recorded in ~/.viper may appear as strings. So, convert to vectors.
8626cfa2
MK
512 (setq macro-name (viper-fixup-macro macro-name))
513 (if (viper-char-array-p macro-name)
514 (setq macro-name (viper-char-array-to-macro macro-name)))
6c2e12f4
KH
515
516 (setq macro-entry (assoc macro-name (eval macro-alist-var)))
517 (if (= (length macro-name) 0)
518 (error "Can't unmap an empty macro name"))
519 (if (null macro-entry)
520 (error "%S is not mapped to a macro for %s in `%s'"
8626cfa2 521 (viper-display-macro macro-name)
6c2e12f4 522 state-name (buffer-name)))
a1506d29 523
8626cfa2
MK
524 (setq buf-mapping (viper-kbd-buf-pair macro-entry)
525 mode-mapping (viper-kbd-mode-pair macro-entry)
526 global-mapping (viper-kbd-global-pair macro-entry))
a1506d29 527
6c2e12f4
KH
528 (cond ((and (cdr buf-mapping)
529 (or (and (not (cdr mode-mapping)) (not (cdr global-mapping)))
530 (y-or-n-p
531 (format "Unmap %S for `%s' only? "
8626cfa2 532 (viper-display-macro macro-name)
6c2e12f4
KH
533 (buffer-name)))))
534 (setq macro-pair buf-mapping)
a1506d29 535 (message "%S is unmapped for %s in `%s'"
8626cfa2 536 (viper-display-macro macro-name)
6c2e12f4
KH
537 state-name (buffer-name)))
538 ((and (cdr mode-mapping)
539 (or (not (cdr global-mapping))
540 (y-or-n-p
541 (format "Unmap %S for the major mode `%S' only? "
8626cfa2 542 (viper-display-macro macro-name)
6c2e12f4
KH
543 major-mode))))
544 (setq macro-pair mode-mapping)
545 (message "%S is unmapped for %s in %S"
8626cfa2 546 (viper-display-macro macro-name) state-name major-mode))
3f9526a3 547 ((cdr (setq macro-pair global-mapping))
6c2e12f4 548 (message
1e70790f 549 "Global mapping for %S in %s is removed"
8626cfa2 550 (viper-display-macro macro-name) state-name))
6c2e12f4 551 (t (error "%S is not mapped to a macro for %s in `%s'"
8626cfa2 552 (viper-display-macro macro-name)
6c2e12f4
KH
553 state-name (buffer-name))))
554 (setcdr macro-pair nil)
555 (or (cdr buf-mapping)
556 (cdr mode-mapping)
557 (cdr global-mapping)
558 (progn
559 (set macro-alist-var (delq macro-entry (eval macro-alist-var)))
a1506d29 560 (if (viper-can-release-key (aref macro-name 0)
3f9526a3 561 (eval macro-alist-var))
6c2e12f4
KH
562 (define-key
563 keymap
8626cfa2 564 (vector (viper-key-to-emacs-key (aref macro-name 0)))
6c2e12f4
KH
565 nil))
566 ))
567 ))
a1506d29 568
546fe085 569;; Check if MACRO-ALIST has an entry for a macro name starting with
3af0304a 570;; CHAR. If not, this indicates that the binding for this char
8626cfa2
MK
571;; in viper-vi/insert-kbd-map can be released.
572(defun viper-can-release-key (char macro-alist)
6c2e12f4
KH
573 (let ((lis macro-alist)
574 (can-release t)
575 macro-name)
a1506d29 576
6c2e12f4
KH
577 (while (and lis can-release)
578 (setq macro-name (car (car lis)))
579 (if (eq char (aref macro-name 0))
580 (setq can-release nil))
581 (setq lis (cdr lis)))
582 can-release))
583
584
8626cfa2 585(defun viper-exec-mapped-kbd-macro (count)
6c2e12f4
KH
586 "Dispatch kbd macro."
587 (interactive "P")
8626cfa2
MK
588 (let* ((macro-alist (cond ((eq viper-current-state 'vi-state)
589 viper-vi-kbd-macro-alist)
590 ((memq viper-current-state
6c2e12f4 591 '(insert-state replace-state))
8626cfa2 592 viper-insert-kbd-macro-alist)
6c2e12f4 593 (t
8626cfa2 594 viper-emacs-kbd-macro-alist)))
6c2e12f4
KH
595 (unmatched-suffix "")
596 ;; Macros and keys are executed with other macros turned off
597 ;; For macros, this is done to avoid macro recursion
8626cfa2
MK
598 viper-vi-kbd-minor-mode viper-insert-kbd-minor-mode
599 viper-emacs-kbd-minor-mode
6c2e12f4
KH
600 next-best-match keyseq event-seq
601 macro-first-char macro-alist-elt macro-body
602 command)
a1506d29 603
6c2e12f4 604 (setq macro-first-char last-command-event
8626cfa2
MK
605 event-seq (viper-read-fast-keysequence macro-first-char macro-alist)
606 keyseq (viper-events-to-macro event-seq)
6c2e12f4 607 macro-alist-elt (assoc keyseq macro-alist)
8626cfa2 608 next-best-match (viper-find-best-matching-macro macro-alist keyseq))
a1506d29 609
6c2e12f4
KH
610 (if (null macro-alist-elt)
611 (setq macro-alist-elt (car next-best-match)
8ea74b0e 612 unmatched-suffix (viper-subseq event-seq (cdr next-best-match))))
6c2e12f4
KH
613
614 (cond ((null macro-alist-elt))
8626cfa2
MK
615 ((setq macro-body (viper-kbd-buf-definition macro-alist-elt)))
616 ((setq macro-body (viper-kbd-mode-definition macro-alist-elt)))
617 ((setq macro-body (viper-kbd-global-definition macro-alist-elt))))
a1506d29 618
6c2e12f4
KH
619 ;; when defining keyboard macro, don't use the macro mappings
620 (if (and macro-body (not defining-kbd-macro))
621 ;; block cmd executed as part of a macro from entering command history
622 (let ((command-history command-history))
8626cfa2
MK
623 (setq viper-this-kbd-macro (car macro-alist-elt))
624 (execute-kbd-macro (viper-macro-to-events macro-body) count)
625 (setq viper-this-kbd-macro nil
626 viper-last-kbd-macro (car macro-alist-elt))
627 (viper-set-unread-command-events unmatched-suffix))
6c2e12f4
KH
628 ;; If not a macro, or the macro is suppressed while defining another
629 ;; macro, put keyseq back on the event queue
8626cfa2 630 (viper-set-unread-command-events event-seq)
6c2e12f4
KH
631 ;; if the user typed arg, then use it if prefix arg is not set by
632 ;; some other command (setting prefix arg can happen if we do, say,
3af0304a 633 ;; 2dw and there is a macro starting with 2. Then control will go to
6c2e12f4 634 ;; this routine
a1506d29 635 (or prefix-arg (setq prefix-arg count))
6c2e12f4
KH
636 (setq command (key-binding (read-key-sequence nil)))
637 (if (commandp command)
638 (command-execute command)
639 (beep 1)))
640 ))
641
642
643\f
644;;; Displaying and completing macros
a1506d29 645
8626cfa2 646(defun viper-describe-kbd-macros ()
6c2e12f4
KH
647 "Show currently defined keyboard macros."
648 (interactive)
8626cfa2 649 (with-output-to-temp-buffer " *viper-info*"
6c2e12f4 650 (princ "Macros in Vi state:\n===================\n")
1ca2d34b 651 (mapc 'viper-describe-one-macro viper-vi-kbd-macro-alist)
6c2e12f4 652 (princ "\n\nMacros in Insert and Replace states:\n====================================\n")
1ca2d34b 653 (mapc 'viper-describe-one-macro viper-insert-kbd-macro-alist)
6c2e12f4 654 (princ "\n\nMacros in Emacs state:\n======================\n")
8626cfa2 655 (mapcar 'viper-describe-one-macro viper-emacs-kbd-macro-alist)
6c2e12f4 656 ))
a1506d29 657
8626cfa2 658(defun viper-describe-one-macro (macro)
6c2e12f4 659 (princ (format "\n *** Mappings for %S:\n ------------\n"
8626cfa2 660 (viper-display-macro (car macro))))
6c2e12f4 661 (princ " ** Buffer-specific:")
8626cfa2 662 (if (viper-kbd-buf-alist macro)
1ca2d34b 663 (mapc 'viper-describe-one-macro-elt (viper-kbd-buf-alist macro))
6c2e12f4
KH
664 (princ " none\n"))
665 (princ "\n ** Mode-specific:")
8626cfa2 666 (if (viper-kbd-mode-alist macro)
1ca2d34b 667 (mapc 'viper-describe-one-macro-elt (viper-kbd-mode-alist macro))
6c2e12f4
KH
668 (princ " none\n"))
669 (princ "\n ** Global:")
8626cfa2
MK
670 (if (viper-kbd-global-definition macro)
671 (princ (format "\n %S" (cdr (viper-kbd-global-pair macro))))
6c2e12f4
KH
672 (princ " none"))
673 (princ "\n"))
a1506d29 674
8626cfa2 675(defun viper-describe-one-macro-elt (elt)
6c2e12f4
KH
676 (let ((name (car elt))
677 (defn (cdr elt)))
678 (princ (format "\n * %S:\n %S\n" name defn))))
a1506d29
JB
679
680
681
6c2e12f4 682;; check if SEQ is a prefix of some car of an element in ALIST
8626cfa2
MK
683(defun viper-keyseq-is-a-possible-macro (seq alist)
684 (let ((converted-seq (viper-events-to-macro seq)))
a1506d29 685 (eval (cons 'or
6c2e12f4 686 (mapcar
3af0304a 687 (lambda (elt) (viper-prefix-subseq-p converted-seq elt))
8626cfa2 688 (viper-this-buffer-macros alist))))))
a1506d29 689
6c2e12f4 690;; whether SEQ1 is a prefix of SEQ2
8626cfa2 691(defun viper-prefix-subseq-p (seq1 seq2)
6c2e12f4
KH
692 (let ((len1 (length seq1))
693 (len2 (length seq2)))
694 (if (<= len1 len2)
8ea74b0e 695 (equal seq1 (viper-subseq seq2 0 len1)))))
a1506d29 696
6c2e12f4 697;; find the longest common prefix
8626cfa2 698(defun viper-common-seq-prefix (&rest seqs)
6c2e12f4
KH
699 (let* ((first (car seqs))
700 (rest (cdr seqs))
701 (pref [])
702 (idx 0)
703 len)
704 (if (= (length seqs) 0)
705 (setq len 0)
706 (setq len (apply 'min (mapcar 'length seqs))))
707 (while (< idx len)
a1506d29 708 (if (eval (cons 'and
3af0304a 709 (mapcar (lambda (s) (equal (elt first idx) (elt s idx)))
6c2e12f4
KH
710 rest)))
711 (setq pref (vconcat pref (vector (elt first idx)))))
712 (setq idx (1+ idx)))
713 pref))
a1506d29 714
6c2e12f4 715;; get all sequences that match PREFIX from a given A-LIST
8626cfa2 716(defun viper-extract-matching-alist-members (pref alist)
3af0304a 717 (delq nil (mapcar (lambda (elt) (if (viper-prefix-subseq-p pref elt) elt))
8626cfa2 718 (viper-this-buffer-macros alist))))
a1506d29 719
8626cfa2
MK
720(defun viper-do-sequence-completion (seq alist compl-message)
721 (let* ((matches (viper-extract-matching-alist-members seq alist))
722 (new-seq (apply 'viper-common-seq-prefix matches))
6c2e12f4
KH
723 )
724 (cond ((and (equal seq new-seq) (= (length matches) 1))
725 (message "%s (Sole completion)" compl-message)
726 (sit-for 2))
a1506d29 727 ((null matches)
6c2e12f4
KH
728 (message "%s (No match)" compl-message)
729 (sit-for 2)
730 (setq new-seq seq))
a1506d29 731 ((member seq matches)
6c2e12f4
KH
732 (message "%s (Complete, but not unique)" compl-message)
733 (sit-for 2)
8626cfa2 734 (viper-display-vector-completions matches))
6c2e12f4 735 ((equal seq new-seq)
8626cfa2 736 (viper-display-vector-completions matches)))
6c2e12f4 737 new-seq))
a1506d29
JB
738
739
8626cfa2 740(defun viper-display-vector-completions (list)
6c2e12f4 741 (with-output-to-temp-buffer "*Completions*"
a1506d29 742 (display-completion-list
6c2e12f4 743 (mapcar 'prin1-to-string
8626cfa2 744 (mapcar 'viper-display-macro list)))))
a1506d29
JB
745
746
747
6c2e12f4
KH
748;; alist is the alist of macros
749;; str is the fast key sequence entered
750;; returns: (matching-macro-def . unmatched-suffix-start-index)
8626cfa2 751(defun viper-find-best-matching-macro (alist str)
6c2e12f4
KH
752 (let ((lis alist)
753 (def-len 0)
754 (str-len (length str))
755 match unmatched-start-idx found macro-def)
756 (while (and (not found) lis)
757 (setq macro-def (car lis)
758 def-len (length (car macro-def)))
759 (if (and (>= str-len def-len)
8ea74b0e 760 (equal (car macro-def) (viper-subseq str 0 def-len)))
8626cfa2
MK
761 (if (or (viper-kbd-buf-definition macro-def)
762 (viper-kbd-mode-definition macro-def)
763 (viper-kbd-global-definition macro-def))
6c2e12f4
KH
764 (setq found t))
765 )
766 (setq lis (cdr lis)))
a1506d29 767
6c2e12f4
KH
768 (if found
769 (setq match macro-def
770 unmatched-start-idx def-len)
771 (setq match nil
772 unmatched-start-idx 0))
a1506d29 773
6c2e12f4 774 (cons match unmatched-start-idx)))
a1506d29
JB
775
776
777
6c2e12f4 778;; returns a list of names of macros defined for the current buffer
8626cfa2 779(defun viper-this-buffer-macros (macro-alist)
6c2e12f4
KH
780 (let (candidates)
781 (setq candidates
3af0304a
MK
782 (mapcar (lambda (elt)
783 (if (or (viper-kbd-buf-definition elt)
784 (viper-kbd-mode-definition elt)
785 (viper-kbd-global-definition elt))
786 (car elt)))
6c2e12f4
KH
787 macro-alist))
788 (setq candidates (delq nil candidates))))
a1506d29
JB
789
790
546fe085 791;; if seq of Viper key symbols (representing a macro) can be converted to a
3af0304a 792;; string--do so. Otherwise, do nothing.
8626cfa2
MK
793(defun viper-display-macro (macro-name-or-body)
794 (cond ((viper-char-symbol-sequence-p macro-name-or-body)
edff961b 795 (mapconcat 'symbol-name macro-name-or-body ""))
8626cfa2 796 ((viper-char-array-p macro-name-or-body)
edff961b
MK
797 (mapconcat 'char-to-string macro-name-or-body ""))
798 (t macro-name-or-body)))
a1506d29 799
df93b82b
MK
800;; convert sequence of events (that came presumably from emacs kbd macro) into
801;; Viper's macro, which is a vector of the form
802;; [ desc desc ... ]
803;; Each desc is either a symbol of (meta symb), (shift symb), etc.
3af0304a 804;; Here we purge events that happen to be lists. In most cases, these events
df93b82b
MK
805;; got into a macro definition unintentionally; say, when the user moves mouse
806;; during a macro definition, then something like (switch-frame ...) might get
3af0304a 807;; in. Another reason for purging lists-events is that we can't store them in
df93b82b 808;; textual form (say, in .emacs) and then read them back.
8626cfa2 809(defun viper-events-to-macro (event-seq)
3af0304a
MK
810 (vconcat (delq nil (mapcar (lambda (elt) (if (consp elt)
811 nil
812 (viper-event-key elt)))
df93b82b 813 event-seq))))
a1506d29 814
546fe085 815;; convert strings or arrays of characters to Viper macro form
8626cfa2 816(defun viper-char-array-to-macro (array)
6c2e12f4
KH
817 (let ((vec (vconcat array))
818 macro)
e83d1fe8 819 (if (featurep 'xemacs)
6c2e12f4
KH
820 (setq macro (mapcar 'character-to-event vec))
821 (setq macro vec))
8626cfa2 822 (vconcat (mapcar 'viper-event-key macro))))
a1506d29 823
edff961b 824;; For macros bodies and names, goes over MACRO and checks if all members are
6c2e12f4 825;; names of keys (actually, it only checks if they are symbols or lists
edff961b
MK
826;; if a digit is found, it is converted into a symbol (e.g., 0 -> \0, etc).
827;; If MACRO is not a list or vector -- doesn't change MACRO.
8626cfa2 828(defun viper-fixup-macro (macro)
6c2e12f4
KH
829 (let ((len (length macro))
830 (idx 0)
831 elt break)
832 (if (or (vectorp macro) (listp macro))
833 (while (and (< idx len) (not break))
834 (setq elt (elt macro idx))
835 (cond ((numberp elt)
836 ;; fix number
837 (if (and (<= 0 elt) (<= elt 9))
838 (cond ((arrayp macro)
839 (aset macro
840 idx
841 (intern (char-to-string (+ ?0 elt)))))
842 ((listp macro)
843 (setcar (nthcdr idx macro)
844 (intern (char-to-string (+ ?0 elt)))))
845 )))
6c2e12f4 846 ((listp elt)
8626cfa2 847 (viper-fixup-macro elt))
6c2e12f4
KH
848 ((symbolp elt) nil)
849 (t (setq break t)))
850 (setq idx (1+ idx))))
a1506d29 851
6c2e12f4
KH
852 (if break
853 (error "Wrong type macro component, symbol-or-listp, %S" elt)
854 macro)))
a1506d29 855
8626cfa2
MK
856(defun viper-macro-to-events (macro-body)
857 (vconcat (mapcar 'viper-key-to-emacs-key macro-body)))
a1506d29
JB
858
859
6c2e12f4
KH
860\f
861;;; Reading fast key sequences
a1506d29 862
6c2e12f4 863;; Assuming that CHAR was the first character in a fast succession of key
3af0304a 864;; strokes, read the rest. Return the vector of keys that was entered in
6c2e12f4
KH
865;; this fast succession of key strokes.
866;; A fast keysequence is one that is terminated by a pause longer than
8626cfa2
MK
867;; viper-fast-keyseq-timeout.
868(defun viper-read-fast-keysequence (event macro-alist)
6c2e12f4
KH
869 (let ((lis (vector event))
870 next-event)
8626cfa2 871 (while (and (viper-fast-keysequence-p)
2ee00512
MK
872 (viper-keyseq-is-a-possible-macro lis macro-alist))
873 ;; Seems that viper-read-event is more robust here. We need to be able to
874 ;; place these events on unread-command-events list. If we use
875 ;; viper-read-key then events will be converted to keys, and sometimes
876 ;; (e.g., (control \[)) those keys differ from the corresponding events.
877 ;; So, do not use (setq next-event (viper-read-key))
878 (setq next-event (viper-read-event))
8626cfa2 879 (or (viper-mouse-event-p next-event)
6c2e12f4
KH
880 (setq lis (vconcat lis (vector next-event)))))
881 lis))
882
883\f
884;;; Keyboard macros in registers
885
886;; sets register to last-kbd-macro carefully.
8626cfa2 887(defun viper-set-register-macro (reg)
6c2e12f4 888 (if (get-register reg)
3af0304a 889 (if (y-or-n-p "Register contains data. Overwrite? ")
6c2e12f4
KH
890 ()
891 (error
3af0304a 892 "Macro not saved in register. Can still be invoked via `C-x e'")))
6c2e12f4
KH
893 (set-register reg last-kbd-macro))
894
8626cfa2 895(defun viper-register-macro (count)
6c2e12f4
KH
896 "Keyboard macros in registers - a modified \@ command."
897 (interactive "P")
898 (let ((reg (downcase (read-char))))
899 (cond ((or (and (<= ?a reg) (<= reg ?z)))
8626cfa2 900 (setq viper-last-macro-reg reg)
6c2e12f4
KH
901 (if defining-kbd-macro
902 (progn
903 (end-kbd-macro)
8626cfa2 904 (viper-set-register-macro reg))
6c2e12f4
KH
905 (execute-kbd-macro (get-register reg) count)))
906 ((or (= ?@ reg) (= ?\^j reg) (= ?\^m reg))
a1506d29 907 (if viper-last-macro-reg
6c2e12f4
KH
908 nil
909 (error "No previous kbd macro"))
8626cfa2 910 (execute-kbd-macro (get-register viper-last-macro-reg) count))
6c2e12f4
KH
911 ((= ?\# reg)
912 (start-kbd-macro count))
913 ((= ?! reg)
914 (setq reg (downcase (read-char)))
915 (if (or (and (<= ?a reg) (<= reg ?z)))
916 (progn
8626cfa2
MK
917 (setq viper-last-macro-reg reg)
918 (viper-set-register-macro reg))))
6c2e12f4 919 (t
ae37fce9 920 (error "`%c': Unknown register" reg)))))
a1506d29 921
6c2e12f4 922
8626cfa2 923(defun viper-global-execute ()
6c2e12f4
KH
924 "Call last keyboad macro for each line in the region."
925 (if (> (point) (mark t)) (exchange-point-and-mark))
926 (beginning-of-line)
927 (call-last-kbd-macro)
928 (while (< (point) (mark t))
929 (forward-line 1)
930 (beginning-of-line)
931 (call-last-kbd-macro)))
932
933
cbee283d 934;; arch-tag: ecd3cc5c-8cd0-4bbe-b2ec-7e75a4b7d0aa
60370d40 935;;; viper-macs.el ends here