diff --git a/yasnippet-tests.el b/yasnippet-tests.el index f1219fa..007d125 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 () @@ -111,34 +112,84 @@ 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/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")))))) + (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" + (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) + (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 -;;; +;;; + +(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)))) + (yas/exit-all-snippets)) + +(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 +208,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"))))) @@ -179,10 +230,23 @@ TODO: correct this bug!" (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 + (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 +;;; +(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 diff --git a/yasnippet.el b/yasnippet.el index d8fe8b1..23348a8 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) @@ -721,42 +722,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/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)) (push mode modes-to-activate)) (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))))) + (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") @@ -793,16 +807,21 @@ 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)) + ;; 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 + ;; + (yas/load-pending-jits)) (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)) (defvar yas/dont-activate nil "If non-nil don't let `yas/minor-mode-on' active yas for this buffer. @@ -831,10 +850,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 @@ -933,11 +957,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 @@ -1138,12 +1157,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 @@ -1267,11 +1285,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 @@ -1281,31 +1295,15 @@ 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'." - (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))))))))) - (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. @@ -1578,7 +1576,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)) @@ -1602,57 +1600,67 @@ TEMPLATES is a list of `yas/template'." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Loading snippets from files ;; -(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 - ;; - (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) - (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 (or snippet-defs - (cdr major-mode-and-parents)) - (yas/define-snippets mode-sym - snippet-defs - parents)) - ;; now recurse to a lower level - ;; - (dolist (subdir (yas/subdirs directory)) - (yas/load-directory-1 subdir - mode-sym - parents - 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)) (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))) + (yas/define-parents mode-sym parents) + (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 (<= yas/verbosity 2))) + (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) + ;; 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) @@ -1660,21 +1668,26 @@ 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 interactive) +(defun yas/reload-all (&optional nojit) "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.... @@ -1685,7 +1698,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) @@ -1694,6 +1707,18 @@ Below TOP-LEVEL-DIR., each directory is a mode name." (yas/trigger-key-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\\\\!\"" @@ -1710,63 +1735,73 @@ 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))) + (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) + (end-of-buffer) + ))) + (yas/define-snippets + (mode snippets) + (insert ";;; Snippet definitions:\n;;;\n") + (let ((literal-snippets (list)) + (print-length nil)) + (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?))) -(defun yas/compile-snippets (input-dir &optional output-file) - "Compile snippets files in INPUT-DIR to OUTPUT-FILE file. +(defun yas/recompile-all () + "Compile every dir in `yas/snippet-dirs'." + (interactive) + (mapc #'yas/compile-directory (yas/snippet-dirs))) -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 &optional parent-or-parents) - (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 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))) +;;; JIT loading +;;; + +(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) + (puthash mode + (cons form + (gethash mode yas/scheduled-jit-loads)) + yas/scheduled-jit-loads)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1779,7 +1814,14 @@ 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-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. SNIPPETS is a list of snippet definitions, each taking the @@ -1805,32 +1847,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))) @@ -1982,7 +2001,7 @@ ommited from MODE's menu, even if they're manually loaded. (define-key keymap (vector (gensym)) '(menu-item "----"))) (t - (yas/message 3 "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. @@ -2999,7 +3018,7 @@ snippet as ordinary text." ;; again from `yas/take-care-of-redo'.... (setf (yas/snippet-fields snippet) nil))) - (yas/message 3 "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 @@ -3688,7 +3707,7 @@ SNIPPET-MARKERS." (widen) (condition-case err (indent-according-to-mode) - (error (yas/message 3 "warning: yas/indent-according-to-mode habing problems running %s" indent-line-function) + (error (yas/message 3 "Warning: `yas/indent-according-to-mode' having problems running %s" indent-line-function) nil))) (mapc #'(lambda (marker) (set-marker marker (point))) @@ -4031,7 +4050,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 (yas/message 3 "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)