comparison lisp/tempo.el @ 12321:35899872cb3f

Documented the `l' tag. (tempo-insert-template): Check for zmacs-regions. Wrapped it in unwind-protect. (tempo-save-named): New function. (tempo-insert-prompt): Added NO-INSERT parameter. Handles previous values better. Cleaned up interface. Check for already saved value. (tempo-remember-insertion): Function deleted. (tempo-insert-named): Use tempo-insert if data is not a string. Use tempo-lookup-named. (tempo-insert-prompt-compat): New function. (tempo-lookup-named): New function.
author Richard M. Stallman <rms@gnu.org>
date Mon, 19 Jun 1995 21:27:06 +0000
parents e6bdaaa6ce1b
children 5364f0b969f3
comparison
equal deleted inserted replaced
12320:979836b1a1a9 12321:35899872cb3f
1 ;;; tempo.el --- Flexible template insertion 1 ;;; tempo.el --- Flexible template insertion
2 ;; Copyright (C) 1994, 1995 Free Software Foundation, Inc. 2 ;; Copyright (C) 1994, 1995 Free Software Foundation, Inc.
3 3
4 ;; Author: David K}gedal <davidk@lysator.liu.se > 4 ;; Author: David K}gedal <davidk@lysator.liu.se >
5 ;; Created: 16 Feb 1994 5 ;; Created: 16 Feb 1994
6 ;; Version: 1.2.2 6 ;; K}gedal's last version number: 1.2.3
7 ;; Keywords: extensions, languages, tools 7 ;; Keywords: extensions, languages, tools
8 ;; $Revision: 1.7 $
9 8
10 ;; This file is part of GNU Emacs. 9 ;; This file is part of GNU Emacs.
11 10
12 ;; GNU Emacs is free software; you can redistribute it and/or modify 11 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by 12 ;; it under the terms of the GNU General Public License as published by
73 ;; interactive function that inserts the template at the point. 72 ;; interactive function that inserts the template at the point.
74 73
75 ;; The latest tempo.el distribution can be fetched from 74 ;; The latest tempo.el distribution can be fetched from
76 ;; ftp.lysator.liu.se in the directory /pub/emacs 75 ;; ftp.lysator.liu.se in the directory /pub/emacs
77 76
77 ;; There is also a WWW page at
78 ;; http://www.lysator.liu.se/~davidk/elisp/ which has some information
79
78 ;;; Known bugs: 80 ;;; Known bugs:
79 81
80 ;; If the 'o is the first element in a template, strange things can 82 ;; If the 'o is the first element in a template, strange things can
81 ;; happen when the template is inserted at the beginning of a 83 ;; happen when the template is inserted at the beginning of a
82 ;; line. This is due to strange behaviour in open-line. But it should 84 ;; line. This is due to strange behaviour in open-line. But it should
130 132
131 ;;; Internal variables 133 ;;; Internal variables
132 134
133 (defvar tempo-insert-string-functions nil 135 (defvar tempo-insert-string-functions nil
134 "List of functions to run when inserting a string. 136 "List of functions to run when inserting a string.
135 Each function is called with a single arg, STRING." ) 137 Each function is called with a single arg, STRING and should return
138 another string. This could be used for making all strings upcase by
139 setting it to '(upcase), for example.")
136 140
137 (defvar tempo-tags nil 141 (defvar tempo-tags nil
138 "An association list with tags and corresponding templates") 142 "An association list with tags and corresponding templates")
139 143
140 (defvar tempo-local-tags '((tempo-tags . nil)) 144 (defvar tempo-local-tags '((tempo-tags . nil))
237 - A string. It is sent to the hooks in `tempo-insert-string-functions', 241 - A string. It is sent to the hooks in `tempo-insert-string-functions',
238 and the result is inserted. 242 and the result is inserted.
239 - The symbol 'p. This position is saved in `tempo-marks'. 243 - The symbol 'p. This position is saved in `tempo-marks'.
240 - The symbol 'r. If `tempo-insert' is called with ON-REGION non-nil 244 - The symbol 'r. If `tempo-insert' is called with ON-REGION non-nil
241 the current region is placed here. Otherwise it works like 'p. 245 the current region is placed here. Otherwise it works like 'p.
242 - (p PROMPT <NAME>) If `tempo-interactive' is non-nil, the user is 246 - (p PROMPT <NAME> <NOINSERT>) If `tempo-interactive' is non-nil, the
243 prompted in the minbuffer with PROMPT for a string to be inserted. 247 user is prompted in the minbuffer with PROMPT for a string to be
244 If the optional parameter NAME is non-nil, the text is saved for 248 inserted. If the optional parameter NAME is non-nil, the text is
245 later insertion with the `s' tag. 249 saved for later insertion with the `s' tag. If there already is
246 If `tempo-interactive' is nil, it works like 'p. 250 something saved under NAME that value is used instead and no
247 - (r PROMPT) like the previous, but if `tempo-interactive' is nil 251 prompting is made. If NOINSERT is provided and non-nil, nothing is
248 and `tempo-insert' is called with ON-REGION non-nil, the current 252 inserted, but text is still saved when a NAME is provided. For
249 region is placed here. This usually happens when you call the 253 clarity, the symbol 'noinsert should be used as argument.
250 template function with a prefix argument. 254 - (P PROMPT <NAME> <NOINSERT>) Works just like the previous tag, but
255 forces tempo-interactive to be true.
256 - (r PROMPT <NAME> <NOINSERT>) like the previous, but if
257 `tempo-interactive' is nil and `tempo-insert' is called with
258 ON-REGION non-nil, the current region is placed here. This usually
259 happens when you call the template function with a prefix argument.
251 - (s NAME) Inserts text previously read with the (p ..) construct. 260 - (s NAME) Inserts text previously read with the (p ..) construct.
252 Finds the insertion saved under NAME and inserts it. Acts like 'p 261 Finds the insertion saved under NAME and inserts it. Acts like 'p
253 if tempo-interactive is nil. 262 if tempo-interactive is nil.
254 - '& If there is only whitespace between the line start and point, 263 - '& If there is only whitespace between the line start and point,
255 nothing happens. Otherwise a newline is inserted. 264 nothing happens. Otherwise a newline is inserted.
257 nothing happens. Otherwise a newline is inserted. 266 nothing happens. Otherwise a newline is inserted.
258 - 'n inserts a newline. 267 - 'n inserts a newline.
259 - '> The line is indented using `indent-according-to-mode'. Note that 268 - '> The line is indented using `indent-according-to-mode'. Note that
260 you often should place this item after the text you want on the 269 you often should place this item after the text you want on the
261 line. 270 line.
271 - 'r> Like r, but it also indents the region.
262 - 'n> Inserts a newline and indents line. 272 - 'n> Inserts a newline and indents line.
263 - 'o Like '% but leaves the point before the newline. 273 - 'o Like '% but leaves the point before the newline.
264 - nil. It is ignored. 274 - nil. It is ignored.
265 - Anything else. It is evaluated and the result is parsed again." 275 - Anything else. It is evaluated and the result is treated as an
276 element to be inserted. One additional tag is useful for these
277 cases. If an expression returns a list '(l foo bar), the elements
278 after 'l will be inserted according to the usual rules. This makes
279 it possible to return several elements from one expression."
266 280
267 (let* ((template-name (intern (concat "tempo-template-" 281 (let* ((template-name (intern (concat "tempo-template-"
268 name))) 282 name)))
269 (command-name template-name)) 283 (command-name template-name))
270 (set template-name elements) 284 (set template-name elements)
286 (defun tempo-insert-template (template on-region) 300 (defun tempo-insert-template (template on-region)
287 "Insert a template. 301 "Insert a template.
288 TEMPLATE is the template to be inserted. If ON-REGION is non-nil the 302 TEMPLATE is the template to be inserted. If ON-REGION is non-nil the
289 `r' elements are replaced with the current region. In Transient Mark 303 `r' elements are replaced with the current region. In Transient Mark
290 mode, ON-REGION is ignored and assumed true if the region is active." 304 mode, ON-REGION is ignored and assumed true if the region is active."
291 (if (and (boundp 'transient-mark-mode) 305 (unwind-protect
292 transient-mark-mode 306 (progn
293 mark-active) 307 (if (or (and (boundp 'transient-mark-mode) ; For XEmacs
294 (setq on-region t)) 308 transient-mark-mode
295 (and on-region 309 mark-active)
296 (set-marker tempo-region-start (min (mark) (point))) 310 (and (boundp 'zmacs-regions) ; For Emacs
297 (set-marker tempo-region-stop (max (mark) (point)))) 311 zmacs-regions (mark)))
298 (if on-region 312 (setq on-region t))
299 (goto-char tempo-region-start)) 313 (and on-region
300 (save-excursion 314 (set-marker tempo-region-start (min (mark) (point)))
301 (tempo-insert-mark (point-marker)) 315 (set-marker tempo-region-stop (max (mark) (point))))
302 (mapcar (function (lambda (elt) 316 (if on-region
303 (tempo-insert elt on-region))) 317 (goto-char tempo-region-start))
304 (symbol-value template)) 318 (save-excursion
305 (tempo-insert-mark (point-marker))) 319 (tempo-insert-mark (point-marker))
306 (tempo-forward-mark) 320 (mapcar (function (lambda (elt)
307 (tempo-forget-insertions) 321 (tempo-insert elt on-region)))
308 (and (boundp 'transient-mark-mode) 322 (symbol-value template))
309 transient-mark-mode 323 (tempo-insert-mark (point-marker)))
310 (deactivate-mark))) 324 (tempo-forward-mark))
325 (tempo-forget-insertions)
326 ;; Should I check for zmacs here too???
327 (and (boundp 'transient-mark-mode)
328 transient-mark-mode
329 (deactivate-mark))))
311 330
312 ;;; 331 ;;;
313 ;;; tempo-insert 332 ;;; tempo-insert
314 333
315 (defun tempo-insert (element on-region) 334 (defun tempo-insert (element on-region)
318 elements are replaced with the current region. 337 elements are replaced with the current region.
319 338
320 See documentation for `tempo-define-template' for the kind of elements 339 See documentation for `tempo-define-template' for the kind of elements
321 possible." 340 possible."
322 (cond ((stringp element) (tempo-process-and-insert-string element)) 341 (cond ((stringp element) (tempo-process-and-insert-string element))
323 ((and (consp element) (eq (car element) 'p)) 342 ((and (consp element)
324 (tempo-insert-prompt (cdr element))) 343 (eq (car element) 'p)) (tempo-insert-prompt-compat
325 ((and (consp element) (eq (car element) 'P)) 344 (cdr element)))
326 (let ((tempo-interactive t)) 345 ((and (consp element)
327 (tempo-insert-prompt (cdr element)))) 346 (eq (car element) 'P)) (let ((tempo-interactive t))
328 ((and (consp element) (eq (car element) 'r)) 347 (tempo-insert-prompt-compat
329 (if on-region 348 (cdr element))))
330 (goto-char tempo-region-stop) 349 ;;; ((and (consp element)
331 (tempo-insert-prompt (cdr element)))) 350 ;;; (eq (car element) 'v)) (tempo-save-named
332 ((and (consp element) (eq (car element) 's)) 351 ;;; (nth 1 element)
333 (tempo-insert-named (car (cdr element)))) 352 ;;; nil
334 ((and (consp element) (eq (car element) 'l)) 353 ;;; (nth 2 element)))
335 (mapcar (function (lambda (elt) (tempo-insert elt on-region))) 354 ((and (consp element)
336 (cdr element))) 355 (eq (car element) 'r)) (if on-region
356 (goto-char tempo-region-stop)
357 (tempo-insert-prompt-compat
358 (cdr element))))
359 ((and (consp element)
360 (eq (car element) 's)) (tempo-insert-named (car (cdr element))))
361 ((and (consp element)
362 (eq (car element) 'l)) (mapcar (function
363 (lambda (elt)
364 (tempo-insert elt on-region)))
365 (cdr element)))
337 ((eq element 'p) (tempo-insert-mark (point-marker))) 366 ((eq element 'p) (tempo-insert-mark (point-marker)))
338 ((eq element 'r) (if on-region 367 ((eq element 'r) (if on-region
339 (goto-char tempo-region-stop) 368 (goto-char tempo-region-stop)
340 (tempo-insert-mark (point-marker)))) 369 (tempo-insert-mark (point-marker))))
341 ((eq element 'r>) (if on-region 370 ((eq element 'r>) (if on-region
371 on-region)))) 400 on-region))))
372 401
373 ;;; 402 ;;;
374 ;;; tempo-insert-prompt 403 ;;; tempo-insert-prompt
375 404
376 (defun tempo-insert-prompt (prompt) 405 (defun tempo-insert-prompt-compat (prompt)
406 "Compatibility hack for tempo-insert-prompt.
407 PROMPT can be either a prompt string, or a list of arguments to
408 tempo-insert-prompt, or nil."
409 (if (consp prompt) ; not NIL either
410 (apply 'tempo-insert-prompt prompt)
411 (tempo-insert-prompt prompt)))
412
413 (defun tempo-insert-prompt (prompt &optional save-name no-insert)
377 "Prompt for a text string and insert it in the current buffer. 414 "Prompt for a text string and insert it in the current buffer.
378 If the variable `tempo-interactive' is non-nil the user is prompted 415 If the variable `tempo-interactive' is non-nil the user is prompted
379 for a string in the minibuffer, which is then inserted in the current 416 for a string in the minibuffer, which is then inserted in the current
380 buffer. If `tempo-interactive' is nil, the current point is placed on 417 buffer. If `tempo-interactive' is nil, the current point is placed on
381 `tempo-mark'. 418 `tempo-mark'.
382 419
383 PROMPT is the prompt string or a list containing the prompt string and 420 PROMPT is the prompt string, SAVE-NAME is a name to save the inserted
384 a name to save the inserted text under." 421 text under. If the optional argument NO-INSERT is non-nil, no text i
385 (if tempo-interactive 422 inserted. This can be useful when there is a SAVE-NAME.
386 (let ((prompt-string (if (listp prompt) 423
387 (car prompt) 424 If there already is a value for SAVE-NAME, it is used and the user is
388 prompt)) 425 never prompted."
389 (save-name (and (listp prompt) (nth 1 prompt))) 426 (let (insertion
390 inserted-text) 427 (previous (and save-name
391 428 (tempo-lookup-named save-name))))
392 (progn 429 (cond
393 (setq inserted-text (read-string prompt-string)) 430 ;; Insert previous value, unless no-insert is non-nil
394 (insert inserted-text) 431 ((and previous
395 (if save-name 432 (not no-insert))
396 (tempo-remember-insertion save-name inserted-text)))) 433 (tempo-insert-named save-name)) ; A double lookup here, but who
397 (tempo-insert-mark (point-marker)))) 434 ; cares
435 ;; If no-insert is non-nil, don't insert the previous value. Just
436 ;; keep it
437 (previous
438 nil)
439 ;; No previous value. Prompt or insert mark
440 (tempo-interactive
441 (if (not (stringp prompt))
442 (error "tempo: The prompt (%s) is not a string" prompt))
443 (setq insertion (read-string prompt))
444 (or no-insert
445 (insert insertion))
446 (if save-name
447 (tempo-save-named save-name insertion)))
448 (t
449 (tempo-insert-mark (point-marker))))))
398 450
399 ;;; 451 ;;;
400 ;;; tempo-is-user-element 452 ;;; tempo-is-user-element
401 453
402 (defun tempo-is-user-element (element) 454 (defun tempo-is-user-element (element)
409 (if result (throw 'found result))))) 461 (if result (throw 'found result)))))
410 tempo-user-elements) 462 tempo-user-elements)
411 (throw 'found nil))) 463 (throw 'found nil)))
412 464
413 ;;; 465 ;;;
414 ;;; tempo-remember-insertion
415
416 (defun tempo-remember-insertion (save-name string)
417 "Save the text in STRING under the name SAVE-NAME for later retrieval."
418 (setq tempo-named-insertions (cons (cons save-name string)
419 tempo-named-insertions)))
420
421 ;;;
422 ;;; tempo-forget-insertions 466 ;;; tempo-forget-insertions
423 467
424 (defun tempo-forget-insertions () 468 (defun tempo-forget-insertions ()
425 "Forget all the saved named insertions." 469 "Forget all the saved named insertions."
426 (setq tempo-named-insertions nil)) 470 (setq tempo-named-insertions nil))
427 471
428 ;;; 472 ;;;
473 ;;; tempo-save-named
474
475 (defun tempo-save-named (name data) ; Had an optional prompt for 'v
476 "Save some data for later insertion
477 The contents of DATA is saved under the name NAME.
478
479 The data can later be retrieved with `tempo-lookup-named'.
480
481 This function returns nil, so it can be used in a template without
482 inserting anything."
483 (setq tempo-named-insertions
484 (cons (cons name data)
485 tempo-named-insertions))
486 nil)
487
488 ;;;
489 ;;; tempo-lookup-named
490
491 (defun tempo-lookup-named (name)
492 "Lookup some saved data under the name NAME.
493 Returns the data if NAME was found, and nil otherwise."
494 (cdr (assq name tempo-named-insertions)))
495
496 ;;;
429 ;;; tempo-insert-named 497 ;;; tempo-insert-named
430 498
431 (defun tempo-insert-named (name) 499 (defun tempo-insert-named (name)
432 "Insert the previous insertion saved under a named specified in NAME. 500 "Insert the previous insertion saved under a named specified in NAME.
433 If there is no such name saved, a tempo mark is inserted." 501 If there is no such name saved, a tempo mark is inserted.
434 (let* ((insertion (cdr (assq name tempo-named-insertions)))) 502
435 (if insertion 503 Note that if the data is a string, it will not be run through the string
436 (insert insertion) 504 processor."
437 (tempo-insert-mark (point-marker))))) 505 (let* ((insertion (tempo-lookup-named name)))
506 (cond ((null insertion)
507 (tempo-insert-mark (point-marker)))
508 ((stringp insertion)
509 (insert insertion))
510 (t
511 (tempo-insert insertion nil)))))
512
438 513
439 ;;; 514 ;;;
440 ;;; tempo-process-and-insert-string 515 ;;; tempo-process-and-insert-string
441 516
442 (defun tempo-process-and-insert-string (string) 517 (defun tempo-process-and-insert-string (string)