diff --git a/snippet.el b/snippet.el index 8b00def..864bea5 100644 --- a/snippet.el +++ b/snippet.el @@ -19,6 +19,66 @@ ;; along with this program. If not, see . ;;; Commentary: +;; The yasnippet snippet insertion and navigation engine, though very powerful, +;; is bloated and its implementation much contrived. +;; +;; snippet.el's main goal is to provide yasnippet and other snippet-managing +;; frontends with the bare minimum funcionality to define, insert, navigate and +;; undo snippets. +;; +;; Snippets are defined via the `define-snippet' and `make-snippet' +;; entrypoints.The snippet definition syntax is as powerful as yasnippet's +;; (inspired by textmate's). Since the syntax is now sexp-based, snippets +;; definitions are easily manipulated and generated by macros. +;; +;; Another improvement is that `define-snippet' calls can be now be `edebug'ed +;; and stepped through on snippet insertion and navigation. +;; +;; Once inserted into a buffer, snippets are navigated using +;; `snippet-next-field' and `snippet-prev-field', bound to TAB and S-TAB by +;; default. +;; +;; There is a PROPERTIES argument, unimplemented at time of writing, in the +;; `define-snippet' macro which will *probably* understand a set of properties +;; controlling snippet's indentation, custom keymapping and other per-snippet +;; characteristics affecting snippet.el's core functionality. +;; +;; Funcionality such as snippet management, mode management, tab-trigerring or +;; any other fanciness are *not* offered. `define-snippet's PROPERTIES +;; mechanism *might* become extensible to provide frontends such as yasnippet +;; the capability to conveniently implement said fanciness. +;; +;; TODO: indentation +;; +;; TODO: undo, specifically snippet revival +;; +;; TODO: more documentation +;; +;; TODO: "protection overlays" or some robust mechanism preventing the use from +;; inadvertenly destroying the snippet's structure and leaving its +;; incoherent carcass behind. Alternatively, detect this and exit the +;; snippet beforehand. +;; +;; TODO: primary field transformations: the (&transform ...) option to &field +;; constructs. +;; +;; TODO: (&exit ...) constructs with a default string should leave it marked and +;; highlighted in the buffer on snippet-exit. Yasnippet tried, but does +;; not support this correctly. +;; +;; TODO: stacked insertion, aka snippet-in-snippet: the ability to expand a +;; second snippet while navigating a snippet's field, and returning to the +;; original field after exiting the second snippet. +;; +;; TODO: sub-snippets: the ability to insert navigable sub-snippets into a +;; snippet definition by chaining them to the adjoining objects. Yasnippet +;; does not provide this. Might become a (&snippet ...) construct to +;; `define-snippet'. +;; +;; TODO: dynamic fields: the ability dinamically add snippet fields and mirrors +;; to the snippet currently being navigated. Yasnippet does not provide +;; this and seems hard to do. Might become obsolete if stacked insertion +;; and primary field transformations are implemented nicely. ;; ;;; Code: @@ -58,7 +118,7 @@ (`(&eval ,_) form) (`(&eval . ,_) - (error "provide only one form after &eval in %S" form)) + (error "Provide only one form after &eval in %S" form)) (`(&mirror ,name) `(&mirror ,name (&transform field-string))) (`(&mirror ,_ (&transform ,_)) @@ -66,10 +126,10 @@ (`(&field ,_ (,(or `&transform `&eval) ,_)) form) (`(,(or `&mirror `&field) ,_ (,(or `&transform `&eval) ,_ . (,extra))) - (error "expected one form after &eval or &transform in %S, you have %d" + (error "Expected one form after &eval or &transform in %S, you have %d" form (1+ (length extra)))) (`(,(or `&mirror `&field) ,name ,_ . (,extra)) - (error "expected one form after '%S' in %S, you have %d" + (error "Expected one form after '%S' in %S, you have %d" name form (1+ (length extra)))) (`(&field ,name (&nested . ,more-forms)) @@ -90,7 +150,7 @@ ((pred consp) `(&eval ,form)) (t - (error "invalid snippet form %s" form)))) + (error "Invalid snippet form %s" form)))) (defun snippet--unfold-forms (forms &optional parent-sym) (cl-loop for form in forms @@ -102,7 +162,8 @@ (snippet--make-field-sym name)))))) (defun snippet--define-body (body) - "Does the actual work for `define-snippet'" + "Does the actual work for `define-snippet'. +Argument BODY is a list of forms as described in `define-snippet'." (let ((unfolded (snippet--unfold-forms (mapcar #'snippet--canonicalize-form body))) all-objects exit-object) @@ -142,7 +203,7 @@ ',transform)))) (`(&exit (&eval ,form) (&parent ,parent)) (when exit-object - (error "too many &exit forms given")) + (error "Too many &exit forms given")) (setq sym (snippet--make-exit-sym) exit-object sym) `((,sym (snippet--make-and-insert-exit @@ -164,7 +225,7 @@ (snippet--activate-snippet (list ,@all-objects)))))) -(cl-defmacro define-snippet (name () &rest snippet-forms) +(cl-defmacro define-snippet (name (&rest properties) &rest snippet-forms) "Define NAME as a snippet-inserting function. NAME's function definition is set to a function with no arguments @@ -223,8 +284,8 @@ empty string. If the form CONSTANT returns nil or the empty string, it is considered to have returned a single whitespace. -ARGS is an even-numbered property list of (KEY VAL) pairs. Its -meaning is not decided yet" +PROPERTIES is an even-numbered property list of (KEY VAL) +pairs. Its meaning is not decided yet" (declare (debug (&define name sexp &rest snippet-form))) `(defun ,name () ,(snippet--define-body snippet-forms))) @@ -236,7 +297,8 @@ meaning is not decided yet" def-form)) (defun make-snippet (forms) - "Same as `define-snippet', but return an anonymous function." + "Same as `define-snippet', but return an anonymous function. +Argument FORMS is a list of forms as described in `define-snippet'." `(lambda () ,(snippet--define-body forms))) @@ -456,6 +518,11 @@ meaning is not decided yet" (snippet--field-modified-p parent)))) (defun snippet-next-field (&optional prev) + "Move to the start of next field in the current snippet. + +Skips over nested fields if their parent has been modified. + +PREV means move to the previous field." (interactive) (let* ((field (overlay-get snippet--field-overlay 'snippet--field)) (sorted (overlay-get snippet--field-overlay 'snippet--fields)) @@ -474,6 +541,9 @@ meaning is not decided yet" (snippet-exit-snippet)))) (defun snippet-prev-field () + "Move the the start of the previous field in the current snippet. + +Skips over nested fields if their parent has been modified." (interactive) (snippet-next-field t)) @@ -604,4 +674,5 @@ meaning is not decided yet" ;; whitespace-line-column: 80 ;; fill-column: 80 ;; End: + ;; snippet.el ends here