From 6b755c952195e70297d7612545c54faea1a49380 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Tue, 28 Feb 2012 01:45:59 +0000 Subject: [PATCH 01/33] need the comma when deferring errors to the future in yas/eval-lisp --- yasnippet.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index 44154c1..594e018 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1240,7 +1240,7 @@ return an expression that when evaluated will issue an error." (condition-case err (read string) (error (and (not nil-on-error) - `(error (error-message-string err)))))) + `(error (error-message-string ,err)))))) (defun yas/read-keybinding (keybinding) "Read KEYBINDING as a snippet keybinding, return a vector." From 3cd8cbdd12e0ac48324e15ab65f676d8901f8bfb Mon Sep 17 00:00:00 2001 From: Le Wang Date: Sun, 4 Mar 2012 12:33:09 +0800 Subject: [PATCH 02/33] clean up trailing white space --- yasnippet.el | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 594e018..80f71cf 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -29,7 +29,7 @@ ;;; Commentary: ;; Basic steps to setup: -;; +;; ;; (add-to-list 'load-path ;; "~/.emacs.d/plugins/yasnippet") ;; (require 'yasnippet) @@ -899,7 +899,7 @@ Do this unless `yas/dont-activate' is truish " keybinding uuid menu-binding-pair - group ;; as dictated by the #group: directive or .yas-make-groups + group ;; as dictated by the #group: directive or .yas-make-groups perm-group ;; as dictated by `yas/define-menu' ) @@ -1051,7 +1051,7 @@ Also takes care of adding and updaring to the associated menu." (yas/delete-from-keymap keymap (yas/template-uuid template)) ;; Add necessary subgroups as necessary. - ;; + ;; (dolist (subgroup group) (let ((subgroup-keymap (lookup-key keymap (vector (make-symbol subgroup))))) (unless (and subgroup-keymap @@ -1060,9 +1060,9 @@ Also takes care of adding and updaring to the associated menu." (define-key keymap (vector (make-symbol subgroup)) `(menu-item ,subgroup ,subgroup-keymap))) (setq keymap subgroup-keymap))) - + ;; Add this entry to the keymap - ;; + ;; (let ((menu-binding-pair (yas/snippet-menu-binding-pair-get-create template))) (define-key keymap (vector (make-symbol (yas/template-uuid template))) (car menu-binding-pair)))))) @@ -1304,7 +1304,7 @@ Guessing is done by looking up the MODE-SYMBOL's (and (not dont-search-parents) (get major-mode 'derived-mode-parent))))))))) - (remove-duplicates + (remove-duplicates (append mode-tables (mapcan #'yas/table-get-all-parents mode-tables))))) @@ -1895,7 +1895,7 @@ not need to be a real mode." "Recursively delete items with UUID from KEYMAP and its submenus." ;; XXX: This used to skip any submenus named \"parent mode\" - ;; + ;; ;; First of all, recursively enter submenus, i.e. the tree is ;; searched depth first so that stale submenus can be found in the ;; higher passes. @@ -1906,10 +1906,10 @@ not need to be a real mode." (yas/delete-from-keymap (third (cdr item)) uuid))) (rest keymap)) ;; Set the uuid entry to nil - ;; + ;; (define-key keymap (vector (make-symbol uuid)) nil) ;; Destructively modify keymap - ;; + ;; (setcdr keymap (delete-if #'(lambda (item) (or (null (cdr item)) (and (keymapp (third (cdr item))) @@ -2394,7 +2394,7 @@ With optional prefix argument KILL quit the window and buffer." ;; neatly positioned,... ;; (yas/editing-template - (yas/define-snippets-1 (yas/parse-template (yas/template-file yas/editing-template)) + (yas/define-snippets-1 (yas/parse-template (yas/template-file yas/editing-template)) (yas/template-table yas/editing-template))) ;; Try to use `yas/guessed-modes'. If we don't have that use the ;; value from `yas/compute-major-mode-and-parents' @@ -2418,7 +2418,7 @@ With optional prefix argument KILL quit the window and buffer." nil (if (first yas/guessed-modes) (symbol-name (first yas/guessed-modes)))))))) - (set (make-local-variable 'yas/editing-template) + (set (make-local-variable 'yas/editing-template) (yas/define-snippets-1 (yas/parse-template buffer-file-name) table))))) ;; Now, offer to save this shit iff: @@ -2435,7 +2435,7 @@ With optional prefix argument KILL quit the window and buffer." (second yas/snippet-dirs) (not (string-match (expand-file-name (first yas/snippet-dirs)) (yas/template-file yas/editing-template))))) - + (when (y-or-n-p "[yas] Looks like a library or new snippet. Save to new file? ") (let* ((option (first (yas/guess-snippet-directories (yas/template-table yas/editing-template)))) (chosen (and option @@ -2564,7 +2564,7 @@ With optional prefix argument KILL quit the window and buffer." (setq group (or (yas/template-fine-group v) "(top level)")) (when (yas/template-name v) - + (aput 'groups-alist group (cons v (aget groups-alist group))))) (yas/table-uuidhash table)) (dolist (group-and-templates groups-alist) @@ -2575,7 +2575,7 @@ With optional prefix argument KILL quit the window and buffer." (let ((name (truncate-string-to-width (propertize (format "\\\\snippet `%s'" (yas/template-name p)) 'yasnippet p) 50 0 ? "...")) - (group (prog1 group + (group (prog1 group (setq group (make-string (length group) ? )))) (condition-string (let ((condition (yas/template-condition p))) (if (and condition @@ -2587,7 +2587,7 @@ With optional prefix argument KILL quit the window and buffer." "(a)")))) (insert group " ") (insert condition-string " ") - (insert name + (insert name (if (string-match "\\.\\.\\.$" name) "'" " ") @@ -2893,7 +2893,7 @@ Also create some protection overlays" (yas/place-overlays snippet field) (overlay-put yas/active-field-overlay 'yas/field field) (let ((number (yas/field-number field))) - ;; check for the special ${0: ...} field + ;; check for the special ${0: ...} field (if (and number (zerop number)) (progn (set-mark (yas/field-end field)) @@ -3008,7 +3008,7 @@ snippet, if so cleans up the whole snippet up." (snippet-exit-transform)) (dolist (snippet snippets) (let ((active-field (yas/snippet-active-field snippet))) - (setq snippet-exit-transform (yas/snippet-force-exit snippet)) + (setq snippet-exit-transform (yas/snippet-force-exit snippet)) (cond ((or snippet-exit-transform (not (and active-field (yas/field-contains-point-p active-field)))) (setq snippets-left (delete snippet snippets-left)) @@ -4133,10 +4133,10 @@ Remaining args as in `yas/expand-snippet'." ;;; Some hacks: -;;; -;; `locate-dominating-file' +;;; +;; `locate-dominating-file' ;; `region-active-p' -;; +;; ;; added for compatibility in emacs < 23 (unless (>= emacs-major-version 23) (unless (fboundp 'region-active-p) From 087388e21a7b8efb08bb5d5b0b27a1088a6fac55 Mon Sep 17 00:00:00 2001 From: Le Wang Date: Sun, 4 Mar 2012 12:33:53 +0800 Subject: [PATCH 03/33] add comment definition for snippet-mode --- yasnippet.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yasnippet.el b/yasnippet.el index 80f71cf..4d0817c 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -882,6 +882,8 @@ Do this unless `yas/dont-activate' is truish " (setq font-lock-defaults '(yas/font-lock-keywords)) (set (make-local-variable 'require-final-newline) nil) (use-local-map snippet-mode-map)) + (set (make-local-variable 'comment-start) "#") + (set (make-local-variable 'comment-start-skip) "#+[\t ]*")) From 1bfc3793e467c6f1381ea9392193108ce5d7467d Mon Sep 17 00:00:00 2001 From: Le Wang Date: Sun, 4 Mar 2012 12:34:20 +0800 Subject: [PATCH 04/33] remove redundant declaration of defaults for snippet-mode --- yasnippet.el | 2 -- 1 file changed, 2 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 4d0817c..ec75a1f 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -878,10 +878,8 @@ Do this unless `yas/dont-activate' is truish " (define-derived-mode snippet-mode text-mode "Snippet" "A mode for editing yasnippets" - (set-syntax-table (standard-syntax-table)) (setq font-lock-defaults '(yas/font-lock-keywords)) (set (make-local-variable 'require-final-newline) nil) - (use-local-map snippet-mode-map)) (set (make-local-variable 'comment-start) "#") (set (make-local-variable 'comment-start-skip) "#+[\t ]*")) From fe6351b18fdcee605d3c8e221bcfa7abfe217160 Mon Sep 17 00:00:00 2001 From: Joao Tavora Date: Tue, 6 Mar 2012 14:35:54 +0000 Subject: [PATCH 05/33] Sligthly saner `yas/load-directory-1' --- yasnippet.el | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index ec75a1f..d2ebae7 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1601,7 +1601,7 @@ TEMPLATES is a list of `yas/template'." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Loading snippets from files ;; -(defun yas/load-directory-1 (directory &optional mode-sym parents no-compiled-snippets) +(defun yas/load-directory-1 (directory mode-sym parents &optional no-compiled-snippets) "Recursively load snippet templates from DIRECTORY." (unless (file-exists-p (concat directory "/" ".yas-skip")) ;; Load .yas-setup.el files wherever we find them @@ -1610,11 +1610,7 @@ TEMPLATES is a list of `yas/template'." (if (and (not no-compiled-snippets) (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror)) (message "Loading much faster .yas-compiled-snippets from %s" directory) - (let* ((major-mode-and-parents (if mode-sym - (cons mode-sym parents) - (yas/compute-major-mode-and-parents (concat directory - "/dummy")))) - (default-directory directory) + (let* ((default-directory directory) (snippet-defs nil)) ;; load the snippet files ;; @@ -1626,15 +1622,15 @@ TEMPLATES is a list of `yas/template'." snippet-defs)))) (when (or snippet-defs (cdr major-mode-and-parents)) - (yas/define-snippets (car major-mode-and-parents) + (yas/define-snippets mode-sym snippet-defs - (cdr major-mode-and-parents))) + parents)) ;; now recurse to a lower level ;; (dolist (subdir (yas/subdirs directory)) (yas/load-directory-1 subdir - (car major-mode-and-parents) - (cdr major-mode-and-parents) + mode-sym + parents t)))))) (defun yas/load-directory (top-level-dir) @@ -1647,7 +1643,11 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (unless yas/snippet-dirs (setq yas/snippet-dirs top-level-dir)) (dolist (dir (yas/subdirs top-level-dir)) - (yas/load-directory-1 dir)) + (let ((major-mode-and-parents (yas/compute-major-mode-and-parents + (concat dir "/dummy")))) + (yas/load-directory-1 dir + (car major-mode-and-parents) + (cdr major-mode-and-parents)))) (when (interactive-p) (message "[yas] Loaded snippets from %s." top-level-dir))) From 47ed49116eb271641c33e96a4eac2762fc708449 Mon Sep 17 00:00:00 2001 From: Joao Tavora Date: Tue, 6 Mar 2012 15:34:55 +0000 Subject: [PATCH 06/33] prototype, many bugs, especially with with parent modes... --- yasnippet.el | 74 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index d2ebae7..78de215 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -746,7 +746,8 @@ all defined direct keybindings to the command (cons table (yas/table-get-all-parents table)))) yas/tables)) -(defun yas/direct-keymaps-set-vars () +(defun yas/modes-to-activate () + "Compute list of mode symbols that are active for `yas/expand' and friends." (let ((modes-to-activate (list major-mode)) (mode major-mode)) (while (setq mode (get mode 'derived-mode-parent)) @@ -754,9 +755,10 @@ all defined direct keybindings to the command (dolist (mode (yas/extra-modes)) (push mode modes-to-activate)) (dolist (mode modes-to-activate) - (let ((name (intern (format "yas//direct-%s" mode)))) - (set-default name nil) - (set (make-local-variable name) t))))) + (dolist (parent (get mode 'yas/parents)) + + (pushnew parent modes-to-activate))) + modes-to-activate)) (defvar yas/minor-mode-hook nil "Hook run when yas/minor-mode is turned on") @@ -793,16 +795,28 @@ Key bindings: ;; (add-hook 'emulation-mode-map-alists 'yas/direct-keymaps) (add-hook 'post-command-hook 'yas/post-command-handler nil t) - (add-hook 'yas/minor-mode-hook 'yas/direct-keymaps-set-vars-runonce 'append)) + (add-hook 'yas/minor-mode-hook 'yas/runonce-on-minor-mode-hook 'append)) (t ;; Uninstall the direct keymaps and the post-command hook ;; (remove-hook 'post-command-hook 'yas/post-command-handler t) (remove-hook 'emulation-mode-map-alists 'yas/direct-keymaps)))) -(defun yas/direct-keymaps-set-vars-runonce () - (yas/direct-keymaps-set-vars) - (remove-hook 'yas/minor-mode-hook 'yas/direct-keymaps-set-vars-runonce)) +(defun yas/runonce-on-minor-mode-hook () + ;; Set the `yas//direct-%s' vars for direct keymap expansion + ;; + (dolist (mode (yas/modes-to-activate)) + (let ((name (intern (format "yas//direct-%s" mode)))) + (set-default name nil) + (set (make-local-variable name) t))) + ;; Perform JIT loads + ;; + (dolist (mode (yas/modes-to-activate)) + (let ((forms (aget yas/scheduled-jit-loads mode))) + (message "Evaling %s!!!" forms))) + ;; Remove self from the yas/minor-mode-hook + ;; + (remove-hook 'yas/minor-mode-hook 'yas/runonce-on-minor-mode-hook)) (defvar yas/dont-activate nil "If non-nil don't let `yas/minor-mode-on' active yas for this buffer. @@ -1282,28 +1296,16 @@ already have such a property." (yas/table-direct-keymap table))) table)) -(defun yas/get-snippet-tables (&optional mode-symbol dont-search-parents) +(defun yas/get-snippet-tables () "Get snippet tables for current buffer. -Return a list of 'yas/table' objects indexed by mode. - -The modes are tried in this order: optional MODE-SYMBOL, then -`yas/extra-modes', then `major-mode' then, unless -DONT-SEARCH-PARENTS is non-nil, the guessed parent mode of either -MODE-SYMBOL or `major-mode'. - -Guessing is done by looking up the MODE-SYMBOL's -`derived-mode-parent' property, see also `derived-mode-p'." +Return a list of `yas/table' objects indexed by mode. The list of +modes to consider is returned by `yas/modes-to-activate'" (let ((mode-tables (remove nil (mapcar #'(lambda (mode) (gethash mode yas/tables)) - (remove nil (append (list mode-symbol) - (yas/extra-modes) - (list major-mode - (and (not dont-search-parents) - (get major-mode - 'derived-mode-parent))))))))) + (yas/modes-to-activate))))) (remove-duplicates (append mode-tables (mapcan #'yas/table-get-all-parents mode-tables))))) @@ -1643,11 +1645,16 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (unless yas/snippet-dirs (setq yas/snippet-dirs top-level-dir)) (dolist (dir (yas/subdirs top-level-dir)) - (let ((major-mode-and-parents (yas/compute-major-mode-and-parents - (concat dir "/dummy")))) - (yas/load-directory-1 dir - (car major-mode-and-parents) - (cdr major-mode-and-parents)))) + (let* ((major-mode-and-parents (yas/compute-major-mode-and-parents + (concat dir "/dummy"))) + (mode-sym (car major-mode-and-parents)) + (parents (cdr major-mode-and-parents))) + (message "HEY putting %s in %s" parents mode-sym) + (put mode-sym 'yas/parents parents) + (yas/schedule-jit mode-sym + `(yas/load-directory-1 ,dir + ',mode-sym + ',(cdr major-mode-and-parents))))) (when (interactive-p) (message "[yas] Loaded snippets from %s." top-level-dir))) @@ -1760,6 +1767,15 @@ Prompts for INPUT-DIR and OUTPUT-FILE if called-interactively" (find-file-other-window output-file))) +;;; JIT loading +;;; + +(defvar yas/scheduled-jit-loads (list) + "Alist of mode-symbols to forms to be evaled when `yas/minor-mode' kicks in.") + +(defun yas/schedule-jit (mode form) + (aput 'yas/scheduled-jit-loads mode (cons form (aget yas/scheduled-jit-loads mode)))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Some user level functions From 1dc9ea386e7adada3f0879abbcdc374b8167dfb9 Mon Sep 17 00:00:00 2001 From: Joao Tavora Date: Thu, 8 Mar 2012 13:43:19 +0000 Subject: [PATCH 07/33] Restructured mostly loading code, improved jit-loading and parent discovery. Some bugs may lurk --- yasnippet.el | 206 ++++++++++++++++++++++++--------------------------- 1 file changed, 95 insertions(+), 111 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 78de215..b01f75b 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -721,44 +721,55 @@ With optional UNBIND-KEY, try to unbind that key from (define-key yas/minor-mode-map (read-kbd-macro yas/trigger-key) 'yas/expand))) (defvar yas/tables (make-hash-table) - "A hash table of MAJOR-MODE symbols to `yas/table' objects.") + "A hash table of mode symbols to `yas/table' objects.") + +(defvar yas/parents (make-hash-table) + "A hash table of mode symbols do lists of direct parent mode symbols. + +This list is populated when reading the \".yas-parents\" files +found when traversing snippet directories with +`yas/load-directory'. + +There might be additionalal parenting information stored in the +`derived-mode-parent' property of some mode symbols, but that is +not recorded here.") (defvar yas/direct-keymaps (list) "Keymap alist supporting direct snippet keybindings. -This variable is is placed `emulation-mode-map-alists'. +This variable is is placed in `emulation-mode-map-alists'. -Its elements looks like (TABLE-NAME . KEYMAP) and are -calculated when loading snippets. TABLE-NAME is a variable -set buffer-locally when entering `yas/minor-mode'. KEYMAP binds -all defined direct keybindings to the command -`yas/expand-from-keymap', which acts similarly to `yas/expand'") +Its elements looks like (TABLE-NAME . KEYMAP). They're +instantiated on `yas/reload-all' but KEYMAP is added to only when +loading snippets. `yas//direct-TABLE-NAME' is then a variable set +buffer-locally when entering `yas/minor-mode'. KEYMAP binds all +defined direct keybindings to the command +`yas/expand-from-keymap' which then which snippet to expand.") (defun yas/direct-keymaps-reload () "Force reload the direct keybinding for active snippet tables." (interactive) (setq yas/direct-keymaps nil) (maphash #'(lambda (name table) - (mapc #'(lambda (table) - (push (cons (intern (format "yas//direct-%s" name)) - (yas/table-direct-keymap table)) - yas/direct-keymaps)) - (cons table (yas/table-get-all-parents table)))) + (push (cons (intern (format "yas//direct-%s" name)) + (yas/table-direct-keymap table)) + yas/direct-keymaps)) yas/tables)) (defun yas/modes-to-activate () - "Compute list of mode symbols that are active for `yas/expand' and friends." + "Compute list of mode symbols that are active for `yas/expand' +and friends." (let ((modes-to-activate (list major-mode)) (mode major-mode)) (while (setq mode (get mode 'derived-mode-parent)) (push mode modes-to-activate)) (dolist (mode (yas/extra-modes)) (push mode modes-to-activate)) - (dolist (mode modes-to-activate) - (dolist (parent (get mode 'yas/parents)) - - (pushnew parent modes-to-activate))) - modes-to-activate)) + (remove-duplicates + (append modes-to-activate + (mapcan #'(lambda (mode) + (yas/all-parents mode)) + modes-to-activate))))) (defvar yas/minor-mode-hook nil "Hook run when yas/minor-mode is turned on") @@ -795,28 +806,26 @@ Key bindings: ;; (add-hook 'emulation-mode-map-alists 'yas/direct-keymaps) (add-hook 'post-command-hook 'yas/post-command-handler nil t) - (add-hook 'yas/minor-mode-hook 'yas/runonce-on-minor-mode-hook 'append)) + ;; Set the `yas//direct-%s' vars for direct keymap expansion + ;; + (dolist (mode (yas/modes-to-activate)) + (let ((name (intern (format "yas//direct-%s" mode)))) + (set-default name nil) + (set (make-local-variable name) t))) + ;; Perform JIT loads + ;; + (dolist (mode (yas/modes-to-activate)) + (let ((forms (gethash mode yas/scheduled-jit-loads))) + (dolist (form forms) + (message "[yas] Loading snippets for %s, just in time: %s!" mode form) + (eval form)) + (remhash mode yas/scheduled-jit-loads)))) (t ;; Uninstall the direct keymaps and the post-command hook ;; (remove-hook 'post-command-hook 'yas/post-command-handler t) (remove-hook 'emulation-mode-map-alists 'yas/direct-keymaps)))) -(defun yas/runonce-on-minor-mode-hook () - ;; Set the `yas//direct-%s' vars for direct keymap expansion - ;; - (dolist (mode (yas/modes-to-activate)) - (let ((name (intern (format "yas//direct-%s" mode)))) - (set-default name nil) - (set (make-local-variable name) t))) - ;; Perform JIT loads - ;; - (dolist (mode (yas/modes-to-activate)) - (let ((forms (aget yas/scheduled-jit-loads mode))) - (message "Evaling %s!!!" forms))) - ;; Remove self from the yas/minor-mode-hook - ;; - (remove-hook 'yas/minor-mode-hook 'yas/runonce-on-minor-mode-hook)) (defvar yas/dont-activate nil "If non-nil don't let `yas/minor-mode-on' active yas for this buffer. @@ -845,10 +854,15 @@ Do this unless `yas/dont-activate' is truish " :group 'yasnippet :require 'yasnippet) -(add-hook 'yas/global-mode-hook 'yas/reload-all-maybe) -(defun yas/reload-all-maybe () - (if yas/global-mode - (yas/reload-all))) +(defadvice yas/global-mode (before yas/reload-with-jit (arg) activate) + (cond ((and arg + (numberp arg) + (> arg 1)) + ;; explicitly enabling + (yas/reload-all 'with-jit)) + ((not yas/global-mode) + ;; toggling + (yas/reload-all 'with-jit)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Major mode stuff @@ -947,11 +961,6 @@ Has the following fields: another hash of (NAME . TEMPLATE) where NAME is the snippet's name and TEMPLATE is a `yas/template' object. -`yas/table-parents' - - A list of tables considered parents of this table: i.e. when - searching for expansions they are searched as well. - `yas/table-direct-keymap' A keymap for the snippets in this table that have direct @@ -1153,12 +1162,11 @@ conditions to filter out potential expansions." (t (eq requirement result))))) -(defun yas/table-get-all-parents (table) - "Returns a list of all parent tables of TABLE" - (let ((parents (yas/table-parents table))) - (when parents - (append (copy-list parents) - (mapcan #'yas/table-get-all-parents parents))))) +(defun yas/all-parents (mode) + "Returns a list of all parent modes of MODE" + (let ((parents (gethash mode yas/parents))) + (append parents + (mapcan #'yas/all-parents parents)))) (defun yas/table-templates (table) (when table @@ -1282,11 +1290,7 @@ ensure your use `make-local-variable' when you set it.") (defvaralias 'yas/mode-symbol 'yas/extra-modes) (defun yas/table-get-create (mode) - "Get the snippet table corresponding to MODE. - -Optional DIRECTORY gets recorded as the default directory to -search for snippet files if the retrieved/created table didn't -already have such a property." + "Get or create the snippet table corresponding to MODE." (let ((table (gethash mode yas/tables))) (unless table @@ -1299,16 +1303,12 @@ already have such a property." (defun yas/get-snippet-tables () "Get snippet tables for current buffer. -Return a list of `yas/table' objects indexed by mode. The list of -modes to consider is returned by `yas/modes-to-activate'" - (let ((mode-tables - (remove nil - (mapcar #'(lambda (mode) - (gethash mode yas/tables)) - (yas/modes-to-activate))))) - (remove-duplicates - (append mode-tables - (mapcan #'yas/table-get-all-parents mode-tables))))) +Return a list of `yas/table' objects. The list of modes to +consider is returned by `yas/modes-to-activate'" + (remove nil + (mapcar #'(lambda (mode-name) + (gethash mode-name yas/tables)) + (yas/modes-to-activate)))) (defun yas/menu-keymap-get-create (table) "Get or create the main menu keymap correspondong to MODE. @@ -1579,7 +1579,7 @@ TEMPLATES is a list of `yas/template'." filtered-choices chosen d - (completion-fn (or completion-fn + (completion-fn (or completion-fnn #'completing-read))) (dolist (choice choices) (setq d (or (and display-fn (funcall display-fn choice)) @@ -1603,7 +1603,7 @@ TEMPLATES is a list of `yas/template'." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Loading snippets from files ;; -(defun yas/load-directory-1 (directory mode-sym parents &optional no-compiled-snippets) +(defun yas/load-directory-1 (directory mode-sym &optional no-compiled-snippets) "Recursively load snippet templates from DIRECTORY." (unless (file-exists-p (concat directory "/" ".yas-skip")) ;; Load .yas-setup.el files wherever we find them @@ -1611,7 +1611,7 @@ TEMPLATES is a list of `yas/template'." (load (expand-file-name ".yas-setup" directory) 'noerror) (if (and (not no-compiled-snippets) (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror)) - (message "Loading much faster .yas-compiled-snippets from %s" directory) + (message "[yas] Loading much faster .yas-compiled-snippets from %s" directory) (let* ((default-directory directory) (snippet-defs nil)) ;; load the snippet files @@ -1625,14 +1625,12 @@ TEMPLATES is a list of `yas/template'." (when (or snippet-defs (cdr major-mode-and-parents)) (yas/define-snippets mode-sym - snippet-defs - parents)) + snippet-defs)) ;; now recurse to a lower level ;; (dolist (subdir (yas/subdirs directory)) (yas/load-directory-1 subdir mode-sym - parents t)))))) (defun yas/load-directory (top-level-dir) @@ -1649,12 +1647,13 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (concat dir "/dummy"))) (mode-sym (car major-mode-and-parents)) (parents (cdr major-mode-and-parents))) - (message "HEY putting %s in %s" parents mode-sym) - (put mode-sym 'yas/parents parents) + (puthash mode-sym (remove-duplicates + (append parents + (gethash mode-sym yas/parents))) + yas/parents) (yas/schedule-jit mode-sym `(yas/load-directory-1 ,dir - ',mode-sym - ',(cdr major-mode-and-parents))))) + ',mode-sym)))) (when (interactive-p) (message "[yas] Loaded snippets from %s." top-level-dir))) @@ -1666,14 +1665,19 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (yas/load-directory directory)) (call-interactively 'yas/load-directory))) -(defun yas/reload-all (&optional interactive) +(defun yas/reload-all (&optional with-jit) "Reload all snippets and rebuild the YASnippet menu. " (interactive "p") (let ((errors)) - ;; Empty all snippet tables and all menu tables + ;; Empty all snippet tables, parenting info and all menu tables ;; (setq yas/tables (make-hash-table)) + (setq yas/parents (make-hash-table)) (setq yas/menu-table (make-hash-table)) + + ;; Cancel all pending 'yas/scheduled-jit-loads' + ;; + (setq yas/scheduled-jit-loads (make-hash-table)) ;; Init the `yas/minor-mode-map', taking care not to break the ;; menu.... @@ -1729,7 +1733,7 @@ Prompts for INPUT-DIR and OUTPUT-FILE if called-interactively" (let ((default-directory input-dir)) (with-temp-file (setq output-file (or output-file ".yas-compiled-snippets.el")) (flet ((yas/define-snippets - (mode snippets &optional parent-or-parents) + (mode snippets) (insert (format ";;; %s - automatically compiled snippets for `%s' , do not edit!\n" (file-name-nondirectory output-file) mode)) (insert ";;;\n") @@ -1759,7 +1763,7 @@ Prompts for INPUT-DIR and OUTPUT-FILE if called-interactively" (insert (format ";;; %s - automatically compiled snippets for `%s' end here\n" (file-name-nondirectory output-file) mode)) (insert ";;;")))) - (yas/load-directory-1 input-dir nil nil 'no-compiled-snippets)))) + (yas/load-directory-1 input-dir nil 'no-compiled-snippets)))) (if (and (called-interactively-p) (yes-or-no-p (format "Open the resulting file (%s)? " @@ -1770,11 +1774,14 @@ Prompts for INPUT-DIR and OUTPUT-FILE if called-interactively" ;;; JIT loading ;;; -(defvar yas/scheduled-jit-loads (list) +(defvar yas/scheduled-jit-loads (make-hash-table) "Alist of mode-symbols to forms to be evaled when `yas/minor-mode' kicks in.") (defun yas/schedule-jit (mode form) - (aput 'yas/scheduled-jit-loads mode (cons form (aget yas/scheduled-jit-loads mode)))) + (puthash mode + (cons form + (gethash mode yas/scheduled-jit-loads)) + yas/scheduled-jit-loads)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1787,7 +1794,7 @@ Prompts for INPUT-DIR and OUTPUT-FILE if called-interactively" yas/version ") -- pluskid /joaotavora "))) -(defun yas/define-snippets (mode snippets &optional parent-mode) +(defun yas/define-snippets (mode snippets) "Define SNIPPETS for MODE. SNIPPETS is a list of snippet definitions, each taking the @@ -1813,32 +1820,9 @@ UUID is the snippets \"unique-id\". Loading a second snippet file with the same uuid replaced the previous snippet. You can use `yas/parse-template' to return such lists based on -the current buffers contents. - -Optional PARENT-MODE can be used to specify the parent tables of -MODE. It can be a mode symbol of a list of mode symbols. It does -not need to be a real mode." - ;; X) `snippet-table' is created or retrieved for MODE, same goes - ;; for the list of snippet tables `parent-tables'. - ;; +the current buffers contents." (let ((snippet-table (yas/table-get-create mode)) - (parent-tables (mapcar #'yas/table-get-create - (if (listp parent-mode) - parent-mode - (list parent-mode)))) (template nil)) - ;; X) Connect `snippet-table' with `parent-tables'. - ;; - ;; TODO: this should be a remove-duplicates of the concatenation - ;; of `snippet-table's existings parents with the new parents... - ;; - (dolist (parent parent-tables) - (unless (find parent (yas/table-parents snippet-table)) - (push parent - (yas/table-parents snippet-table)))) - - ;; X) Now, iterate for evey snippet def list - ;; (dolist (snippet snippets) (setq template (yas/define-snippets-1 snippet snippet-table))) @@ -1990,7 +1974,7 @@ ommited from MODE's menu, even if they're manually loaded. (define-key keymap (vector (gensym)) '(menu-item "----"))) (t - (message "[yas] don't know anything about menu entry %s" (first e)))))) + (message "[yas] Don't know anything about menu entry %s" (first e)))))) (defun yas/define (mode key template &optional name condition group) "Define a snippet. Expanding KEY into TEMPLATE. @@ -2480,7 +2464,7 @@ With optional prefix argument KILL quit the window and buffer." (fboundp (car major-mode-and-parent)) (car major-mode-and-parent)) (first yas/guessed-modes) - (intern (read-from-minibuffer "[yas] please input a mode: ")))) + (intern (read-from-minibuffer "[yas] Please input a mode: ")))) (yas/current-template (and parsed (fboundp test-mode) @@ -2666,7 +2650,7 @@ If found, the content of subexp group SUBEXP (default 0) is Otherwise throw exception." (when (and yas/moving-away-p (notany #'(lambda (pos) (string= pos yas/text)) possibilities)) - (yas/throw (format "[yas] field only allows %s" possibilities)))) + (yas/throw (format "[yas] Field only allows %s" possibilities)))) (defun yas/field-value (number) "Get the string for field with NUMBER. @@ -3007,7 +2991,7 @@ snippet as ordinary text." ;; again from `yas/take-care-of-redo'.... (setf (yas/snippet-fields snippet) nil))) - (message "[yas] snippet %s exited." (yas/snippet-id snippet))) + (message "[yas] Snippet %s exited." (yas/snippet-id snippet))) (defun yas/safely-run-hooks (hook-var) (condition-case error @@ -3696,7 +3680,7 @@ SNIPPET-MARKERS." (widen) (condition-case err (indent-according-to-mode) - (error (message "[yas] warning: yas/indent-according-to-mode habing problems running %s" indent-line-function) + (error (message "[yas] warning: `yas/indent-according-to-mode' having problems running %s" indent-line-function) nil))) (mapc #'(lambda (marker) (set-marker marker (point))) @@ -4039,7 +4023,7 @@ that the rest of `yas/post-command-handler' runs.") (apply (car fn-and-args) (cdr fn-and-args))) yas/post-command-runonce-actions) - (error (message "[yas] problem running `yas/post-command-runonce-actions'!"))) + (error (message "[yas] Problem running `yas/post-command-runonce-actions'!"))) (setq yas/post-command-runonce-actions nil)) (cond (yas/protection-violation (goto-char yas/protection-violation) From fcbbdbdbbc3a99101ae3e2a9be33ee0388467008 Mon Sep 17 00:00:00 2001 From: Joao Tavora Date: Fri, 9 Mar 2012 11:05:39 +0000 Subject: [PATCH 08/33] Don\'t abort loading more snippet dirs if one of them failed --- yasnippet.el | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index d2ebae7..f237863 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1654,10 +1654,17 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (defun yas/load-snippet-dirs () "Reload the directories listed in `yas/snippet-dirs' or prompt the user to select one." - (if yas/snippet-dirs - (dolist (directory (reverse (yas/snippet-dirs))) - (yas/load-directory directory)) - (call-interactively 'yas/load-directory))) + (let (errors) + (if yas/snippet-dirs + (dolist (directory (reverse (yas/snippet-dirs))) + (condition-case oops + (progn + (yas/load-directory directory) + (message "[yas] Loaded %s" directory)) + (error (push oops errors) + (message "[yas] Check your `yas/snippet-dirs': %s" (second oops))))) + (call-interactively 'yas/load-directory)) + errors)) (defun yas/reload-all (&optional interactive) "Reload all snippets and rebuild the YASnippet menu. " @@ -1677,10 +1684,7 @@ Below TOP-LEVEL-DIR., each directory is a mode name." ;; Reload the directories listed in `yas/snippet-dirs' or prompt ;; the user to select one. ;; - (condition-case oops - (yas/load-snippet-dirs) - (error (push oops errors) - (message "[yas] Check your `yas/snippet-dirs': %s" (second oops)))) + (setq errors (yas/load-snippet-dirs)) ;; Reload the direct keybindings ;; (yas/direct-keymaps-reload) From 66e804dad0e2b06dac1c37a7fdf3a774b8b7d2b6 Mon Sep 17 00:00:00 2001 From: Joao Tavora Date: Tue, 13 Mar 2012 11:23:38 +0000 Subject: [PATCH 09/33] Added a few ert unit tests, mostly for very basic snippet mechanics --- yasnippet-tests.el | 123 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100755 yasnippet-tests.el diff --git a/yasnippet-tests.el b/yasnippet-tests.el new file mode 100755 index 0000000..0cbff75 --- /dev/null +++ b/yasnippet-tests.el @@ -0,0 +1,123 @@ +;;; yasnippet-tests.el --- some yasnippet tests + +;; Copyright (C) 2012 João Távora + +;; Author: João Távora +;; Keywords: emulations, convenience + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; Attempt to test basic snippet mechanics and the loading system + +;;; Code: + +(require 'yasnippet) +(require 'ert) +(require 'ert-x) + + +;;; Snippet mechanics + +(ert-deftest field-navigation () + (with-temp-buffer + (yas/minor-mode 1) + (yas/expand-snippet "${1:brother} from another ${2:mother}") + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "brother from another mother")) + + (should (looking-at "brother")) + (ert-simulate-command '(yas/next-field-or-maybe-expand)) + (should (looking-at "mother")) + (ert-simulate-command '(yas/prev-field)) + (should (looking-at "brother")))) + +(ert-deftest simple-mirror () + (with-temp-buffer + (yas/minor-mode 1) + (yas/expand-snippet "${1:brother} from another $1") + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "brother from another brother")) + (ert-simulate-command `(yas/mock-insert "bla")) + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "bla from another bla")))) + +(ert-deftest mirror-with-transformation () + (with-temp-buffer + (yas/minor-mode 1) + (yas/expand-snippet "${1:brother} from another ${1:$(upcase yas/text)}") + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "brother from another BROTHER")) + (ert-simulate-command `(yas/mock-insert "bla")) + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "bla from another BLA")))) + +(ert-deftest nested-placeholders-kill-superfield () + (with-temp-buffer + (yas/minor-mode 1) + (yas/expand-snippet "brother from ${2:another ${3:mother}}!") + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "brother from another mother!")) + (ert-simulate-command `(yas/mock-insert "bla")) + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "brother from bla!")))) + +(ert-deftest nested-placeholders-use-subfield () + (with-temp-buffer + (yas/minor-mode 1) + (yas/expand-snippet "brother from ${2:another ${3:mother}}!") + (ert-simulate-command '(yas/next-field-or-maybe-expand)) + (ert-simulate-command `(yas/mock-insert "bla")) + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "brother from another bla!")))) + +;; (ert-deftest in-snippet-undo () +;; (with-temp-buffer +;; (yas/minor-mode 1) +;; (yas/expand-snippet "brother from ${2:another ${3:mother}}!") +;; (ert-simulate-command '(yas/next-field-or-maybe-expand)) +;; (ert-simulate-command `(yas/mock-insert "bla")) +;; (ert-simulate-command '(undo)) +;; (should (string= (buffer-substring-no-properties (point-min) (point-max)) +;; "brother from another mother!")))) + + +;;; Misc tests +;;; + +(ert-deftest protection-overlay-no-cheating () + "Protection overlays at the very end of the buffer, are dealt by cheatingly inserting a newline! + +TODO: correct this bug!" + :expected-result :failed + (with-temp-buffer + (yas/minor-mode 1) + (yas/expand-snippet "${2:brother} from another ${1:mother}") + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "brother from another mother") ;; no newline should be here! + ))) + +;;; Helpers +;;; + +(defun yas/mock-insert (string) + (interactive) + (do ((i 0 (1+ i))) + ((= i (length string))) + (insert (aref string i)))) + + +(provide 'yasnippet-tests) +;;; yasnippet-tests.el ends here From 43232a10db98213a14a3254cab1470c5a127812c Mon Sep 17 00:00:00 2001 From: Joao Tavora Date: Tue, 20 Mar 2012 09:14:18 +0000 Subject: [PATCH 10/33] If no 'key' or 'binding' directives fall back to filename as trigger key --- yasnippet.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yasnippet.el b/yasnippet.el index f237863..8de4a39 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1396,6 +1396,8 @@ Here's a list of currently recognized directives: (setq binding (match-string-no-properties 2))))) (setq template (buffer-substring-no-properties (point-min) (point-max)))) + (unless (or key binding) + (setq key (and file (file-name-nondirectory file)))) (when (eq type 'command) (setq template (yas/read-lisp (concat "(progn" template ")")))) (when group From 2188a9d1d100d084ba79bf1bf4237bc72088d311 Mon Sep 17 00:00:00 2001 From: Joao Tavora Date: Tue, 20 Mar 2012 09:15:07 +0000 Subject: [PATCH 11/33] Some loading/reloading with useful fixture code --- yasnippet-tests.el | 65 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/yasnippet-tests.el b/yasnippet-tests.el index 0cbff75..f1219fa 100755 --- a/yasnippet-tests.el +++ b/yasnippet-tests.el @@ -109,6 +109,34 @@ TODO: correct this bug!" "brother from another mother") ;; no newline should be here! ))) +;;; Loading +;;; +(ert-deftest basic-loading () + "Test basic loading and expansion of snippets" + (yas/saving-variables + (with-snippet-dirs + '((".emacs.d/snippets" + ("c-mode" + (".yas-parents" . "cc-mode") + ("printf" . "printf($1);")) + ("emacs-lisp-mode" ("ert-deftest" . "(ert-deftest ${1:name} () $0)")) + ("lisp-interaction-mode" (".yas-parents" . "emacs-lisp-mode"))) + ("library/snippets" + ("c-mode" (".yas-parents" . "c++-mode")) + ("cc-mode" ("def" . "# define")) + ("emacs-lisp-mode" ("dolist" . "(dolist)")) + ("lisp-interaction-mode" ("sc" . "brother from another mother")))) + (yas/reload-all) + (with-temp-buffer + (lisp-interaction-mode) + (yas/minor-mode 1) + (insert "sc") + (ert-simulate-command '(yas/expand)) + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + "brother from another mother")))))) + + + ;;; Helpers ;;; @@ -118,6 +146,43 @@ TODO: correct this bug!" ((= i (length string))) (insert (aref string i)))) +(defun yas/make-file-or-dirs (ass) + (let ((file-or-dir-name (car ass)) + (content (cdr ass))) + (cond ((listp content) + (make-directory file-or-dir-name 'parents) + (let ((default-directory (concat default-directory "/" file-or-dir-name))) + (mapc #'yas/make-file-or-dirs content))) + ((stringp content) + (with-current-buffer (find-file file-or-dir-name) + (insert content) + (save-buffer) + (kill-buffer))) + (t + (message "[yas] oops don't know this content"))))) + + +(defun yas/variables () + (let ((syms)) + (mapatoms #'(lambda (sym) + (if (and (string-match "^yas/[^/]" (symbol-name sym)) + (boundp sym)) + (push sym syms)))) + syms)) + + +(defmacro yas/saving-variables (&rest body) + `(let ,(mapcar #'(lambda (sym) + `(,sym ,sym)) + (yas/variables)) + ,@body)) + +(defmacro with-snippet-dirs (dirs &rest body) + `(let ((default-directory (make-temp-file "yasnippet-fixture" t))) + (setq yas/snippet-dirs ',(mapcar #'car (cadr dirs))) + (mapc #'yas/make-file-or-dirs ,dirs) + ,@body)) + (provide 'yasnippet-tests) ;;; yasnippet-tests.el ends here From 440b6936a5dd91f7f811317de84586326d289654 Mon Sep 17 00:00:00 2001 From: Joao Tavora Date: Tue, 20 Mar 2012 09:16:00 +0000 Subject: [PATCH 12/33] makes 'yas/template' objects easier to read in the echo area --- yasnippet.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index 8de4a39..d9c3882 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -889,7 +889,6 @@ Do this unless `yas/dont-activate' is truish " (defstruct (yas/template (:constructor yas/make-blank-template)) "A template for a snippet." - table key content name @@ -901,6 +900,7 @@ Do this unless `yas/dont-activate' is truish " menu-binding-pair group ;; as dictated by the #group: directive or .yas-make-groups perm-group ;; as dictated by `yas/define-menu' + table ) (defun yas/populate-template (template &rest args) From 012ce9cba0014ad1909c1b4409e525d80400c884 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 25 Mar 2012 14:46:30 +0100 Subject: [PATCH 13/33] This shouldn't be here --- yasnippet.el | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 6966ea1..99ba109 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1624,8 +1624,7 @@ TEMPLATES is a list of `yas/template'." (insert-file-contents file nil nil nil t) (push (yas/parse-template file) snippet-defs)))) - (when (or snippet-defs - (cdr major-mode-and-parents)) + (when snippet-defs (yas/define-snippets mode-sym snippet-defs)) ;; now recurse to a lower level From 63235678091f6c420deade918c6b18df03a73f87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 25 Mar 2012 15:02:46 +0100 Subject: [PATCH 14/33] Introduced 'yas/message and 'yas/verbosity, make everything log to level 3 for now. Implements #224. --- yasnippet.el | 59 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index d9c3882..f0aaaeb 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1093,8 +1093,7 @@ string and TEMPLATE is a `yas/template' structure." (save-match-data (eval condition)))) (error (progn - (message (format "[yas] error in condition evaluation: %s" - (error-message-string err))) + (yas/message 1 "Error in condition evaluation: %s" (error-message-string err)) nil)))) @@ -1216,8 +1215,8 @@ a list of modes like this to help the judgement." (when result (format "%s" result)))))) (error (if yas/good-grace - (format "[yas] elisp error! %s" (error-message-string err)) - (error (format "[yas] elisp error: %s" + (yas/format "elisp error! %s" (error-message-string err)) + (error (yas/format "elisp error: %s" (error-message-string err))))))))) (when (and (consp retval) (eq 'yas/exception (car retval))) @@ -1228,8 +1227,8 @@ a list of modes like this to help the judgement." (condition-case err (eval form) (error (if yas/good-grace - (format "[yas] elisp error! %s" (error-message-string err)) - (error (format "[yas] elisp error: %s" + (yas/format "elisp error! %s" (error-message-string err)) + (error (yas/format "elisp error: %s" (error-message-string err))))))) (defun yas/read-lisp (string &optional nil-on-error) @@ -1252,7 +1251,7 @@ return an expression that when evaluated will issue an error." (read-kbd-macro keybinding 'need-vector)))) res) (error - (message "[yas] warning: keybinding \"%s\" invalid since %s." + (yas/message 3 "warning: keybinding \"%s\" invalid since %s." keybinding (error-message-string err)) nil)))) @@ -1651,7 +1650,7 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (car major-mode-and-parents) (cdr major-mode-and-parents)))) (when (interactive-p) - (message "[yas] Loaded snippets from %s." top-level-dir))) + (yas/message 3 "Loaded snippets from %s." top-level-dir))) (defun yas/load-snippet-dirs () "Reload the directories listed in `yas/snippet-dirs' or @@ -1662,9 +1661,9 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (condition-case oops (progn (yas/load-directory directory) - (message "[yas] Loaded %s" directory)) + (yas/message 3 "Loaded %s" directory)) (error (push oops errors) - (message "[yas] Check your `yas/snippet-dirs': %s" (second oops))))) + (yas/message 3 "Check your `yas/snippet-dirs': %s" (second oops))))) (call-interactively 'yas/load-directory)) errors)) @@ -1690,7 +1689,7 @@ Below TOP-LEVEL-DIR., each directory is a mode name." ;; Reload the direct keybindings ;; (yas/direct-keymaps-reload) - (message "[yas] Reloaded everything...%s." (if errors " (some errors, check *Messages*)" "")))) + (yas/message 3 "Reloaded everything...%s." (if errors " (some errors, check *Messages*)" "")))) (defun yas/quote-string (string) "Escape and quote STRING. @@ -1980,7 +1979,7 @@ ommited from MODE's menu, even if they're manually loaded. (define-key keymap (vector (gensym)) '(menu-item "----"))) (t - (message "[yas] don't know anything about menu entry %s" (first e)))))) + (yas/message 3 "don't know anything about menu entry %s" (first e)))))) (defun yas/define (mode key template &optional name condition group) "Define a snippet. Expanding KEY into TEMPLATE. @@ -2179,7 +2178,7 @@ by condition." (car where) (cdr where) (yas/template-expand-env yas/current-template)) - (message "[yas] No snippets can be inserted here!")))) + (yas/message 3 "No snippets can be inserted here!")))) (defun yas/visit-snippet-file () "Choose a snippet to edit, selection like `yas/insert-snippet'. @@ -2268,7 +2267,7 @@ where snippets of table might exist." (or (some #'(lambda (dir) (when (file-directory-p dir) dir)) (cdr table-and-dirs)) (let ((candidate (first (cdr table-and-dirs)))) (unless (file-writable-p (file-name-directory candidate)) - (error "[yas] %s is not writable." candidate)) + (error (yas/format "%s is not writable." candidate))) (if (y-or-n-p (format "Guessed directory (%s) for%s%s table \"%s\" does not exist! Create? " candidate (if (gethash (intern (yas/table-name (car table-and-dirs))) @@ -2442,7 +2441,7 @@ With optional prefix argument KILL quit the window and buffer." (not (string-match (expand-file-name (first yas/snippet-dirs)) (yas/template-file yas/editing-template))))) - (when (y-or-n-p "[yas] Looks like a library or new snippet. Save to new file? ") + (when (y-or-n-p (yas/format "Looks like a library or new snippet. Save to new file? ")) (let* ((option (first (yas/guess-snippet-directories (yas/template-table yas/editing-template)))) (chosen (and option (yas/make-directory-maybe option)))) @@ -2456,7 +2455,7 @@ With optional prefix argument KILL quit the window and buffer." (setf (yas/template-file yas/editing-template) buffer-file-name)))))) (when kill (quit-window kill)) - (message "[yas] Snippet \"%s\" loaded for %s." + (yas/message 3 "Snippet \"%s\" loaded for %s." (yas/template-name yas/editing-template) (yas/table-name (yas/template-table yas/editing-template)))) @@ -2470,7 +2469,7 @@ With optional prefix argument KILL quit the window and buffer." (fboundp (car major-mode-and-parent)) (car major-mode-and-parent)) (first yas/guessed-modes) - (intern (read-from-minibuffer "[yas] please input a mode: ")))) + (intern (read-from-minibuffer (yas/format "Please input a mode: "))))) (yas/current-template (and parsed (fboundp test-mode) @@ -2495,7 +2494,7 @@ With optional prefix argument KILL quit the window and buffer." (require 'yasnippet-debug nil t)) (add-hook 'post-command-hook 'yas/debug-snippet-vars nil t)))) (t - (message "[yas] Cannot test snippet for unknown major mode"))))) + (yas/message 3 "Cannot test snippet for unknown major mode"))))) (defun yas/template-fine-group (template) (car (last (or (yas/template-group template) @@ -2656,7 +2655,7 @@ If found, the content of subexp group SUBEXP (default 0) is Otherwise throw exception." (when (and yas/moving-away-p (notany #'(lambda (pos) (string= pos yas/text)) possibilities)) - (yas/throw (format "[yas] field only allows %s" possibilities)))) + (yas/throw (yas/format "Field only allows %s" possibilities)))) (defun yas/field-value (number) "Get the string for field with NUMBER. @@ -2997,13 +2996,13 @@ snippet as ordinary text." ;; again from `yas/take-care-of-redo'.... (setf (yas/snippet-fields snippet) nil))) - (message "[yas] snippet %s exited." (yas/snippet-id snippet))) + (yas/message 3 "snippet %s exited." (yas/snippet-id snippet))) (defun yas/safely-run-hooks (hook-var) (condition-case error (run-hooks hook-var) (error - (message "[yas] %s error: %s" hook-var (error-message-string error))))) + (yas/message 3 "%s error: %s" hook-var (error-message-string error))))) (defun yas/check-commit-snippet () @@ -3402,7 +3401,7 @@ considered when expanding the snippet." (when first-field (sit-for 0) ;; fix issue 125 (yas/move-to-field snippet first-field))) - (message "[yas] snippet expanded.") + (yas/message 3 "snippet expanded.") t)))) (defun yas/take-care-of-redo (beg end snippet) @@ -3686,7 +3685,7 @@ SNIPPET-MARKERS." (widen) (condition-case err (indent-according-to-mode) - (error (message "[yas] warning: yas/indent-according-to-mode habing problems running %s" indent-line-function) + (error (yas/message 3 "warning: yas/indent-according-to-mode habing problems running %s" indent-line-function) nil))) (mapc #'(lambda (marker) (set-marker marker (point))) @@ -4029,7 +4028,7 @@ that the rest of `yas/post-command-handler' runs.") (apply (car fn-and-args) (cdr fn-and-args))) yas/post-command-runonce-actions) - (error (message "[yas] problem running `yas/post-command-runonce-actions'!"))) + (error (yas/message 3 "problem running `yas/post-command-runonce-actions'!"))) (setq yas/post-command-runonce-actions nil)) (cond (yas/protection-violation (goto-char yas/protection-violation) @@ -4136,6 +4135,18 @@ Remaining args as in `yas/expand-snippet'." (gethash uuid (yas/table-uuidhash table))))) (when yas/current-template (yas/expand-snippet (yas/template-content yas/current-template))))) + +;;; Utils +;;; + +(defvar yas/verbosity 4 + "Log level for `yas/message' 4 means trace most anything, 0 means nothing.") +(defun yas/message (level message &rest args) + (when (> yas/verbosity level) + (message (apply #'yas/format message args)))) + +(defun yas/format (format-control &rest format-args) + (apply #'format (concat "[yas] " format-control) format-args)) ;;; Some hacks: From 7e3ce48d3c12b8013b0837dc28c5b5ea40808272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 26 Mar 2012 01:27:16 +0100 Subject: [PATCH 15/33] Fix #207 --- README.mdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.mdown b/README.mdown index a46fbe3..f785efa 100644 --- a/README.mdown +++ b/README.mdown @@ -13,7 +13,7 @@ SQL, LaTeX, HTML, CSS and more. The snippet syntax is inspired from [textmate-snippets]: http://manual.macromates.com/en/snippets [import-docs]: http://yasnippet.googlecode.com/svn/trunk/doc/snippet-development.html#importing-textmate-snippets -[youtube-demo]: http://www.youtube.com/watch?v=76Ygeg9miao +[youtube-demo]: http://www.youtube.com/watch?v=ZCGmZK4V7Sg [high-res-demo]: http://yasnippet.googlecode.com/files/yas_demo.avi # Installation From 59e18a999efd978c57a818d8e3e96dda106d7388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 26 Mar 2012 03:44:01 +0100 Subject: [PATCH 16/33] Richer tests --- yasnippet-tests.el | 63 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/yasnippet-tests.el b/yasnippet-tests.el index f1219fa..a537b7f 100755 --- a/yasnippet-tests.el +++ b/yasnippet-tests.el @@ -20,7 +20,7 @@ ;;; Commentary: -;; Attempt to test basic snippet mechanics and the loading system +;; Test basic snippet mechanics and the loading system ;;; Code: @@ -29,6 +29,7 @@ (require 'ert-x) + ;;; Snippet mechanics (ert-deftest field-navigation () @@ -126,19 +127,44 @@ TODO: correct this bug!" ("cc-mode" ("def" . "# define")) ("emacs-lisp-mode" ("dolist" . "(dolist)")) ("lisp-interaction-mode" ("sc" . "brother from another mother")))) - (yas/reload-all) + (yas/reload-all 'with-jit) (with-temp-buffer - (lisp-interaction-mode) - (yas/minor-mode 1) - (insert "sc") - (ert-simulate-command '(yas/expand)) - (should (string= (buffer-substring-no-properties (point-min) (point-max)) - "brother from another mother")))))) - - + (should (= 4 (hash-table-count yas/scheduled-jit-loads))) + (should (= 0 (hash-table-count yas/tables))) + (lisp-interaction-mode) (yas/minor-mode 1) ;; either one will load two tables depending on yas/global-mode (FIXME) + (should (= 2 (hash-table-count yas/scheduled-jit-loads))) + (should (= 2 (hash-table-count yas/tables))) + (should (= 1 (hash-table-count (yas/table-uuidhash (gethash 'lisp-interaction-mode yas/tables))))) + (should (= 2 (hash-table-count (yas/table-uuidhash (gethash 'emacs-lisp-mode yas/tables))))) + (yas/should-expand '(("sc" . "brother from another mother") + ("dolist" . "(dolist)") + ("ert-deftest" . "(ert-deftest name () )"))) + (c-mode) + (yas/should-expand '(("printf" . "printf();") + ("def" . "# define"))) + (yas/should-not-expand '("sc" "dolist" "ert-deftest")))))) ;;; Helpers -;;; +;;; + +(defun yas/should-expand (keys-and-expansions) + (dolist (key-and-expansion keys-and-expansions) + (yas/exit-all-snippets) + (erase-buffer) + (insert (car key-and-expansion)) + (let ((yas/fallback-behavior nil)) + (ert-simulate-command '(yas/expand))) + (should (string= (buffer-substring-no-properties (point-min) (point-max)) + (cdr key-and-expansion))))) + +(defun yas/should-not-expand (keys) + (dolist (key keys) + (yas/exit-all-snippets) + (erase-buffer) + (insert key) + (let ((yas/fallback-behavior nil)) + (ert-simulate-command '(yas/expand))) + (should (string= (buffer-substring-no-properties (point-min) (point-max)) key)))) (defun yas/mock-insert (string) (interactive) @@ -157,7 +183,7 @@ TODO: correct this bug!" (with-current-buffer (find-file file-or-dir-name) (insert content) (save-buffer) - (kill-buffer))) + (kill-buffer (current-buffer)))) (t (message "[yas] oops don't know this content"))))) @@ -181,8 +207,19 @@ TODO: correct this bug!" `(let ((default-directory (make-temp-file "yasnippet-fixture" t))) (setq yas/snippet-dirs ',(mapcar #'car (cadr dirs))) (mapc #'yas/make-file-or-dirs ,dirs) - ,@body)) + ,@body + (when (>= emacs-major-version 23) + (delete-directory default-directory 'recursive)))) +;;; Older emacsen +;;; +(unless (fboundp 'special-mode) + (define-minor-mode special-mode "Just a placeholder for something isn't in emacs 22")) + +;;; btw to test this in emacs22 mac osx: +;;; curl -L -O https://github.com/mirrors/emacs/raw/master/lisp/emacs-lisp/ert.el +;;; curl -L -O https://github.com/mirrors/emacs/raw/master/lisp/emacs-lisp/ert-x.el +;;; /usr/bin/emacs -nw -Q -L . -l yasnippet-tests.el --batch -e ert (provide 'yasnippet-tests) ;;; yasnippet-tests.el ends here From 271f985c0a1f177410852dde1696a671b7bc5a14 Mon Sep 17 00:00:00 2001 From: Randy Morris Date: Thu, 12 Apr 2012 15:54:29 -0300 Subject: [PATCH 17/33] Fix documentation typo. --- yasnippet.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index f0aaaeb..f7c5794 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -765,7 +765,7 @@ all defined direct keybindings to the command (define-minor-mode yas/minor-mode "Toggle YASnippet mode. -When YASnippet mode is enabled, the `tas/trigger-key' key expands +When YASnippet mode is enabled, the `yas/trigger-key' key expands snippets of code depending on the mode. With no argument, this command toggles the mode. From 69a10619556a6caf6cb17265f6c9e595e63d3519 Mon Sep 17 00:00:00 2001 From: immerrr Date: Thu, 19 Apr 2012 23:29:37 +0400 Subject: [PATCH 18/33] yas/ido-prompt: play nice with autoloading of ido-completing-read --- yasnippet.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index f0aaaeb..e9c0dfd 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1551,7 +1551,7 @@ TEMPLATES is a list of `yas/template'." (keyboard-quit)))) (defun yas/ido-prompt (prompt choices &optional display-fn) - (when (featurep 'ido) + (when (fboundp 'ido-completing-read) (yas/completing-prompt prompt choices display-fn #'ido-completing-read))) (eval-when-compile (require 'dropdown-list nil t)) From 61ccd9b4abef4ea574b259a8199329020b090c1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Mon, 26 Mar 2012 03:48:31 +0100 Subject: [PATCH 19/33] Should really exit all snippets --- yasnippet.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index e9c0dfd..c7a37bd 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -2940,7 +2940,7 @@ Also create some protection overlays" (mapc #'(lambda (snippet) (yas/exit-snippet snippet) (yas/check-commit-snippet)) - (yas/snippets-at-point))) + (yas/snippets-at-point 'all-snippets))) ;;; Some low level snippet-routines From 9dedf9120936e2fa85d5e4fad4f1e1618e1074a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sat, 21 Apr 2012 11:58:12 +0100 Subject: [PATCH 20/33] with-snippet-dirs: use UNWIND-PROTECT --- yasnippet-tests.el | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/yasnippet-tests.el b/yasnippet-tests.el index a537b7f..6474294 100755 --- a/yasnippet-tests.el +++ b/yasnippet-tests.el @@ -204,12 +204,13 @@ TODO: correct this bug!" ,@body)) (defmacro with-snippet-dirs (dirs &rest body) - `(let ((default-directory (make-temp-file "yasnippet-fixture" t))) - (setq yas/snippet-dirs ',(mapcar #'car (cadr dirs))) - (mapc #'yas/make-file-or-dirs ,dirs) - ,@body + `(unwind-protect + (let ((default-directory (make-temp-file "yasnippet-fixture" t))) + (setq yas/snippet-dirs ',(mapcar #'car (cadr dirs))) + (mapc #'yas/make-file-or-dirs ,dirs) + ,@body) (when (>= emacs-major-version 23) - (delete-directory default-directory 'recursive)))) + (delete-directory default-directory 'recursive)))) ;;; Older emacsen ;;; From 0bdb370c0631389040b203790619d084eb836caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sat, 21 Apr 2012 11:58:50 +0100 Subject: [PATCH 21/33] yas/compile-directory: now works :-) --- yasnippet.el | 200 ++++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 96 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index 93566fb..13579aa 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1604,39 +1604,13 @@ TEMPLATES is a list of `yas/template'." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Loading snippets from files ;; -(defun yas/load-directory-1 (directory mode-sym &optional no-compiled-snippets) - "Recursively load snippet templates from DIRECTORY." - (unless (file-exists-p (concat directory "/" ".yas-skip")) - ;; Load .yas-setup.el files wherever we find them - ;; - (load (expand-file-name ".yas-setup" directory) 'noerror) - (if (and (not no-compiled-snippets) - (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror)) - (message "[yas] Loading much faster .yas-compiled-snippets from %s" directory) - (let* ((default-directory directory) - (snippet-defs nil)) - ;; load the snippet files - ;; - (with-temp-buffer - (dolist (file (yas/subdirs directory 'no-subdirs-just-files)) - (when (file-readable-p file) - (insert-file-contents file nil nil nil t) - (push (yas/parse-template file) - snippet-defs)))) - (when snippet-defs - (yas/define-snippets mode-sym - snippet-defs)) - ;; now recurse to a lower level - ;; - (dolist (subdir (yas/subdirs directory)) - (yas/load-directory-1 subdir - mode-sym - t)))))) +(defun yas/load-yas-setup-file (file) + (load file 'noerror)) -(defun yas/load-directory (top-level-dir) +(defun yas/load-directory (top-level-dir &optional nojit) "Load snippet definition from directory hierarchy under TOP-LEVEL-DIR. -Below TOP-LEVEL-DIR., each directory is a mode name." +Below TOP-LEVEL-DIR each directory is a mode name." (interactive "DSelect the root directory: ") (unless (file-directory-p top-level-dir) (error "%s is not a directory" top-level-dir)) @@ -1647,17 +1621,50 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (concat dir "/dummy"))) (mode-sym (car major-mode-and-parents)) (parents (cdr major-mode-and-parents))) - (puthash mode-sym (remove-duplicates - (append parents - (gethash mode-sym yas/parents))) - yas/parents) - (yas/schedule-jit mode-sym - `(yas/load-directory-1 ,dir - ',mode-sym)))) + (let ((form `(yas/load-directory-1 ,dir + ',mode-sym + ',parents))) + (if (or (called-interactively-p) + nojit) + (eval form) + (yas/schedule-jit mode-sym form))))) (when (interactive-p) (yas/message 3 "Loaded snippets from %s." top-level-dir))) -(defun yas/load-snippet-dirs () +(defun yas/load-directory-1 (directory mode-sym parents &optional no-compiled-snippets) + "Recursively load snippet templates from DIRECTORY." + (unless (file-exists-p (concat directory "/" ".yas-skip")) + (if (and (not no-compiled-snippets) + (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror)) + (message "[yas] Loading much faster .yas-compiled-snippets from %s" directory) + (yas/load-directory-2 directory mode-sym parents)))) + +(defun yas/load-directory-2 (directory mode-sym parents) + (yas/define-parents mode-sym parents) + ;; Load .yas-setup.el files wherever we find them + ;; + (yas/load-yas-setup-file (expand-file-name ".yas-setup" directory)) + (let* ((default-directory directory) + (snippet-defs nil)) + ;; load the snippet files + ;; + (with-temp-buffer + (dolist (file (yas/subdirs directory 'no-subdirs-just-files)) + (when (file-readable-p file) + (insert-file-contents file nil nil nil t) + (push (yas/parse-template file) + snippet-defs)))) + (when snippet-defs + (yas/define-snippets mode-sym + snippet-defs)) + ;; now recurse to a lower level + ;; + (dolist (subdir (yas/subdirs directory)) + (yas/load-directory-2 subdir + mode-sym + nil)))) + +(defun yas/load-snippet-dirs (&optional nojit) "Reload the directories listed in `yas/snippet-dirs' or prompt the user to select one." (let (errors) @@ -1665,14 +1672,14 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (dolist (directory (reverse (yas/snippet-dirs))) (condition-case oops (progn - (yas/load-directory directory) + (yas/load-directory directory nojit) (yas/message 3 "Loaded %s" directory)) (error (push oops errors) (yas/message 3 "Check your `yas/snippet-dirs': %s" (second oops))))) (call-interactively 'yas/load-directory)) errors)) -(defun yas/reload-all (&optional with-jit) +(defun yas/reload-all (&optional nojit) "Reload all snippets and rebuild the YASnippet menu. " (interactive "p") (let ((errors)) @@ -1695,7 +1702,7 @@ Below TOP-LEVEL-DIR., each directory is a mode name." ;; Reload the directories listed in `yas/snippet-dirs' or prompt ;; the user to select one. ;; - (setq errors (yas/load-snippet-dirs)) + (setq errors (yas/load-snippet-dirs nojit)) ;; Reload the direct keybindings ;; (yas/direct-keymaps-reload) @@ -1717,62 +1724,56 @@ foo\"bar\\! -> \"foo\\\"bar\\\\!\"" "For backward compatibility, enable `yas/minor-mode' globally" (yas/global-mode 1)) -(defun yas/compile-top-level-dir (top-level-dir) - "Create .yas-compiled-snippets.el files under subdirs of TOP-LEVEL-DIR." +(defun yas/compile-directory (top-level-dir) + "Create .yas-compiled-snippets.el files under subdirs of TOP-LEVEL-DIR. + +This works by stubbing a few functions, then calling +`yas/load-directory'." (interactive "DTop level snippet directory?") - (dolist (dir (yas/subdirs top-level-dir)) - (yas/compile-snippets dir))) - -(defun yas/compile-snippets (input-dir &optional output-file) - "Compile snippets files in INPUT-DIR to OUTPUT-FILE file. - -Prompts for INPUT-DIR and OUTPUT-FILE if called-interactively" - (interactive (let* ((input-dir (read-directory-name "Snippet dir ")) - (output-file (let ((ido-everywhere nil)) - (read-file-name "Output file " - input-dir nil nil - ".yas-compiled-snippets.el" - nil)))) - (list input-dir output-file))) - (let ((default-directory input-dir)) - (with-temp-file (setq output-file (or output-file ".yas-compiled-snippets.el")) - (flet ((yas/define-snippets - (mode snippets) - (insert (format ";;; %s - automatically compiled snippets for `%s' , do not edit!\n" - (file-name-nondirectory output-file) mode)) - (insert ";;;\n") - (let ((literal-snippets (list))) - (dolist (snippet snippets) - (let ((key (first snippet)) - (template-content (second snippet)) - (name (third snippet)) - (condition (fourth snippet)) - (group (fifth snippet)) - (expand-env (sixth snippet)) - (file nil) ;; (seventh snippet)) ;; omit on purpose - (binding (eighth snippet)) - (uuid (ninth snippet))) - (push `(,key - ,template-content - ,name - ,condition - ,group - ,expand-env - ,file - ,binding - ,uuid) - literal-snippets))) - (insert (pp-to-string `(yas/define-snippets ',mode ',literal-snippets ',parent-or-parents))) - (insert "\n\n") - (insert (format ";;; %s - automatically compiled snippets for `%s' end here\n" - (file-name-nondirectory output-file) mode)) - (insert ";;;")))) - (yas/load-directory-1 input-dir nil 'no-compiled-snippets)))) - - (if (and (called-interactively-p) - (yes-or-no-p (format "Open the resulting file (%s)? " - (expand-file-name output-file)))) - (find-file-other-window output-file))) + (flet ((yas/load-yas-setup-file + (file) + (let ((elfile (concat file ".el"))) + (when (file-exists-p elfile) + (insert ";;; .yas-setup.el support file if any:\n;;;\n") + (insert-file-contents elfile)))) + (yas/define-parents + (mode parents) + (insert ";;; Parent definitions:\n;;;\n") + (insert (pp-to-string `(yas/define-parents ',mode ',parents)))) + (yas/define-snippets + (mode snippets) + (insert ";;; Snippet definitions:\n;;;\n") + (let ((literal-snippets (list))) + (dolist (snippet snippets) + (let ((key (first snippet)) + (template-content (second snippet)) + (name (third snippet)) + (condition (fourth snippet)) + (group (fifth snippet)) + (expand-env (sixth snippet)) + (file nil) ;; (seventh snippet)) ;; omit on purpose + (binding (eighth snippet)) + (uuid (ninth snippet))) + (push `(,key + ,template-content + ,name + ,condition + ,group + ,expand-env + ,file + ,binding + ,uuid) + literal-snippets))) + (insert (pp-to-string `(yas/define-snippets ',mode ',literal-snippets))) + (insert "\n\n"))) + (yas/load-directory-1 + (dir mode parents &rest ignore) + (let ((output-file (concat (file-name-as-directory dir) ".yas-compiled-snippets.el"))) + (with-temp-file output-file + (insert (format ";;; Compiled snippets and support files for `%s'\n" mode)) + (yas/load-directory-2 dir mode parents) + (insert (format ";;; Do not edit! File generated at %s\n" (current-time-string))))))) + (yas/load-directory top-level-dir 'im-compiling-so-no-jit-ok?))) ;;; JIT loading @@ -1798,6 +1799,13 @@ Prompts for INPUT-DIR and OUTPUT-FILE if called-interactively" yas/version ") -- pluskid /joaotavora "))) +(defun yas/define-parents (mode parents) + "Add PARENTS to the list of MODE's parents" + (puthash mode-sym (remove-duplicates + (append parents + (gethash mode-sym yas/parents))) + yas/parents)) + (defun yas/define-snippets (mode snippets) "Define SNIPPETS for MODE. From 4ae3bc0affdeffceeac6f54512bf58ee7c26a02b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 16:29:57 +0100 Subject: [PATCH 22/33] with-snippet-dirs: correct use of `unwind-protect` --- yasnippet-tests.el | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/yasnippet-tests.el b/yasnippet-tests.el index 6474294..969eb06 100755 --- a/yasnippet-tests.el +++ b/yasnippet-tests.el @@ -204,13 +204,14 @@ TODO: correct this bug!" ,@body)) (defmacro with-snippet-dirs (dirs &rest body) - `(unwind-protect - (let ((default-directory (make-temp-file "yasnippet-fixture" t))) - (setq yas/snippet-dirs ',(mapcar #'car (cadr dirs))) - (mapc #'yas/make-file-or-dirs ,dirs) - ,@body) - (when (>= emacs-major-version 23) - (delete-directory default-directory 'recursive)))) + `(let ((default-directory (make-temp-file "yasnippet-fixture" t))) + (unwind-protect + (progn + (setq yas/snippet-dirs ',(mapcar #'car (cadr dirs))) + (mapc #'yas/make-file-or-dirs ,dirs) + ,@body) + (when (>= emacs-major-version 23) + (delete-directory default-directory 'recursive))))) ;;; Older emacsen ;;; From a948b92aa2ac217d0025e344eba30a5fd063f864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 16:30:58 +0100 Subject: [PATCH 23/33] bugfix: also exit all snippets at end of should-expand test --- yasnippet-tests.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yasnippet-tests.el b/yasnippet-tests.el index 969eb06..3d18309 100755 --- a/yasnippet-tests.el +++ b/yasnippet-tests.el @@ -155,7 +155,8 @@ TODO: correct this bug!" (let ((yas/fallback-behavior nil)) (ert-simulate-command '(yas/expand))) (should (string= (buffer-substring-no-properties (point-min) (point-max)) - (cdr key-and-expansion))))) + (cdr key-and-expansion)))) + (yas/exit-all-snippets)) (defun yas/should-not-expand (keys) (dolist (key keys) From e30b67f9ca2879565260c1c82ee231e6cd16ff6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 16:33:02 +0100 Subject: [PATCH 24/33] enhancement: add `yas/recompile-all` --- yasnippet.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yasnippet.el b/yasnippet.el index 13579aa..a9e545e 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1775,6 +1775,9 @@ This works by stubbing a few functions, then calling (insert (format ";;; Do not edit! File generated at %s\n" (current-time-string))))))) (yas/load-directory top-level-dir 'im-compiling-so-no-jit-ok?))) +(defun yas/recompile-all () + (mapc #'yas/compile-directory (yas/snippet-dirs))) + ;;; JIT loading ;;; From d317a408c3a76c0a2cb473cb6e0b5688f1ee1c44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 16:34:12 +0100 Subject: [PATCH 25/33] enhancement: test snippet compilation and loading. refactor test helpers --- yasnippet-tests.el | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/yasnippet-tests.el b/yasnippet-tests.el index 3d18309..157debb 100755 --- a/yasnippet-tests.el +++ b/yasnippet-tests.el @@ -112,8 +112,31 @@ TODO: correct this bug!" ;;; Loading ;;; -(ert-deftest basic-loading () +(defmacro with-some-interesting-snippet-dirs (&rest body) + `(yas/saving-variables + (with-snippet-dirs + '((".emacs.d/snippets" + ("c-mode" + (".yas-parents" . "cc-mode") + ("printf" . "printf($1);")) + ("emacs-lisp-mode" ("ert-deftest" . "(ert-deftest ${1:name} () $0)")) + ("lisp-interaction-mode" (".yas-parents" . "emacs-lisp-mode"))) + ("library/snippets" + ("c-mode" (".yas-parents" . "c++-mode")) + ("cc-mode" ("def" . "# define")) + ("emacs-lisp-mode" ("dolist" . "(dolist)")) + ("lisp-interaction-mode" ("sc" . "brother from another mother")))) + ,@body))) + +(ert-deftest basic-jit-loading () "Test basic loading and expansion of snippets" + (yas/basic-jit-loading-1)) + +(ert-deftest basic-jit-loading-with-compiled-snippets () + "Test basic loading and expansion of snippets" + (yas/basic-jit-loading-1 'compile)) + +(defun yas/basic-jit-loading-1 (&optional compile) (yas/saving-variables (with-snippet-dirs '((".emacs.d/snippets" @@ -127,7 +150,7 @@ TODO: correct this bug!" ("cc-mode" ("def" . "# define")) ("emacs-lisp-mode" ("dolist" . "(dolist)")) ("lisp-interaction-mode" ("sc" . "brother from another mother")))) - (yas/reload-all 'with-jit) + (yas/reload-all) (with-temp-buffer (should (= 4 (hash-table-count yas/scheduled-jit-loads))) (should (= 0 (hash-table-count yas/tables))) @@ -140,6 +163,7 @@ TODO: correct this bug!" ("dolist" . "(dolist)") ("ert-deftest" . "(ert-deftest name () )"))) (c-mode) + (yas/minor-mode 1) (yas/should-expand '(("printf" . "printf();") ("def" . "# define"))) (yas/should-not-expand '("sc" "dolist" "ert-deftest")))))) From 26c311ee8ab55e6f6b68269b97c7963d9b95d6e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 16:34:57 +0100 Subject: [PATCH 26/33] yas/load-directory: bugfix: `yas/define-parents` must be called earlier on. --- yasnippet.el | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/yasnippet.el b/yasnippet.el index a9e545e..e50370d 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -181,6 +181,7 @@ as the default for storing the user's new snippets." (equal old new)) (yas/reload-all))))) (defun yas/snippet-dirs () + "Returns `yas/snippet-dirs' (which see) as a list." (if (listp yas/snippet-dirs) yas/snippet-dirs (list yas/snippet-dirs))) (defvaralias 'yas/root-directory 'yas/snippet-dirs) @@ -1621,6 +1622,7 @@ Below TOP-LEVEL-DIR each directory is a mode name." (concat dir "/dummy"))) (mode-sym (car major-mode-and-parents)) (parents (cdr major-mode-and-parents))) + (yas/define-parents mode-sym parents) (let ((form `(yas/load-directory-1 ,dir ',mode-sym ',parents))) @@ -1640,7 +1642,6 @@ Below TOP-LEVEL-DIR each directory is a mode name." (yas/load-directory-2 directory mode-sym parents)))) (defun yas/load-directory-2 (directory mode-sym parents) - (yas/define-parents mode-sym parents) ;; Load .yas-setup.el files wherever we find them ;; (yas/load-yas-setup-file (expand-file-name ".yas-setup" directory)) @@ -1736,10 +1737,6 @@ This works by stubbing a few functions, then calling (when (file-exists-p elfile) (insert ";;; .yas-setup.el support file if any:\n;;;\n") (insert-file-contents elfile)))) - (yas/define-parents - (mode parents) - (insert ";;; Parent definitions:\n;;;\n") - (insert (pp-to-string `(yas/define-parents ',mode ',parents)))) (yas/define-snippets (mode snippets) (insert ";;; Snippet definitions:\n;;;\n") From 3eff698e6851076d402fa519d30a9770f37c3f60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 17:10:25 +0100 Subject: [PATCH 27/33] bugfix: also use here --- yasnippet.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index b004ffc..0dc1214 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1638,7 +1638,7 @@ Below TOP-LEVEL-DIR each directory is a mode name." (unless (file-exists-p (concat directory "/" ".yas-skip")) (if (and (not no-compiled-snippets) (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror)) - (message "[yas] Loading much faster .yas-compiled-snippets from %s" directory) + (yas/message 2 "Loading much faster .yas-compiled-snippets from %s" directory) (yas/load-directory-2 directory mode-sym parents)))) (defun yas/load-directory-2 (directory mode-sym parents) From 023f1ebad4550bedfba5b5037b1eaa05773b428a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 17:11:23 +0100 Subject: [PATCH 28/33] bugfix: need to to go to end of buffer after inserting .yas-setup.el --- yasnippet.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index 0dc1214..49d7e1b 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1736,7 +1736,9 @@ This works by stubbing a few functions, then calling (let ((elfile (concat file ".el"))) (when (file-exists-p elfile) (insert ";;; .yas-setup.el support file if any:\n;;;\n") - (insert-file-contents elfile)))) + (insert-file-contents elfile) + (end-of-buffer) + ))) (yas/define-snippets (mode snippets) (insert ";;; Snippet definitions:\n;;;\n") From cb3f1254392e4924329a2605b8de14f21b0351ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 17:12:13 +0100 Subject: [PATCH 29/33] bugfix: print-legnth has to be infinity here --- yasnippet.el | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index 49d7e1b..7a2a13f 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1742,7 +1742,8 @@ This works by stubbing a few functions, then calling (yas/define-snippets (mode snippets) (insert ";;; Snippet definitions:\n;;;\n") - (let ((literal-snippets (list))) + (let ((literal-snippets (list)) + (print-length nil)) (dolist (snippet snippets) (let ((key (first snippet)) (template-content (second snippet)) From b32edcca4c2fb65e0f3e28600a89e86dbd3b8be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 17:12:49 +0100 Subject: [PATCH 30/33] bugfix: needs to be interactive --- yasnippet.el | 2 ++ 1 file changed, 2 insertions(+) diff --git a/yasnippet.el b/yasnippet.el index 7a2a13f..bc537d8 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1776,6 +1776,8 @@ This works by stubbing a few functions, then calling (yas/load-directory top-level-dir 'im-compiling-so-no-jit-ok?))) (defun yas/recompile-all () + "Compile every dir in `yas/snippet-dirs'." + (interactive) (mapc #'yas/compile-directory (yas/snippet-dirs))) From 584d1d80bfe016a15083bdd0a874f3e174f8fc8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 22 Apr 2012 17:27:00 +0100 Subject: [PATCH 31/33] yas/load-directory-1: also start supressing emacs-lisp load messages when yas/verbosity is 2 or lower --- yasnippet.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yasnippet.el b/yasnippet.el index bc537d8..736cfa0 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1637,7 +1637,7 @@ Below TOP-LEVEL-DIR each directory is a mode name." "Recursively load snippet templates from DIRECTORY." (unless (file-exists-p (concat directory "/" ".yas-skip")) (if (and (not no-compiled-snippets) - (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror)) + (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror (<= yas/verbosity 2))) (yas/message 2 "Loading much faster .yas-compiled-snippets from %s" directory) (yas/load-directory-2 directory mode-sym parents)))) From 7bf15178986172224b97e9e2fc31e205a0c38ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sat, 28 Apr 2012 17:20:03 +0100 Subject: [PATCH 32/33] Fix #237 --- yasnippet.el | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yasnippet.el b/yasnippet.el index 2eb1fed..d8fe8b1 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -1689,6 +1689,9 @@ Below TOP-LEVEL-DIR., each directory is a mode name." ;; Reload the direct keybindings ;; (yas/direct-keymaps-reload) + ;; Reload the trigger-key (shoudn't be needed, but see issue #237) + ;; + (yas/trigger-key-reload) (yas/message 3 "Reloaded everything...%s." (if errors " (some errors, check *Messages*)" "")))) (defun yas/quote-string (string) From fcb4dfe43d05a64a172f8a5bf7bb1717b4b250cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20T=C3=A1vora?= Date: Sun, 29 Apr 2012 12:43:42 +0100 Subject: [PATCH 33/33] jit-loading: some minor refactoring and better tests --- yasnippet-tests.el | 64 +++++++++++++++++++++++----------------------- yasnippet.el | 19 +++++++++----- 2 files changed, 45 insertions(+), 38 deletions(-) diff --git a/yasnippet-tests.el b/yasnippet-tests.el index 157debb..007d125 100755 --- a/yasnippet-tests.el +++ b/yasnippet-tests.el @@ -130,43 +130,43 @@ TODO: correct this bug!" (ert-deftest basic-jit-loading () "Test basic loading and expansion of snippets" - (yas/basic-jit-loading-1)) + (with-some-interesting-snippet-dirs + (yas/reload-all) + (yas/basic-jit-loading-1))) (ert-deftest basic-jit-loading-with-compiled-snippets () "Test basic loading and expansion of snippets" - (yas/basic-jit-loading-1 'compile)) + (with-some-interesting-snippet-dirs + (yas/reload-all) + (yas/recompile-all) + (flet ((yas/load-directory-2 + (&rest dummies) + (ert-fail "yas/load-directory-2 shouldn't be called when snippets have been compiled"))) + (yas/reload-all) + (yas/basic-jit-loading-1)))) (defun yas/basic-jit-loading-1 (&optional compile) - (yas/saving-variables - (with-snippet-dirs - '((".emacs.d/snippets" - ("c-mode" - (".yas-parents" . "cc-mode") - ("printf" . "printf($1);")) - ("emacs-lisp-mode" ("ert-deftest" . "(ert-deftest ${1:name} () $0)")) - ("lisp-interaction-mode" (".yas-parents" . "emacs-lisp-mode"))) - ("library/snippets" - ("c-mode" (".yas-parents" . "c++-mode")) - ("cc-mode" ("def" . "# define")) - ("emacs-lisp-mode" ("dolist" . "(dolist)")) - ("lisp-interaction-mode" ("sc" . "brother from another mother")))) - (yas/reload-all) - (with-temp-buffer - (should (= 4 (hash-table-count yas/scheduled-jit-loads))) - (should (= 0 (hash-table-count yas/tables))) - (lisp-interaction-mode) (yas/minor-mode 1) ;; either one will load two tables depending on yas/global-mode (FIXME) - (should (= 2 (hash-table-count yas/scheduled-jit-loads))) - (should (= 2 (hash-table-count yas/tables))) - (should (= 1 (hash-table-count (yas/table-uuidhash (gethash 'lisp-interaction-mode yas/tables))))) - (should (= 2 (hash-table-count (yas/table-uuidhash (gethash 'emacs-lisp-mode yas/tables))))) - (yas/should-expand '(("sc" . "brother from another mother") - ("dolist" . "(dolist)") - ("ert-deftest" . "(ert-deftest name () )"))) - (c-mode) - (yas/minor-mode 1) - (yas/should-expand '(("printf" . "printf();") - ("def" . "# define"))) - (yas/should-not-expand '("sc" "dolist" "ert-deftest")))))) + (with-temp-buffer + (should (= 4 (hash-table-count yas/scheduled-jit-loads))) + (should (= 0 (hash-table-count yas/tables))) + (lisp-interaction-mode) + (yas/minor-mode 1) + (should (= 2 (hash-table-count yas/scheduled-jit-loads))) + (should (= 2 (hash-table-count yas/tables))) + (should (= 1 (hash-table-count (yas/table-uuidhash (gethash 'lisp-interaction-mode yas/tables))))) + (should (= 2 (hash-table-count (yas/table-uuidhash (gethash 'emacs-lisp-mode yas/tables))))) + (yas/should-expand '(("sc" . "brother from another mother") + ("dolist" . "(dolist)") + ("ert-deftest" . "(ert-deftest name () )"))) + (c-mode) + (yas/minor-mode 1) + (should (= 0 (hash-table-count yas/scheduled-jit-loads))) + (should (= 4 (hash-table-count yas/tables))) + (should (= 1 (hash-table-count (yas/table-uuidhash (gethash 'c-mode yas/tables))))) + (should (= 1 (hash-table-count (yas/table-uuidhash (gethash 'cc-mode yas/tables))))) + (yas/should-expand '(("printf" . "printf();") + ("def" . "# define"))) + (yas/should-not-expand '("sc" "dolist" "ert-deftest")))) ;;; Helpers ;;; diff --git a/yasnippet.el b/yasnippet.el index 736cfa0..677353a 100644 --- a/yasnippet.el +++ b/yasnippet.el @@ -815,12 +815,7 @@ Key bindings: (set (make-local-variable name) t))) ;; Perform JIT loads ;; - (dolist (mode (yas/modes-to-activate)) - (let ((forms (gethash mode yas/scheduled-jit-loads))) - (dolist (form forms) - (message "[yas] Loading snippets for %s, just in time: %s!" mode form) - (eval form)) - (remhash mode yas/scheduled-jit-loads)))) + (yas/load-pending-jits)) (t ;; Uninstall the direct keymaps and the post-command hook ;; @@ -1709,6 +1704,18 @@ Below TOP-LEVEL-DIR each directory is a mode name." (yas/direct-keymaps-reload) (yas/message 3 "Reloaded everything...%s." (if errors " (some errors, check *Messages*)" "")))) +(defun yas/load-pending-jits () + (when yas/minor-mode + (dolist (mode (yas/modes-to-activate)) + (let ((forms (gethash mode yas/scheduled-jit-loads))) + (dolist (form forms) + (yas/message 3 "Loading snippets for %s, just in time: %s!" mode form) + (eval form)) + (remhash mode yas/scheduled-jit-loads))))) + +;; (when (<= emacs-major-version 22) +;; (add-hook 'after-change-major-mode-hook 'yas/load-pending-jits)) + (defun yas/quote-string (string) "Escape and quote STRING. foo\"bar\\! -> \"foo\\\"bar\\\\!\""