Mercurial > hg > xemacs-beta
diff lisp/prim/macros.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 0293115a14e9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/prim/macros.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,271 @@ +;;; macros.el --- non-primitive commands for keyboard macros. + +;; Copyright (C) 1985, 86, 87, 92, 94, 95 Free Software Foundation, Inc. + +;; Maintainer: FSF +;; Keywords: abbrev + +;; This file is part of XEmacs. + +;; XEmacs 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. + +;; XEmacs 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 XEmacs; see the file COPYING. If not, write to the Free +;; Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Synched up with: FSF 19.30. + +;;; Commentary: + +;; Extension commands for keyboard macros. These permit you to assign +;; a name to the last-defined keyboard macro, expand and insert the +;; lisp corresponding to a macro, query the user from within a macro, +;; or apply a macro to each line in the reason. + +;;; Code: + +;;;###autoload +(defun name-last-kbd-macro (symbol) + "Assign a name to the last keyboard macro defined. +Argument SYMBOL is the name to define. +The symbol's function definition becomes the keyboard macro string. +Such a \"function\" cannot be called from Lisp, but it is a valid +editor command." + (interactive "SName for last kbd macro: ") + (or last-kbd-macro + (error "No keyboard macro defined")) + (and (fboundp symbol) + (not (stringp (symbol-function symbol))) + (not (vectorp (symbol-function symbol))) + (error "Function %s is already defined and not a keyboard macro." + symbol)) + (fset symbol last-kbd-macro)) + +(defun insert-kbd-macro-pretty-string (string) + ;; Convert control characters to the traditional readable representation: + ;; put the four characters \M-x in the buffer instead of the one char \370, + ;; which would deceptively print as `oslash' with the default settings. + (save-restriction + (narrow-to-region (point) (point)) + (prin1 string (current-buffer)) + (goto-char (1+ (point-min))) + (while (not (eobp)) + (cond ((= (following-char) 0) (insert "\\C-@") (delete-char 1)) + ((= (following-char) ?\n) (insert "\\n") (delete-char 1)) + ((= (following-char) ?\r) (insert "\\r") (delete-char 1)) + ((= (following-char) ?\t) (insert "\\t") (delete-char 1)) + ((= (following-char) ?\e) (insert "\\e") (delete-char 1)) + ((= (following-char) 127) (insert "\\C-?") (delete-char 1)) + ((= (following-char) 128) (insert "\\M-\\C-@") (delete-char 1)) + ((= (following-char) 255) (insert "\\M-\\C-?") (delete-char 1)) + ((and (> (following-char) 127) (< (following-char) 155)) + (insert "\\M-\\C-") + (insert (- (following-char) 32)) + (delete-char 1) + (forward-char -1)) + ((and (>= (following-char) 155) (< (following-char) 160)) + (insert "\\M-\\C-") + (insert (- (following-char) 64)) + (delete-char 1) + (forward-char -1)) + ((>= (following-char) 160) + (insert "\\M-") + (insert (- (following-char) 128)) + (delete-char 1) + (forward-char -1)) + ((< (following-char) 27) + ;;(insert "\\^") (insert (+ (following-char) 64)) + (insert "\\C-") (insert (+ (following-char) 96)) + (delete-char 1) + (forward-char -1)) + ((< (following-char) 32) + ;;(insert "\\^") (insert (+ (following-char) 64)) + (insert "\\C-") (insert (+ (following-char) 64)) + (delete-char 1) + (forward-char -1)) + (t + (forward-char 1)))))) + +;;;###autoload +(defun insert-kbd-macro (macroname &optional keys) + "Insert in buffer the definition of kbd macro NAME, as Lisp code. +Optional second argument KEYS means also record the keys it is on +\(this is the prefix argument, when calling interactively). + +This Lisp code will, when executed, define the kbd macro with the +same definition it has now. If you say to record the keys, +the Lisp code will also rebind those keys to the macro. +Only global key bindings are recorded since executing this Lisp code +always makes global bindings. + +To save a kbd macro, visit a file of Lisp code such as your `~/.emacs', +use this command, and then save the file." + (interactive "CInsert kbd macro (name): \nP") + (let (definition) + (if (string= (symbol-name macroname) "") + (progn + (setq macroname 'last-kbd-macro + definition last-kbd-macro) + (insert "(setq ")) + (progn + (setq definition (symbol-function macroname)) + (insert "(fset '"))) + (prin1 macroname (current-buffer)) + (insert "\n ") + (let ((string (events-to-keys definition t))) + (if (stringp string) + (insert-kbd-macro-pretty-string string) + (prin1 string (current-buffer)))) + (insert ")\n") + (if keys + (let ((keys (where-is-internal macroname))) + (while keys + (insert "(global-set-key ") + (prin1 (car keys) (current-buffer)) + (insert " '") + (prin1 macroname (current-buffer)) + (insert ")\n") + (setq keys (cdr keys))))))) + +;;;###autoload +(defun kbd-macro-query (flag) + "Query user during kbd macro execution. +With prefix argument, enters recursive edit, + reading keyboard commands even within a kbd macro. + You can give different commands each time the macro executes. +Without prefix argument, asks whether to continue running the macro. +Your options are: \\<query-replace-map> +\\[act] Finish this iteration normally and continue with the next. +\\[skip] Skip the rest of this iteration, and start the next. +\\[exit] Stop the macro entirely right now. +\\[recenter] Redisplay the frame, then ask again. +\\[edit] Enter recursive edit; ask again when you exit from that." + (interactive "P") + (or executing-macro + defining-kbd-macro + (error "Not defining or executing kbd macro")) + (if flag + (let (executing-macro defining-kbd-macro) + (recursive-edit)) + (if (not executing-macro) + nil + (let ((loop t) + (msg (substitute-command-keys + "Proceed with macro?\\<query-replace-map>\ + (\\[act], \\[skip], \\[exit], \\[recenter], \\[edit]) "))) + (while loop + (let ((key (let ((executing-macro nil) + (defining-kbd-macro nil)) + (message msg) + (read-char))) + def) + (setq key (vector key)) + (setq def (lookup-key query-replace-map key)) + (cond ((eq def 'act) + (setq loop nil)) + ((eq def 'skip) + (setq loop nil) + (setq executing-macro "")) + ((eq def 'exit) + (setq loop nil) + (setq executing-macro t)) + ((eq def 'recenter) + (recenter nil)) + ((eq def 'edit) + (let (executing-macro defining-kbd-macro) + (recursive-edit))) + ((eq def 'quit) + (setq quit-flag t)) + (t + (or (eq def 'help) + (ding)) + (with-output-to-temp-buffer "*Help*" + (princ + (substitute-command-keys + "Specify how to proceed with keyboard macro execution. +Possibilities: \\<query-replace-map> +\\[act] Finish this iteration normally and continue with the next. +\\[skip] Skip the rest of this iteration, and start the next. +\\[exit] Stop the macro entirely right now. +\\[recenter] Redisplay the frame, then ask again. +\\[edit] Enter recursive edit; ask again when you exit from that.")) + (save-excursion + (set-buffer standard-output) + (help-mode))))))))))) + +;;;###autoload +(defun apply-macro-to-region-lines (top bottom &optional macro) + "For each complete line between point and mark, move to the beginning +of the line, and run the last keyboard macro. + +When called from lisp, this function takes two arguments TOP and +BOTTOM, describing the current region. TOP must be before BOTTOM. +The optional third argument MACRO specifies a keyboard macro to +execute. + +This is useful for quoting or unquoting included text, adding and +removing comments, or producing tables where the entries are regular. + +For example, in Usenet articles, sections of text quoted from another +author are indented, or have each line start with `>'. To quote a +section of text, define a keyboard macro which inserts `>', put point +and mark at opposite ends of the quoted section, and use +`\\[apply-macro-to-region-lines]' to mark the entire section. + +Suppose you wanted to build a keyword table in C where each entry +looked like this: + + { \"foo\", foo_data, foo_function }, + { \"bar\", bar_data, bar_function }, + { \"baz\", baz_data, baz_function }, + +You could enter the names in this format: + + foo + bar + baz + +and write a macro to massage a word into a table entry: + + \\C-x ( + \\M-d { \"\\C-y\", \\C-y_data, \\C-y_function }, + \\C-x ) + +and then select the region of un-tablified names and use +`\\[apply-macro-to-region-lines]' to build the table from the names. +" + (interactive "r") + (or macro + (progn + (if (null last-kbd-macro) + (error "No keyboard macro has been defined.")) + (setq macro last-kbd-macro))) + (save-excursion + (let ((end-marker (progn + (goto-char bottom) + (beginning-of-line) + (point-marker))) + next-line-marker) + (goto-char top) + (if (not (bolp)) + (forward-line 1)) + (setq next-line-marker (point-marker)) + (while (< next-line-marker end-marker) + (goto-char next-line-marker) + (save-excursion + (forward-line 1) + (set-marker next-line-marker (point))) + (save-excursion + (execute-kbd-macro (or macro last-kbd-macro)))) + (set-marker end-marker nil) + (set-marker next-line-marker nil)))) + +;;; macros.el ends here