]> code.delx.au - gnu-emacs-elpa/blobdiff - yasnippet.el
Add yas-backport-obsolete-alias option
[gnu-emacs-elpa] / yasnippet.el
index c93d886c19e2fed28fafbf2091b5dc3e7687248f..0f3e290ef65b86f42d04a06a7d0402d778b11de9 100644 (file)
@@ -1,13 +1,15 @@
 ;;; yasnippet.el --- Yet another snippet extension for Emacs.
 
 ;;; yasnippet.el --- Yet another snippet extension for Emacs.
 
-;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
-;; Authors: pluskid <pluskid@gmail.com>,  João Távora <joaotavora@gmail.com>
-;; Maintainer: João Távora <joaotavora@gmail.com>
-;; Version: 0.8.1
-;; Package-version: 0.8.0
+;; Copyright (C) 2008-2016 Free Software Foundation, Inc.
+;; Authors: pluskid <pluskid@gmail.com>,
+;;          João Távora <joaotavora@gmail.com>,
+;;          Noam Postavsky <npostavs@gmail.com>
+;; Maintainer: Noam Postavsky <npostavs@gmail.com>
+;; Version: 0.9.1
 ;; X-URL: http://github.com/capitaomorte/yasnippet
 ;; Keywords: convenience, emulation
 ;; URL: http://github.com/capitaomorte/yasnippet
 ;; X-URL: http://github.com/capitaomorte/yasnippet
 ;; Keywords: convenience, emulation
 ;; URL: http://github.com/capitaomorte/yasnippet
+;; Package-Requires: ((cl-lib "0.5"))
 ;; EmacsWiki: YaSnippetMode
 
 ;; This program is free software: you can redistribute it and/or modify
 ;; EmacsWiki: YaSnippetMode
 
 ;; This program is free software: you can redistribute it and/or modify
@@ -41,7 +43,7 @@
 ;;           stored.  Can also be a list of directories.  In that case,
 ;;           when used for bulk (re)loading of snippets (at startup or
 ;;           via `yas-reload-all'), directories appearing earlier in
 ;;           stored.  Can also be a list of directories.  In that case,
 ;;           when used for bulk (re)loading of snippets (at startup or
 ;;           via `yas-reload-all'), directories appearing earlier in
-;;           the list shadow other dir's snippets.  Also, the first
+;;           the list override other dir's snippets.  Also, the first
 ;;           directory is taken as the default for storing the user's
 ;;           new snippets.
 ;;
 ;;           directory is taken as the default for storing the user's
 ;;           new snippets.
 ;;
 (defvar yas-installed-snippets-dir nil)
 (setq yas-installed-snippets-dir
       (when load-file-name
 (defvar yas-installed-snippets-dir nil)
 (setq yas-installed-snippets-dir
       (when load-file-name
-        (concat (file-name-directory load-file-name) "snippets")))
+        (expand-file-name "snippets" (file-name-directory load-file-name))))
+
+(defconst yas--default-user-snippets-dir
+  (expand-file-name "snippets" user-emacs-directory))
 
 (defcustom yas-snippet-dirs (remove nil
 
 (defcustom yas-snippet-dirs (remove nil
-                                    (list "~/.emacs.d/snippets"
+                                    (list yas--default-user-snippets-dir
                                           'yas-installed-snippets-dir))
   "List of top-level snippet directories.
 
                                           'yas-installed-snippets-dir))
   "List of top-level snippet directories.
 
@@ -165,13 +170,14 @@ Each element, a string or a symbol whose value is a string,
 designates a top-level directory where per-mode snippet
 directories can be found.
 
 designates a top-level directory where per-mode snippet
 directories can be found.
 
-Elements appearing earlier in the list shadow later elements'
+Elements appearing earlier in the list override later elements'
 snippets.
 
 The first directory is taken as the default for storing snippet's
 created with `yas-new-snippet'. "
 snippets.
 
 The first directory is taken as the default for storing snippet's
 created with `yas-new-snippet'. "
-  :type '(choice (string :tag "Single directory (string)")
-                 (repeat :args (string) :tag "List of directories (strings)"))
+  :type '(choice (directory :tag "Single directory")
+                 (repeat :tag "List of directories"
+                         (choice (directory) (variable))))
   :group 'yasnippet
   :require 'yasnippet
   :set #'(lambda (symbol new)
   :group 'yasnippet
   :require 'yasnippet
   :set #'(lambda (symbol new)
@@ -199,10 +205,9 @@ created with `yas-new-snippet'. "
 (defvaralias 'yas/root-directory 'yas-snippet-dirs)
 
 (defcustom yas-new-snippet-default "\
 (defvaralias 'yas/root-directory 'yas-snippet-dirs)
 
 (defcustom yas-new-snippet-default "\
-# -*- mode: snippet; require-final-newline: nil -*-
+# -*- mode: snippet -*-
 # name: $1
 # name: $1
-# key: ${2:${1:$(yas--key-from-desc yas-text)}}${3:
-# binding: ${4:direct-keybinding}}
+# key: ${2:${1:$(yas--key-from-desc yas-text)}}
 # --
 $0"
   "Default snippet to use when creating a new snippet.
 # --
 $0"
   "Default snippet to use when creating a new snippet.
@@ -210,10 +215,9 @@ If nil, don't use any snippet."
   :type 'string
   :group 'yasnippet)
 
   :type 'string
   :group 'yasnippet)
 
-(defcustom yas-prompt-functions '(yas-x-prompt
-                                  yas-dropdown-prompt
+(defcustom yas-prompt-functions '(yas-dropdown-prompt
                                   yas-completing-prompt
                                   yas-completing-prompt
-                                  yas-ido-prompt
+                                  yas-maybe-ido-prompt
                                   yas-no-prompt)
   "Functions to prompt for keys, templates, etc interactively.
 
                                   yas-no-prompt)
   "Functions to prompt for keys, templates, etc interactively.
 
@@ -342,11 +346,16 @@ Any other non-nil value, every submenu is listed."
   :group 'yasnippet)
 
 (defcustom yas-wrap-around-region nil
   :group 'yasnippet)
 
 (defcustom yas-wrap-around-region nil
-  "If non-nil, snippet expansion wraps around selected region.
-
-The wrapping occurs just before the snippet's exit marker.  This
-can be overridden on a per-snippet basis."
-  :type 'boolean
+  "What to insert for snippet's $0 field.
+
+If set to a character, insert contents of corresponding register.
+If non-nil insert region contents.  This can be overridden on a
+per-snippet basis.  A value of `cua' is considered equivalent to
+`?0' for backwards compatibility."
+  :type '(choice (character :tag "Insert from register")
+                 (const t :tag "Insert region contents")
+                 (const nil :tag "Don't insert anything")
+                 (const cua)) ; backwards compat
   :group 'yasnippet)
 
 (defcustom yas-good-grace t
   :group 'yasnippet)
 
 (defcustom yas-good-grace t
@@ -377,6 +386,11 @@ the trigger key itself."
   :type '(repeat function)
   :group 'yasnippet)
 
   :type '(repeat function)
   :group 'yasnippet)
 
+(defcustom yas-backport-obsolete-alias t
+  "If non-nil backport function and variables from old version of yasnippet."
+  :type 'boolean
+  :group 'yasnippet)
+
 ;; Only two faces, and one of them shouldn't even be used...
 ;;
 (defface yas-field-highlight-face
 ;; Only two faces, and one of them shouldn't even be used...
 ;;
 (defface yas-field-highlight-face
@@ -459,10 +473,10 @@ Attention: These hooks are not run when exiting nested/stacked snippet expansion
   "Hooks to run just before expanding a snippet.")
 
 (defvar yas-buffer-local-condition
   "Hooks to run just before expanding a snippet.")
 
 (defvar yas-buffer-local-condition
-  '(if (and (or (fourth (syntax-ppss))
-                (fifth (syntax-ppss)))
-           this-command
-            (eq this-command 'yas-expand-from-trigger-key))
+  '(if (and (let ((ppss (syntax-ppss)))
+              (or (nth 3 ppss) (nth 4 ppss)))
+            (memq this-command '(yas-expand yas-expand-from-trigger-key
+                                            yas-expand-from-keymap)))
        '(require-snippet-condition . force-in-comment)
      t)
   "Snippet expanding condition.
        '(require-snippet-condition . force-in-comment)
      t)
   "Snippet expanding condition.
@@ -507,7 +521,7 @@ snippets returning the symbol 'force-in-comment in their
 conditions.
 
  (add-hook 'python-mode-hook
 conditions.
 
  (add-hook 'python-mode-hook
-           '(lambda ()
+           (lambda ()
               (setq yas-buffer-local-condition
                     '(if (python-in-string/comment)
                          '(require-snippet-condition . force-in-comment)
               (setq yas-buffer-local-condition
                     '(if (python-in-string/comment)
                          '(require-snippet-condition . force-in-comment)
@@ -521,15 +535,11 @@ snippet itself contains a condition that returns the symbol
 \f
 ;;; Internal variables
 
 \f
 ;;; Internal variables
 
-(defvar yas--version "0.8.0beta")
+(defvar yas--version "0.9.1")
 
 (defvar yas--menu-table (make-hash-table)
   "A hash table of MAJOR-MODE symbols to menu keymaps.")
 
 
 (defvar yas--menu-table (make-hash-table)
   "A hash table of MAJOR-MODE symbols to menu keymaps.")
 
-(defvar yas--known-modes
-  '(ruby-mode rst-mode markdown-mode)
-  "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.")
 (defvar yas--escaped-characters
   '(?\\ ?` ?\" ?' ?$ ?} ?{ ?\( ?\))
   "List of characters which *might* need to be escaped.")
@@ -691,7 +701,7 @@ snippet itself contains a condition that returns the symbol
 
 This variable probably makes more sense as buffer-local, so
 ensure your use `make-local-variable' when you set it.")
 
 This variable probably makes more sense as buffer-local, so
 ensure your use `make-local-variable' when you set it.")
-(define-obsolete-variable-alias 'yas-extra-modes 'yas--extra-modes "0.8.1")
+(define-obsolete-variable-alias 'yas-extra-modes 'yas--extra-modes "0.9.1")
 
 (defvar yas--tables (make-hash-table)
   "A hash table of mode symbols to `yas--table' objects.")
 
 (defvar yas--tables (make-hash-table)
   "A hash table of mode symbols to `yas--table' objects.")
@@ -729,23 +739,26 @@ defined direct keybindings to the command
                      yas--direct-keymaps))
            yas--tables))
 
                      yas--direct-keymaps))
            yas--tables))
 
-(defun yas--modes-to-activate ()
-  "Compute list of mode symbols that are active for `yas-expand'
-and friends."
-  (let (dfs)
-    (setq dfs (lambda (mode &optional explored)
-                (push mode explored)
-                (cons mode
-                      (loop for neighbour
-                            in (cl-list* (get mode 'derived-mode-parent)
-                                         (ignore-errors (symbol-function mode))
-                                         (gethash mode yas--parents))
-                            when (and neighbour
-                                      (not (memq neighbour explored))
-                                      (symbolp neighbour))
-                            append (funcall dfs neighbour explored)))))
-    (remove-duplicates (append yas--extra-modes
-                               (funcall dfs major-mode)))))
+(defun yas--modes-to-activate (&optional mode)
+  "Compute list of mode symbols that are active for `yas-expand' and friends."
+  (defvar yas--dfs)        ;We rely on dynbind.  We could use `letrec' instead!
+  (let* ((explored (if mode (list mode) ; Building up list in reverse.
+                     (cons major-mode (reverse yas--extra-modes))))
+         (yas--dfs
+          (lambda (mode)
+            (cl-loop for neighbour
+                     in (cl-list* (get mode 'derived-mode-parent)
+                                  ;; NOTE: `fboundp' check is redundant
+                                  ;; since Emacs 24.4.
+                                  (and (fboundp mode) (symbol-function mode))
+                                  (gethash mode yas--parents))
+                     when (and neighbour
+                               (not (memq neighbour explored))
+                               (symbolp neighbour))
+                     do (push neighbour explored)
+                     (funcall yas--dfs neighbour)))))
+    (mapc yas--dfs explored)
+    (nreverse explored)))
 
 (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.")
@@ -768,7 +781,7 @@ Key bindings:
   ;; The indicator for the mode line.
   " yas"
   :group 'yasnippet
   ;; The indicator for the mode line.
   " yas"
   :group 'yasnippet
-  (cond (yas-minor-mode
+  (cond ((and yas-minor-mode (featurep 'yasnippet))
          ;; Install the direct keymaps in `emulation-mode-map-alists'
          ;; (we use `add-hook' even though it's not technically a hook,
          ;; but it works). Then define variables named after modes to
          ;; Install the direct keymaps in `emulation-mode-map-alists'
          ;; (we use `add-hook' even though it's not technically a hook,
          ;; but it works). Then define variables named after modes to
@@ -776,8 +789,8 @@ Key bindings:
          ;;
          ;; Also install the post-command-hook.
          ;;
          ;;
          ;; Also install the post-command-hook.
          ;;
-         (add-hook 'emulation-mode-map-alists 'yas--direct-keymaps)
-         (add-hook 'post-command-hook 'yas--post-command-handler nil t)
+         (cl-pushnew 'yas--direct-keymaps emulation-mode-map-alists)
+         (add-hook 'post-command-hook #'yas--post-command-handler nil t)
          ;; Set the `yas--direct-%s' vars for direct keymap expansion
          ;;
          (dolist (mode (yas--modes-to-activate))
          ;; Set the `yas--direct-%s' vars for direct keymap expansion
          ;;
          (dolist (mode (yas--modes-to-activate))
@@ -790,8 +803,9 @@ Key bindings:
         (t
          ;; Uninstall the direct keymaps and the post-command hook
          ;;
         (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))))
+         (remove-hook 'post-command-hook #'yas--post-command-handler t)
+         (setq emulation-mode-map-alists
+               (remove 'yas--direct-keymaps emulation-mode-map-alists)))))
 
 (defun yas-activate-extra-mode (mode)
   "Activates the snippets for the given `mode' in the buffer.
 
 (defun yas-activate-extra-mode (mode)
   "Activates the snippets for the given `mode' in the buffer.
@@ -823,21 +837,20 @@ activate snippets associated with that mode."
        (remove mode
                yas--extra-modes)))
 
        (remove mode
                yas--extra-modes)))
 
-(defvar yas-dont-activate '(minibufferp)
-  "If non-nil don't let `yas-global-mode' affect some buffers.
-
-If a function of zero arguments, then its result is used.
-
-If a list of functions, then all functions must return nil to
-activate yas for this buffer.
+(define-obsolete-variable-alias 'yas-dont-activate
+  'yas-dont-activate-functions "0.9.2")
+(defvar yas-dont-activate-functions (list #'minibufferp)
+  "Special hook to control which buffers `yas-global-mode' affects.
+Functions are called with no argument, and should return non-nil to prevent
+`yas-global-mode' from enabling yasnippet in this buffer.
 
 
-In Emacsen <= 23, this variable is buffer-local.  Because
+In Emacsen < 24, this variable is buffer-local.  Because
 `yas-minor-mode-on' is called by `yas-global-mode' after
 executing the buffer's major mode hook, setting this variable
 there is an effective way to define exceptions to the \"global\"
 activation behaviour.
 
 `yas-minor-mode-on' is called by `yas-global-mode' after
 executing the buffer's major mode hook, setting this variable
 there is an effective way to define exceptions to the \"global\"
 activation behaviour.
 
-In Emacsen > 23, only the global value is used.  To define
+In Emacsen >= 24, only the global value is used.  To define
 per-mode exceptions to the \"global\" activation behaviour, call
 `yas-minor-mode' with a negative argument directily in the major
 mode's hook.")
 per-mode exceptions to the \"global\" activation behaviour, call
 `yas-minor-mode' with a negative argument directily in the major
 mode's hook.")
@@ -849,14 +862,14 @@ mode's hook.")
 (defun yas-minor-mode-on ()
   "Turn on YASnippet minor mode.
 
 (defun yas-minor-mode-on ()
   "Turn on YASnippet minor mode.
 
-Honour `yas-dont-activate', which see."
+Honour `yas-dont-activate-functions', which see."
   (interactive)
   (interactive)
-  ;; Check `yas-dont-activate'
-  (unless (cond ((functionp yas-dont-activate)
-                 (funcall yas-dont-activate))
-                ((consp yas-dont-activate)
-                 (some #'funcall yas-dont-activate))
-                (yas-dont-activate))
+  (unless (or
+           ;; The old behavior used for Emacs<24 was to set
+           ;; `yas-dont-activate-functions' to t buffer-locally.
+           (not (or (listp yas-dont-activate-functions)
+                    (functionp yas-dont-activate-functions)))
+           (run-hook-with-args-until-success 'yas-dont-activate-functions))
     (yas-minor-mode 1)))
 
 ;;;###autoload
     (yas-minor-mode 1)))
 
 ;;;###autoload
@@ -868,22 +881,28 @@ Honour `yas-dont-activate', which see."
   "Run `yas-reload-all' when `yas-global-mode' is on."
   (when yas-global-mode (yas-reload-all)))
 
   "Run `yas-reload-all' when `yas-global-mode' is on."
   (when yas-global-mode (yas-reload-all)))
 
-(add-hook 'yas-global-mode-hook 'yas--global-mode-reload-with-jit-maybe)
+(add-hook 'yas-global-mode-hook #'yas--global-mode-reload-with-jit-maybe)
 
 \f
 ;;; Major mode stuff
 
 (defvar yas--font-lock-keywords
   (append '(("^#.*$" . font-lock-comment-face))
 
 \f
 ;;; Major mode stuff
 
 (defvar yas--font-lock-keywords
   (append '(("^#.*$" . font-lock-comment-face))
-          lisp-font-lock-keywords-2
+          (with-temp-buffer
+            (let ((prog-mode-hook nil)
+                  (emacs-lisp-mode-hook nil))
+              (ignore-errors (emacs-lisp-mode)))
+            (font-lock-set-defaults)
+            (if (eq t (car-safe font-lock-keywords))
+                ;; They're "compiled", so extract the source.
+                (cadr font-lock-keywords)
+              font-lock-keywords))
           '(("$\\([0-9]+\\)"
              (0 font-lock-keyword-face)
              (1 font-lock-string-face t))
             ("${\\([0-9]+\\):?"
              (0 font-lock-keyword-face)
              (1 font-lock-warning-face t))
           '(("$\\([0-9]+\\)"
              (0 font-lock-keyword-face)
              (1 font-lock-string-face t))
             ("${\\([0-9]+\\):?"
              (0 font-lock-keyword-face)
              (1 font-lock-warning-face t))
-            ("${" . font-lock-keyword-face)
-            ("$[0-9]+?" . font-lock-preprocessor-face)
             ("\\(\\$(\\)" 1 font-lock-preprocessor-face)
             ("}"
              (0 font-lock-keyword-face)))))
             ("\\(\\$(\\)" 1 font-lock-preprocessor-face)
             ("}"
              (0 font-lock-keyword-face)))))
@@ -905,6 +924,7 @@ Honour `yas-dont-activate', which see."
   "The keymap used when `snippet-mode' is active.")
 
 
   "The keymap used when `snippet-mode' is active.")
 
 
+;;;###autoload
 (define-derived-mode snippet-mode text-mode "Snippet"
   "A mode for editing yasnippets"
   (setq font-lock-defaults '(yas--font-lock-keywords))
 (define-derived-mode snippet-mode text-mode "Snippet"
   "A mode for editing yasnippets"
   (setq font-lock-defaults '(yas--font-lock-keywords))
@@ -916,14 +936,39 @@ Honour `yas-dont-activate', which see."
 \f
 ;;; Internal structs for template management
 
 \f
 ;;; Internal structs for template management
 
-(defstruct (yas--template (:constructor yas--make-blank-template))
+(cl-defstruct (yas--template
+               (:constructor yas--make-template)
+               ;; Handles `yas-define-snippets' format, plus the
+               ;; initial TABLE argument.
+               (:constructor
+                yas--define-snippets-2
+                (table
+                 key content
+                 &optional xname condition group
+                 expand-env load-file xkeybinding xuuid save-file
+                 &aux
+                 (name (or xname
+                           ;; A little redundant: we always get a name
+                           ;; from `yas--parse-template' except when
+                           ;; there isn't a file.
+                           (and load-file (file-name-nondirectory load-file))
+                           (and save-file (file-name-nondirectory save-file))
+                           key))
+                 (keybinding (yas--read-keybinding xkeybinding))
+                 (uuid (or xuuid name))
+                 (old (gethash uuid (yas--table-uuidhash table)))
+                 (menu-binding-pair
+                  (and old (yas--template-menu-binding-pair old)))
+                 (perm-group
+                  (and old (yas--template-perm-group old))))))
   "A template for a snippet."
   key
   content
   name
   condition
   expand-env
   "A template for a snippet."
   key
   content
   name
   condition
   expand-env
-  file
+  load-file
+  save-file
   keybinding
   uuid
   menu-binding-pair
   keybinding
   uuid
   menu-binding-pair
@@ -932,16 +977,6 @@ Honour `yas-dont-activate', which see."
   table
   )
 
   table
   )
 
-(defun yas--populate-template (template &rest args)
-  "Helper function to populate TEMPLATE with properties."
-  (while args
-    (aset template
-          (position (intern (substring (symbol-name (car args)) 1))
-                    (mapcar #'car (get 'yas--template 'cl-struct-slots)))
-          (second args))
-    (setq args (cddr args)))
-  template)
-
 (defstruct (yas--table (:constructor yas--make-snippet-table (name)))
   "A table to store snippets for a particular mode.
 
 (defstruct (yas--table (:constructor yas--make-snippet-table (name)))
   "A table to store snippets for a particular mode.
 
@@ -1093,7 +1128,8 @@ keybinding)."
 (defun yas--update-template (table template)
   "Add or update TEMPLATE in TABLE.
 
 (defun yas--update-template (table template)
   "Add or update TEMPLATE in TABLE.
 
-Also takes care of adding and updating to the associated menu."
+Also takes care of adding and updating to the associated menu.
+Return TEMPLATE."
   ;; Remove from table by uuid
   ;;
   (yas--remove-template-by-uuid table (yas--template-uuid template))
   ;; Remove from table by uuid
   ;;
   (yas--remove-template-by-uuid table (yas--template-uuid template))
@@ -1102,7 +1138,8 @@ Also takes care of adding and updating to the associated menu."
   (yas--add-template table template)
   ;; Take care of the menu
   ;;
   (yas--add-template table template)
   ;; Take care of the menu
   ;;
-  (yas--update-template-menu table template))
+  (yas--update-template-menu table template)
+  template)
 
 (defun yas--update-template-menu (table template)
   "Update every menu-related for TEMPLATE."
 
 (defun yas--update-template-menu (table template)
   "Update every menu-related for TEMPLATE."
@@ -1257,7 +1294,8 @@ Returns (TEMPLATES START END). This function respects
                            'again)
                  (setq methods (cdr methods))))
               (t
                            'again)
                  (setq methods (cdr methods))))
               (t
-               (yas--warning "Warning invalid element %s in `yas-key-syntaxes'" method)))
+               (setq methods (cdr methods))
+               (yas--warning "Invalid element `%s' in `yas-key-syntaxes'" method)))
         (let ((possible-key (buffer-substring-no-properties (point) original)))
           (save-excursion
             (goto-char original)
         (let ((possible-key (buffer-substring-no-properties (point) original)))
           (save-excursion
             (goto-char original)
@@ -1283,16 +1321,6 @@ Returns (TEMPLATES START END). This function respects
 \f
 ;;; Internal functions and macros:
 
 \f
 ;;; Internal functions and macros:
 
-(defun yas--real-mode? (mode)
-  "Try to find out if MODE is a real mode.
-
-The MODE bound to a function (like `c-mode') is considered real
-mode.  Other well known mode like `ruby-mode' which is not part of
-Emacs might not bound to a function until it is loaded.  So
-yasnippet keeps a list of modes like this to help the judgment."
-  (or (fboundp mode)
-      (find mode yas--known-modes)))
-
 (defun yas--handle-error (err)
   "Handle error depending on value of `yas-good-grace'."
   (let ((msg (yas--format "elisp error: %s" (error-message-string err))))
 (defun yas--handle-error (err)
   "Handle error depending on value of `yas-good-grace'."
   (let ((msg (yas--format "elisp error: %s" (error-message-string err))))
@@ -1341,7 +1369,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
-       (yas--message 3 "warning: keybinding \"%s\" invalid since %s."
+       (yas--message 2 "warning: keybinding \"%s\" invalid since %s."
                 keybinding (error-message-string err))
        nil))))
 
                 keybinding (error-message-string err))
        nil))))
 
@@ -1357,15 +1385,17 @@ return an expression that when evaluated will issue an error."
             yas--direct-keymaps))
     table))
 
             yas--direct-keymaps))
     table))
 
-(defun yas--get-snippet-tables ()
-  "Get snippet tables for current buffer.
+(defun yas--get-snippet-tables (&optional mode)
+  "Get snippet tables for MODE.
+
+MODE defaults to the current buffer's `major-mode'.
 
 Return a list of `yas--table' objects.  The list of modes to
 consider is returned by `yas--modes-to-activate'"
   (remove nil
           (mapcar #'(lambda (name)
                       (gethash name yas--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 (name)
                       (gethash name yas--tables))
-                  (yas--modes-to-activate))))
+                  (yas--modes-to-activate mode))))
 
 (defun yas--menu-keymap-get-create (mode &optional parents)
   "Get or create the menu keymap for MODE and its PARENTS.
 
 (defun yas--menu-keymap-get-create (mode &optional parents)
   "Get or create the menu keymap for MODE and its PARENTS.
@@ -1380,16 +1410,6 @@ them all in `yas--menu-table'"
                     :visible (yas--show-menu-p ',mode)))
     menu-keymap))
 
                     :visible (yas--show-menu-p ',mode)))
     menu-keymap))
 
-
-(defmacro yas--called-interactively-p (&optional kind)
-  "A backward-compatible version of `called-interactively-p'.
-
-Optional KIND is as documented at `called-interactively-p'
-in GNU Emacs 24.1 or higher."
-  (if (string< emacs-version "24.1")
-      '(called-interactively-p)
-    `(called-interactively-p ,kind)))
-
 \f
 ;;; Template-related and snippet loading functions
 
 \f
 ;;; Template-related and snippet loading functions
 
@@ -1404,7 +1424,7 @@ otherwise we attempt to calculate it from FILE.
 
 Return a snippet-definition, i.e. a list
 
 
 Return a snippet-definition, i.e. a list
 
- (KEY TEMPLATE NAME CONDITION GROUP VARS FILE KEYBINDING UUID)
+ (KEY TEMPLATE NAME CONDITION GROUP VARS LOAD-FILE KEYBINDING UUID)
 
 If the buffer contains a line of \"# --\" then the contents above
 this line are ignored. Directives can set most of these with the syntax:
 
 If the buffer contains a line of \"# --\" then the contents above
 this line are ignored. Directives can set most of these with the syntax:
@@ -1441,7 +1461,7 @@ Here's a list of currently recognized directives:
                                                      (point-max)))
                (setq bound (point))
                (goto-char (point-min))
                                                      (point-max)))
                (setq bound (point))
                (goto-char (point-min))
-               (while (re-search-forward "^# *\\([^ ]+?\\) *: *\\(.*\\)$" bound t)
+               (while (re-search-forward "^# *\\([^ ]+?\\) *: *\\(.*?\\)[[:space:]]*$" bound t)
                  (when (string= "uuid" (match-string-no-properties 1))
                    (setq uuid (match-string-no-properties 2)))
                  (when (string= "type" (match-string-no-properties 1))
                  (when (string= "uuid" (match-string-no-properties 1))
                    (setq uuid (match-string-no-properties 2)))
                  (when (string= "type" (match-string-no-properties 1))
@@ -1476,10 +1496,7 @@ Here's a list of currently recognized directives:
   (let* ((dominating-dir (locate-dominating-file file
                                                  ".yas-make-groups"))
          (extra-path (and dominating-dir
   (let* ((dominating-dir (locate-dominating-file file
                                                  ".yas-make-groups"))
          (extra-path (and dominating-dir
-                          (replace-regexp-in-string (concat "^"
-                                                            (expand-file-name dominating-dir))
-                                                    ""
-                                                    (expand-file-name file))))
+                          (file-relative-name file dominating-dir)))
          (extra-dir (and extra-path
                          (file-name-directory extra-path)))
          (group (and extra-dir
          (extra-dir (and extra-path
                          (file-name-directory extra-path)))
          (group (and extra-dir
@@ -1490,17 +1507,17 @@ Here's a list of currently recognized directives:
 
 (defun yas--subdirs (directory &optional filep)
   "Return subdirs or files of DIRECTORY according to FILEP."
 
 (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))
-                   (string-match "^#.*#$"
-                                 (file-name-nondirectory file))
-                   (string-match "~$"
-                                 (file-name-nondirectory file))
-                   (if filep
-                       (file-directory-p file)
-                     (not (file-directory-p file)))))
-             (directory-files directory t)))
+  (cl-remove-if (lambda (file)
+                  (or (string-match "\\`\\."
+                                    (file-name-nondirectory file))
+                      (string-match "\\`#.*#\\'"
+                                    (file-name-nondirectory file))
+                      (string-match "~\\'"
+                                    (file-name-nondirectory file))
+                      (if filep
+                          (file-directory-p file)
+                        (not (file-directory-p file)))))
+                (directory-files directory t)))
 
 (defun yas--make-menu-binding (template)
   (let ((mode (yas--table-mode (yas--template-table template))))
 
 (defun yas--make-menu-binding (template)
   (let ((mode (yas--table-mode (yas--template-table template))))
@@ -1568,6 +1585,9 @@ Optional PROMPT sets the prompt to use."
 (defun yas-x-prompt (prompt choices &optional display-fn)
   "Display choices in a x-window prompt."
   (when (and window-system choices)
 (defun yas-x-prompt (prompt choices &optional display-fn)
   "Display choices in a x-window prompt."
   (when (and window-system choices)
+    ;; Let window position be recalculated to ensure that
+    ;; `posn-at-point' returns non-nil.
+    (redisplay)
     (or
      (x-popup-menu
       (if (fboundp 'posn-at-point)
     (or
      (x-popup-menu
       (if (fboundp 'posn-at-point)
@@ -1582,11 +1602,13 @@ Optional PROMPT sets the prompt to use."
                             (if display-fn (mapcar display-fn choices) choices)))))
      (keyboard-quit))))
 
                             (if display-fn (mapcar display-fn choices) choices)))))
      (keyboard-quit))))
 
+(defun yas-maybe-ido-prompt (prompt choices &optional display-fn)
+  (when (bound-and-true-p ido-mode)
+    (yas-ido-prompt prompt choices display-fn)))
+
 (defun yas-ido-prompt (prompt choices &optional display-fn)
 (defun yas-ido-prompt (prompt choices &optional display-fn)
-  (when (and (fboundp 'ido-completing-read)
-            (or (>= emacs-major-version 24)
-                ido-mode))
-    (yas-completing-prompt prompt choices display-fn #'ido-completing-read)))
+  (require 'ido)
+  (yas-completing-prompt prompt choices display-fn #'ido-completing-read))
 
 (defun yas-dropdown-prompt (_prompt choices &optional display-fn)
   (when (fboundp 'dropdown-list)
 
 (defun yas-dropdown-prompt (_prompt choices &optional display-fn)
   (when (fboundp 'dropdown-list)
@@ -1620,43 +1642,10 @@ Optional PROMPT sets the prompt to use."
 
 (defun yas--define-snippets-1 (snippet snippet-table)
   "Helper for `yas-define-snippets'."
 
 (defun yas--define-snippets-1 (snippet snippet-table)
   "Helper for `yas-define-snippets'."
-  ;; X) Calculate some more defaults on the values returned by
-  ;; `yas--parse-template'.
-  ;;
-  (let* ((file (seventh snippet))
-         (key (car snippet))
-         (name (or (third snippet)
-                   (and file
-                        (file-name-directory file))))
-         (condition (fourth snippet))
-         (group (fifth snippet))
-         (keybinding (yas--read-keybinding (eighth snippet)))
-         (uuid (or (ninth snippet)
-                  name))
-         (template (or (gethash uuid (yas--table-uuidhash snippet-table))
-                       (yas--make-blank-template))))
-    ;; X) populate the template object
-    ;;
-    (yas--populate-template template
-                           :table       snippet-table
-                           :key         key
-                           :content     (second snippet)
-                           :name        (or name key)
-                           :group       group
-                           :condition   condition
-                           :expand-env  (sixth snippet)
-                           :file        (seventh snippet)
-                           :keybinding  keybinding
-                           :uuid         uuid)
-    ;; X) Update this template in the appropriate table. This step
-    ;;    also will take care of adding the key indicators in the
-    ;;    templates menu entry, if any
-    ;;
-    (yas--update-template snippet-table template)
-    ;; X) Return the template
-    ;;
-    ;;
-    template))
+  ;; Update the appropriate table.  Also takes care of adding the
+  ;; key indicators in the templates menu entry, if any.
+  (yas--update-template
+   snippet-table (apply #'yas--define-snippets-2 snippet-table snippet)))
 
 (defun yas-define-snippets (mode snippets)
   "Define SNIPPETS for MODE.
 
 (defun yas-define-snippets (mode snippets)
   "Define SNIPPETS for MODE.
@@ -1664,7 +1653,7 @@ Optional PROMPT sets the prompt to use."
 SNIPPETS is a list of snippet definitions, each taking the
 following form
 
 SNIPPETS is a list of snippet definitions, each taking the
 following form
 
- (KEY TEMPLATE NAME CONDITION GROUP EXPAND-ENV FILE KEYBINDING UUID)
+ (KEY TEMPLATE NAME CONDITION GROUP EXPAND-ENV LOAD-FILE KEYBINDING UUID SAVE-FILE)
 
 Within these, only KEY and TEMPLATE are actually mandatory.
 
 
 Within these, only KEY and TEMPLATE are actually mandatory.
 
@@ -1686,33 +1675,19 @@ file with the same uuid would replace the previous snippet.
 You can use `yas--parse-template' to return such lists based on
 the current buffers contents."
   (if yas--creating-compiled-snippets
 You can use `yas--parse-template' to return such lists based on
 the current buffers contents."
   (if yas--creating-compiled-snippets
-      (progn
+      (let ((print-length nil))
         (insert ";;; Snippet definitions:\n;;;\n")
         (insert ";;; Snippet definitions:\n;;;\n")
-        (let ((literal-snippets (list))
-              (print-length nil))
-          (dolist (snippet snippets)
-            (let ((key                    (nth 0 snippet))
-                  (template-content       (nth 1 snippet))
-                  (name                   (nth 2 snippet))
-                  (condition              (nth 3 snippet))
-                  (group                  (nth 4 snippet))
-                  (expand-env             (nth 5 snippet))
-                  (file                   nil) ;; omit on purpose
-                  (binding                (nth 7 snippet))
-                  (uuid                   (nth 8 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")))
+        (dolist (snippet snippets)
+          ;; Fill in missing elements with nil.
+          (setq snippet (append snippet (make-list (- 10 (length snippet)) nil)))
+          ;; Move LOAD-FILE to SAVE-FILE because we will load from the
+          ;; compiled file, not LOAD-FILE.
+          (let ((load-file (nth 6 snippet)))
+            (setcar (nthcdr 6 snippet) nil)
+            (setcar (nthcdr 9 snippet) load-file)))
+        (insert (pp-to-string
+                 `(yas-define-snippets ',mode ',snippets)))
+        (insert "\n\n"))
     ;; Normal case.
     (let ((snippet-table (yas--table-get-create mode))
           (template nil))
     ;; Normal case.
     (let ((snippet-table (yas--table-get-create mode))
           (template nil))
@@ -1724,13 +1699,22 @@ the current buffers contents."
 \f
 ;;; Loading snippets from files
 
 \f
 ;;; Loading snippets from files
 
+(defun yas--template-get-file (template)
+  "Return TEMPLATE's LOAD-FILE or SAVE-FILE."
+  (or (yas--template-load-file template)
+      (let ((file (yas--template-save-file template)))
+        (when file
+          (yas--message 3 "%s has no load file, using save file, %s, instead."
+                        (yas--template-name template) file))
+        file)))
+
 (defun yas--load-yas-setup-file (file)
   (if (not yas--creating-compiled-snippets)
       ;; Normal case.
 (defun yas--load-yas-setup-file (file)
   (if (not yas--creating-compiled-snippets)
       ;; Normal case.
-      (load file 'noerror)
+      (load file 'noerror (<= yas-verbosity 4))
     (let ((elfile (concat file ".el")))
       (when (file-exists-p elfile)
     (let ((elfile (concat file ".el")))
       (when (file-exists-p elfile)
-        (insert ";;; .yas-setup.el support file if any:\n;;;\n")
+        (insert ";;; contents of the .yas-setup.el support file:\n;;;\n")
         (insert-file-contents elfile)
         (goto-char (point-max))))))
 
         (insert-file-contents elfile)
         (goto-char (point-max))))))
 
@@ -1778,16 +1762,16 @@ With prefix argument USE-JIT do jit-loading of snippets."
             (funcall fun)))
         ;; Look for buffers that are already in `mode-sym', and so
         ;; need the new snippets immediately...
             (funcall fun)))
         ;; Look for buffers that are already in `mode-sym', and so
         ;; need the new snippets immediately...
-        ;; 
-        (when use-jit 
+        ;;
+        (when use-jit
           (cl-loop for buffer in (buffer-list)
                    do (with-current-buffer buffer
                         (when (eq major-mode mode-sym)
           (cl-loop for buffer in (buffer-list)
                    do (with-current-buffer buffer
                         (when (eq major-mode mode-sym)
-                          (yas--message 3 "Discovered there was already %s in %s" buffer mode-sym)
+                          (yas--message 4 "Discovered there was already %s in %s" buffer mode-sym)
                           (push buffer impatient-buffers)))))))
     ;; ...after TOP-LEVEL-DIR has been completely loaded, call
     ;; `yas--load-pending-jits' in these impatient buffers.
                           (push buffer impatient-buffers)))))))
     ;; ...after TOP-LEVEL-DIR has been completely loaded, call
     ;; `yas--load-pending-jits' in these impatient buffers.
-    ;; 
+    ;;
     (cl-loop for buffer in impatient-buffers
              do (with-current-buffer buffer (yas--load-pending-jits))))
   (when interactive
     (cl-loop for buffer in impatient-buffers
              do (with-current-buffer buffer (yas--load-pending-jits))))
   (when interactive
@@ -1805,10 +1789,10 @@ With prefix argument USE-JIT do jit-loading of snippets."
           (insert (format ";;; Do not edit! File generated at %s\n"
                           (current-time-string)))))
     ;; Normal case.
           (insert (format ";;; Do not edit! File generated at %s\n"
                           (current-time-string)))))
     ;; Normal case.
-    (unless (file-exists-p (concat directory "/" ".yas-skip"))
-      (if (and (progn (yas--message 2 "Loading compiled snippets from %s" directory) t)
-               (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror (<= yas-verbosity 3)))
-          (yas--message 2 "Loading snippet files from %s" directory)
+    (unless (file-exists-p (expand-file-name ".yas-skip" directory))
+      (unless (and (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror (<= yas-verbosity 3))
+                   (progn (yas--message 4 "Loaded compiled snippets from %s" directory) t))
+        (yas--message 4 "Loading snippet files from %s" directory)
         (yas--load-directory-2 directory mode-sym)))))
 
 (defun yas--load-directory-2 (directory mode-sym)
         (yas--load-directory-2 directory mode-sym)))))
 
 (defun yas--load-directory-2 (directory mode-sym)
@@ -1838,16 +1822,18 @@ With prefix argument USE-JIT do jit-loading of snippets."
   "Reload the directories listed in `yas-snippet-dirs' or
 prompt the user to select one."
   (let (errors)
   "Reload the directories listed in `yas-snippet-dirs' or
 prompt the user to select one."
   (let (errors)
-    (if yas-snippet-dirs
-        (dolist (directory (reverse (yas-snippet-dirs)))
-          (cond ((file-directory-p directory)
-                 (yas-load-directory directory (not nojit))
-                 (if nojit
-                     (yas--message 3 "Loaded %s" directory)
-                   (yas--message 3 "Prepared just-in-time loading for %s" directory)))
-                (t
-                 (push (yas--message 0 "Check your `yas-snippet-dirs': %s is not a directory" directory) errors))))
-      (call-interactively 'yas-load-directory))
+    (if (null yas-snippet-dirs)
+        (call-interactively 'yas-load-directory)
+      (when (member yas--default-user-snippets-dir yas-snippet-dirs)
+        (make-directory yas--default-user-snippets-dir t))
+      (dolist (directory (reverse (yas-snippet-dirs)))
+        (cond ((file-directory-p directory)
+               (yas-load-directory directory (not nojit))
+               (if nojit
+                   (yas--message 4 "Loaded %s" directory)
+                 (yas--message 4 "Prepared just-in-time loading for %s" directory)))
+              (t
+               (push (yas--message 0 "Check your `yas-snippet-dirs': %s is not a directory" directory) errors)))))
     errors))
 
 (defun yas-reload-all (&optional no-jit interactive)
     errors))
 
 (defun yas-reload-all (&optional no-jit interactive)
@@ -1910,9 +1896,9 @@ prefix argument."
       (yas-direct-keymaps-reload)
 
       (run-hooks 'yas-after-reload-hook)
       (yas-direct-keymaps-reload)
 
       (run-hooks 'yas-after-reload-hook)
-      (yas--message 3 "Reloaded everything%s...%s."
-                   (if no-jit "" " (snippets will load just-in-time)")
-                   (if errors " (some errors, check *Messages*)" "")))))
+      (yas--message (if errors 2 3) "Reloaded everything%s...%s."
+                    (if no-jit "" " (snippets will load just-in-time)")
+                    (if errors " (some errors, check *Messages*)" "")))))
 
 (defvar yas-after-reload-hook nil
   "Hooks run after `yas-reload-all'.")
 
 (defvar yas-after-reload-hook nil
   "Hooks run after `yas-reload-all'.")
@@ -1922,7 +1908,7 @@ prefix argument."
     (let ((funs (reverse (gethash mode yas--scheduled-jit-loads))))
       ;; must reverse to maintain coherence with `yas-snippet-dirs'
       (dolist (fun funs)
     (let ((funs (reverse (gethash mode yas--scheduled-jit-loads))))
       ;; must reverse to maintain coherence with `yas-snippet-dirs'
       (dolist (fun funs)
-        (yas--message  3 "Loading for `%s', just-in-time: %s!" mode fun)
+        (yas--message 4 "Loading for `%s', just-in-time: %s!" mode fun)
         (funcall fun))
       (remhash mode yas--scheduled-jit-loads))))
 
         (funcall fun))
       (remhash mode yas--scheduled-jit-loads))))
 
@@ -1941,10 +1927,6 @@ foo\"bar\\! -> \"foo\\\"bar\\\\!\""
 \f
 ;;; Snippet compilation function
 
 \f
 ;;; Snippet compilation function
 
-(defun yas--initialize ()
-  "For backward compatibility, enable `yas-minor-mode' globally."
-  (yas-global-mode 1))
-
 (defun yas-compile-directory (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.
 
@@ -1977,12 +1959,12 @@ This works by stubbing a few functions, then calling
   (interactive)
   (message (concat "yasnippet (version "
                    yas--version
   (interactive)
   (message (concat "yasnippet (version "
                    yas--version
-                   ") -- pluskid <pluskid@gmail.com>/joaotavora <joaotavora@gmail.com>")))
+                   ") -- pluskid/joaotavora/npostavs")))
 
 \f
 ;;; Apropos snippet menu:
 ;;
 
 \f
 ;;; Apropos snippet menu:
 ;;
-;; The snippet menu keymaps are store by mode in hash table called
+;; The snippet menu keymaps are stored by mode in hash table called
 ;; `yas--menu-table'. They are linked to the main menu in
 ;; `yas--menu-keymap-get-create' and are initially created empty,
 ;; reflecting the table hierarchy.
 ;; `yas--menu-table'. They are linked to the main menu in
 ;; `yas--menu-keymap-get-create' and are initially created empty,
 ;; reflecting the table hierarchy.
@@ -2004,9 +1986,9 @@ This works by stubbing a few functions, then calling
 ;;   duplicate entries. The `yas--template' objects are created in
 ;;   `yas-define-menu', holding nothing but the menu entry,
 ;;   represented by a pair of ((menu-item NAME :keys KEYS) TYPE) and
 ;;   duplicate entries. The `yas--template' objects are created in
 ;;   `yas-define-menu', holding nothing but the menu entry,
 ;;   represented by a pair of ((menu-item NAME :keys KEYS) TYPE) and
-;;   stored in `yas--template-menu-binding-pair'. The (menu-item ...)
+;;   stored in `yas--template-menu-binding-pair'.  The (menu-item ...)
 ;;   part is then stored in the menu keymap itself which make the item
 ;;   part is then stored in the menu keymap itself which make the item
-;;   appear to the user. These limitations could probably be revised.
+;;   appear to the user.  These limitations could probably be revised.
 ;;
 ;; * The `yas--template-perm-group' slot is only used in
 ;;   `yas-describe-tables'.
 ;;
 ;; * The `yas--template-perm-group' slot is only used in
 ;;   `yas-describe-tables'.
@@ -2089,11 +2071,10 @@ omitted from MODE's menu, even if they're manually loaded."
                         hash)
     (dolist (uuid omit-items)
       (let ((template (or (gethash uuid hash)
                         hash)
     (dolist (uuid omit-items)
       (let ((template (or (gethash uuid hash)
-                          (yas--populate-template (puthash uuid
-                                                           (yas--make-blank-template)
-                                                           hash)
-                                                  :table table
-                                                  :uuid uuid))))
+                          (puthash uuid
+                                   (yas--make-template :table table
+                                                       :uuid uuid)
+                                   hash))))
         (setf (yas--template-menu-binding-pair template) (cons nil :none))))))
 
 (defun yas--define-menu-1 (table menu-keymap menu uuidhash &optional group-list)
         (setf (yas--template-menu-binding-pair template) (cons nil :none))))))
 
 (defun yas--define-menu-1 (table menu-keymap menu uuidhash &optional group-list)
@@ -2101,12 +2082,12 @@ omitted from MODE's menu, even if they're manually loaded."
   (dolist (e (reverse menu))
     (cond ((eq (first e) 'yas-item)
            (let ((template (or (gethash (second e) uuidhash)
   (dolist (e (reverse menu))
     (cond ((eq (first e) 'yas-item)
            (let ((template (or (gethash (second e) uuidhash)
-                               (yas--populate-template (puthash (second e)
-                                                               (yas--make-blank-template)
-                                                               uuidhash)
-                                                      :table table
-                                                      :perm-group group-list
-                                                      :uuid (second e)))))
+                               (puthash (second e)
+                                        (yas--make-template
+                                         :table table
+                                         :perm-group group-list
+                                         :uuid (second e))
+                                        uuidhash))))
              (define-key menu-keymap (vector (gensym))
                (car (yas--template-menu-binding-pair-get-create template :stay)))))
           ((eq (first e) 'yas-submenu)
              (define-key menu-keymap (vector (gensym))
                (car (yas--template-menu-binding-pair-get-create template :stay)))))
           ((eq (first e) 'yas-submenu)
@@ -2122,7 +2103,7 @@ omitted from MODE's menu, even if they're manually loaded."
            (define-key menu-keymap (vector (gensym))
              '(menu-item "----")))
           (t
            (define-key menu-keymap (vector (gensym))
              '(menu-item "----")))
           (t
-           (yas--message 3 "Don't know anything about menu entry %s" (first e))))))
+           (yas--message 1 "Don't know anything about menu entry %s" (first e))))))
 \f
 (defun yas--define (mode key template &optional name condition group)
   "Define a snippet.  Expanding KEY into TEMPLATE.
 \f
 (defun yas--define (mode key template &optional name condition group)
   "Define a snippet.  Expanding KEY into TEMPLATE.
@@ -2196,9 +2177,13 @@ object satisfying `yas--field-p' to restrict the expansion to."
                                     (yas--templates-for-key-at-point))
                                 (yas--templates-for-key-at-point))))
     (if templates-and-pos
                                     (yas--templates-for-key-at-point))
                                 (yas--templates-for-key-at-point))))
     (if templates-and-pos
-        (yas--expand-or-prompt-for-template (first templates-and-pos)
-                                            (second templates-and-pos)
-                                            (third templates-and-pos))
+        (yas--expand-or-prompt-for-template
+         (nth 0 templates-and-pos)
+         ;; Delete snippet key and active region when expanding.
+         (min (if (use-region-p) (region-beginning) most-positive-fixnum)
+              (nth 1 templates-and-pos))
+         (max (if (use-region-p) (region-end) most-negative-fixnum)
+              (nth 2 templates-and-pos)))
       (yas--fallback))))
 
 (defun yas-expand-from-keymap ()
       (yas--fallback))))
 
 (defun yas-expand-from-keymap ()
@@ -2258,12 +2243,12 @@ Common gateway for `yas-expand-from-trigger-key' and
                 ;; loops when other extensions use mechanisms similar
                 ;; to `yas--keybinding-beyond-yasnippet'. (github #525
                 ;; and #526)
                 ;; loops when other extensions use mechanisms similar
                 ;; to `yas--keybinding-beyond-yasnippet'. (github #525
                 ;; and #526)
-                ;; 
+                ;;
                 (yas-minor-mode nil)
                 (beyond-yasnippet (yas--keybinding-beyond-yasnippet)))
            (yas--message 4 "Falling back to %s"  beyond-yasnippet)
            (assert (or (null beyond-yasnippet) (commandp beyond-yasnippet)))
                 (yas-minor-mode nil)
                 (beyond-yasnippet (yas--keybinding-beyond-yasnippet)))
            (yas--message 4 "Falling back to %s"  beyond-yasnippet)
            (assert (or (null beyond-yasnippet) (commandp beyond-yasnippet)))
-           (setq this-original-command beyond-yasnippet)
+           (setq this-command beyond-yasnippet)
            (when beyond-yasnippet
              (call-interactively beyond-yasnippet))))
         ((and (listp yas-fallback-behavior)
            (when beyond-yasnippet
              (call-interactively beyond-yasnippet))))
         ((and (listp yas-fallback-behavior)
@@ -2335,6 +2320,28 @@ Honours `yas-choose-tables-first', `yas-choose-keys-first' and
             (remove-duplicates (mapcan #'yas--table-templates tables)
                                :test #'equal))))
 
             (remove-duplicates (mapcan #'yas--table-templates tables)
                                :test #'equal))))
 
+(defun yas--lookup-snippet-1 (name mode)
+  "Get the snippet called NAME in MODE's tables."
+  (let ((yas-choose-tables-first nil)   ; avoid prompts
+        (yas-choose-keys-first nil))
+    (cl-find name (yas--all-templates
+                   (yas--get-snippet-tables mode))
+             :key #'yas--template-name :test #'string=)))
+
+(defun yas-lookup-snippet (name &optional mode noerror)
+  "Get the snippet content for the snippet NAME in MODE's tables.
+
+MODE defaults to the current buffer's `major-mode'.  If NOERROR
+is non-nil, then don't signal an error if there isn't any snippet
+called NAME.
+
+Honours `yas-buffer-local-condition'."
+  (let ((snippet (yas--lookup-snippet-1 name mode)))
+    (cond
+     (snippet (yas--template-content snippet))
+     (noerror nil)
+     (t (error "No snippet named: %s" name)))))
+
 (defun yas-insert-snippet (&optional no-condition)
   "Choose a snippet to expand, pop-up a list of choices according
 to `yas-prompt-functions'.
 (defun yas-insert-snippet (&optional no-condition)
   "Choose a snippet to expand, pop-up a list of choices according
 to `yas-prompt-functions'.
@@ -2359,7 +2366,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))
-      (yas--message 3 "No snippets can be inserted here!"))))
+      (yas--message 1 "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'.
@@ -2369,7 +2376,6 @@ visited file in `snippet-mode'."
   (interactive)
   (let* ((yas-buffer-local-condition 'always)
          (templates (yas--all-templates (yas--get-snippet-tables)))
   (interactive)
   (let* ((yas-buffer-local-condition 'always)
          (templates (yas--all-templates (yas--get-snippet-tables)))
-         (yas-prompt-functions '(yas-ido-prompt yas-completing-prompt))
          (template (and templates
                         (or (yas--prompt-for-template templates
                                                      "Choose a snippet template to edit: ")
          (template (and templates
                         (or (yas--prompt-for-template templates
                                                      "Choose a snippet template to edit: ")
@@ -2381,7 +2387,7 @@ visited file in `snippet-mode'."
 
 (defun yas--visit-snippet-file-1 (template)
   "Helper for `yas-visit-snippet-file'."
 
 (defun yas--visit-snippet-file-1 (template)
   "Helper for `yas-visit-snippet-file'."
-  (let ((file (yas--template-file template)))
+  (let ((file (yas--template-get-file template)))
     (cond ((and file (file-readable-p file))
            (find-file-other-window file)
            (snippet-mode)
     (cond ((and file (file-readable-p file))
            (find-file-other-window file)
            (snippet-mode)
@@ -2424,13 +2430,11 @@ tables (or optional TABLE).
 Returns a list of elements (TABLE . DIRS) where TABLE is a
 `yas--table' object and DIRS is a list of all possible directories
 where snippets of table might exist."
 Returns a list of elements (TABLE . DIRS) where TABLE is a
 `yas--table' object and DIRS is a list of all possible directories
 where snippets of table might exist."
-  (let ((main-dir (replace-regexp-in-string
-                   "/+$" ""
-                   (or (first (or (yas-snippet-dirs)
-                                  (setq yas-snippet-dirs '("~/.emacs.d/snippets")))))))
-        (tables (or (and table
-                         (list table))
-                    (yas--get-snippet-tables))))
+  (let ((main-dir (car (or (yas-snippet-dirs)
+                           (setq yas-snippet-dirs
+                                 (list yas--default-user-snippets-dir)))))
+        (tables (if table (list table)
+                  (yas--get-snippet-tables))))
     ;; HACK! the snippet table created here is actually registered!
     ;;
     (unless (or table (gethash major-mode yas--tables))
     ;; HACK! the snippet table created here is actually registered!
     ;;
     (unless (or table (gethash major-mode yas--tables))
@@ -2440,7 +2444,7 @@ where snippets of table might exist."
     (mapcar #'(lambda (table)
                 (cons table
                       (mapcar #'(lambda (subdir)
     (mapcar #'(lambda (table)
                 (cons table
                       (mapcar #'(lambda (subdir)
-                                  (concat main-dir "/" subdir))
+                                  (expand-file-name subdir main-dir))
                               (yas--guess-snippet-directories-1 table))))
             tables)))
 
                               (yas--guess-snippet-directories-1 table))))
             tables)))
 
@@ -2545,17 +2549,15 @@ neither do the elements of PARENTS."
 
 (defun yas-load-snippet-buffer (table &optional interactive)
   "Parse and load current buffer's snippet definition into TABLE.
 
 (defun yas-load-snippet-buffer (table &optional interactive)
   "Parse and load current buffer's snippet definition into TABLE.
-
-TABLE is a symbol naming a passed to `yas--table-get-create'.
-
-When called interactively, prompt for the table name."
+TABLE is a symbol name passed to `yas--table-get-create'.  When
+called interactively, prompt for the table name."
   (interactive (list (yas--read-table) t))
   (cond
    ;;  We have `yas--editing-template', this buffer's content comes from a
    ;;  template which is already loaded and neatly positioned,...
    ;;
    (yas--editing-template
   (interactive (list (yas--read-table) t))
   (cond
    ;;  We have `yas--editing-template', this buffer's content comes from a
    ;;  template which is already loaded and 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-load-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'
@@ -2573,11 +2575,10 @@ When called interactively, prompt for the table name."
                   (yas--table-name (yas--template-table yas--editing-template)))))
 
 (defun yas-load-snippet-buffer-and-close (table &optional kill)
                   (yas--table-name (yas--template-table yas--editing-template)))))
 
 (defun yas-load-snippet-buffer-and-close (table &optional kill)
-  "Load the snippet with `yas-load-snippet-buffer', possibly
-  save, then `quit-window' if saved.
-
-If the snippet is new, ask the user whether (and where) to save
-it. If the snippet already has a file, just save it.
+  "Load and save the snippet, then `quit-window' if saved.
+Loading is performed by `yas-load-snippet-buffer'.  If the
+snippet is new, ask the user whether (and where) to save it.  If
+the snippet already has a file, just save it.
 
 The prefix argument KILL is passed to `quit-window'.
 
 
 The prefix argument KILL is passed to `quit-window'.
 
@@ -2585,29 +2586,28 @@ Don't use this from a Lisp program, call `yas-load-snippet-buffer'
 and `kill-buffer' instead."
   (interactive (list (yas--read-table) current-prefix-arg))
   (yas-load-snippet-buffer table t)
 and `kill-buffer' instead."
   (interactive (list (yas--read-table) current-prefix-arg))
   (yas-load-snippet-buffer table t)
-  (when (and (or
-              ;; Only offer to save this if it looks like a library or new
-              ;; snippet (loaded from elisp, from a dir in `yas-snippet-dirs'
-              ;; which is not the first, or from an unwritable file)
-              ;;
-              (not (yas--template-file yas--editing-template))
-              (not (file-writable-p (yas--template-file yas--editing-template)))
-              (and (listp yas-snippet-dirs)
-                   (second yas-snippet-dirs)
-                   (not (string-match (expand-file-name (first yas-snippet-dirs))
-                                      (yas--template-file yas--editing-template)))))
-             (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))))
-      (when chosen
-        (let ((default-file-name (or (and (yas--template-file yas--editing-template)
-                                          (file-name-nondirectory (yas--template-file yas--editing-template)))
-                                     (yas--template-name yas--editing-template))))
-          (write-file (concat chosen "/"
-                              (read-from-minibuffer (format "File name to create in %s? " chosen)
-                                                    default-file-name)))
-          (setf (yas--template-file yas--editing-template) buffer-file-name)))))
+  (let ((file (yas--template-get-file yas--editing-template)))
+    (when (and (or
+                ;; Only offer to save this if it looks like a library or new
+                ;; snippet (loaded from elisp, from a dir in `yas-snippet-dirs'
+                ;; which is not the first, or from an unwritable file)
+                ;;
+                (not file)
+                (not (file-writable-p file))
+                (and (cdr-safe yas-snippet-dirs)
+                     (not (string-prefix-p (expand-file-name (car yas-snippet-dirs)) file))))
+               (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))))
+        (when chosen
+          (let ((default-file-name (or (and file (file-name-nondirectory file))
+                                       (yas--template-name yas--editing-template))))
+            (write-file (expand-file-name
+                         (read-file-name (format "File name to create in %s? " chosen)
+                                         chosen default-file-name)
+                         chosen))
+            (setf (yas--template-load-file yas--editing-template) buffer-file-name))))))
   (when buffer-file-name
     (save-buffer)
     (quit-window kill)))
   (when buffer-file-name
     (save-buffer)
     (quit-window kill)))
@@ -2625,12 +2625,11 @@ and `kill-buffer' instead."
          (yas--current-template
           (and parsed
                (fboundp test-mode)
          (yas--current-template
           (and parsed
                (fboundp test-mode)
-               (yas--populate-template (yas--make-blank-template)
-                                      :table       nil ;; no tables for ephemeral snippets
-                                      :key         (first parsed)
-                                      :content     (second parsed)
-                                      :name        (third parsed)
-                                      :expand-env  (sixth parsed)))))
+               (yas--make-template :table       nil ;; no tables for ephemeral snippets
+                                   :key         (nth 0 parsed)
+                                   :content     (nth 1 parsed)
+                                   :name        (nth 2 parsed)
+                                   :expand-env  (nth 5 parsed)))))
     (cond (yas--current-template
            (let ((buffer-name (format "*testing snippet: %s*" (yas--template-name yas--current-template))))
              (kill-buffer (get-buffer-create buffer-name))
     (cond (yas--current-template
            (let ((buffer-name (format "*testing snippet: %s*" (yas--template-name yas--current-template))))
              (kill-buffer (get-buffer-create buffer-name))
@@ -2647,7 +2646,7 @@ and `kill-buffer' instead."
                         (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
-           (yas--message 3 "Cannot test snippet for unknown major mode")))))
+           (yas--message 1 "Cannot test snippet for unknown major mode")))))
 
 (defun yas-active-keys ()
   "Return all active trigger keys for current buffer and point."
 
 (defun yas-active-keys ()
   "Return all active trigger keys for current buffer and point."
@@ -2680,7 +2679,7 @@ and `kill-buffer' instead."
       (setq buffer-read-only nil)
       (erase-buffer)
       (cond ((not by-name-hash)
       (setq buffer-read-only nil)
       (erase-buffer)
       (cond ((not by-name-hash)
-             (insert "YASnippet tables: \n")
+             (insert "YASnippet tables:\n")
              (while (and table-lists
                          continue)
                (dolist (table (car table-lists))
              (while (and table-lists
                          continue)
                (dolist (table (car table-lists))
@@ -2736,31 +2735,32 @@ and `kill-buffer' instead."
          (setq group (truncate-string-to-width group 25 0 ?  "..."))
          (insert (make-string 100 ?-) "\n")
          (dolist (p 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"))))
+           (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)")))
+                  (key-description-string (key-description (yas--template-keybinding p)))
+                  (template-key-padding (if (string= key-description-string "") nil ? )))
+             (insert group " "
+                     condition-string " "
+                     name (if (string-match "\\.\\.\\.$" name)
+                              "'" " ")
+                     " "
+                     (truncate-string-to-width (or (yas--template-key p) "")
+                                               15 0 template-key-padding "...")
+                     (or template-key-padding "")
+                     (truncate-string-to-width key-description-string
+                                               15 0 nil "...")
+                     "\n"))))
      groups-hash)))
 
 
      groups-hash)))
 
 
@@ -2973,7 +2973,6 @@ If there is a transform but it returns nil, return the empty
 string iff EMPTY-ON-NIL-P is true."
   (let* ((yas-text (yas--field-text-for-display field))
          (yas-modified-p (yas--field-modified-p field))
 string iff EMPTY-ON-NIL-P is true."
   (let* ((yas-text (yas--field-text-for-display field))
          (yas-modified-p (yas--field-modified-p field))
-         (yas-moving-away-p nil)
          (transform (if (yas--mirror-p field-or-mirror)
                         (yas--mirror-transform field-or-mirror)
                       (yas--field-transform field-or-mirror)))
          (transform (if (yas--mirror-p field-or-mirror)
                         (yas--mirror-transform field-or-mirror)
                       (yas--field-transform field-or-mirror)))
@@ -3047,18 +3046,19 @@ through the field's start point"
    ;; the field numbered 0, just before the exit marker, should
    ;; never be skipped
    ;;
    ;; the field numbered 0, just before the exit marker, should
    ;; never be skipped
    ;;
-   (not (zerop (yas--field-number field)))))
+   (not (and (yas--field-number field)
+             (zerop (yas--field-number field))))))
 
 (defun yas--snippets-at-point (&optional all-snippets)
   "Return a sorted list of snippets at point.
 
 The most recently-inserted snippets are returned first."
   (sort
 
 (defun yas--snippets-at-point (&optional all-snippets)
   "Return a sorted list of snippets at point.
 
 The most recently-inserted snippets are returned first."
   (sort
-   (remove nil (remove-duplicates (mapcar #'(lambda (ov)
-                                              (overlay-get ov 'yas--snippet))
-                                          (if all-snippets
-                                              (overlays-in (point-min) (point-max))
-                                            (nconc (overlays-at (point)) (overlays-at (1- (point))))))))
+   (delq nil (delete-dups
+              (mapcar (lambda (ov) (overlay-get ov 'yas--snippet))
+                      (if all-snippets (overlays-in (point-min) (point-max))
+                        (nconc (overlays-at (point))
+                               (overlays-at (1- (point))))))))
    #'(lambda (s1 s2)
        (<= (yas--snippet-id s2) (yas--snippet-id s1)))))
 
    #'(lambda (s1 s2)
        (<= (yas--snippet-id s2) (yas--snippet-id s1)))))
 
@@ -3075,38 +3075,41 @@ Otherwise delegate to `yas-next-field'."
             (yas-next-field))))
     (yas-next-field)))
 
             (yas-next-field))))
     (yas-next-field)))
 
+(defun yas-next-field-will-exit-p (&optional arg)
+  "Return non-nil if (yas-next-field ARG) would exit the current snippet."
+  (let ((snippet (car (yas--snippets-at-point)))
+        (active (overlay-get yas--active-field-overlay 'yas--field)))
+    (when snippet
+      (not (yas--find-next-field arg snippet active)))))
+
+(defun yas--find-next-field (n snippet active)
+  "Return the Nth field after the ACTIVE one in SNIPPET."
+  (let ((live-fields (cl-remove-if
+                      (lambda (field)
+                        (and (not (eq field active))
+                             (yas--field-probably-deleted-p snippet field)))
+                      (yas--snippet-fields snippet))))
+    (if (>= n 0) (nth n (memq active live-fields))
+      (car (last (memq active (reverse live-fields)) (- n))))))
+
 (defun yas-next-field (&optional arg)
   "Navigate to the ARGth next field.
 
 If there's none, exit the snippet."
   (interactive)
 (defun yas-next-field (&optional arg)
   "Navigate to the ARGth next field.
 
 If there's none, exit the snippet."
   (interactive)
-  (let* ((arg (or arg
-                  1))
-         (snippet (first (yas--snippets-at-point)))
+  (unless arg (setq arg 1))
+  (let* ((snippet (car (yas--snippets-at-point)))
          (active-field (overlay-get yas--active-field-overlay 'yas--field))
          (active-field (overlay-get yas--active-field-overlay 'yas--field))
-         (live-fields (remove-if #'(lambda (field)
-                                     (and (not (eq field active-field))
-                                          (yas--field-probably-deleted-p snippet field)))
-                                 (yas--snippet-fields snippet)))
-         (active-field-pos (position active-field live-fields))
-         (target-pos (and active-field-pos (+ arg active-field-pos)))
-         (target-field (and target-pos (nth target-pos live-fields))))
-    ;; First check if we're moving out of a field with a transform
-    ;;
-    (when (and active-field
-               (yas--field-transform active-field))
-      (let* ((yas-moving-away-p t)
-             (yas-text (yas--field-text-for-display active-field))
-             (yas-modified-p (yas--field-modified-p active-field)))
-        ;; primary field transform: exit call to field-transform
-        (yas--eval-lisp (yas--field-transform active-field))))
+         (target-field (yas--find-next-field arg snippet active-field)))
+    ;; Apply transform to active field.
+    (when active-field
+      (let ((yas-moving-away-p t))
+        (when (yas--field-update-display active-field)
+          (yas--update-mirrors snippet))))
     ;; Now actually move...
     ;; Now actually move...
-    (cond ((and target-pos (>= target-pos (length live-fields)))
-           (yas-exit-snippet snippet))
-          (target-field
-           (yas--move-to-field snippet target-field))
-          (t
-           nil))))
+    (if target-field
+        (yas--move-to-field snippet target-field)
+      (yas-exit-snippet snippet))))
 
 (defun yas--place-overlays (snippet field)
   "Correctly place overlays for SNIPPET's FIELD."
 
 (defun yas--place-overlays (snippet field)
   "Correctly place overlays for SNIPPET's FIELD."
@@ -3171,12 +3174,6 @@ Also create some protection overlays"
 (defvar yas--inhibit-overlay-hooks nil
   "Bind this temporarily to non-nil to prevent running `yas--on-*-modification'.")
 
 (defvar yas--inhibit-overlay-hooks nil
   "Bind this temporarily to non-nil to prevent running `yas--on-*-modification'.")
 
-(defmacro yas--inhibit-overlay-hooks (&rest body)
-  "Run BODY with `yas--inhibit-overlay-hooks' set to t."
-  (declare (indent 0))
-  `(let ((yas--inhibit-overlay-hooks t))
-     ,@body))
-
 (defvar yas-snippet-beg nil "Beginning position of the last snippet committed.")
 (defvar yas-snippet-end nil "End position of the last snippet committed.")
 
 (defvar yas-snippet-beg nil "Beginning position of the last snippet committed.")
 (defvar yas-snippet-end nil "End position of the last snippet committed.")
 
@@ -3196,7 +3193,7 @@ This renders the snippet as ordinary text."
       (setq yas-snippet-end (overlay-end control-overlay))
       (delete-overlay control-overlay))
 
       (setq yas-snippet-end (overlay-end control-overlay))
       (delete-overlay control-overlay))
 
-    (yas--inhibit-overlay-hooks
+    (let ((yas--inhibit-overlay-hooks t))
       (when yas--active-field-overlay
         (delete-overlay yas--active-field-overlay))
       (when yas--field-protection-overlays
       (when yas--active-field-overlay
         (delete-overlay yas--active-field-overlay))
       (when yas--field-protection-overlays
@@ -3229,7 +3226,7 @@ This renders the snippet as ordinary text."
   (condition-case error
       (run-hooks hook-var)
     (error
   (condition-case error
       (run-hooks hook-var)
     (error
-     (yas--message 3 "%s error: %s" hook-var (error-message-string error)))))
+     (yas--message 2 "%s error: %s" hook-var (error-message-string error)))))
 
 
 (defun yas--check-commit-snippet ()
 
 
 (defun yas--check-commit-snippet ()
@@ -3366,15 +3363,17 @@ Otherwise deletes a character normally by calling `delete-char'."
           (t
            (call-interactively 'delete-char)))))
 
           (t
            (call-interactively 'delete-char)))))
 
-(defun yas--skip-and-clear (field)
-  "Deletes the region of FIELD and sets it's modified state to t."
+(defun yas--skip-and-clear (field &optional from)
+  "Deletes the region of FIELD and sets it's modified state to t.
+If given, FROM indicates position to start at instead of FIELD's beginning."
   ;; Just before skipping-and-clearing the field, mark its children
   ;; fields as modified, too. If the children have mirrors-in-fields
   ;; this prevents them from updating erroneously (we're skipping and
   ;; deleting!).
   ;;
   (yas--mark-this-and-children-modified field)
   ;; Just before skipping-and-clearing the field, mark its children
   ;; fields as modified, too. If the children have mirrors-in-fields
   ;; this prevents them from updating erroneously (we're skipping and
   ;; deleting!).
   ;;
   (yas--mark-this-and-children-modified field)
-  (delete-region (yas--field-start field) (yas--field-end field)))
+  (unless (= (yas--field-start field) (yas--field-end field))
+    (delete-region (or from (yas--field-start field)) (yas--field-end field))))
 
 (defun yas--mark-this-and-children-modified (field)
   (setf (yas--field-modified-p field) t)
 
 (defun yas--mark-this-and-children-modified (field)
   (setf (yas--field-modified-p field) t)
@@ -3408,29 +3407,33 @@ Move the overlay, or create it if it does not exit."
     (overlay-put yas--active-field-overlay 'insert-behind-hooks
                  '(yas--on-field-overlay-modification))))
 
     (overlay-put yas--active-field-overlay 'insert-behind-hooks
                  '(yas--on-field-overlay-modification))))
 
-(defun yas--on-field-overlay-modification (overlay after? _beg _end &optional _length)
+(defun yas--skip-and-clear-field-p (field beg _end length)
+  "Tell if newly modified FIELD should be cleared and skipped.
+BEG, END and LENGTH like overlay modification hooks."
+  (and (= length 0) ; A 0 pre-change length indicates insertion.
+       (= beg (yas--field-start field)) ; Insertion at field start?
+       (not (yas--field-modified-p field))))
+
+(defun yas--on-field-overlay-modification (overlay after? beg end &optional length)
   "Clears the field and updates mirrors, conditionally.
 
   "Clears the field and updates mirrors, conditionally.
 
-Only clears the field if it hasn't been modified and it point it
-at field start.  This hook doesn't do anything if an undo is in
-progress."
-  (unless (or yas--inhibit-overlay-hooks
+Only clears the field if it hasn't been modified and point is at
+field start.  This hook does nothing if an undo is in progress."
+  (unless (or (not after?)
+              yas--inhibit-overlay-hooks
+              (not (overlayp yas--active-field-overlay)) ; Avoid Emacs bug #21824.
               (yas--undo-in-progress))
               (yas--undo-in-progress))
-    (let* ((field (overlay-get overlay 'yas--field))
+    (let* ((inhibit-modification-hooks t)
+           (field (overlay-get overlay 'yas--field))
            (snippet (overlay-get yas--active-field-overlay 'yas--snippet)))
            (snippet (overlay-get yas--active-field-overlay 'yas--snippet)))
-      (cond (after?
-             (yas--advance-end-maybe field (overlay-end overlay))
-             (save-excursion
-               (yas--field-update-display field))
-             (yas--update-mirrors snippet))
-            (field
-             (when (and (not after?)
-                        (not (yas--field-modified-p field))
-                        (eq (point) (if (markerp (yas--field-start field))
-                                        (marker-position (yas--field-start field))
-                                      (yas--field-start field))))
-               (yas--skip-and-clear field))
-             (setf (yas--field-modified-p field) t))))))
+      (when (yas--skip-and-clear-field-p field beg end length)
+        ;; We delete text starting from the END of insertion.
+        (yas--skip-and-clear field end))
+      (setf (yas--field-modified-p field) t)
+      (yas--advance-end-maybe field (overlay-end overlay))
+      (save-excursion
+        (yas--field-update-display field))
+      (yas--update-mirrors snippet))))
 \f
 ;;; Apropos protection overlays:
 ;;
 \f
 ;;; Apropos protection overlays:
 ;;
@@ -3438,16 +3441,9 @@ progress."
 ;; snippet outside the active field. Actual protection happens in
 ;; `yas--on-protection-overlay-modification'.
 ;;
 ;; snippet outside the active field. Actual protection happens in
 ;; `yas--on-protection-overlay-modification'.
 ;;
-;; Currently this signals an error which inhibits the command. For
-;; commands that move point (like `kill-line'), point is restored in
-;; the `yas--post-command-handler' using a global
-;; `yas--protection-violation' variable.
-;;
-;; Alternatively, I've experimented with an implementation that
-;; commits the snippet before actually calling `this-command'
-;; interactively, and then signals an error, which is ignored. but
-;; blocks all other million modification hooks. This presented some
-;; problems with stacked expansion.
+;; As of github #537 this no longer inhibits the command by issuing an
+;; error: all the snippets at point, including nested snippets, are
+;; automatically commited and the current command can proceed.
 ;;
 (defun yas--make-move-field-protection-overlays (snippet field)
   "Place protection overlays surrounding SNIPPET's FIELD.
 ;;
 (defun yas--make-move-field-protection-overlays (snippet field)
   "Place protection overlays surrounding SNIPPET's FIELD.
@@ -3462,7 +3458,7 @@ Move the overlays, or create them if they do not exit."
     ;;
     (when (< (buffer-size) end)
       (save-excursion
     ;;
     (when (< (buffer-size) end)
       (save-excursion
-        (yas--inhibit-overlay-hooks
+        (let ((yas--inhibit-overlay-hooks t))
           (goto-char (point-max))
           (newline))))
     ;; go on to normal overlay creation/moving
           (goto-char (point-max))
           (newline))))
     ;; go on to normal overlay creation/moving
@@ -3481,29 +3477,16 @@ Move the overlays, or create them if they do not exit."
              ;; (overlay-put ov 'evaporate t)
              (overlay-put ov 'modification-hooks '(yas--on-protection-overlay-modification)))))))
 
              ;; (overlay-put ov 'evaporate t)
              (overlay-put ov 'modification-hooks '(yas--on-protection-overlay-modification)))))))
 
-(defvar yas--protection-violation nil
-  "When non-nil, signals attempts to erroneously exit or modify the snippet.
-
-Functions in the `post-command-hook', for example
-`yas--post-command-handler' can check it and reset its value to
-nil.  The variables value is the point where the violation
-originated")
-
-(defun yas--on-protection-overlay-modification (_overlay after? _beg _end &optional _length)
-  "Signals a snippet violation, then issues error.
-
-The error should be ignored in `debug-ignored-errors'"
-  (unless yas--inhibit-overlay-hooks
-    (cond ((not (or after?
-                    (yas--undo-in-progress)))
-           (cond (t
-                  (let ((snippets (yas--snippets-at-point)))
-                    (yas--message 3 "Comitting snippets. Action would destroy a protection overlay.")
-                    (cl-loop for snippet in snippets
-                             do (yas--commit-snippet snippet))))
-                 (nil
-                  (setq yas--protection-violation (point))
-                  (error "Exit the snippet first!")))))))
+(defun yas--on-protection-overlay-modification (_overlay after? beg end &optional length)
+  "Commit the snippet if the protection overlay is being killed."
+  (unless (or yas--inhibit-overlay-hooks
+              (not after?)
+              (= length (- end beg)) ; deletion or insertion
+              (yas--undo-in-progress))
+    (let ((snippets (yas--snippets-at-point)))
+      (yas--message 2 "Committing snippets. Action would destroy a protection overlay.")
+      (cl-loop for snippet in snippets
+               do (yas--commit-snippet snippet)))))
 
 (add-to-list 'debug-ignored-errors "^Exit the snippet first!$")
 
 
 (add-to-list 'debug-ignored-errors "^Exit the snippet first!$")
 
@@ -3537,8 +3520,12 @@ The error should be ignored in `debug-ignored-errors'"
   "Expand snippet CONTENT at current point.
 
 Text between START and END will be deleted before inserting
   "Expand snippet CONTENT at current point.
 
 Text between START and END will be deleted before inserting
-template.  EXPAND-ENV is are let-style variable to value bindings
+template.  EXPAND-ENV is a list of (SYM VALUE) let-style dynamic bindings
 considered when expanding the snippet."
 considered when expanding the snippet."
+  (cl-assert (and yas-minor-mode
+                  (memq 'yas--post-command-handler post-command-hook))
+             nil
+             "[yas] `yas-expand-snippet' needs properly setup `yas-minor-mode'")
   (run-hooks 'yas-before-expand-snippet-hook)
 
   ;;
   (run-hooks 'yas-before-expand-snippet-hook)
 
   ;;
@@ -3586,14 +3573,21 @@ considered when expanding the snippet."
              ;; them mostly to make the undo information
              ;;
              (setq yas--start-column (current-column))
              ;; them mostly to make the undo information
              ;;
              (setq yas--start-column (current-column))
-             (yas--inhibit-overlay-hooks
+             (let ((yas--inhibit-overlay-hooks t)
+                   ;; Avoid major-mode's syntax propertizing function,
+                   ;; since we mess with the syntax-table and also
+                   ;; insert things that are not valid in the
+                   ;; major-mode language syntax anyway.
+                   (syntax-propertize-function nil))
                (setq snippet
                      (if expand-env
                          (eval `(let* ,expand-env
                                   (insert content)
                                   (yas--snippet-create start (point))))
                        (insert content)
                (setq snippet
                      (if expand-env
                          (eval `(let* ,expand-env
                                   (insert content)
                                   (yas--snippet-create start (point))))
                        (insert content)
-                       (yas--snippet-create start (point))))))
+                       (yas--snippet-create start (point)))))
+             ;; Invalidate any syntax-propertizing done while `syntax-propertize-function' was nil
+             (syntax-ppss-flush-cache start))
 
            ;; stacked-expansion: This checks for stacked expansion, save the
            ;; `yas--previous-active-field' and advance its boundary.
 
            ;; stacked-expansion: This checks for stacked expansion, save the
            ;; `yas--previous-active-field' and advance its boundary.
@@ -3633,7 +3627,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)))
-           (yas--message 3 "snippet expanded.")
+           (yas--message 4 "snippet expanded.")
            t))))
 
 (defun yas--take-care-of-redo (_beg _end snippet)
            t))))
 
 (defun yas--take-care-of-redo (_beg _end snippet)
@@ -3840,6 +3834,9 @@ cons cells to this var.")
 backquoted Lisp expressions should be inserted at the end of
 expansion.")
 
 backquoted Lisp expressions should be inserted at the end of
 expansion.")
 
+(defvar yas--indent-markers nil
+  "List of markers for manual indentation.")
+
 (defun yas--snippet-parse-create (snippet)
   "Parse a recently inserted snippet template, creating all
 necessary fields, mirrors and exit points.
 (defun yas--snippet-parse-create (snippet)
   "Parse a recently inserted snippet template, creating all
 necessary fields, mirrors and exit points.
@@ -3859,6 +3856,9 @@ Meant to be called in a narrowed buffer, does various passes"
     ;; protect escaped characters
     ;;
     (yas--protect-escapes)
     ;; protect escaped characters
     ;;
     (yas--protect-escapes)
+    ;; Parse indent markers: `$>'.
+    (goto-char parse-start)
+    (yas--indent-parse-create snippet)
     ;; parse fields with {}
     ;;
     (goto-char parse-start)
     ;; parse fields with {}
     ;;
     (goto-char parse-start)
@@ -3876,7 +3876,22 @@ Meant to be called in a narrowed buffer, does various passes"
     (yas--calculate-adjacencies snippet)
     ;; Delete $-constructs
     ;;
     (yas--calculate-adjacencies snippet)
     ;; Delete $-constructs
     ;;
-    (save-restriction (widen) (yas--delete-regions yas--dollar-regions))
+    (save-restriction
+      (widen)
+      (yas--delete-regions yas--dollar-regions))
+    ;; Make sure to do this insertion *after* deleting the dollar
+    ;; regions, otherwise we invalidate the calculated positions of
+    ;; all the fields following $0.
+    (let ((exit (yas--snippet-exit snippet)))
+      (goto-char (if exit (yas--exit-marker exit) (point-max))))
+    (when (eq yas-wrap-around-region 'cua)
+      (setq yas-wrap-around-region ?0))
+    (cond ((and yas-wrap-around-region yas-selected-text)
+           (insert yas-selected-text))
+          ((and (characterp yas-wrap-around-region)
+                (get-register yas-wrap-around-region))
+           (insert (prog1 (get-register yas-wrap-around-region)
+                     (set-register yas-wrap-around-region nil)))))
     ;; restore backquoted expression values
     ;;
     (yas--restore-backquotes)
     ;; restore backquoted expression values
     ;;
     (yas--restore-backquotes)
@@ -3892,8 +3907,9 @@ Meant to be called in a narrowed buffer, does various passes"
     (goto-char parse-start)
     (yas--indent snippet)))
 
     (goto-char parse-start)
     (yas--indent snippet)))
 
-(defun yas--indent-according-to-mode (snippet-markers)
-  "Indent current line according to mode, preserving SNIPPET-MARKERS."
+(defun yas--indent-region (from to snippet)
+  "Indent the lines between FROM and TO with `indent-according-to-mode'.
+The SNIPPET's markers are preserved."
   ;;; Apropos indenting problems....
   ;;
   ;; `indent-according-to-mode' uses whatever `indent-line-function'
   ;;; Apropos indenting problems....
   ;;
   ;; `indent-according-to-mode' uses whatever `indent-line-function'
@@ -3906,54 +3922,54 @@ Meant to be called in a narrowed buffer, does various passes"
   ;; `front-advance' property set to nil.
   ;;
   ;; This is why I have these `trouble-markers', they are the ones at
   ;; `front-advance' property set to nil.
   ;;
   ;; This is why I have these `trouble-markers', they are the ones at
-  ;; they are the ones at the first non-whitespace char at the line
-  ;; (i.e. at `yas--real-line-beginning'. After indentation takes place
-  ;; we should be at the correct to restore them to. All other
-  ;; non-trouble-markers have been *pushed* and don't need special
-  ;; attention.
-  ;;
-  (goto-char (yas--real-line-beginning))
-  (let ((trouble-markers (remove-if-not #'(lambda (marker)
-                                            (= marker (point)))
-                                        snippet-markers)))
-    (save-restriction
-      (widen)
-      (condition-case _
-          (indent-according-to-mode)
-        (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)))
-          trouble-markers)))
+  ;; the first non-whitespace char at the line.  After indentation
+  ;; takes place we should be at the correct to restore them.  All
+  ;; other non-trouble-markers should have been *pushed* and don't
+  ;; need special attention.
+  (let* ((snippet-markers (yas--collect-snippet-markers snippet))
+         (to (set-marker (make-marker) to)))
+    (save-excursion
+      (goto-char from)
+      (save-restriction
+        (widen)
+        ;; Indent each non-empty line.
+        (cl-loop if (/= (line-beginning-position) (line-end-position)) do
+                 (back-to-indentation)
+                 (let ((trouble-markers ; The markers at (point).
+                        (cl-remove (point) snippet-markers :test #'/=)))
+                   (unwind-protect
+                       (indent-according-to-mode)
+                     (dolist (marker trouble-markers)
+                       (set-marker marker (point)))))
+                 while (and (zerop (forward-line 1))
+                            (< (point) to)))))))
 
 (defvar yas--indent-original-column nil)
 (defun yas--indent (snippet)
 
 (defvar yas--indent-original-column nil)
 (defun yas--indent (snippet)
-  (let ((snippet-markers (yas--collect-snippet-markers snippet)))
-    ;; Look for those $>
-    (save-excursion
-      (while (re-search-forward "$>" nil t)
-        (delete-region (match-beginning 0) (match-end 0))
-        (when (not (eq yas-indent-line 'auto))
-          (yas--indent-according-to-mode snippet-markers))))
-    ;; Now do stuff for 'fixed and 'auto
-    (save-excursion
-      (cond ((eq yas-indent-line 'fixed)
-             (while (and (zerop (forward-line))
-                         (zerop (current-column)))
-               (indent-to-column yas--indent-original-column)))
-            ((eq yas-indent-line 'auto)
-             (let ((end (set-marker (make-marker) (point-max)))
-                   (indent-first-line-p yas-also-auto-indent-first-line))
-               (while (and (zerop (if indent-first-line-p
-                                      (prog1
-                                          (forward-line 0)
-                                        (setq indent-first-line-p nil))
-                                    (forward-line 1)))
-                           (not (eobp))
-                           (<= (point) end))
-                 (yas--indent-according-to-mode snippet-markers))))
-            (t
-             nil)))))
+  ;; Indent lines that had indent markers (`$>') on them.
+  (save-excursion
+    (dolist (marker yas--indent-markers)
+      (unless (eq yas-indent-line 'auto)
+        (goto-char marker)
+        (yas--indent-region (line-beginning-position)
+                            (line-end-position)
+                            snippet))
+      ;; Finished with this marker.
+      (set-marker marker nil))
+    (setq yas--indent-markers nil))
+  ;; Now do stuff for `fixed' and `auto'.
+  (save-excursion
+    (cond ((eq yas-indent-line 'fixed)
+           (while (and (zerop (forward-line))
+                       (zerop (current-column)))
+             (indent-to-column yas--indent-original-column)))
+          ((eq yas-indent-line 'auto)
+           (let ((end (set-marker (make-marker) (point-max))))
+             (unless yas-also-auto-indent-first-line
+               (forward-line 1))
+             (yas--indent-region (line-beginning-position)
+                                 (point-max)
+                                 snippet))))))
 
 (defun yas--collect-snippet-markers (snippet)
   "Make a list of all the markers used by SNIPPET."
 
 (defun yas--collect-snippet-markers (snippet)
   "Make a list of all the markers used by SNIPPET."
@@ -3970,15 +3986,6 @@ Meant to be called in a narrowed buffer, does various passes"
         (push (yas--exit-marker snippet-exit) markers)))
     markers))
 
         (push (yas--exit-marker snippet-exit) markers)))
     markers))
 
-(defun yas--real-line-beginning ()
-  (let ((c (char-after (line-beginning-position)))
-        (n (line-beginning-position)))
-    (while (or (eql c ?\ )
-               (eql c ?\t))
-      (cl-incf n)
-      (setq c (char-after n)))
-    n))
-
 (defun yas--escape-string (escaped)
   (concat "YASESCAPE" (format "%d" escaped) "PROTECTGUARD"))
 
 (defun yas--escape-string (escaped)
   (concat "YASESCAPE" (format "%d" escaped) "PROTECTGUARD"))
 
@@ -4044,11 +4051,10 @@ with their evaluated value into `yas--backquote-markers-and-strings'."
         (set-marker marker nil)))))
 
 (defun yas--scan-sexps (from count)
         (set-marker marker nil)))))
 
 (defun yas--scan-sexps (from count)
-  (condition-case _
+  (ignore-errors
+    (save-match-data ; `scan-sexps' may modify match data.
       (with-syntax-table (standard-syntax-table)
       (with-syntax-table (standard-syntax-table)
-        (scan-sexps from count))
-    (error
-     nil)))
+        (scan-sexps from count)))))
 
 (defun yas--make-marker (pos)
   "Create a marker at POS with nil `marker-insertion-type'."
 
 (defun yas--make-marker (pos)
   "Create a marker at POS with nil `marker-insertion-type'."
@@ -4056,6 +4062,16 @@ with their evaluated value into `yas--backquote-markers-and-strings'."
     (set-marker-insertion-type marker nil)
     marker))
 
     (set-marker-insertion-type marker nil)
     marker))
 
+(defun yas--indent-parse-create (snippet)
+  "Parse the \"$>\" indentation markers in SNIPPET."
+  (setq yas--indent-markers ())
+  (while (search-forward "$>" nil t)
+    (delete-region (match-beginning 0) (match-end 0))
+    ;; Mark the beginning of the line.
+    (push (yas--make-marker (line-beginning-position))
+          yas--indent-markers))
+  (setq yas--indent-markers (nreverse yas--indent-markers)))
+
 (defun yas--field-parse-create (snippet &optional parent-field)
   "Parse most field expressions in SNIPPET, except for the simple one \"$n\".
 
 (defun yas--field-parse-create (snippet &optional parent-field)
   "Parse most field expressions in SNIPPET, except for the simple one \"$n\".
 
@@ -4080,9 +4096,8 @@ When multiple expressions are found, only the last one counts."
                                    ;; after the ":", this will be
                                    ;; caught as a mirror with
                                    ;; transform later.
                                    ;; after the ":", this will be
                                    ;; caught as a mirror with
                                    ;; transform later.
-                                   (not (save-match-data
-                                          (eq (string-match "$[ \t\n]*("
-                                                            (match-string-no-properties 2)) 0)))
+                                   (not (string-match-p "\\`\\$[ \t\n]*("
+                                                        (match-string-no-properties 2)))
                                    ;; allow ${0: some exit text}
                                    ;; (not (and number (zerop number)))
                                    (yas--make-field number
                                    ;; allow ${0: some exit text}
                                    ;; (not (and number (zerop number)))
                                    (yas--make-field number
@@ -4159,21 +4174,10 @@ When multiple expressions are found, only the last one counts."
   (while (re-search-forward yas--simple-mirror-regexp nil t)
     (let ((number (string-to-number (match-string-no-properties 1))))
       (cond ((zerop number)
   (while (re-search-forward yas--simple-mirror-regexp nil t)
     (let ((number (string-to-number (match-string-no-properties 1))))
       (cond ((zerop number)
-
              (setf (yas--snippet-exit snippet)
                    (yas--make-exit (yas--make-marker (match-end 0))))
              (setf (yas--snippet-exit snippet)
                    (yas--make-exit (yas--make-marker (match-end 0))))
-             (save-excursion
-               (goto-char (match-beginning 0))
-               (when yas-wrap-around-region
-                 (cond (yas-selected-text
-                        (insert yas-selected-text))
-                       ((and (eq yas-wrap-around-region 'cua)
-                             cua-mode
-                             (get-register ?0))
-                        (insert (prog1 (get-register ?0)
-                                  (set-register ?0 nil))))))
-               (push (cons (point) (yas--exit-marker (yas--snippet-exit snippet)))
-                     yas--dollar-regions)))
+             (push (cons (match-beginning 0) (yas--exit-marker (yas--snippet-exit snippet)))
+                   yas--dollar-regions))
             (t
              (let ((field (yas--snippet-find-field snippet number)))
                (if field
             (t
              (let ((field (yas--snippet-find-field snippet number)))
                (if field
@@ -4222,43 +4226,45 @@ When multiple expressions are found, only the last one counts."
 
 (defun yas--update-mirrors (snippet)
   "Update all the mirrors of SNIPPET."
 
 (defun yas--update-mirrors (snippet)
   "Update all the mirrors of SNIPPET."
-  (save-excursion
-    (dolist (field-and-mirror (sort
-                               ;; make a list of ((F1 . M1) (F1 . M2) (F2 . M3) (F2 . M4) ...)
-                               ;; where F is the field that M is mirroring
-                               ;;
-                               (mapcan #'(lambda (field)
-                                           (mapcar #'(lambda (mirror)
-                                                       (cons field mirror))
-                                                   (yas--field-mirrors field)))
-                                       (yas--snippet-fields snippet))
-                               ;; then sort this list so that entries with mirrors with parent
-                               ;; fields appear before. This was important for fixing #290, and
-                               ;; luckily also handles the case where a mirror in a field causes
-                               ;; another mirror to need reupdating
-                               ;;
-                               #'(lambda (field-and-mirror1 field-and-mirror2)
-                                   (> (yas--calculate-mirror-depth (cdr field-and-mirror1))
-                                      (yas--calculate-mirror-depth (cdr field-and-mirror2))))))
-      (let* ((field (car field-and-mirror))
-             (mirror (cdr field-and-mirror))
-             (parent-field (yas--mirror-parent-field mirror)))
-        ;; before updating a mirror with a parent-field, maybe advance
-        ;; its start (#290)
-        ;;
-        (when parent-field
-          (yas--advance-start-maybe mirror (yas--fom-start parent-field)))
-        ;; update this mirror
-        ;;
-        (yas--mirror-update-display mirror field)
-        ;; `yas--place-overlays' is needed if the active field and
-        ;; protected overlays have been changed because of insertions
-        ;; in `yas--mirror-update-display'
-        ;;
-        (when (eq field (yas--snippet-active-field snippet))
-          (yas--place-overlays snippet field))))))
-
-(defun yas--mirror-update-display (mirror field)
+  (save-restriction
+    (widen)
+    (save-excursion
+      (dolist (field-and-mirror
+               (sort
+                ;; make a list of ((F1 . M1) (F1 . M2) (F2 . M3) (F2 . M4) ...)
+                ;; where F is the field that M is mirroring
+                ;;
+                (cl-mapcan #'(lambda (field)
+                               (mapcar #'(lambda (mirror)
+                                           (cons field mirror))
+                                       (yas--field-mirrors field)))
+                           (yas--snippet-fields snippet))
+                ;; then sort this list so that entries with mirrors with parent
+                ;; fields appear before. This was important for fixing #290, and
+                ;; luckily also handles the case where a mirror in a field causes
+                ;; another mirror to need reupdating
+                ;;
+                #'(lambda (field-and-mirror1 field-and-mirror2)
+                    (> (yas--calculate-mirror-depth (cdr field-and-mirror1))
+                       (yas--calculate-mirror-depth (cdr field-and-mirror2))))))
+        (let* ((field (car field-and-mirror))
+               (mirror (cdr field-and-mirror))
+               (parent-field (yas--mirror-parent-field mirror)))
+          ;; before updating a mirror with a parent-field, maybe advance
+          ;; its start (#290)
+          ;;
+          (when parent-field
+            (yas--advance-start-maybe mirror (yas--fom-start parent-field)))
+          ;; update this mirror
+          ;;
+          (yas--mirror-update-display mirror field snippet)
+          ;; `yas--place-overlays' is needed since the active field and
+          ;; protected overlays might have been changed because of insertions
+          ;; in `yas--mirror-update-display'.
+          (let ((active-field (yas--snippet-active-field snippet)))
+            (when active-field (yas--place-overlays snippet active-field))))))))
+
+(defun yas--mirror-update-display (mirror field snippet)
   "Update MIRROR according to FIELD (and mirror transform)."
 
   (let* ((mirror-parent-field (yas--mirror-parent-field mirror))
   "Update MIRROR according to FIELD (and mirror transform)."
 
   (let* ((mirror-parent-field (yas--mirror-parent-field mirror))
@@ -4270,14 +4276,18 @@ When multiple expressions are found, only the last one counts."
                (not (string= reflection (buffer-substring-no-properties (yas--mirror-start mirror)
                                                                         (yas--mirror-end mirror)))))
       (goto-char (yas--mirror-start mirror))
                (not (string= reflection (buffer-substring-no-properties (yas--mirror-start mirror)
                                                                         (yas--mirror-end mirror)))))
       (goto-char (yas--mirror-start mirror))
-      (yas--inhibit-overlay-hooks
+      (let ((yas--inhibit-overlay-hooks t))
         (insert reflection))
       (if (> (yas--mirror-end mirror) (point))
           (delete-region (point) (yas--mirror-end mirror))
         (set-marker (yas--mirror-end mirror) (point))
         (yas--advance-start-maybe (yas--mirror-next mirror) (point))
         ;; super-special advance
         (insert reflection))
       (if (> (yas--mirror-end mirror) (point))
           (delete-region (point) (yas--mirror-end mirror))
         (set-marker (yas--mirror-end mirror) (point))
         (yas--advance-start-maybe (yas--mirror-next mirror) (point))
         ;; super-special advance
-        (yas--advance-end-of-parents-maybe mirror-parent-field (point))))))
+        (yas--advance-end-of-parents-maybe mirror-parent-field (point)))
+      (let ((yas--inhibit-overlay-hooks t))
+        (yas--indent-region (yas--mirror-start mirror)
+                            (yas--mirror-end mirror)
+                            snippet)))))
 
 (defun yas--field-update-display (field)
   "Much like `yas--mirror-update-display', but for fields."
 
 (defun yas--field-update-display (field)
   "Much like `yas--mirror-update-display', but for fields."
@@ -4289,7 +4299,7 @@ When multiple expressions are found, only the last one counts."
                                                                            (yas--field-end field)))))
         (setf (yas--field-modified-p field) t)
         (goto-char (yas--field-start field))
                                                                            (yas--field-end field)))))
         (setf (yas--field-modified-p field) t)
         (goto-char (yas--field-start field))
-        (yas--inhibit-overlay-hooks
+        (let ((yas--inhibit-overlay-hooks t))
           (insert transformed)
           (if (> (yas--field-end field) (point))
               (delete-region (point) (yas--field-end field))
           (insert transformed)
           (if (> (yas--field-end field) (point))
               (delete-region (point) (yas--field-end field))
@@ -4302,10 +4312,7 @@ When multiple expressions are found, only the last one counts."
 ;;
 (defun yas--post-command-handler ()
   "Handles various yasnippet conditions after each command."
 ;;
 (defun yas--post-command-handler ()
   "Handles various yasnippet conditions after each command."
-  (cond (yas--protection-violation
-         (goto-char yas--protection-violation)
-         (setq yas--protection-violation nil))
-        ((eq 'undo this-command)
+  (cond ((eq 'undo this-command)
          ;;
          ;; After undo revival the correct field is sometimes not
          ;; restored correctly, this condition handles that
          ;;
          ;; After undo revival the correct field is sometimes not
          ;; restored correctly, this condition handles that
@@ -4340,7 +4347,7 @@ When multiple expressions are found, only the last one counts."
                    (or (and fallback
                             (format "call command `%s'."
                                     (pp-to-string fallback)))
                    (or (and fallback
                             (format "call command `%s'."
                                     (pp-to-string fallback)))
-                       "do nothing (`yas-expand' doesn't shadow\nanything).")))
+                       "do nothing (`yas-expand' doesn't override\nanything).")))
                 ((eq yas-fallback-behavior 'return-nil)
                  "do nothing.")
                 (t "defer to `yas-fallback-behavior' (which see)."))))
                 ((eq yas-fallback-behavior 'return-nil)
                  "do nothing.")
                 (t "defer to `yas-fallback-behavior' (which see)."))))
@@ -4354,7 +4361,7 @@ object satisfying `yas--field-p' to restrict the expansion to.")))
      '(yas--expand-from-keymap-doc t))
 (defun yas--expand-from-keymap-doc (context)
   "A doc synthesizer for `yas--expand-from-keymap-doc'."
      '(yas--expand-from-keymap-doc t))
 (defun yas--expand-from-keymap-doc (context)
   "A doc synthesizer for `yas--expand-from-keymap-doc'."
-  (add-hook 'temp-buffer-show-hook 'yas--snippet-description-finish-runonce)
+  (add-hook 'temp-buffer-show-hook #'yas--snippet-description-finish-runonce)
   (concat "Expand/run snippets from keymaps, possibly falling back to original binding.\n"
           (when (and context (eq this-command 'describe-key))
             (let* ((vec (this-single-command-keys))
   (concat "Expand/run snippets from keymaps, possibly falling back to original binding.\n"
           (when (and context (eq this-command 'describe-key))
             (let* ((vec (this-single-command-keys))
@@ -4389,7 +4396,8 @@ object satisfying `yas--field-p' to restrict the expansion to.")))
 (defun yas--snippet-description-finish-runonce ()
   "Final adjustments for the help buffer when snippets are concerned."
   (yas--create-snippet-xrefs)
 (defun yas--snippet-description-finish-runonce ()
   "Final adjustments for the help buffer when snippets are concerned."
   (yas--create-snippet-xrefs)
-  (remove-hook 'temp-buffer-show-hook 'yas--snippet-description-finish-runonce))
+  (remove-hook 'temp-buffer-show-hook
+               #'yas--snippet-description-finish-runonce))
 
 (defun yas--create-snippet-xrefs ()
   (save-excursion
 
 (defun yas--create-snippet-xrefs ()
   (save-excursion
@@ -4399,12 +4407,12 @@ object satisfying `yas--field-p' to restrict the expansion to.")))
                                          'yasnippet)))
         (when template
           (help-xref-button 1 'help-snippet-def template)
                                          'yasnippet)))
         (when template
           (help-xref-button 1 'help-snippet-def template)
-          (kill-region (match-end 1) (match-end 0))
-          (kill-region (match-beginning 0) (match-beginning 1)))))))
+          (delete-region (match-end 1) (match-end 0))
+          (delete-region (match-beginning 0) (match-beginning 1)))))))
 \f
 ;;; Utils
 
 \f
 ;;; Utils
 
-(defvar yas-verbosity 4
+(defvar yas-verbosity 3
   "Log level for `yas--message' 4 means trace most anything, 0 means nothing.")
 
 (defun yas--message (level message &rest args)
   "Log level for `yas--message' 4 means trace most anything, 0 means nothing.")
 
 (defun yas--message (level message &rest args)
@@ -4480,6 +4488,11 @@ and return the directory.  Return nil if not found."
 \f
 ;;; Backward compatibility to yasnippet <= 0.7
 
 \f
 ;;; Backward compatibility to yasnippet <= 0.7
 
+(defun yas-initialize ()
+  "For backward compatibility, enable `yas-minor-mode' globally."
+  (declare (obsolete "Use (yas-global-mode 1) instead." "0.8"))
+  (yas-global-mode 1))
+
 (defvar yas--backported-syms '(;; `defcustom's
                              ;;
                              yas-snippet-dirs
 (defvar yas--backported-syms '(;; `defcustom's
                              ;;
                              yas-snippet-dirs
@@ -4545,6 +4558,7 @@ and return the directory.  Return nil if not found."
                              yas-exit-snippet
                              yas-exit-all-snippets
                              yas-skip-and-clear-or-delete-char
                              yas-exit-snippet
                              yas-exit-all-snippets
                              yas-skip-and-clear-or-delete-char
+                             yas-initialize
 
                              ;; symbols that I "exported" for use
                              ;; in snippets and hookage
 
                              ;; symbols that I "exported" for use
                              ;; in snippets and hookage
@@ -4589,14 +4603,15 @@ and return the directory.  Return nil if not found."
 
 They are mapped to \"yas/*\" variants.")
 
 
 They are mapped to \"yas/*\" variants.")
 
-(dolist (sym yas--backported-syms)
-  (let ((backported (intern (replace-regexp-in-string "^yas-" "yas/" (symbol-name sym)))))
-    (when (boundp sym)
-      (make-obsolete-variable backported sym "yasnippet 0.8")
-      (defvaralias backported sym))
-    (when (fboundp sym)
-      (make-obsolete backported sym "yasnippet 0.8")
-      (defalias backported sym))))
+(when yas-backport-obsolete-alias
+  (dolist (sym yas--backported-syms)
+    (let ((backported (intern (replace-regexp-in-string "\\`yas-" "yas/" (symbol-name sym)))))
+      (when (boundp sym)
+        (make-obsolete-variable backported sym "yasnippet 0.8")
+        (defvaralias backported sym))
+      (when (fboundp sym)
+        (make-obsolete backported sym "yasnippet 0.8")
+        (defalias backported sym)))))
 
 (defvar yas--exported-syms
   (let (exported)
 
 (defvar yas--exported-syms
   (let (exported)
@@ -4605,7 +4620,7 @@ They are mapped to \"yas/*\" variants.")
                                   (not (get atom 'byte-obsolete-variable)))
                              (and (fboundp atom)
                                   (not (get atom 'byte-obsolete-info))))
                                   (not (get atom 'byte-obsolete-variable)))
                              (and (fboundp atom)
                                   (not (get atom 'byte-obsolete-info))))
-                         (string-match-p "^yas-[^-]" (symbol-name atom)))
+                         (string-match-p "\\`yas-[^-]" (symbol-name atom)))
                     (push atom exported))))
     exported)
   "Exported yasnippet symbols.
                     (push atom exported))))
     exported)
   "Exported yasnippet symbols.