tempo.el: Templates

Die Dokumentation steckt im wesentlichen in lisp/tempo.el; dort wird auf http://www.lysator.liu.se/~davidk/elisp/ verwiesen.

Mit tempo.el ist es möglich, intelligente Textbausteine zu schreiben. Das folgende Beispiel erstellt das Template tempo-template-anrede, welches mit M-x tempo-template-anrede aufgerufen werden kann.

(require 'tempo)
(tempo-define-template "anrede"
                       '((if (y-or-n-p "Herr? ")
                             "Sehr geehrter Herr "
                           "Sehr verehrte Frau ") p "," n n
                           "Ihre Anfrage vom " p " habe ich dankend erhalten." n))

tempo-template-anrede fragt nach Herr/Frau und fügt den Beginn eines Schreibens ein. Dabei wird der Point (Cursor) auf den ersten point of interest (= p) gesetzt; in diesem Fall also vor das Komma. Mit M-x tempo-forward-mark geht man dann zum nächsten point of interest, dem p nach "Anfrage vom".

Die n-Buchstaben stehen übrigens für Newline (neue Zeile).

Dies kann mit dem Einfügen des aktuellen Datums kombiniert und auf die Tastenkombination C-c a gelegt werden:

(tempo-define-template "anrede"
                       '((make-string 50 ? ) "Nürnberg, den "
                          (format-time-string "%Y-%m-%d") n n
                         (if (y-or-n-p "Herr? ")
                             "Sehr geehrter Herr "
                           "Sehr verehrte Frau ") p "," n n
                           "Ihre Anfrage vom " p " habe ich dankend erhalten." n))

(global-set-key (kbd "C-c a") 'tempo-template-anrede)

Für Tastatur-Liebhaber, um von einem point zum nächsten mit Control-Tab bzw. mit Control-Shift-Tab wieder zurück zu springen:

(global-set-key [C-tab] 'tempo-forward-mark)
(global-set-key [S-C-tab] 'tempo-backward-mark)
;; for now, these are needed:
(global-set-key [S-iso-lefttab] 'tempo-backward-mark)
(global-set-key [C-S-iso-lefttab] 'tempo-backward-mark)

Bisweilen ist es schön, wenn man gleich im Minibuffer nach dem einzufügenden Wert gefragt wird:

(tempo-define-template "erdbeeren"
                       '("\
Wie bestellt, lasse ich Ihnen " (P "Erdbeeren (kg): ") " kg Erdbeeren liefern." n))

(global-set-key (kbd "C-c e") 'tempo-template-erdbeeren)

Oder man merkt sich die Eingabe zunächst, um dann alles in einem Rutsch in den Emacs-Puffer einfügen zu lassen:

(tempo-define-template "erdbeeren"
                       '((P "Erdbeeren (kg): " menge 'noinsert) "\
Wie bestellt, lasse ich Ihnen " (s menge) " kg Erdbeeren liefern." n))

(global-set-key (kbd "C-c e") 'tempo-template-erdbeeren)

Nun ist es an der Zeit, auf die weiteren Elemente hinzuweisen, die vorkommen können:

tempo-define-template is a compiled Lisp function in `tempo'.
(tempo-define-template NAME ELEMENTS &optional TAG DOCUMENTATION TAGLIST)

Define a template.
This function creates a template variable `tempo-template-NAME' and an
interactive function `tempo-template-NAME' that inserts the template
at the point.  The created function is returned.

NAME is a string that contains the name of the template, ELEMENTS is a
list of elements in the template, TAG is the tag used for completion,
DOCUMENTATION is the documentation string for the insertion command
created, and TAGLIST (a symbol) is the tag list that TAG (if provided)
should be added to).  If TAGLIST is nil and TAG is non-nil, TAG is
added to `tempo-tags'

The elements in ELEMENTS can be of several types:

 - A string. It is sent to the hooks in `tempo-insert-string-functions',
   and the result is inserted.
 - The symbol 'p. This position is saved in `tempo-marks'.
 - The symbol 'r. If `tempo-insert' is called with ON-REGION non-nil
   the current region is placed here. Otherwise it works like 'p.
 - (p PROMPT <NAME> <NOINSERT>) If `tempo-interactive' is non-nil, the
   user is prompted in the minbuffer with PROMPT for a string to be
   inserted. If the optional parameter NAME is non-nil, the text is
   saved for later insertion with the `s' tag. If there already is
   something saved under NAME that value is used instead and no
   prompting is made. If NOINSERT is provided and non-nil, nothing is
   inserted, but text is still saved when a NAME is provided. For
   clarity, the symbol 'noinsert should be used as argument.
 - (P PROMPT <NAME> <NOINSERT>) Works just like the previous tag, but
   forces tempo-interactive to be true.
 - (r PROMPT <NAME> <NOINSERT>) like the previous, but if
   `tempo-interactive' is nil and `tempo-insert' is called with
   ON-REGION non-nil, the current region is placed here. This usually
   happens when you call the template function with a prefix argument.
 - (s NAME) Inserts text previously read with the (p ..) construct.
   Finds the insertion saved under NAME and inserts it. Acts like 'p
   if tempo-interactive is nil.
 - '& If there is only whitespace between the line start and point,
   nothing happens. Otherwise a newline is inserted.
 - '% If there is only whitespace between point and end-of-line
   nothing happens. Otherwise a newline is inserted.
 - 'n inserts a newline.
 - '> The line is indented using `indent-according-to-mode'. Note that
   you often should place this item after the text you want on the
   line.
 - 'r> Like r, but it also indents the region.
 - 'n> Inserts a newline and indents line.
 - 'o Like '% but leaves the point before the newline.
 - nil. It is ignored.
 - Anything else. It is evaluated and the result is treated as an
   element to be inserted. One additional tag is useful for these
   cases. If an expression returns a list '(l foo bar), the elements
   after 'l will be inserted according to the usual rules. This makes
   it possible to return several elements from one expression.

Oder so, wenn man gleich ein wenig rechnen muss (aber das führt nun doch vom eigentlichen Thema ab, da diese Lösung nichts mehr mit tempo.el zu tun hat):

(defun template-erdbeeren (menge)
  "`menge' Erdbeeren einfügen und berechnen, das kg zu DM 5.55."
  (interactive "*nErdbeeren (kg): ")
  (insert "\
Wie bestellt, erhalten Sie " (number-to-string menge) " kg Erdbeeren.
Der Preis beträgt insgesamt DM "
(substring (format "%-02f" (* 5.55 menge)) 0 -4) ".\n" ))

(global-set-key (kbd "C-c e") 'template-erdbeeren)