Internal documentation overhaul. Still unfinished.

This commit is contained in:
João Távora 2015-04-05 13:51:18 +01:00
parent ad2bb8bed1
commit 73f208d6d5

View File

@ -48,6 +48,11 @@
;; mechanism *might* become extensible to provide frontends such as yasnippet ;; mechanism *might* become extensible to provide frontends such as yasnippet
;; the capability to conveniently implement said fanciness. ;; the capability to conveniently implement said fanciness.
;; ;;
;; TODO: primary field transformations: the (&transform ...) option to &field
;; constructs. In `define-dynamic-snippet', mirror forms should only be
;; evaluated for value. &exit should be generalized to also allow nested
;; fields.
;;
;; TODO: auto-indentation of the inserted snippet ;; TODO: auto-indentation of the inserted snippet
;; ;;
;; TODO: there should be somewhere a PROPERTIES argument, unimplemented at time ;; TODO: there should be somewhere a PROPERTIES argument, unimplemented at time
@ -59,9 +64,6 @@
;; ;;
;; TODO: more documentation ;; TODO: more documentation
;; ;;
;; TODO: primary field transformations: the (&transform ...) option to &field
;; constructs.
;;
;; TODO: (&exit ...) constructs with a default string should leave it marked and ;; TODO: (&exit ...) constructs with a default string should leave it marked and
;; highlighted in the buffer on snippet-exit. Yasnippet tried, but does ;; highlighted in the buffer on snippet-exit. Yasnippet tried, but does
;; not support this correctly. ;; not support this correctly.
@ -240,60 +242,71 @@ As `define-static-snippet' but doesn't define a function."
(defmacro define-static-snippet (name _properties &optional docstring (defmacro define-static-snippet (name _properties &optional docstring
&rest snippet-forms) &rest snippet-forms)
"Define NAME as a snippet-inserting function. "Define NAME as an interactive snippet-inserting function.
Each form in SNIPPET-FORMS, inserted at point in order, can be: Each form in SNIPPET-FORMS, inserted at point in order, can be:
* A cons (&field FIELD-NAME FIELD-DEFAULT) definining a snippet * A cons (&field [FIELD-NAME [FIELD-DEFAULT]]) definining a snippet
field. A snippet field can be navigated to using field. Snippet fields can be edited and be navigated to using
`snippet-next-field' and `snippet-prev-field'. FIELD-NAME is `snippet-next-field' and `snippet-prev-field'. FIELD-NAME is
optional and used for referring to the field in mirror optional and used for referring to the field in mirror
transforms. FIELD-DEFAULT is also optional and used for transforms.
producing a string that populates the field's default value at
snippet-insertion time.
FIELD-DEFAULT can thus be a string literal, a lisp form FIELD-DEFAULT is optional and determines the field's starting
returning a string, or have the form (&nested SUB-FORM ...) text. It can be any lisp form returning a string or have be a cons
where each SUB-FORM is evaluated recursively according to the (&transform FIELD-TRANSFORM) where FIELD-TRANSFORM is again a
rules of SNIPPET-FORMS. lisp form returning a string. Choosing between these varieties
defines when and how these forms are evaluated. See below for
details.
FIELD-DEFAULT can additionally also be (&transform FIELD-DEFAULT can also be a cons (&nested SUB-FORMS) where each
FIELD-TRANSFORM) in which case the string value produced by form in SUB-FORMS is evaluated recursively according to the
FIELD-TRANSFORM is used for populating not only the field's rules of SNIPPET-FORMS, thus producing nested fields and
default value, but also the field's value after each command mirrors.
while the snippet is alive.
* A cons (&mirror FIELD-NAME MIRROR-TRANSFORM) defining a mirror * A cons (&mirror FIELD-NAME [MIRROR-TRANSFORM]) defining a mirror
of the field named FIELD-NAME. MIRROR-TRANSFORM is an optional of the field named FIELD-NAME. MIRROR-TRANSFORM is an optional
form, called after each command while the snippet is alive to form producing a string that becomes the mirror text. If it is
produce a string that becomes the mirror text. not provided the mirror's text always matches FIELD-NAME's.
* A string literal or a lisp form, call it CONSTANT, evaluated at * Any lisp form producing a string, call it CONSTANT, that is a
snippet-insertion time and producing a string that is a part of part of the snippet but constant while the snippet is alive.
the snippet but constant while the snippet is alive.
* A form (&exit EXIT-DEFAULT), defining the point within the * A cons (&exit [EXIT-DEFAULT]), defining a special field within
snippet where point should be placed when the snippet is the snippet where point should be placed when the snippet is
exited. EXIT-DEFAULT is optional and is evaluated at exited normally. EXIT-DEFAULT has the same semantics as
snippet-insertion time to produce a string that remains a FIELD-DEFAULT.
constant part of the snippet while it is alive, but is
automatically selected when the snippet is exited.
The forms CONSTANT, FIELD-DEFAULT, MIRROR-TRANSFORM, The forms CONSTANT, FIELD-DEFAULT, MIRROR-TRANSFORM,
FIELD-TRANSFORM and EXIT-DEFAULT are evaluated with the variable FIELD-TRANSFORM and EXIT-DEFAULT are all evaluated at
`region-string' set to the text of the buffer selected at snippet-insertion-time and with the variable `region-string' set
snippet-insertion time. If no region was selected the value of to the text of the buffer selected at snippet-insertion time. If
this variable is the empty string. no region was active the value of this variable is the empty
string.
The forms MIRROR-TRANSFORM and FIELD-TRANSFORM are evaluated with The forms MIRROR-TRANSFORM and FIELD-TRANSFORM are additionally
the variable `field-string' set to the text contained in the also evaluated each time the field is changed. Moreover,
corresponding field. If the field is empty, this variable is the FIELD-TRANSFORM is also evaluated when the field is entered or
empty string and the additional variable `field-empty-p' is t. left. These forms are evaluated with the following variables set:
* `field-string' is set to the text contained in the field;
* `field-left' is non-nil if the field is being left;
* `field-entered' is non-nil if the field is being entered;
* `field-modified-p' is non-nil if the field has ever been modified
since snippet creation
If the form CONSTANT returns nil or the empty string, it is If the form CONSTANT returns nil or the empty string, it is
considered to have returned a single whitespace. If any other considered to have returned a single whitespace.
form returns nil, it is considered to have returned the empty
string. If FIELD-TRANSFORM returns a string, it replaces the fields text,
either at snippet-insertion-time or when the field is being
edited, entered or left. If FIELD-TRANSFORM returns nil at
snippet-insertion-time, it is considered to have returned the
empty string. If it returns nil on any other occasion, the field
is left unchanged.
If any other form returns nil, it is considered to have returned
the empty string.
PROPERTIES is an even-numbered property list of (KEY VAL) PROPERTIES is an even-numbered property list of (KEY VAL)
pairs. Its meaning is not decided yet" pairs. Its meaning is not decided yet"
@ -303,6 +316,7 @@ pairs. Its meaning is not decided yet"
(push docstring snippet-forms) (push docstring snippet-forms)
(setq docstring nil)) (setq docstring nil))
`(defun ,name () ,docstring `(defun ,name () ,docstring
(interactive)
(with-static-snippet ,@snippet-forms))) (with-static-snippet ,@snippet-forms)))
@ -377,13 +391,80 @@ pairs. Its meaning is not decided yet"
(defmacro define-dynamic-snippet (name args &optional docstring &rest body) (defmacro define-dynamic-snippet (name args &optional docstring &rest body)
"Define NAME as a snippet-inserting function.
Inside BODY the following local macros are available to
create snippet fields and mirrors:
* (&field NAME [FIELD-BODY]) declares the start of a snippet
field at point. Snippet fields can be edited and be navigated
to using `snippet-next-field' and
`snippet-prev-field'. FIELD-BODY is a list of lisp forms which
are evaluted for both return value and side-effects: Any text
inserted becomes the field's starting text. If a string is
returned, it is also inserted at the end of the field. Since
FIELD-BODY is evaluated according to the rules of BODY, nested
mirrors and fields become possible. Alternatively, FIELD-BODY
can also be a single form, a cons (&transform
FIELD-TRANSFORM-ARGS FIELD-TRANSFORM). See below for details.
* (&mirror FIELD-NAME [MIRROR-TRANSFORM-ARGS MIRROR-TRANSFORM])
declares the start of a mirror at point. If
MIRROR-TRANSFORM-ARGS and MIRROR-TRANSFORM are ommited the
mirror's text always matches FIELD-NAME'S. If provided,
MIRROR-TRANSFORM-ARGS is a list of 0 to 4 symbols that are
automatically bound to values extracted from the snippet field
FIELD-NAME and that can be used by the single form
MIRROR-TRANSFORM to produce the mirror's text. The values
passed in are, in order:
* a string containing the field's text;
* a boolean indicating if the field has just been entered;
* a boolean indicating if the field has just been left;
* a boolean indicating if the field has ever been modified since
insertion
MIRROR-TRANSFORM can also refer to any lexically available
symbols established in by other forms in BODY.
* (&exit [EXIT-BODY]) declares a special field special within the
snippet where point should be placed when the snippet is exited
normally. EXIT-BODY has the same semantics as FIELD-BODY.
Except for these special cases, forms in BODY are evaluated
normally. If at least one snippet field was declared, a navigable
snippet is inserted at the end.
MIRROR-TRANSFORM is evaluated at snippet-insertion time and each
time the corresponding field changes to produce the mirror's
text. If it returns nil, it is considered to have returned the
empty string.
If FIELD-BODY has the form (&transform FIELD-TRANSFORM-ARGS
FIELD-TRANSFORM), FIELD-TRANSFORM is passed the same parameters
as MIRROR-TRANSFORM, except that at snippet-insertion time, the
value of the first parameter to FIELD-TRANSFORM-ARGS is nil. At
snippet-insertion time the field's starting text should be
produced. If it returns nil, it is considered to have returned
the empty string.
FIELD-TRANSFORM is also called every time the field is edited or
when it is entered or left. It may then return a string replacing
the field's text or return nil to leave it unchanged. If the
field is changed in this manner, any corresponding mirror's
MIRROR-TRANSFORMS are also evaluated at the time."
(declare (debug (&define name sexp def-body)) (declare (debug (&define name sexp def-body))
(indent defun)) (indent defun))
(unless (stringp docstring) (let ((interactive nil))
(push docstring body) (unless (stringp docstring)
(setq docstring nil)) (push docstring body)
`(defun ,name ,args ,docstring (setq docstring nil))
(with-dynamic-snippet ,@body))) (if (eq (car-safe (car body)) 'interactive)
(setq interactive (pop body)))
`(defun ,name ,args ,docstring
,@(when interactive
`(,interactive))
(with-dynamic-snippet ,@body))))
(def-edebug-spec &mirror (sexp &optional sexp &rest form)) (def-edebug-spec &mirror (sexp &optional sexp &rest form))
(def-edebug-spec &field (sexp &rest form)) (def-edebug-spec &field (sexp &rest form))