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