]> code.delx.au - gnu-emacs-elpa/blobdiff - yasnippet.el
bugfix: fix #245
[gnu-emacs-elpa] / yasnippet.el
index d7920652e8ccdc75d36121da832eb1e62ff01fd3..305cae913aabd4e25c1360f91054fde2aef6cf96 100644 (file)
@@ -6,9 +6,9 @@
 ;; Authors: pluskid <pluskid@gmail.com>, joaotavora <joaotavora@gmail.com>
 ;; Version: 0.7.0
 ;; Package-version: 0.7.0
 ;; Authors: pluskid <pluskid@gmail.com>, joaotavora <joaotavora@gmail.com>
 ;; Version: 0.7.0
 ;; Package-version: 0.7.0
-;; X-URL: http://code.google.com/p/yasnippet/
+;; X-URL: http://github.com/capitaomorte/yasnippet
 ;; Keywords: convenience, emulation
 ;; Keywords: convenience, emulation
-;; URL: http://code.google.com/p/yasnippet/
+;; URL: http://github.com/capitaomorte/yasnippet
 ;; EmacsWiki: YaSnippetMode
 
 ;; This file is free software; you can redistribute it and/or modify
 ;; EmacsWiki: YaSnippetMode
 
 ;; This file is free software; you can redistribute it and/or modify
 
 ;; Basic steps to setup:
 ;;
 
 ;; Basic steps to setup:
 ;;
-;;   1. In your .emacs file:
-;;        (add-to-list 'load-path "/dir/to/yasnippet.el")
-;;        (require 'yasnippet)
-;;   2. Place the `snippets' directory somewhere.  E.g: ~/.emacs.d/snippets
-;;   3. In your .emacs file
-;;        (setq yas/snippet-dirs "~/.emacs/snippets")
-;;        (yas/load-directory yas/snippet-dirs)
-;;   4. To enable the YASnippet menu and tab-trigger expansion
-;;        M-x yas/minor-mode
-;;   5. To globally enable the minor mode in *all* buffers
-;;        M-x yas/global-mode
+;;    (add-to-list 'load-path
+;;                 "~/.emacs.d/plugins/yasnippet")
+;;    (require 'yasnippet)
+;;    (yas/global-mode 1)
 ;;
 ;;
-;;   Steps 4. and 5. are optional, you don't have to use the minor
-;;   mode to use YASnippet.
 ;;
 ;;   Interesting variables are:
 ;;
 ;;
 ;;   Interesting variables are:
 ;;
 ;;   `custom-set-variables' is executed in your .emacs file.
 ;;
 ;;   For more information and detailed usage, refer to the project page:
 ;;   `custom-set-variables' is executed in your .emacs file.
 ;;
 ;;   For more information and detailed usage, refer to the project page:
-;;      http://code.google.com/p/yasnippet/
+;;      http://github.com/capitaomorte/yasnippet
 
 ;;; Code:
 
 (require 'cl)
 
 ;;; Code:
 
 (require 'cl)
-(require 'assoc)
 (require 'easymenu)
 (require 'help-mode)
 
 (require 'easymenu)
 (require 'help-mode)
 
@@ -190,6 +180,7 @@ as the default for storing the user's new snippets."
                          (equal old new))
                (yas/reload-all)))))
 (defun yas/snippet-dirs ()
                          (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)
 
   (if (listp yas/snippet-dirs) yas/snippet-dirs (list yas/snippet-dirs)))
 (defvaralias 'yas/root-directory 'yas/snippet-dirs)
 
@@ -489,7 +480,8 @@ Attention: These hooks are not run when exiting nested/stackd snippet expansion!
      t)
   "Snippet expanding condition.
 
      t)
   "Snippet expanding condition.
 
-This variable is a lisp form:
+This variable is a lisp form which is evaluated everytime a
+snippet expansion is attemped:
 
     * If it evaluates to nil, no snippets can be expanded.
 
 
     * If it evaluates to nil, no snippets can be expanded.
 
@@ -552,7 +544,7 @@ snippet itself contains a condition that returns the symbol
   "A list of mode which is well known but not part of emacs.")
 
 (defvar yas/escaped-characters
   "A list of mode which is well known but not part of emacs.")
 
 (defvar yas/escaped-characters
-  '(?\\ ?` ?' ?$ ?} ?{ ?\( ?\))
+  '(?\\ ?` ?\" ?' ?$ ?} ?{ ?\( ?\))
   "List of characters which *might* need to be escaped.")
 
 (defconst yas/field-regexp
   "List of characters which *might* need to be escaped.")
 
 (defconst yas/field-regexp
@@ -729,42 +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)
     (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.
 
 
 (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)
 
 (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))
 
            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))
   (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")
 
 (defvar yas/minor-mode-hook nil
   "Hook run when yas/minor-mode is turned on")
@@ -773,7 +778,7 @@ all defined direct keybindings to the command
 (define-minor-mode yas/minor-mode
   "Toggle YASnippet mode.
 
 (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.
 snippets of code depending on the mode.
 
 With no argument, this command toggles the mode.
@@ -801,16 +806,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 '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))))
 
         (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.
 
 (defvar yas/dont-activate nil
   "If non-nil don't let `yas/minor-mode-on' active yas for this buffer.
@@ -839,10 +849,15 @@ Do this unless `yas/dont-activate' is truish "
   :group 'yasnippet
   :require 'yasnippet)
 
   :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))
+        ((not yas/global-mode)
+         ;; toggling
+         (yas/reload-all))))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Major mode stuff
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Major mode stuff
@@ -886,10 +901,10 @@ Do this unless `yas/dont-activate' is truish "
 
 (define-derived-mode snippet-mode text-mode "Snippet"
   "A mode for editing yasnippets"
 
 (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)
   (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 ]*"))
 
 
 \f
 
 
 \f
@@ -897,7 +912,6 @@ Do this unless `yas/dont-activate' is truish "
 
 (defstruct (yas/template (:constructor yas/make-blank-template))
   "A template for a snippet."
 
 (defstruct (yas/template (:constructor yas/make-blank-template))
   "A template for a snippet."
-  table
   key
   content
   name
   key
   content
   name
@@ -907,8 +921,9 @@ Do this unless `yas/dont-activate' is truish "
   keybinding
   uuid
   menu-binding-pair
   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'
   perm-group ;; as dictated by `yas/define-menu'
+  table
   )
 
 (defun yas/populate-template (template &rest args)
   )
 
 (defun yas/populate-template (template &rest args)
@@ -941,11 +956,6 @@ Has the following fields:
   another hash of (NAME . TEMPLATE) where NAME is the snippet's
   name and TEMPLATE is a `yas/template' object.
 
   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
 `yas/table-direct-keymap'
 
   A keymap for the snippets in this table that have direct
@@ -1007,7 +1017,6 @@ Has the following fields:
         ;;
         (remhash uuid (yas/table-uuidhash table))))))
 
         ;;
         (remhash uuid (yas/table-uuidhash table))))))
 
-
 (defun yas/add-template (table template)
   "Store in TABLE the snippet template TEMPLATE.
 
 (defun yas/add-template (table template)
   "Store in TABLE the snippet template TEMPLATE.
 
@@ -1016,7 +1025,7 @@ keybinding)."
   (let ((name (yas/template-name template))
         (key (yas/template-key template))
         (keybinding (yas/template-keybinding template))
   (let ((name (yas/template-name template))
         (key (yas/template-key template))
         (keybinding (yas/template-keybinding template))
-        (menu-binding (car (yas/template-menu-binding-pair template))))
+        (menu-binding-pair (yas/snippet-menu-binding-pair-get-create template)))
     (dolist (k (remove nil (list key keybinding)))
       (puthash name
                template
     (dolist (k (remove nil (list key keybinding)))
       (puthash name
                template
@@ -1028,28 +1037,27 @@ keybinding)."
       (when (vectorp k)
         (define-key (yas/table-direct-keymap table) k 'yas/expand-from-keymap)))
 
       (when (vectorp k)
         (define-key (yas/table-direct-keymap table) k 'yas/expand-from-keymap)))
 
-    (when menu-binding
-      (setf (getf (cdr menu-binding) :keys)
-            (or (and keybinding (key-description keybinding))
-                (and key (concat key yas/trigger-symbol))))
-      (setcar (cdr menu-binding)
-              name))
+    ;; Update trigger & keybinding in the menu-binding pair
+    ;;
+    (setf (getf (cdr (car menu-binding-pair)) :keys)
+          (or (and keybinding (key-description keybinding))
+              (and key (concat key yas/trigger-symbol))))
 
     (puthash (yas/template-uuid template) template (yas/table-uuidhash table))))
 
 
     (puthash (yas/template-uuid template) template (yas/table-uuidhash table))))
 
-(defun yas/update-template (snippet-table template)
-  "Add or update TEMPLATE in SNIPPET-TABLE.
+(defun yas/update-template (table template)
+  "Add or update TEMPLATE in TABLE.
 
 
-Also takes care of adding and updaring to the associated menu."
+Also takes care of adding and updating to the associated menu."
   ;; Remove from table by uuid
   ;;
   ;; Remove from table by uuid
   ;;
-  (yas/remove-template-by-uuid snippet-table (yas/template-uuid template))
+  (yas/remove-template-by-uuid table (yas/template-uuid template))
   ;; Add to table again
   ;;
   ;; Add to table again
   ;;
-  (yas/add-template snippet-table template)
+  (yas/add-template table template)
   ;; Take care of the menu
   ;;
   ;; Take care of the menu
   ;;
-  (let ((keymap (yas/menu-keymap-get-create snippet-table))
+  (let ((keymap (yas/menu-keymap-get-create table))
         (group (yas/template-group template)))
     (when (and yas/use-menu
                keymap
         (group (yas/template-group template)))
     (when (and yas/use-menu
                keymap
@@ -1059,7 +1067,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.
       (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
       (dolist (subgroup group)
         (let ((subgroup-keymap (lookup-key keymap (vector (make-symbol subgroup)))))
           (unless (and subgroup-keymap
@@ -1068,9 +1076,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)))
             (define-key keymap (vector (make-symbol subgroup))
               `(menu-item ,subgroup ,subgroup-keymap)))
             (setq keymap subgroup-keymap)))
-      
+
       ;; Add this entry to the 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))))))
 
       (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))))))
 
@@ -1101,8 +1109,7 @@ string and TEMPLATE is a `yas/template' structure."
           (save-match-data
             (eval condition))))
     (error (progn
           (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))))
 
 
              nil))))
 
 
@@ -1147,12 +1154,11 @@ conditions to filter out potential expansions."
           (t
            (eq requirement result)))))
 
           (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
 
 (defun yas/table-templates (table)
   (when table
@@ -1224,8 +1230,8 @@ a list of modes like this to help the judgement."
                               (when result
                                 (format "%s" result))))))
                     (error (if yas/good-grace
                               (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)))
                                             (error-message-string err)))))))))
     (when (and (consp retval)
                (eq 'yas/exception (car retval)))
@@ -1236,8 +1242,8 @@ a list of modes like this to help the judgement."
   (condition-case err
       (eval form)
     (error (if yas/good-grace
   (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)
                             (error-message-string err)))))))
 
 (defun yas/read-lisp (string &optional nil-on-error)
@@ -1248,7 +1254,7 @@ return an expression that when evaluated will issue an error."
   (condition-case err
       (read string)
     (error (and (not nil-on-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."
 
 (defun yas/read-keybinding (keybinding)
   "Read KEYBINDING as a snippet keybinding, return a vector."
@@ -1260,7 +1266,7 @@ return an expression that when evaluated will issue an error."
                        (read-kbd-macro keybinding 'need-vector))))
           res)
       (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))))
 
                 keybinding (error-message-string err))
        nil))))
 
@@ -1276,45 +1282,26 @@ ensure your use `make-local-variable' when you set it.")
 (defvaralias 'yas/mode-symbol 'yas/extra-modes)
 
 (defun yas/table-get-create (mode)
 (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
       (setq table (yas/make-snippet-table (symbol-name mode)))
       (puthash mode table yas/tables)
   (let ((table (gethash mode
                         yas/tables)))
     (unless table
       (setq table (yas/make-snippet-table (symbol-name mode)))
       (puthash mode table yas/tables)
-      (aput 'yas/direct-keymaps (intern (format "yas//direct-%s" mode))
-            (yas/table-direct-keymap table)))
+      (push (cons (intern (format "yas//direct-%s" mode))
+                  (yas/table-direct-keymap table))
+            yas/direct-keymaps))
     table))
 
     table))
 
-(defun yas/get-snippet-tables (&optional mode-symbol dont-search-parents)
+(defun yas/get-snippet-tables ()
   "Get snippet tables for current buffer.
 
   "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.
 
 (defun yas/menu-keymap-get-create (table)
   "Get or create the main menu keymap correspondong to MODE.
@@ -1404,6 +1391,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))))
                    (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
     (when (eq type 'command)
       (setq template (yas/read-lisp (concat "(progn" template ")"))))
     (when group
@@ -1427,8 +1416,8 @@ Here's a list of currently recognized directives:
                                                (directory-file-name extra-dir)))))
     group))
 
                                                (directory-file-name extra-dir)))))
     group))
 
-(defun yas/subdirs (directory &optional file?)
-  "Return subdirs or files of DIRECTORY according to FILE?."
+(defun yas/subdirs (directory &optional filep)
+  "Return subdirs or files of DIRECTORY according to FILEP."
   (remove-if (lambda (file)
                (or (string-match "^\\."
                                  (file-name-nondirectory file))
   (remove-if (lambda (file)
                (or (string-match "^\\."
                                  (file-name-nondirectory file))
@@ -1436,7 +1425,7 @@ Here's a list of currently recognized directives:
                                  (file-name-nondirectory file))
                    (string-match "~$"
                                  (file-name-nondirectory file))
                                  (file-name-nondirectory file))
                    (string-match "~$"
                                  (file-name-nondirectory file))
-                   (if file?
+                   (if filep
                        (file-directory-p file)
                      (not (file-directory-p file)))))
              (directory-files directory t)))
                        (file-directory-p file)
                      (not (file-directory-p file)))))
              (directory-files directory t)))
@@ -1463,6 +1452,10 @@ Here's a list of currently recognized directives:
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Popping up for keys and templates
 ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Popping up for keys and templates
 ;;
+(defvar yas/x-pretty-prompt-templates nil
+  "If non-nil, attempt to prompt for templates like TextMate.")
+
+
 (defun yas/prompt-for-template (templates &optional prompt)
   "Interactively choose a template from the list TEMPLATES.
 
 (defun yas/prompt-for-template (templates &optional prompt)
   "Interactively choose a template from the list TEMPLATES.
 
@@ -1525,26 +1518,27 @@ TEMPLATES is a list of `yas/template'."
       (or chosen
           (keyboard-quit)))))
 
       (or chosen
           (keyboard-quit)))))
 
-(defvar yas/x-pretty-prompt-templates nil
-  "If non-nil, attempt to prompt for templates like TextMate.")
 (defun yas/x-pretty-prompt-templates (prompt templates)
   "Display TEMPLATES, grouping neatly by table name."
 (defun yas/x-pretty-prompt-templates (prompt templates)
   "Display TEMPLATES, grouping neatly by table name."
-  (let ((pretty-alist (list))
+  (let ((organized (make-hash-table :test #'equal))
         menu
         more-than-one-table
         prefix)
     (dolist (tl templates)
         menu
         more-than-one-table
         prefix)
     (dolist (tl templates)
-      (aput 'pretty-alist (yas/template-table tl) (cons tl (aget pretty-alist (yas/template-table tl)))))
-    (setq more-than-one-table (> (length pretty-alist) 1))
+      (puthash (yas/template-table tl)
+               (cons tl
+                     (gethash (yas/template-table tl) organized))
+               organized))
+    (setq more-than-one-table (> (hash-table-count organized) 1))
     (setq prefix (if more-than-one-table
                      "   " ""))
     (setq prefix (if more-than-one-table
                      "   " ""))
-    (dolist (table-and-templates pretty-alist)
-      (when (cdr table-and-templates)
-        (if more-than-one-table
-            (push (yas/table-name (car table-and-templates)) menu))
-        (dolist (template (cdr table-and-templates))
-          (push (cons (concat prefix (yas/template-name template))
-                      template) menu))))
+    (if more-than-one-table
+        (maphash #'(lambda (table templates)
+                     (push (yas/table-name table) menu)
+                     (dolist (tl templates)
+                       (push (cons (concat prefix (yas/template-name tl)) tl) menu))) organized)
+      (setq menu (mapcar #'(lambda (tl) (cons (concat prefix (yas/template-name tl)) tl)) templates)))
+
     (setq menu (nreverse menu))
     (or (x-popup-menu (if (fboundp 'posn-at-point)
                           (let ((x-y (posn-x-y (posn-at-point (point)))))
     (setq menu (nreverse menu))
     (or (x-popup-menu (if (fboundp 'posn-at-point)
                           (let ((x-y (posn-x-y (posn-at-point (point)))))
@@ -1556,7 +1550,7 @@ TEMPLATES is a list of `yas/template'."
         (keyboard-quit))))
 
 (defun yas/ido-prompt (prompt choices &optional display-fn)
         (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))
     (yas/completing-prompt prompt choices display-fn #'ido-completing-read)))
 
 (eval-when-compile (require 'dropdown-list nil t))
@@ -1607,96 +1601,138 @@ TEMPLATES is a list of `yas/template'."
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Loading snippets from files
 ;;
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Loading snippets from files
 ;;
-(defun yas/load-directory-1 (directory &optional mode-sym parents)
-  "Recursively load snippet templates from DIRECTORY."
+(defun yas/load-yas-setup-file (file)
+  (load file 'noerror))
 
 
-  ;; Load .yas-setup.el files wherever we find them
-  ;;
-  (let ((file (concat directory "/" ".yas-setup")))
-    (when (or (file-readable-p (concat file ".el"))
-              (file-readable-p (concat file ".elc")))
-      (load file)))
+(defun yas/load-directory (top-level-dir &optional use-jit)
+  "Load snippets in directory hierarchy TOP-LEVEL-DIR.
 
 
-  ;;
-  ;;
-  (unless (file-exists-p (concat directory "/" ".yas-skip"))
-    (let* ((major-mode-and-parents (if mode-sym
-                                       (cons mode-sym parents)
-                                     (yas/compute-major-mode-and-parents (concat directory
-                                                                                 "/dummy"))))
-           (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 (car major-mode-and-parents)
-                             snippet-defs
-                             (cdr major-mode-and-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))))))
-
-(defun yas/load-directory (directory)
-  "Load snippet definition from a directory hierarchy.
-
-Below the top-level directory, each directory is a mode
-name.  And under each subdirectory, each file is a definition
-of a snippet.  The file name is the trigger key and the
-content of the file is the template."
+Below TOP-LEVEL-DIR each directory should be a mode name.
+
+Optional USE-JIT use jit-loading of snippets."
   (interactive "DSelect the root directory: ")
   (interactive "DSelect the root directory: ")
-  (unless (file-directory-p directory)
-    (error "%s is not a directory" directory))
   (unless yas/snippet-dirs
   (unless yas/snippet-dirs
-    (setq yas/snippet-dirs directory))
-  (dolist (dir (yas/subdirs directory))
-    (yas/load-directory-1 dir))
+    (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")))
+           (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 use-jit
+            (yas/schedule-jit mode-sym form)
+            (eval form)))))
   (when (interactive-p)
   (when (interactive-p)
-    (message "[yas] Loaded snippets from %s." directory)))
+    (yas/message 3 "Loaded snippets from %s." top-level-dir)))
+
+(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))))
 
 
-(defun yas/load-snippet-dirs ()
+(defun yas/load-directory-2 (directory mode-sym)
+  ;; 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))))
+
+(defun yas/load-snippet-dirs (&optional nojit)
   "Reload the directories listed in `yas/snippet-dirs' or
    prompt the user to select one."
   "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)))
-
-(defun yas/reload-all (&optional interactive)
-  "Reload all snippets and rebuild the YASnippet menu. "
+  (let (errors)
+    (if yas/snippet-dirs
+        (dolist (directory (reverse (yas/snippet-dirs)))
+          (cond ((file-directory-p directory)
+                 (yas/load-directory directory (not nojit))
+                 (yas/message 3 "Loaded %s" directory))
+                (t
+                 (push (yas/message 0 "Check your `yas/snippet-dirs': %s is not a directory" directory) errors))))
+      (call-interactively 'yas/load-directory))
+    errors))
+
+(defun yas/reload-all (&optional no-jit)
+  "Reload all snippets and rebuild the YASnippet menu.
+
+Behaviour is affected by `yas/no-jit', which see."
   (interactive "p")
   (interactive "p")
-  (let ((errors))
-    ;; Empty all snippet tables and all menu tables
-    ;;
-    (setq yas/tables (make-hash-table))
-    (setq yas/menu-table (make-hash-table))
+  (catch 'abort
+    (let ((errors)
+          (snippet-editing-buffers
+           (remove-if-not #'(lambda (buffer)
+                              (with-current-buffer buffer yas/editing-template))
+                          (buffer-list))))
+      ;; Warn if there are buffers visiting snippets, since reloading will break
+      ;; any on-line editing of those buffers.
+      ;;
+      (if snippet-editing-buffers
+          (if (y-or-n-p "Some buffers editing live snippets, close them and proceed with reload?")
+              (mapcar #'kill-buffer snippet-editing-buffers)
+            (yas/message 1 "Aborted reload...")
+            (throw 'abort nil)))
 
 
-    ;; Init the `yas/minor-mode-map', taking care not to break the
-    ;; menu....
-    ;;
-    (setf (cdr yas/minor-mode-map)
-          (cdr (yas/init-minor-keymap)))
+      ;; 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))
 
 
-    ;; 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))))
-    ;; Reload the direct keybindings
-    ;;
-    (yas/direct-keymaps-reload)
-    (message "[yas] Reloaded everything...%s." (if errors " (some errors, check *Messages*)" ""))))
+      ;; 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....
+      ;;
+      (setf (cdr yas/minor-mode-map)
+            (cdr (yas/init-minor-keymap)))
+
+      ;; Reload the directories listed in `yas/snippet-dirs' or prompt
+      ;; the user to select one.
+      ;;
+      (setq errors (yas/load-snippet-dirs no-jit))
+      ;; 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/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.
 
 (defun yas/quote-string (string)
   "Escape and quote STRING.
@@ -1708,139 +1744,80 @@ foo\"bar\\! -> \"foo\\\"bar\\\\!\""
                                     t)
           "\""))
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                                     t)
           "\""))
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Yasnippet Bundle
+;;; Snippet compilation function
 
 (defun yas/initialize ()
   "For backward compatibility, enable `yas/minor-mode' globally"
   (yas/global-mode 1))
 
 
 (defun yas/initialize ()
   "For backward compatibility, enable `yas/minor-mode' globally"
   (yas/global-mode 1))
 
-(defun yas/compile-bundle
-  (&optional yasnippet yasnippet-bundle snippet-roots code dropdown)
-  "Compile snippets in SNIPPET-ROOTS to a single bundle file.
-
-YASNIPPET is the yasnippet.el file path.
-
-YASNIPPET-BUNDLE is the output file of the compile result.
+(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?")
+  (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)
+              (insert (format ";;; Do not edit! File generated at %s\n" (current-time-string)))))))
+    (yas/load-directory top-level-dir nil)))
+
+(defun yas/recompile-all ()
+  "Compile every dir in `yas/snippet-dirs'."
+  (interactive)
+  (mapc #'yas/compile-directory (yas/snippet-dirs)))
 
 
-SNIPPET-ROOTS is a list of root directories that contains the
-snippets definition.
 
 
-CODE is the code to be placed at the end of the generated file
-and that can initialize the YASnippet bundle.
+;;; JIT loading
+;;;
 
 
-Last optional argument DROPDOWN is the filename of the
-dropdown-list.el library.
+(defvar yas/scheduled-jit-loads (make-hash-table)
+  "Alist of mode-symbols to forms to be evaled when `yas/minor-mode' kicks in.")
 
 
-Here's the default value for all the parameters:
+(defun yas/schedule-jit (mode form)
+  (puthash mode
+           (cons form
+                 (gethash mode yas/scheduled-jit-loads))
+           yas/scheduled-jit-loads))
 
 
-  (yas/compile-bundle \"yasnippet.el\"
-                      \"yasnippet-bundle.el\"
-                      \"snippets\")
-                      \"(yas/initialize-bundle)
-                        ### autoload
-                        (require 'yasnippet-bundle)`\"
-                      \"dropdown-list.el\")
-"
-  (interactive (concat "ffind the yasnippet.el file: \nFTarget bundle file: "
-                       "\nDSnippet directory to bundle: \nMExtra code? \nfdropdown-library: "))
-
-  (let* ((yasnippet (or yasnippet
-                        "yasnippet.el"))
-         (yasnippet-bundle (or yasnippet-bundle
-                               "./yasnippet-bundle.el"))
-         (snippet-roots (or snippet-roots
-                            "snippets"))
-         (dropdown (or dropdown
-                       "dropdown-list.el"))
-         (code (or (and code
-                        (condition-case err (read code) (error nil))
-                        code)
-                   (concat "(yas/initialize-bundle)"
-                           "\n;;;###autoload" ; break through so that won't
-                           "(require 'yasnippet-bundle)")))
-         (dirs (or (and (listp snippet-roots) snippet-roots)
-                   (list snippet-roots)))
-         (bundle-buffer nil))
-    (with-temp-file yasnippet-bundle
-      (insert ";;; yasnippet-bundle.el --- "
-              "Yet another snippet extension (Auto compiled bundle)\n")
-      (insert-file-contents yasnippet)
-      (goto-char (point-max))
-      (insert "\n")
-      (when dropdown
-        (insert-file-contents dropdown))
-      (goto-char (point-max))
-      (insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n")
-      (insert ";;;;      Auto-generated code         ;;;;\n")
-      (insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n")
-      (insert "(defun yas/initialize-bundle ()\n"
-              "  \"Initialize YASnippet and load snippets in the bundle.\"")
-      (flet ((yas/define-snippets
-              (mode snippets &optional parent-or-parents)
-              (insert ";;; snippets for " (symbol-name mode) ", subdir " (file-name-nondirectory (replace-regexp-in-string "/$" "" default-directory)) "\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"))))
-        (dolist (dir dirs)
-          (dolist (subdir (yas/subdirs dir))
-            (let ((file (concat subdir "/.yas-setup.el")))
-              (when (file-readable-p file)
-                (insert "\n;; Supporting elisp for subdir " (file-name-nondirectory subdir) "\n\n")
-                (with-temp-buffer
-                  (insert-file-contents file)
-                  (replace-regexp "^;;.*$" "" nil (point-min) (point-max))
-                  (replace-regexp "^[\s\t]*\n\\([\s\t]*\n\\)+" "\n" nil (point-min) (point-max))
-                  (kill-region (point-min) (point-max)))
-                (yank)))
-            (yas/load-directory-1 subdir nil))))
-
-      (insert (pp-to-string `(yas/global-mode 1)))
-      (insert ")\n\n" code "\n")
-
-      ;; bundle-specific provide and value for yas/dont-activate
-      (let ((bundle-feature-name (file-name-nondirectory
-                                  (file-name-sans-extension
-                                   yasnippet-bundle))))
-        (insert (pp-to-string `(set-default 'yas/dont-activate
-                                            #'(lambda ()
-                                                (and (or yas/snippet-dirs
-                                                         (featurep ',(make-symbol bundle-feature-name)))
-                                                     (null (yas/get-snippet-tables)))))))
-        (insert (pp-to-string `(provide ',(make-symbol bundle-feature-name)))))
-
-      (insert ";;; "
-              (file-name-nondirectory yasnippet-bundle)
-              " ends here\n"))))
-
-(defun yas/compile-textmate-bundle ()
-  (interactive)
-  (yas/compile-bundle "yasnippet.el"
-                      "./yasnippet-textmate-bundle.el"
-                      "extras/imported/"
-                      (concat "(yas/initialize-bundle)"
-                              "\n;;;###autoload" ; break through so that won't
-                              "(require 'yasnippet-textmate-bundle)")
-                      "dropdown-list.el"))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Some user level functions
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; Some user level functions
@@ -1852,7 +1829,14 @@ Here's the default value for all the parameters:
                    yas/version
                    ") -- pluskid <pluskid@gmail.com>/joaotavora <joaotavora@gmail.com>")))
 
                    yas/version
                    ") -- pluskid <pluskid@gmail.com>/joaotavora <joaotavora@gmail.com>")))
 
-(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
   "Define SNIPPETS for MODE.
 
 SNIPPETS is a list of snippet definitions, each taking the
@@ -1878,32 +1862,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
 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))
   (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))
         (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)))
     (dolist (snippet snippets)
       (setq template (yas/define-snippets-1 snippet
                                             snippet-table)))
@@ -1950,7 +1911,10 @@ not need to be a real mode."
     template))
 
 (defun yas/snippet-menu-binding-pair-get-create (template &optional type)
     template))
 
 (defun yas/snippet-menu-binding-pair-get-create (template &optional type)
-  "Get TEMPLATE's menu binding or assign it a new one."
+  "Get TEMPLATE's menu binding or assign it a new one.
+
+TYPE may be `:stay', signalling this menu binding should be
+static in the menu."
   (or (yas/template-menu-binding-pair template)
       (let ((key (yas/template-key template))
             (keybinding (yas/template-keybinding template)))
   (or (yas/template-menu-binding-pair template)
       (let ((key (yas/template-key template))
             (keybinding (yas/template-keybinding template)))
@@ -1976,7 +1940,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\"
   "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.
   ;; 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.
@@ -1987,10 +1951,10 @@ not need to be a real mode."
               (yas/delete-from-keymap (third (cdr item)) uuid)))
         (rest keymap))
   ;; Set the uuid entry to nil
               (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
   (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)))
   (setcdr keymap (delete-if #'(lambda (item)
                                 (or (null (cdr item))
                                     (and (keymapp (third (cdr item)))
@@ -2004,7 +1968,7 @@ MENU is a list, its elements can be:
 
 - (yas/item UUID) : Creates an entry the snippet identified with
   UUID. The menu entry for a snippet thus identified is
 
 - (yas/item UUID) : Creates an entry the snippet identified with
   UUID. The menu entry for a snippet thus identified is
-  permanent, i.e. it will never move in the menu.
+  permanent, i.e. it will never move (be reordered) in the menu.
 
 - (yas/separator) : Creates a separator
 
 
 - (yas/separator) : Creates a separator
 
@@ -2055,7 +2019,7 @@ ommited from MODE's menu, even if they're manually loaded.
            (define-key keymap (vector (gensym))
              '(menu-item "----")))
           (t
            (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.
 
 (defun yas/define (mode key template &optional name condition group)
   "Define a snippet.  Expanding KEY into TEMPLATE.
@@ -2139,7 +2103,10 @@ object satisfying `yas/field-p' to restrict the expansion to."
 If expansion fails, execute the previous binding for this key"
   (interactive)
   (setq yas/condition-cache-timestamp (current-time))
 If expansion fails, execute the previous binding for this key"
   (interactive)
   (setq yas/condition-cache-timestamp (current-time))
-  (let* ((vec (this-command-keys-vector))
+  (let* ((yas/prefix current-prefix-arg)
+         (vec (subseq (this-command-keys-vector) (if current-prefix-arg
+                                                     universal-argument-num-events
+                                                   0)))
          (templates (mapcan #'(lambda (table)
                                 (yas/fetch table vec))
                             (yas/get-snippet-tables))))
          (templates (mapcan #'(lambda (table)
                                 (yas/fetch table vec))
                             (yas/get-snippet-tables))))
@@ -2251,7 +2218,7 @@ by condition."
                             (car where)
                             (cdr where)
                             (yas/template-expand-env yas/current-template))
                             (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'.
 
 (defun yas/visit-snippet-file ()
   "Choose a snippet to edit, selection like `yas/insert-snippet'.
@@ -2340,7 +2307,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))
   (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)))
         (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)))
@@ -2355,8 +2322,11 @@ where snippets of table might exist."
               ;; create the .yas-parents file here...
               candidate)))))
 
               ;; create the .yas-parents file here...
               candidate)))))
 
-(defun yas/new-snippet (&optional choose-instead-of-guess)
-  ""
+(defun yas/new-snippet (&optional no-template)
+  "Pops a new buffer for writing a snippet.
+
+Expands a snippet-writing snippet, unless the optional prefix arg
+NO-TEMPLATE is non-nil."
   (interactive "P")
   (let ((guessed-directories (yas/guess-snippet-directories)))
 
   (interactive "P")
   (let ((guessed-directories (yas/guess-snippet-directories)))
 
@@ -2364,12 +2334,11 @@ where snippets of table might exist."
     (erase-buffer)
     (kill-all-local-variables)
     (snippet-mode)
     (erase-buffer)
     (kill-all-local-variables)
     (snippet-mode)
+    (yas/minor-mode 1)
     (set (make-local-variable 'yas/guessed-modes) (mapcar #'(lambda (d)
                                                               (intern (yas/table-name (car d))))
                                                           guessed-directories))
     (set (make-local-variable 'yas/guessed-modes) (mapcar #'(lambda (d)
                                                               (intern (yas/table-name (car d))))
                                                           guessed-directories))
-    (unless (and choose-instead-of-guess
-                 (not (y-or-n-p "Insert a snippet with useful headers? ")))
-      (yas/expand-snippet "\
+    (unless no-template (yas/expand-snippet "\
 # -*- mode: snippet -*-
 # name: $1
 # key: $2${3:
 # -*- mode: snippet -*-
 # name: $1
 # key: $2${3:
@@ -2421,7 +2390,13 @@ there, otherwise, proposes to create the first option returned by
                 (snippet-mode)))))
       (message "Could not guess snippet dir!"))))
 
                 (snippet-mode)))))
       (message "Could not guess snippet dir!"))))
 
-(defun yas/compute-major-mode-and-parents (file &optional prompt-if-failed)
+(defun yas/compute-major-mode-and-parents (file)
+  "Given FILE, find the nearest snippet directory for a given
+mode, then return a list (MODE-SYM PARENTS), the mode's symbol and a list
+representing one or more of the mode's parents.
+
+Note that MODE-SYM need not be the symbol of a real major mode,
+neither do the elements of PARENTS."
   (let* ((file-dir (and file
                         (directory-file-name (or (some #'(lambda (special)
                                                            (locate-dominating-file file special))
   (let* ((file-dir (and file
                         (directory-file-name (or (some #'(lambda (special)
                                                            (locate-dominating-file file special))
@@ -2433,10 +2408,7 @@ there, otherwise, proposes to create the first option returned by
          (major-mode-name (and file-dir
                                (file-name-nondirectory file-dir)))
          (major-mode-sym (or (and major-mode-name
          (major-mode-name (and file-dir
                                (file-name-nondirectory file-dir)))
          (major-mode-sym (or (and major-mode-name
-                                  (intern major-mode-name))
-                             (when prompt-if-failed
-                               (read-from-minibuffer
-                                "[yas] Cannot auto-detect major mode! Enter a major mode: "))))
+                                  (intern major-mode-name))))
          (parents (when (file-readable-p parents-file-name)
                          (mapcar #'intern
                                  (split-string
          (parents (when (file-readable-p parents-file-name)
                          (mapcar #'intern
                                  (split-string
@@ -2467,7 +2439,7 @@ With optional prefix argument KILL quit the window and buffer."
    ;;  neatly positioned,...
    ;;
    (yas/editing-template
    ;;  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'
                            (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'
@@ -2491,7 +2463,7 @@ With optional prefix argument KILL quit the window and buffer."
                              nil
                              (if (first yas/guessed-modes)
                                  (symbol-name (first yas/guessed-modes))))))))
                              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:
            (yas/define-snippets-1 (yas/parse-template buffer-file-name)
                                   table)))))
   ;; Now, offer to save this shit iff:
@@ -2508,8 +2480,8 @@ 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)))))
                  (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? ")
+
+    (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))))
       (let* ((option (first (yas/guess-snippet-directories (yas/template-table yas/editing-template))))
              (chosen (and option
                           (yas/make-directory-maybe option))))
@@ -2523,7 +2495,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))
             (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))))
 
            (yas/template-name yas/editing-template)
            (yas/table-name (yas/template-table yas/editing-template))))
 
@@ -2537,7 +2509,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)
                              (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)
          (yas/current-template
           (and parsed
                (fboundp test-mode)
@@ -2553,6 +2525,7 @@ With optional prefix argument KILL quit the window and buffer."
              (switch-to-buffer (get-buffer-create buffer-name))
              (setq buffer-undo-list nil)
              (condition-case nil (funcall test-mode) (error nil))
              (switch-to-buffer (get-buffer-create buffer-name))
              (setq buffer-undo-list nil)
              (condition-case nil (funcall test-mode) (error nil))
+             (setq buffer-read-only nil)
              (yas/expand-snippet (yas/template-content yas/current-template)
                                  (point-min)
                                  (point-max)
              (yas/expand-snippet (yas/template-content yas/current-template)
                                  (point-min)
                                  (point-max)
@@ -2561,7 +2534,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
                         (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)
 
 (defun yas/template-fine-group (template)
   (car (last (or (yas/template-group template)
@@ -2630,47 +2603,46 @@ With optional prefix argument KILL quit the window and buffer."
     (insert "\n"))
   (insert (make-string 100 ?-) "\n")
   (insert "group                   state name                                    key             binding\n")
     (insert "\n"))
   (insert (make-string 100 ?-) "\n")
   (insert "group                   state name                                    key             binding\n")
-  (let ((groups-alist (list))
-        group)
+  (let ((groups-hash (make-hash-table :test #'equal)))
     (maphash #'(lambda (k v)
     (maphash #'(lambda (k v)
-                 (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)))))
+                 (let ((group (or (yas/template-fine-group v)
+                                  "(top level)")))
+                   (when (yas/template-name v)
+                     (puthash group
+                              (cons v (gethash group groups-hash))
+                              groups-hash))))
              (yas/table-uuidhash table))
              (yas/table-uuidhash table))
-    (dolist (group-and-templates groups-alist)
-      (when (rest group-and-templates)
-        (setq group (truncate-string-to-width (car group-and-templates) 25 0 ?  "..."))
-        (insert (make-string 100 ?-) "\n")
-        (dolist (p (cdr group-and-templates))
-          (let ((name (truncate-string-to-width (propertize (format "\\\\snippet `%s'" (yas/template-name p))
-                                                            'yasnippet p)
-                                                50 0 ? "..."))
-                (group (prog1 group 
-                         (setq group (make-string (length group) ? ))))
-                (condition-string (let ((condition (yas/template-condition p)))
-                                    (if (and condition
-                                             original-buffer)
-                                        (with-current-buffer original-buffer
-                                          (if (yas/eval-condition condition)
-                                              "(y)"
-                                            "(s)"))
-                                      "(a)"))))
-            (insert group " ")
-            (insert condition-string " ")
-            (insert name 
-                    (if (string-match "\\.\\.\\.$" name)
-                        "'"
-                      " ")
-                    " ")
-            (insert (truncate-string-to-width (or (yas/template-key p) "")
-                                              15 0 ?  "...") " ")
-            (insert (truncate-string-to-width (key-description (yas/template-keybinding p))
-                                              15 0 ?  "...") " ")
-            (insert "\n")))))))
-
-
+    (maphash
+     #'(lambda (group templates)
+         (setq group (truncate-string-to-width group 25 0 ?  "..."))
+         (insert (make-string 100 ?-) "\n")
+         (dolist (p templates)
+           (let ((name (truncate-string-to-width (propertize (format "\\\\snippet `%s'" (yas/template-name p))
+                                                             'yasnippet p)
+                                                 50 0 ? "..."))
+                 (group (prog1 group
+                          (setq group (make-string (length group) ? ))))
+                 (condition-string (let ((condition (yas/template-condition p)))
+                                     (if (and condition
+                                              original-buffer)
+                                         (with-current-buffer original-buffer
+                                           (if (yas/eval-condition condition)
+                                               "(y)"
+                                             "(s)"))
+                                       "(a)"))))
+             (insert group " ")
+             (insert condition-string " ")
+             (insert name
+                     (if (string-match "\\.\\.\\.$" name)
+                         "'"
+                       " ")
+                     " ")
+             (insert (truncate-string-to-width (or (yas/template-key p) "")
+                                               15 0 ?  "...") " ")
+             (insert (truncate-string-to-width (key-description (yas/template-keybinding p))
+                                               15 0 ?  "...") " ")
+             (insert "\n"))))
+     groups-hash)))
 
 
 \f
 
 
 \f
@@ -2722,7 +2694,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))
 
 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.
 
 (defun yas/field-value (number)
   "Get the string for field with NUMBER.
@@ -2888,13 +2860,24 @@ have, compare through the field's start point"
 
 (defun yas/field-probably-deleted-p (snippet field)
   "Guess if SNIPPET's FIELD should be skipped."
 
 (defun yas/field-probably-deleted-p (snippet field)
   "Guess if SNIPPET's FIELD should be skipped."
-  (and (zerop (- (yas/field-start field) (yas/field-end field)))
-       (or (yas/field-parent-field field)
-           (and (eq field (car (last (yas/snippet-fields snippet))))
-                (= (yas/field-start field) (overlay-end (yas/snippet-control-overlay snippet)))))
-       ;; the field numbered 0, just before the exit marker, should
-       ;; never be skipped
-       (not (zerop (yas/field-number field)))))
+  (and
+   ;; field must be zero lentgh
+   ;;
+   (zerop (- (yas/field-start field) (yas/field-end field)))
+   ;; skip if:
+   (or
+    ;;  1) is a nested field and it's been modified
+    ;;
+    (and (yas/field-parent-field field)
+         (yas/field-modified-p field))
+    ;;  2) ends just before the snippet end
+    ;;
+    (and (eq field (car (last (yas/snippet-fields snippet))))
+         (= (yas/field-start field) (overlay-end (yas/snippet-control-overlay snippet)))))
+   ;; the field numbered 0, just before the exit marker, should
+   ;; never be skipped
+   ;;
+   (not (zerop (yas/field-number field)))))
 
 (defun yas/snippets-at-point (&optional all-snippets)
   "Return a sorted list of snippets at point, most recently
 
 (defun yas/snippets-at-point (&optional all-snippets)
   "Return a sorted list of snippets at point, most recently
@@ -2965,7 +2948,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)))
   (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))
     (if (and number (zerop number))
         (progn
           (set-mark (yas/field-end field))
@@ -3007,7 +2990,7 @@ Also create some protection overlays"
   (mapc #'(lambda (snippet)
             (yas/exit-snippet snippet)
             (yas/check-commit-snippet))
   (mapc #'(lambda (snippet)
             (yas/exit-snippet snippet)
             (yas/check-commit-snippet))
-        (yas/snippets-at-point)))
+        (yas/snippets-at-point 'all-snippets)))
 
 \f
 ;;; Some low level snippet-routines
 
 \f
 ;;; Some low level snippet-routines
@@ -3018,16 +3001,14 @@ Also create some protection overlays"
   `(let ((yas/inhibit-overlay-hooks t))
      (progn ,@body)))
 
   `(let ((yas/inhibit-overlay-hooks t))
      (progn ,@body)))
 
+(defvar yas/snippet-beg nil "Beginning position of the last snippet commited.")
+(defvar yas/snippet-end nil "End position of the last snippet commited.")
+
 (defun yas/commit-snippet (snippet)
   "Commit SNIPPET, but leave point as it is.  This renders the
 (defun yas/commit-snippet (snippet)
   "Commit SNIPPET, but leave point as it is.  This renders the
-snippet as ordinary text.
-
-Return a buffer position where the point should be placed if
-exiting the snippet."
+snippet as ordinary text."
 
 
-  (let ((control-overlay (yas/snippet-control-overlay snippet))
-        yas/snippet-beg
-        yas/snippet-end)
+  (let ((control-overlay (yas/snippet-control-overlay snippet)))
     ;;
     ;; Save the end of the moribund snippet in case we need to revive it
     ;; its original expansion.
     ;;
     ;; Save the end of the moribund snippet in case we need to revive it
     ;; its original expansion.
@@ -3065,13 +3046,13 @@ exiting the snippet."
       ;; again from `yas/take-care-of-redo'....
       (setf (yas/snippet-fields snippet) nil)))
 
       ;; 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
 
 (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 ()
 
 
 (defun yas/check-commit-snippet ()
@@ -3082,7 +3063,7 @@ snippet, if so cleans up the whole snippet up."
          (snippet-exit-transform))
     (dolist (snippet snippets)
       (let ((active-field (yas/snippet-active-field snippet)))
          (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))
         (cond ((or snippet-exit-transform
                    (not (and active-field (yas/field-contains-point-p active-field))))
                (setq snippets-left (delete snippet snippets-left))
@@ -3426,7 +3407,7 @@ considered when expanding the snippet."
                (yas/inhibit-overlay-hooks
                  (setq snippet
                        (if expand-env
                (yas/inhibit-overlay-hooks
                  (setq snippet
                        (if expand-env
-                           (eval `(let ,expand-env
+                           (eval `(let* ,expand-env
                                     (insert content)
                                     (yas/snippet-create (point-min) (point-max))))
                          (insert content)
                                     (insert content)
                                     (yas/snippet-create (point-min) (point-max))))
                          (insert content)
@@ -3470,7 +3451,7 @@ considered when expanding the snippet."
              (when first-field
                (sit-for 0) ;; fix issue 125
                (yas/move-to-field snippet first-field)))
              (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)
            t))))
 
 (defun yas/take-care-of-redo (beg end snippet)
@@ -3685,7 +3666,7 @@ Meant to be called in a narrowed buffer, does various passes"
     (setq yas/dollar-regions nil)
     ;; protect escaped quote, backquotes and backslashes
     ;;
     (setq yas/dollar-regions nil)
     ;; protect escaped quote, backquotes and backslashes
     ;;
-    (yas/protect-escapes nil '(?\\ ?` ?'))
+    (yas/protect-escapes nil `(?\\ ?` ?'))
     ;; replace all backquoted expressions
     ;;
     (goto-char parse-start)
     ;; replace all backquoted expressions
     ;;
     (goto-char parse-start)
@@ -3754,7 +3735,7 @@ SNIPPET-MARKERS."
       (widen)
       (condition-case err
           (indent-according-to-mode)
       (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' having problems running %s" indent-line-function)
                nil)))
     (mapc #'(lambda (marker)
               (set-marker marker (point)))
                nil)))
     (mapc #'(lambda (marker)
               (set-marker marker (point)))
@@ -4097,7 +4078,7 @@ that the rest of `yas/post-command-handler' runs.")
                   (apply (car fn-and-args)
                          (cdr fn-and-args)))
               yas/post-command-runonce-actions)
                   (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)
     (setq yas/post-command-runonce-actions nil))
   (cond (yas/protection-violation
          (goto-char yas/protection-violation)
@@ -4204,13 +4185,25 @@ 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)))))
                                     (gethash uuid (yas/table-uuidhash table)))))
     (when yas/current-template
       (yas/expand-snippet (yas/template-content yas/current-template)))))
+\f
+;;; 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))
 
 \f
 ;;; Some hacks:
 
 \f
 ;;; Some hacks:
-;;; 
-;; `locate-dominating-file' 
+;;;
+;; `locate-dominating-file'
 ;; `region-active-p'
 ;; `region-active-p'
-;; 
+;;
 ;; added for compatibility in emacs < 23
 (unless (>= emacs-major-version 23)
   (unless (fboundp 'region-active-p)
 ;; added for compatibility in emacs < 23
 (unless (>= emacs-major-version 23)
   (unless (fboundp 'region-active-p)