Function: viper-record-kbd-macro

viper-record-kbd-macro is a byte-compiled function defined in viper-macs.el.gz.

Signature

(viper-record-kbd-macro MACRO-NAME STATE MACRO-BODY &optional SCOPE)

Documentation

Record a Vi macro.

Can be used in viper-custom-file-name to define permanent macros. MACRO-NAME is a string of characters or a vector of keys. STATE is either vi-state or insert-state. It specifies the Viper state in which to define the macro. MACRO-BODY is a string that represents the keyboard macro. Optional SCOPE says whether the macro should be global (t), mode-specific
(a major-mode symbol), or buffer-specific (buffer name, a string).
If SCOPE is nil, the user is asked to specify the scope.

Source Code

;; Defined in /usr/src/emacs/lisp/emulation/viper-macs.el.gz
;;; Recording, unrecording, executing

;; Accepts as macro names: strings and vectors.
;; strings must be strings of characters; vectors must be vectors of keys
;; in canonical form, which is essentially the form used in XEmacs.
;; More general definitions are inherited by more specific scopes:
;; global->major mode->buffer. More specific definitions override more general
(defun viper-record-kbd-macro (macro-name state macro-body &optional scope)
  "Record a Vi macro.
Can be used in `viper-custom-file-name' to define permanent macros.
MACRO-NAME is a string of characters or a vector of keys.  STATE is
either `vi-state' or `insert-state'.  It specifies the Viper state in which to
define the macro.  MACRO-BODY is a string that represents the keyboard macro.
Optional SCOPE says whether the macro should be global \(t), mode-specific
\(a major-mode symbol), or buffer-specific \(buffer name, a string).
If SCOPE is nil, the user is asked to specify the scope."
  (let* (state-name keymap
	 (macro-alist-var
	  (cond ((eq state 'vi-state)
		 (setq state-name "Vi state"
		       keymap viper-vi-kbd-map)
		 'viper-vi-kbd-macro-alist)
		((memq state '(insert-state replace-state))
		 (setq state-name "Insert state"
		       keymap viper-insert-kbd-map)
		 'viper-insert-kbd-macro-alist)
		(t
		 (setq state-name "Emacs state"
		       keymap viper-emacs-kbd-map)
		 'viper-emacs-kbd-macro-alist)
		 ))
	 new-elt old-elt old-sub-elt msg
	 temp lis lis2)

    (if (= (length macro-name) 0)
	(error "Can't map an empty macro name"))

    ;; Macro-name is usually a vector.  However, command history or macros
    ;; recorded in viper-custom-file-name may be recorded as strings.
    ;; So, convert to vectors.
    (setq macro-name (viper-fixup-macro macro-name))
    (if (viper-char-array-p macro-name)
	(setq macro-name (viper-char-array-to-macro macro-name)))
    (setq macro-body (viper-fixup-macro macro-body))
    (if (viper-char-array-p macro-body)
	(setq macro-body (viper-char-array-to-macro macro-body)))

    ;; don't ask if scope is given and is of the right type
    (or (eq scope t)
	(stringp scope)
	(and scope (symbolp scope))
	(progn
	  (setq scope
		(cond
		 ((y-or-n-p
		   (format-message
		    "Map this macro for buffer `%s' only? "
		    (buffer-name)))
		  (setq msg
			(format-message
			 "%S is mapped to %s for %s in `%s'"
			 (viper-display-macro macro-name)
			 (viper-abbreviate-string
			  (format
			   "%S"
			   (setq temp (viper-display-macro macro-body)))
			  14 "" ""
			  (if (stringp temp) "  ....\"" "  ....]"))
			 state-name (buffer-name)))
		  (buffer-name))
		 ((y-or-n-p
		   (format-message
		    "Map this macro for the major mode `%S' only? "
		    major-mode))
		  (setq msg
			(format-message
			 "%S is mapped to %s for %s in `%S'"
			 (viper-display-macro macro-name)
			 (viper-abbreviate-string
			  (format
			   "%S"
			   (setq temp (viper-display-macro macro-body)))
			  14 "" ""
			  (if (stringp macro-body) "  ....\"" "  ....]"))
			 state-name major-mode))
		  major-mode)
		 (t
		  (setq msg
			(format
			 "%S is globally mapped to %s in %s"
			 (viper-display-macro macro-name)
			 (viper-abbreviate-string
			  (format
			   "%S"
			   (setq temp (viper-display-macro macro-body)))
			  14 "" ""
			  (if (stringp macro-body) "  ....\"" "  ....]"))
			 state-name))
		  t)))
	  (if (y-or-n-p
	       (format "Save this macro in %s? "
		       (abbreviate-file-name viper-custom-file-name)))
	      (viper-save-string-in-file
	       (format "\n(viper-record-kbd-macro %S '%S %s '%S)"
		       (viper-display-macro macro-name)
		       state
		       ;; if we don't let vector macro-body through %S,
		       ;; the symbols `\.' `\[' etc will be converted into
		       ;; characters, causing invalid read  error on recorded
		       ;; macros in viper-custom-file-name.
		       ;; I am not sure is macro-body can still be a string at
		       ;; this point, but I am preserving this option anyway.
		       (if (vectorp macro-body)
			   (format "%S" macro-body)
			 macro-body)
		       scope)
	       viper-custom-file-name))

	  (message "%s" msg)
	  ))

    (setq new-elt
	  (cons macro-name
		(cond ((eq scope t) (list nil nil (cons t nil)))
		      ((symbolp scope)
		       (list nil (list (cons scope nil)) (cons t nil)))
		      ((stringp scope)
		       (list (list (cons scope nil)) nil (cons t nil))))))
    (setq old-elt (assoc macro-name (symbol-value macro-alist-var)))

    (if (null old-elt)
	(progn
	  ;; insert new-elt in macro-alist-var and keep the list sorted
	  (define-key
	    keymap
	    (vector (viper-key-to-emacs-key (aref macro-name 0)))
	    #'viper-exec-mapped-kbd-macro)
	  (setq lis (symbol-value macro-alist-var))
	  (while (and lis (string< (viper-array-to-string (car (car lis)))
				   (viper-array-to-string macro-name)))
	    (setq lis2 (cons (car lis) lis2))
	    (setq lis (cdr lis)))

	  (setq lis2 (reverse lis2))
	  (set macro-alist-var (append lis2 (cons new-elt lis)))
	  (setq old-elt new-elt)))
    (setq old-sub-elt
	  (cond ((eq scope t) (viper-kbd-global-pair old-elt))
		((symbolp scope) (assoc scope (viper-kbd-mode-alist old-elt)))
		((stringp scope) (assoc scope (viper-kbd-buf-alist old-elt)))))
    (if old-sub-elt
	(setcdr old-sub-elt macro-body)
      (cond ((symbolp scope) (setcar (cdr (cdr old-elt))
				     (cons (cons scope macro-body)
					   (viper-kbd-mode-alist old-elt))))
	    ((stringp scope) (setcar (cdr old-elt)
				     (cons (cons scope macro-body)
					   (viper-kbd-buf-alist old-elt))))))
    ))