1 ;;; tinymacro.el --- Fast way to assign newly created macro to a key
3 ;; This file is not part of Emacs
7 ;; Copyright (C) 1995-2007 Jari Aalto
8 ;; Keywords: extensions
10 ;; Maintainer: Jari Aalto
12 ;; To get information on this program, call M-x tinymacro-version.
13 ;; Look at the code with folding.el
17 ;; This program is free software; you can redistribute it and/or modify it
18 ;; under the terms of the GNU General Public License as published by the Free
19 ;; Software Foundation; either version 2 of the License, or (at your option)
22 ;; This program is distributed in the hope that it will be useful, but
23 ;; WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 ;; You should have received a copy of the GNU General Public License
28 ;; along with program; see the file COPYING. If not, write to the
29 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
30 ;; Boston, MA 02110-1301, USA.
32 ;; Visit <http://www.gnu.org/copyleft/gpl.html> for more information
39 ;; ........................................................ &t-install ...
40 ;; Put this file on your Emacs-Lisp load path, add following into your
41 ;; ~/.emacs startup file. Rip code with tinylib.el/ti::package-rip-magic
43 ;; ;; To use default keybinding "C-x(" and "C-x)", add this:
44 ;; (add-hook 'tinymacro-:load-hook 'tinymacro-install-default-keybindings)
45 ;; (require 'tinymacro)
47 ;; or use autoload and your $HOME/.emacs starts faster
49 ;; (global-set-key "\C-x)" 'tinymacro-end-kbd-macro-and-assign)
50 ;; (autoload 'tinymacro-end-kbd-macro-and-assign "tinymacro" "" t)
52 ;; If you have any questions, feedback, use this function
54 ;; M-x tinymacro-submit-bug-report
59 ;; ..................................................... &t-commentary ...
65 ;; This started as a very little project when
66 ;; <mosh@ramanujan.cs.albany.edu> (Mohsin-Ahmed) 1995-03-17 in
67 ;; gnu.emacs.help post asked for easy way to assign newly created
68 ;; macro to some key. In reponse the author sent a simple function to do
69 ;; it, but he informaed that one macro, which was recycled every time,
70 ;; was too little. Author started modifying code more, and that was
71 ;; the birth of this package.
75 ;; o Two keystrokes to make a macro: one to record, one to
77 ;; o To see the macro assignments to keys, just call `tinymacro-macro-info'
78 ;; o Default macro count is 10, increase with `tinymacro-:stack-max'
90 (eval-when-compile (ti::package-use-dynamic-compilation))
92 (ti::package-defgroup-tiny TinyMacro tinymacro-: extensions
93 "Fast way to assign newly created macro to key
96 o Two keystrokes to make a macro: one to record, one to
98 o To see the macro assignments to keys, just call tinymacro-macro-info")
101 ;;{{{ setup: hooks, private
103 (defcustom tinymacro-:macro-assigned-hook nil
104 "*If new macro were asiigned, this hook will be run. The function
105 SYMBOL that was used is in variable tinymacro-:last-macro-func"
109 (defcustom tinymacro-:load-hook nil
110 "*Hook run when file has been loaded."
115 ;;{{{ setup: public, user configurable
117 (defcustom tinymacro-:macro-function-name-prefix "tinymacro--macro"
118 "*The function name prefix to use, when assigning name to last kbd macro"
122 (defcustom tinymacro-:ask-when-stack-wrap-flag nil
123 "*Non-nil means ask user if used function stack wraps."
127 (defcustom tinymacro-:stack-max 10
128 "*Maximum stack depth of unique macronames.
129 The name run from 0..max, and wraps to 0 after max."
133 (defcustom tinymacro-:tmp-buffer "*temp*"
134 "*Temporary buffer. Eg. displaying the macro bindings to keys."
139 ;;{{{ setup: private variables
141 (defvar tinymacro-:stack-ptr 0
142 "Keep record of available stack space.")
144 (defvar tinymacro-:last-macro-func nil
145 "Hold last function SYMBOL that were used in assignment.")
147 (defvar tinymacro-:last-macro-key nil
148 "Hold last key STRING or VECTOR that were used in assignment.")
150 (defvar tinymacro-:function-list nil
151 "List of original KEY -- FUNCTION pairs, whic are currently occupied
157 ;;;###autoload (autoload 'tinymacro-version "tinymacro" "Display commentary." t)
159 (ti::macrof-version-bug-report
162 tinymacro-:version-id
163 "$Id: tinymacro.el,v 2.43 2007/05/01 17:20:50 jaalto Exp $"
164 '(tinymacro-:version-id
166 tinymacro-:last-macro-func
167 tinymacro-:last-macro-key
168 tinymacro-:function-list
169 tinymacro-:macro-assigned-hook
171 tinymacro-:macro-function-name-prefix
172 tinymacro-:ask-when-stack-wrap-flag
174 tinymacro-:tmp-buffer)))
179 ;;; ----------------------------------------------------------------------
181 (defun tinymacro-restore ()
182 "Restores all macro bindings, so that keys that occupy macros
183 are restored to original functions.
186 tinymacro-:function-list list is cleared too."
188 (let* ((list tinymacro-:function-list))
191 (message "TinyMacro: No macros active."))
193 (global-set-key (nth 0 elt) (nth 1 elt)))
194 (setq tinymacro-:function-list nil))))
199 ;;; ----------------------------------------------------------------------
201 (defun tinymacro-create-symbol()
202 "Creates macro variable. Returns NEW or EXISTING SYMBOL."
203 (let* ((max tinymacro-:stack-max)
204 (sp tinymacro-:stack-ptr)
205 (q tinymacro-:ask-when-stack-wrap-flag)
206 (name tinymacro-:macro-function-name-prefix)
211 (< sp max)) ; yes, go ahead with new
212 (setq new (format "%s%d"
214 (if (< sp max) ; 0..max
217 (if (y-or-n-p "Macro stack full, wrap? ")
219 (if (< sp max) ; 0..max
223 (when new ; Must update stack
224 (setq tinymacro-:stack-ptr sp
225 ret (intern-soft new)) ; return symbol
226 (if ret nil ; Already exist
227 ;; a) make it b)s et to nil c) put into ret val
228 (setq sym2 (intern new))
233 ;;; ----------------------------------------------------------------------
235 (defun tinymacro-create-name ()
236 "Creates macro name."
237 (let* ((max tinymacro-:stack-max)
238 (sp tinymacro-:stack-ptr)
239 (q tinymacro-:ask-when-stack-wrap-flag)
240 (n tinymacro-:macro-function-name-prefix)
242 (if (or q (< sp max)) ; yes, go ahead with new
244 (concat n (if (< sp max) ; 0..max
247 (if (y-or-n-p "Macro stack full, wrap? ")
248 (setq new (concat n (if (< sp max) ; 0..max
251 (if new ; Must update stack
252 (setq tinymacro-:stack-ptr sp))
258 ;;; ----------------------------------------------------------------------
260 (defun tinymacro-macro-info ()
261 "Show which macros are assigned to which keys."
263 (let* ((sp tinymacro-:stack-ptr)
264 (max tinymacro-:stack-max)
265 (buf tinymacro-:tmp-buffer)
266 (base tinymacro-:macro-function-name-prefix)
272 (while (< i (1+ max))
273 (setq name (concat base i) i (1+ i) key "")
274 (if (null (intern-soft name)) nil ;not use yet
275 (if (> round 0) nil ;do only once
276 (setq bp (get-buffer-create buf))
277 (set-buffer bp) (erase-buffer)
278 (insert (format "Stack pointer : %d\n" sp )))
279 (if (null (setq key (ti::keymap-function-bind-info (intern name))))
280 (setq key "[??]")) ;should never happen
281 (insert (format "%-10s %s\n" key name))
282 (setq round (1+ round))))
283 (if (and (interactive-p)
285 (message "TinyMacro: No macros bound or set."))
286 (switch-to-buffer-other-window bp)))
288 ;;; ----------------------------------------------------------------------
291 (defun tinymacro-end-kbd-macro-and-assign ()
292 "Terminate reading macro and assign it to key."
295 (call-interactively 'tinymacro-assign))
297 ;;; ----------------------------------------------------------------------
299 (defun tinymacro-install-default-keybindings ()
300 "Install keybinding C-x) to record and assign macro to a key."
302 (global-set-key "\C-x)" 'tinymacro-end-kbd-macro-and-assign)
304 (substitute-command-keys
306 "Tinymacro: command tinymacro-end-kbd-macro-and-assign set to key "
307 "\\[tinymacro-end-kbd-macro-and-assign]"))))
309 ;;; ----------------------------------------------------------------------
312 (defun tinymacro-assign (&optional key verb)
313 "Name last macro and assigns it to user defined KEY.
314 Runs tinymacro-:macro-assigned-hook if key macro gets installed.
315 The query options should be turned off if you call this within
316 function, since it always return nil if the options are on.
320 KEY Should be valid emacs key-bind-sequence/key-vector
321 VERB Boolean, verbose messages
326 nil not assigned `keyboard-quit'"
329 (let* ((f-name "") ;func name
331 macro-name ;our new macro !
332 lookup ;what was found
335 ;; The bullet proof way to find key bind for abort
336 ;; (ti::keymap-function-bind-info 'keyboard-quit global-map)
339 ;; - Or we just say where it is... Nobody relocates it anyway
340 ;; - We use this because function2key does not work in XEmacs
342 (abort-ch (char-to-string ?\007)))
346 (read-key-sequence "Tinymacro: Set last macro to key(s): ")))
347 (if (equal key abort-ch)
350 (message "Tinymacro: Skipping abort key. Not assigned."))
352 ;; Search the key, if it's already assigned
354 (or (and (current-local-map) ;in fundamental-mode this is nil.
355 (lookup-key (current-local-map) key))
356 (lookup-key global-map key) key))
357 ;; ................................................... occupied? ...
359 (if (and (symbolp lookup)
360 (fboundp lookup)) ;just plain function
361 (setq f-name (symbol-name lookup))
362 (setq f-name (prin1-to-string lookup))))
363 ;; ............................................. ask permission? ...
370 "Key already occupied by %s; continue? " f-name))))
371 ;; ................................................ assign macro ...
373 ((and verb (null do-it))
375 (substitute-command-keys
376 "Tinymacro: Cancelled. Use \\[tinymacro-assign] to rebind.")))
378 (setq macro-name (tinymacro-create-symbol))
379 (name-last-kbd-macro macro-name)
381 (when (and (symbolp lookup)
383 (not (string-match "^tim" f-name))
384 (not (assoc key tinymacro-:function-list)))
385 (push (list key lookup) tinymacro-:function-list))
386 (global-set-key key macro-name)
387 (setq tinymacro-:last-macro-func macro-name ;set >> GLOBALS <<
388 tinymacro-:last-macro-key key)
391 "TinyMacro: Created function: %s" (symbol-name macro-name)))
392 (run-hooks 'tinymacro-:macro-assigned-hook)
398 (run-hooks 'tinymacro-:load-hook)
400 ;;; tinymacro.el ends here