emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] master 3fd07de 63/63: * packages/yasnippet: Merge version 0.12.0


From: Noam Postavsky
Subject: [elpa] master 3fd07de 63/63: * packages/yasnippet: Merge version 0.12.0 from upstream.
Date: Mon, 17 Jul 2017 22:54:23 -0400 (EDT)

branch: master
commit 3fd07de87439ffcbfca7fcad573283eb73eecc10
Merge: 2cdd182 75cbf72
Author: Noam Postavsky <address@hidden>
Commit: Noam Postavsky <address@hidden>

    * packages/yasnippet: Merge version 0.12.0 from upstream.
---
 packages/yasnippet/.travis.yml               |    2 +-
 packages/yasnippet/CONTRIBUTING.md           |   66 +-
 packages/yasnippet/NEWS                      |   80 ++
 packages/yasnippet/README.mdown              |    4 +-
 packages/yasnippet/Rakefile                  |   12 +-
 packages/yasnippet/doc/faq.org               |   83 +-
 packages/yasnippet/doc/org-setup.inc         |    2 +-
 packages/yasnippet/doc/snippet-expansion.org |   80 +-
 packages/yasnippet/doc/yas-doc-helper.el     |  138 +--
 packages/yasnippet/yasnippet-debug.el        |  393 +++++++--
 packages/yasnippet/yasnippet-tests.el        |  378 +++++++-
 packages/yasnippet/yasnippet.el              | 1200 ++++++++++++++++----------
 12 files changed, 1658 insertions(+), 780 deletions(-)

diff --git a/packages/yasnippet/.travis.yml b/packages/yasnippet/.travis.yml
index b43d358..1dfb3fa 100644
--- a/packages/yasnippet/.travis.yml
+++ b/packages/yasnippet/.travis.yml
@@ -7,7 +7,7 @@ env:
   - EMACS_VERSION=23.4
   - EMACS_VERSION=24.3
   - EMACS_VERSION=24.5
-  - EMACS_VERSION=25-prerelease
+  - EMACS_VERSION=25.2
 
 install:
   - curl -LO 
https://github.com/npostavs/emacs-travis/releases/download/bins/emacs-bin-${EMACS_VERSION}.tar.gz
diff --git a/packages/yasnippet/CONTRIBUTING.md 
b/packages/yasnippet/CONTRIBUTING.md
index 81c0a1f..bf3b2d3 100644
--- a/packages/yasnippet/CONTRIBUTING.md
+++ b/packages/yasnippet/CONTRIBUTING.md
@@ -1,29 +1,37 @@
-# Submitting Bug Reports
-
-Please read [Important note regarding bug reporting][bugnote].
-
-# Contributing to Yasnippet
-
-## Copyright Assignment
-
-Yasnippet is part of GNU ELPA, so it falls under the same copyright
-assignment policy as the rest of Emacs (see "Copyright Assignment" in
-https://www.gnu.org/software/emacs/CONTRIBUTE). A copyright assignment
-for Emacs also covers Yasnippet.
-
-## Commit message format
-
-The commit message format roughly follows Emacs conventions, although
-there is no separate Changelog file.
-
-    The commit message's first sentence should be capitalized, no period
-
-    It may be followed by a paragraph with a longer explanation. The
-    changelog style entry goes at the end of the message.
-
-    * foo.el (a-function): Terse summary of per-function changes.
-
-For trivial changes, a message consisting of just the changelog entry
-(the `* foo.el ...` part) is fine.
-
-[bugnote]: 
https://github.com/joaotavora/yasnippet#important-note-regarding-bug-reporting
+# Submitting Bug Reports or Patches
+
+As a GNU ELPA package, bugs or patches may be submitted to the main
+Emacs bug list, address@hidden  Alternatively, you may use the
+[Github issue tracker][issues].
+
+Please read [Important note regarding bug reporting][bugnote].
+
+# Contributing to Yasnippet
+
+## Copyright Assignment
+
+Yasnippet is part of GNU ELPA, so it falls under the same copyright
+assignment policy as the rest of Emacs (see "Copyright Assignment" in
+https://www.gnu.org/software/emacs/CONTRIBUTE).  A copyright assignment
+for Emacs also covers Yasnippet.
+
+## Commit message format
+
+The commit message format roughly follows Emacs conventions.  There is
+no separate Changelog file.
+
+    Capitalize the first sentence, no period at the end
+
+    Please make sure the summary line can be understood without having
+    to lookup bug numbers.  It may be followed by a paragraph with a
+    longer explanation.  The changelog style entry goes at the end of
+    the message.
+    * foo.el (a-function): Terse summary of per-function changes.  Use
+    double spacing between sentences (set `sentence-end-double-space'
+    to t).
+
+For trivial changes, a message consisting of just the changelog entry
+(e.g., `* foo.el (a-function): Fix docstring typo.`) is fine.
+
+[bugnote]: 
https://github.com/joaotavora/yasnippet#important-note-regarding-bug-reporting
+[issues]: https://github.com/joaotavora/yasnippet/issues
diff --git a/packages/yasnippet/NEWS b/packages/yasnippet/NEWS
index 6e6629d..0f6b7d8 100644
--- a/packages/yasnippet/NEWS
+++ b/packages/yasnippet/NEWS
@@ -3,8 +3,88 @@ Yasnippet NEWS -- history of user-visible changes.
 Copyright (C) 2016 Free Software Foundation, Inc.
 See the end of the file for license conditions.
 
+
+Don't delete snippets more than once.
+
+
 
+* 0.12.0 (Jul 17, 2017)
+
+** Changes and New Features
+
+*** Snippets can now expand in strings & comments by default again.
+'yas-buffer-local-condition' is now a defcustom See Github #774.
+
+*** 'yas-after-exit-snippet-hook' can now be bound in 'expand-env' of
+snippets.  See Github #28, #702, #779, #786.
+
+*** Snippets under directories in 'yas-snippet-dirs' are now in
+snippet-mode automatically.
+
+*** Snippets can now be expanded in org source blocks, if
+'org-src-tab-acts-natively' and 'org-src-fontify-natively' are set.
+See Github #761.
+
+*** 'yas-fallback-behavior' is now obsolete, 'yas-expand' is now bound
+conditionally with an extended menu item, 'yas-maybe-expand'.
+Therefore users wanting to bind 'yas-expand' to a different key, SPC
+for example, should do
+
+    (define-key yas-minor-mode-map (kbd "SPC") yas-maybe-expand)
+
+See Github #760, #808.
+
+*** The documentation build output is now reproducible.  The timestamp
+now depends on the commit date, or the environment variable
+SOURCE_DATE_EPOCH is that is set.
+
+*** 'yas-indent-line' and 'expand-env' are now respected during mirror
+updates.  See Github #743.
 
+*** New function 'yas-active-snippets'.  Renamed from
+'yas--snippets-at-point', which remains as an obsolete alias.  See
+Github #727.
+
+*** New custom option 'yas-overlay-priority'.  This is can be used to
+give the snippet navigation keymaps higher priority than keymaps from
+overlays created by other packages, like 'auto-complete'.  See Github
+#828.
+
+** Fixed bugs
+
+*** Snippets having ${0:soon-to-be-deleted} with no other fields now
+correctly put the field 0 text in the active region after exiting.
+See Github #653.
+
+*** Fix undo of snippet insertion which also triggers indentation.
+See Github #821.
+
+*** Fixed a bug causing whitespace loss between mirrors.
+
+*** Fixed several bugs causing problems when combining Yasnippet with
+other modes and packages, like 'auto-fill-mode', 'c++-mode',
+'rust-mode', and 'lentic'.
+
+**** Fix another bug with auto-fill-mode.
+See Github #784, #794.
+
+**** Fix a bug in parsing of snippet fields for modes that use the
+'syntax-table' text property, 'c++-mode' is one example of this.  See
+Github #815.
+
+**** 'syntax-propertize-function' is now restored before indenting the
+snippet.  This improves compatibility with modes which rely on it for
+indentation, like 'rust-mode'.  See Github #782, #818.
+
+**** Avoid trying to delete a snippet which is already deleted.  This
+prevents an error when using 'rust-mode's 'rust-format-buffer'
+command.
+
+**** Ensure inhibit-modification-hooks is nil while modifying buffer.
+This fixes problems for packages relying on modification hooks, like
+'lentic'.  See Github #756, #712.
+
+
 * 0.11.0 (Oct 26, 2016)
 ** Changes and New Features
 
diff --git a/packages/yasnippet/README.mdown b/packages/yasnippet/README.mdown
index f4e0594..e3d99f7 100644
--- a/packages/yasnippet/README.mdown
+++ b/packages/yasnippet/README.mdown
@@ -105,7 +105,9 @@ should be added like this to `yas-snippet-dirs`:
 
 Please refer to the comprehensive [documentation][docs] for full
 customisation and support.  If you find a bug in the code or in the
-documentation, please report it on [the GitHub issue tracker][issues].
+documentation, please report it to the main Emacs bug list,
address@hidden, and put "yasnippet" somewhere in the subject.
+Alternatively, you may use the [Github issue tracker][issues].
 
 ## Important note regarding bug reporting
 
diff --git a/packages/yasnippet/Rakefile b/packages/yasnippet/Rakefile
index 48a2086..85133e6 100644
--- a/packages/yasnippet/Rakefile
+++ b/packages/yasnippet/Rakefile
@@ -20,6 +20,12 @@ task :tests do
     " --batch -f ert-run-tests-batch-and-exit"
 end
 
+desc "run test in interactive mode"
+task :itests do
+  sh "#{$EMACS} -Q -L . -l yasnippet-tests.el" +
+     " --eval \"(call-interactively 'ert)\""
+end
+
 desc "create a release package"
 task :package do
   release_dir = "pkg/yasnippet-#{$version}"
@@ -76,16 +82,12 @@ namespace :doc do
       Dir.glob("doc/stylesheets/*.css").each do |file|
         FileUtils.cp file, 'doc/gh-pages/stylesheets'
       end
-      curRev = `git rev-parse --verify HEAD`.chomp()
+      curRev = `git describe`.chomp()
       expRev = IO.read('doc/html-revision').chomp()
       if curRev != expRev
         raise ("The HTML rev: #{expRev},\n" +
                "current  rev: #{curRev}!\n")
       end
-      if !system "git diff-index --quiet HEAD"
-        system "git status --untracked-files=no"
-        raise "You have uncommitted changes!"
-      end
       Dir.chdir 'doc/gh-pages' do
         sh "git commit -a -m 'Automatic documentation update.\n\n" +
           "From #{curRev.chomp()}'"
diff --git a/packages/yasnippet/doc/faq.org b/packages/yasnippet/doc/faq.org
index 79249e8..d80bb3b 100644
--- a/packages/yasnippet/doc/faq.org
+++ b/packages/yasnippet/doc/faq.org
@@ -4,81 +4,14 @@
 
 * Why is there an extra newline?
 
-If you have a newline at the end of the snippet definition file, then
-YASnippet will add a newline when you expanding a snippet. Please don't
-add a newline at the end if you don't want it when you saving the
-snippet file.
+If there is a newline at the end of a snippet definition file,
+YASnippet will add a newline when expanding that snippet. When editing
+or saving a snippet file, please be careful not to accidentally add a
+terminal newline.
 
-Note some editors will automatically add a newline for you. In Emacs, if
-you set =require-final-newline= to =t=, it will add the final newline
-for you automatically.
-
-* Why doesn't TAB expand a snippet?
-
-First check the mode line to see if there's =yas=. If not, then try
-=M-x yas-minor-mode= to manually turn on the minor mode and try to
-expand the snippet again. If it works, then, you can add the following
-code to your =.emacs= /before/ loading YASnippet:
-
-#+BEGIN_SRC emacs-lisp
-  (add-hook 'the-major-mode-hook 'yas-minor-mode-on)
-#+END_SRC
-
-where =the-major-mode= is the major mode in which 
[[sym:yas-minor-mode][=yas-minor-mode=]] isn't
-enabled by default.
-
-From YASnippet 0.6 you can also use the command =M-x yas-global-mode= to
-turn on YASnippet automatically for /all/ major modes.
-
-If [[sym:yas-minor-mode][=yas-minor-mode=]] is on but the snippet still not 
expanded. Then try
-to see what command is bound to the =TAB= key: press =C-h k= and then
-press =TAB=. Emacs will show you the result.
-
-You'll see a buffer prompted by Emacs saying that
-=TAB runs the command ...=. Alternatively, you might see
-=<tab> runs the command ...=, note the difference between =TAB= and
-=<tab>= where the latter has priority. If you see =<tab>= bound to a
-command other than [[sym:yas-expand][=yas-expand=]], (e.g. in =org-mode=) you 
can try the
-following code to work around:
-
-#+BEGIN_SRC emacs-lisp
-  (add-hook 'org-mode-hook
-            (let ((original-command (lookup-key org-mode-map [tab])))
-              `(lambda ()
-                 (setq yas-fallback-behavior
-                       '(apply ,original-command))
-                 (local-set-key [tab] 'yas-expand))))
-#+END_SRC
-
-replace =org-mode-hook= and =org-mode-map= with the major mode hook you
-are dealing with (Use =C-h m= to see what major mode you are in).
-
-As an alternative, you can also try
-
-#+BEGIN_SRC emacs-lisp
-  (defun yas-advise-indent-function (function-symbol)
-    (eval `(defadvice ,function-symbol (around yas-try-expand-first activate)
-             ,(format
-               "Try to expand a snippet before point, then call `%s' as usual"
-               function-symbol)
-             (let ((yas-fallback-behavior nil))
-               (unless (and (interactive-p)
-                            (yas-expand))
-                 ad-do-it)))))
-
-  (yas-advise-indent-function 'ruby-indent-line)
-#+END_SRC
-
-To /advise/ the modes indentation function bound to TAB, (in this case
-=ruby-indent-line=) to first try to run [[sym:yas-expand][=yas-expand=]].
-
-If the output of =C-h k RET <tab>= tells you that =<tab>= is indeed
-bound to [[sym:yas-expand][=yas-expand=]] but YASnippet still doesn't work, 
check your
-configuration and you may also ask for help on the 
[[http://groups.google.com/group/smart-snippet][discussion group]].
-See this particular 
[[http://code.google.com/p/yasnippet/issues/detail?id=93&can=1][thread]] for 
quite some solutions and alternatives.
-
-Don't forget to attach the information on what command is bound to TAB
-as well as the mode information (Can be obtained by =C-h m=).
+Note that some editors will automatically add a newline for you. In
+Emacs, if you set =require-final-newline= to =t=, it will add the
+final newline automatically.
 
 * Why doesn't TAB navigation work with flyspell
 
@@ -107,7 +40,7 @@ Edit the keymaps 
[[sym:yas-minor-mode-map][=yas-minor-mode-map=]] and
 #+begin_src emacs-lisp :exports code
    (define-key yas-minor-mode-map (kbd "<tab>") nil)
    (define-key yas-minor-mode-map (kbd "TAB") nil)
-   (define-key yas-minor-mode-map (kbd "<the new key>") 'yas-expand)
+   (define-key yas-minor-mode-map (kbd "<the new key>") yas-maybe-expand)
 
    ;;keys for navigation
    (define-key yas-keymap [(tab)]       nil)
diff --git a/packages/yasnippet/doc/org-setup.inc 
b/packages/yasnippet/doc/org-setup.inc
index 6ad09c9..60b9382 100644
--- a/packages/yasnippet/doc/org-setup.inc
+++ b/packages/yasnippet/doc/org-setup.inc
@@ -4,7 +4,7 @@
 
 #+LINK: sym file:snippet-reference.org::#%s
 
-#+OPTIONS: author:nil num:nil
+#+OPTIONS: author:nil num:nil timestamp:nil
 #+AUTHOR:
 # org < 8.0 use +STYLE, after use +HTML_HEAD
 #+STYLE: <link rel="stylesheet" type="text/css" href="stylesheets/manual.css" 
/>
diff --git a/packages/yasnippet/doc/snippet-expansion.org 
b/packages/yasnippet/doc/snippet-expansion.org
index 4bd133b..a14ce15 100644
--- a/packages/yasnippet/doc/snippet-expansion.org
+++ b/packages/yasnippet/doc/snippet-expansion.org
@@ -32,17 +32,33 @@
 ** Trigger key
 
 [[sym:yas-expand][=yas-expand=]] tries to expand a /snippet abbrev/ (also 
known as
-/snippet key/) before point.
+/snippet key/) before point.  YASnippet also provides a /conditional
+binding/ for this command: the variable [[sym:yas-expand][=yas-maybe-expand=]] 
contains a
+special value which, when bound in a keymap, tells Emacs to call
+[[sym:yas-expand][=yas-expand=]] if and only if there is a snippet abbrev 
before point.
+If there is no snippet to expand, Emacs will behave as if 
[[sym:yas-expand][=yas-expand=]]
+is unbound and so will run whatever command is bound to that key
+normally.
 
-When [[sym:yas-minor-mode][=yas-minor-mode=]] is enabled, it binds 
[[sym:yas-expand][=yas-expand=]] to =TAB= and
-=<tab>= by default, however, you can freely set it to some other key:
+When [[sym:yas-minor-mode][=yas-minor-mode=]] is enabled, it binds 
[[sym:yas-maybe-expand][=yas-maybe-expand=]] to =TAB=
+and =<tab>= by default, however, you can freely remove those bindings:
 
 #+begin_src emacs-lisp :exports code
    (define-key yas-minor-mode-map (kbd "<tab>") nil)
    (define-key yas-minor-mode-map (kbd "TAB") nil)
-   (define-key yas-minor-mode-map (kbd "<the new key>") 'yas-expand)
 #+end_src
 
+And set your own:
+
+#+begin_src emacs-lisp :exports code
+  ;; Bind `SPC' to `yas-expand' when snippet expansion available (it
+  ;; will still call `self-insert-command' otherwise).
+  (define-key yas-minor-mode-map (kbd "SPC") yas-maybe-expand)
+  ;; Bind `C-c y' to `yas-expand' ONLY.
+  (define-key yas-minor-mode-map (kbd "C-c y") #'yas-expand)
+#+end_src
+
+
 To enable the YASnippet minor mode in all buffers globally use the
 command [[sym:yas-global-mode][=yas-global-mode=]]. This will enable a 
modeline indicator,
 =yas=:
@@ -50,24 +66,14 @@ command [[sym:yas-global-mode][=yas-global-mode=]]. This 
will enable a modeline
 [[./images/minor-mode-indicator.png]]
 
 When you use [[sym:yas-global-mode][=yas-global-mode=]] you can also 
selectively disable
-YASnippet in some buffers by setting the buffer-local variable
-[[sym:yas-dont-active][=yas-dont-active=]] in the buffer's mode hook.
+YASnippet in some buffers by calling [[sym:yas-minor-mode][=yas-minor-mode=]] 
with a negative
+argument in the buffer's mode hook.
 
 *** Fallback behaviour
 
-[[sym:yas-fallback-behaviour][=yas-fallback-behaviour=]] is a customization 
variable bound to
-'=call-other-command= by default. If [[sym:yas-expand][=yas-expand=]] failed 
to find any
-suitable snippet to expand, it will disable the minor mode temporarily
-and find if there's any other command bound to the same key.
-
-If found, the command will be called. Usually this works very well
---when there's a snippet, expand it, otherwise, call whatever command
-originally bind to the trigger key.
-
-However, you can change this behavior by customizing the
-[[sym:yas-fallback-behavior][=yas-fallback-behavior=]] variable. If you set 
this variable to
-'=return-nil=, it will return =nil= instead of trying to call the
-/original/ command when no snippet is found.
+YASnippet used to support a more complicated way of sharing
+keybindings before [[sym:yas-expand][=yas-maybe-expand=]] was added.  This is 
now
+obsolete.
 
 ** Insert at point
 
@@ -175,32 +181,30 @@ In particular, the following things matter:
                 (yas-activate-extra-mode 'rails-mode)))
 #+END_SRC
 
--  Buffer-local
-   [[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]]
-   variable
+-  Buffer-local 
[[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]] variable
 
    This variable provides finer grained control over what snippets can
-   be expanded in the current buffer. The default value won't let you
-   expand snippets inside comments or string literals for example. See
-   The condition system\_ for more info.
+   be expanded in the current buffer.  For example, the constant
+   
[[sym:yas-not-string-or-comment-condition][=yas-not-string-or-comment-condition=]]
 has a value that disables
+   snippet expansion inside comments or string literals.  See 
[[condition-system][the
+   condition system]] for more info.
 
-** The condition system
+** The condition system <<condition-system>>
 
 Consider this scenario: you are an old Emacs hacker. You like the
 abbrev-way and bind [[sym:yas-expand][=yas-expand=]] to =SPC=. However, you 
don't want
 =if= to be expanded as a snippet when you are typing in a comment
 block or a string (e.g. in =python-mode=).
 
-If you use the =# condition := directive (see
-[[./snippet-development.org][Writing Snippets]]) you could just specify
-the condition for =if= to be =(not (python-syntax-comment-or-string-p))=. But 
how
-about =while=, =for=, etc. ? Writing the same condition for all the
-snippets is just boring. So has a buffer local variable
-[[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]]. You can set 
this variable to
-=(not (python-syntax-comment-or-string-p))= in =python-mode-hook=.
+If you use the =# condition := directive (see 
[[./snippet-development.org][Writing Snippets]]) you
+could just specify the condition for =if= to be =(not
+(python-syntax-comment-or-string-p))=.  But how about =while=, =for=,
+etc?  Writing the same condition for all the snippets is just boring.
+So you can instead set 
[[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]] to =(not
+(python-syntax-comment-or-string-p))= in =python-mode-hook=.
 
 Then, what if you really want some particular snippet to expand even
-inside a comment? Set 
[[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]] like this
+inside a comment?  Set 
[[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]] like this
 
 #+BEGIN_SRC emacs-lisp
   (add-hook 'python-mode-hook
@@ -211,10 +215,10 @@ inside a comment? Set 
[[sym:yas-buffer-local-condition][=yas-buffer-local-condit
                        t))))
 #+END_SRC
 
-... and specify the condition for a snippet that you're going to expand
-in comment to be evaluated to the symbol =force-in-comment=. Then it can
-be expanded as you expected, while other snippets like =if= still can't
-expanded in comment.
+... and for a snippet that you want to expand in comments, specify a
+condition which evaluates to the symbol =force-in-comment=.  Then it
+can be expanded as you expected, while other snippets like =if= still
+can't expanded in comments.
 
 For the full set of possible conditions, see the documentation for
 [[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]].
diff --git a/packages/yasnippet/doc/yas-doc-helper.el 
b/packages/yasnippet/doc/yas-doc-helper.el
index 8459eb7..e272e41 100644
--- a/packages/yasnippet/doc/yas-doc-helper.el
+++ b/packages/yasnippet/doc/yas-doc-helper.el
@@ -40,66 +40,58 @@
           tag content tag))
 
 (defun yas--document-symbol (symbol level)
-  (flet ((concat-lines (&rest lines)
-                       (mapconcat #'identity lines "\n")))
-    (let* ((stars (make-string level ?*))
-           (args (and (fboundp symbol)
-                      (mapcar #'symbol-name (help-function-arglist symbol t))))
-           (heading (cond ((fboundp symbol)
-                           (format
-                            "%s =%s= (%s)" stars symbol
-                            (mapconcat (lambda (a)
-                                         (format (if (string-prefix-p "&" a)
-                                                     "/%s/" "=%s=") a))
-                                       args " ")))
-                          (t
-                           (format "%s =%s=\n" stars symbol))))
-           (after-heading
-            (concat-lines ":PROPERTIES:"
-                          (format ":CUSTOM_ID: %s" symbol)
-                          ":END:"))
-           (body (or (cond ((fboundp symbol)
-                            (let ((doc-synth (car-safe (get symbol 
'function-documentation))))
-                              (if (functionp doc-synth)
-                                  (funcall doc-synth nil)
-                                (documentation symbol t))))
-                           ((boundp symbol)
-                            (documentation-property symbol 
'variable-documentation t))
-                           (t
-                            (format "*WARNING*: no symbol named =%s=" symbol)))
-                     (format "*WARNING*: no doc for symbol =%s=" symbol)))
-           (case-fold-search nil))
-      ;; do some transformations on the body:
-      ;; ARGxxx becomes @<code>arg@</code>xxx
-      ;; FOO becomes /foo/
-      ;; `bar' becomes [[#bar][=bar=]]
-      (setq body (replace-regexp-in-string
-                  "\\<\\([A-Z][-A-Z0-9]+\\)\\(\\sw+\\)?\\>"
-                  #'(lambda (match)
-                      (let* ((match1 (match-string 1 match))
-                             (prefix (downcase match1))
-                             (suffix (match-string 2 match))
-                             (fmt (cond
-                                   ((member prefix args)
-                                    (yas--org-raw-html "code" "%s"))
-                                   ((null suffix) "/%s/"))))
-                        (if fmt (format fmt prefix)
-                          match1)))
-                  body t t 1)
-            body (replace-regexp-in-string
-                  "`\\([a-z-]+\\)'"
-                  #'(lambda (match)
-                      (let* ((name (downcase (match-string 1 match)))
-                             (sym (intern name)))
-                        (if (memq sym yas--exported-syms)
-                            (format "[[#%s][=%s=]]" name name)
-                          (format "=%s=" name))))
-                  body t))
-      ;; output the paragraph
-      ;;
-      (concat-lines heading
-                    after-heading
-                    body))))
+  (let* ((stars (make-string level ?*))
+         (args (and (fboundp symbol)
+                    (mapcar #'symbol-name (help-function-arglist symbol t))))
+         (heading (cond ((fboundp symbol)
+                         (format
+                          "%s =%s= (%s)" stars symbol
+                          (mapconcat (lambda (a)
+                                       (format (if (string-prefix-p "&" a)
+                                                   "/%s/" "=%s=") a))
+                                     args " ")))
+                        (t
+                         (format "%s =%s=\n" stars symbol))))
+         (after-heading (format ":PROPERTIES:\n:CUSTOM_ID: %s\n:END:" symbol))
+         (body (or (cond ((fboundp symbol)
+                          (let ((doc-synth (car-safe (get symbol 
'function-documentation))))
+                            (if (functionp doc-synth)
+                                (funcall doc-synth nil)
+                              (documentation symbol t))))
+                         ((boundp symbol)
+                          (documentation-property symbol 
'variable-documentation t))
+                         (t
+                          (format "*WARNING*: no symbol named =%s=" symbol)))
+                   (format "*WARNING*: no doc for symbol =%s=" symbol)))
+         (case-fold-search nil))
+    ;; do some transformations on the body:
+    ;; ARGxxx becomes @<code>arg@</code>xxx
+    ;; FOO becomes /foo/
+    ;; `bar' becomes [[#bar][=bar=]]
+    (setq body (replace-regexp-in-string
+                "\\<\\([A-Z][-A-Z0-9]+\\)\\(\\sw+\\)?\\>"
+                #'(lambda (match)
+                    (let* ((match1 (match-string 1 match))
+                           (prefix (downcase match1))
+                           (suffix (match-string 2 match))
+                           (fmt (cond
+                                 ((member prefix args)
+                                  (yas--org-raw-html "code" "%s"))
+                                 ((null suffix) "/%s/"))))
+                      (if fmt (format fmt prefix)
+                        match1)))
+                body t t 1)
+          body (replace-regexp-in-string
+                "`\\([a-z-]+\\)'"
+                #'(lambda (match)
+                    (let* ((name (downcase (match-string 1 match)))
+                           (sym (intern name)))
+                      (if (memq sym yas--exported-syms)
+                          (format "[[#%s][=%s=]]" name name)
+                        (format "=%s=" name))))
+                body t))
+    ;; output the paragraph
+    (concat heading "\n" after-heading "\n" body)))
 
 (defun yas--document-symbols (level &rest names-and-predicates)
   (let ((sym-lists (make-vector (length names-and-predicates) nil))
@@ -128,11 +120,20 @@
 
 (let* ((dir (if load-file-name (file-name-directory load-file-name)
               default-directory))
-       (rev (with-temp-file (expand-file-name "html-revision" dir)
-              (or (when (eq (call-process "git" nil t nil
-                                          "rev-parse" "--verify" "HEAD") 0)
-                    (buffer-string))
-                  (princ yas--version (current-buffer)))))
+       (src-epoch (getenv "SOURCE_DATE_EPOCH"))
+       ;; Presence of SOURCE_DATE_EPOCH indicates a reproducible
+       ;; build, don't depend on git.
+       (rev (unless src-epoch
+              (ignore-errors
+                (car (process-lines "git" "describe" "--dirty")))))
+       (date (format-time-string
+              "(%Y-%m-%d %H:%M:%S)"
+              (seconds-to-time
+               (string-to-number
+                (or (if rev (car (process-lines "git" "show" "--format=%ct"))
+                      src-epoch)
+                    "0")))
+              t))
        (proj-plist
         `(,@(when (fboundp 'org-html-publish-to-html)
               '(:publishing-function org-html-publish-to-html))
@@ -142,10 +143,13 @@
              (insert-file-contents (expand-file-name "nav-menu.html.inc" dir))
              (buffer-string))
           :html-postamble
-          ,(concat "<hr><p class='creator'>Generated by %c on %d from "
-                   rev "</p>\n"
+          ,(concat "<hr><p class='creator'>Generated by %c from "
+                   (or rev yas--version) " " date "</p>\n"
                    "<p class='xhtml-validation'>%v</p>\n")))
        (project (assoc "yasnippet" org-publish-project-alist)))
+  (when rev ;; Rakefile :doc:upload uses "html-revision".
+    (with-temp-file (expand-file-name "html-revision" dir)
+      (princ rev (current-buffer))))
   (if project
       (setcdr project proj-plist)
     (push `("yasnippet" . ,proj-plist)
diff --git a/packages/yasnippet/yasnippet-debug.el 
b/packages/yasnippet/yasnippet-debug.el
index b12bcd4..7c09412 100644
--- a/packages/yasnippet/yasnippet-debug.el
+++ b/packages/yasnippet/yasnippet-debug.el
@@ -1,8 +1,8 @@
-;;; yasnippet-debug.el --- debug functions for yasnippet
+;;; yasnippet-debug.el --- debug functions for yasnippet -*- lexical-binding: 
t -*-
 
-;; Copyright (C) 2010, 2013, 2014  Free Software Foundation, Inc.
+;; Copyright (C) 2010, 2013, 2014, 2017  Free Software Foundation, Inc.
 
-;; Author: Jo�o T�vora
+;; Author: João Távora
 ;; Keywords: emulations, convenience
 
 ;; This program is free software; you can redistribute it and/or modify
@@ -20,83 +20,334 @@
 
 ;;; Commentary:
 
-;; Just some debug functions
-
+;; Some debug functions.  When loaded from the command line, provides
+;; quick way to test out snippets in a fresh Emacs instance.
+;;
+;; emacs -Q -l yasnippet-debug [-v[v]]
+;;     [-M:<modename>] [-M.<filext>] [-S:[<snippet-file|name>]]
+;;     [-- <more-arguments-passed-to-Emacs>...]
+;;
+;; See the source in `yas-debug-process-command-line' for meaning of
+;; args.
+;;
 ;;; Code:
 
-(require 'yasnippet)
-(require 'cl)
+(defconst yas--loaddir
+  (file-name-directory (or load-file-name buffer-file-name))
+  "Directory that yasnippet was loaded from.")
+
+(require 'yasnippet (expand-file-name "yasnippet" yas--loaddir))
+(require 'cl-lib)
+(eval-when-compile
+  (unless (require 'subr-x nil t)
+    (defmacro when-let (key-val &rest body)
+      (declare (indent 1) (debug ((symbolp form) body)))
+      `(let ((,(car key-val) ,(cadr key-val)))
+         (when ,(car key-val)
+           ,@body)))))
+
+(defvar yas-debug-live-indicators
+  (make-hash-table :test #'eq))
+
+(defun yas-debug-live-colors ()
+  (let ((colors ()))
+    (maphash (lambda (_k v) (push (nth 1 (car v)) colors)) 
yas-debug-live-indicators)
+    colors))
+
+(defvar yas-debug-recently-live-indicators)
+
+(defun yas-debug-get-live-indicator (location)
+  (require 'color)
+  (when (boundp 'yas-debug-recently-live-indicators)
+    (push location yas-debug-recently-live-indicators))
+  (let (beg end)
+    (if (markerp location)
+        (setq beg (setq end (marker-position location)))
+      (setq beg (yas-debug-ov-fom-start location)
+            end (yas-debug-ov-fom-end location)))
+    (or (when-let (color-ov (gethash location yas-debug-live-indicators))
+          (if (and beg end) (move-overlay (cdr color-ov) beg end)
+            (delete-overlay (cdr color-ov)))
+          color-ov)
+        (let* ((live-colors (yas-debug-live-colors))
+               (color
+                (cl-loop with best-color = nil with max-dist = -1
+                         for color = (format "#%06X" (random #x1000000))
+                         for comp = (apply #'color-rgb-to-hex 
(color-complement color))
+                         if (< (color-distance color (face-foreground 
'default))
+                               (color-distance comp (face-foreground 
'default)))
+                         do (setq color comp)
+                         for dist = (cl-loop for c in live-colors
+                                             minimize (color-distance c color))
+                         if (or (not live-colors) (> dist max-dist))
+                         do (setq best-color color) (setq max-dist dist)
+                         repeat (if live-colors 100 1)
+                         finally return `(:background ,best-color)))
+               (ov (make-overlay beg end)))
+          (if (markerp location)
+              (overlay-put ov 'before-string (propertize "↓" 'face color))
+            (overlay-put ov 'before-string (propertize "↘" 'face color))
+            (overlay-put ov 'after-string (propertize "↙" 'face color)))
+          (puthash location (cons color ov) yas-debug-live-indicators)))))
+
+(defun yas-debug-live-marker (marker)
+  (let* ((buffer (current-buffer))
+         (color-ov (yas-debug-get-live-indicator marker))
+         (color (car color-ov))
+         (ov (cdr color-ov))
+         (decorator (overlay-get ov 'before-string))
+         (str (format "at %d" (+ marker))))
+    (if (markerp marker)
+        (propertize str
+                    'cursor-sensor-functions
+                    `(,(lambda (window _oldpos dir)
+                         (overlay-put
+                          ov 'before-string
+                          (propertize decorator
+                                      'face (if (eq dir 'entered)
+                                                'mode-line-highlight color)))))
+                    'face color)
+      str)))
+
+(defun yas-debug-ov-fom-start (ovfom)
+  (cond ((overlayp ovfom) (overlay-start ovfom))
+        ((integerp ovfom) ovfom)
+        (t (yas--fom-start ovfom))))
+(defun yas-debug-ov-fom-end (ovfom)
+  (cond ((overlayp ovfom) (overlay-end ovfom))
+        ((integerp ovfom) ovfom)
+        (t (yas--fom-end ovfom))))
+
+(defun yas-debug-live-range (range)
+  (let* ((color-ov (yas-debug-get-live-indicator range))
+         (color (car color-ov))
+         (ov (cdr color-ov))
+         (decorator-beg (overlay-get ov 'before-string))
+         (decorator-end (overlay-get ov 'after-string))
+         (beg (yas-debug-ov-fom-start range))
+         (end (yas-debug-ov-fom-end range)))
+    (if (and beg end (not (integerp beg)) (not (integerp end)))
+        (propertize (format "from %d to %d" (+ beg) (+ end))
+                    'cursor-sensor-functions
+                    `(,(lambda (window _oldpos dir)
+                         (let ((face (if (eq dir 'entered)
+                                         'mode-line-highlight color)))
+                           (overlay-put ov 'before-string
+                                        (propertize decorator-beg 'face face))
+                           (overlay-put ov 'after-string
+                                        (propertize decorator-end 'face 
face)))))
+                    'face color)
+      "<dead>")))
+
+(defmacro yas-debug-with-tracebuf (outbuf &rest body)
+  (declare (indent 1))
+  (let ((tracebuf-var (make-symbol "tracebuf")))
+    `(let ((,tracebuf-var (or ,outbuf (get-buffer-create "*YASnippet 
trace*"))))
+       (unless (eq ,tracebuf-var (current-buffer))
+         (cl-flet ((printf (fmt &rest args)
+                           (with-current-buffer ,tracebuf-var
+                             (insert (apply #'format fmt args)))))
+           (unless ,outbuf
+             (with-current-buffer ,tracebuf-var
+               (erase-buffer)
+               (when (fboundp 'cursor-sensor-mode)
+                 (cursor-sensor-mode +1))
+               (setq truncate-lines t)))
+           (setq ,outbuf ,tracebuf-var)
+           (save-restriction
+             (widen)
+             ,@body))))))
+
+
+(defun yas-debug-snippet (snippet &optional outbuf)
+  (yas-debug-with-tracebuf outbuf
+    (when-let (overlay (yas--snippet-control-overlay snippet))
+      (printf "\tsid: %d control overlay %s\n"
+              (yas--snippet-id snippet)
+              (yas-debug-live-range overlay)))
+    (when-let (active-field (yas--snippet-active-field snippet))
+      (unless (consp (yas--field-start active-field))
+        (printf "\tactive field: #%d %s %s covering \"%s\"\n"
+                (yas--field-number active-field)
+                (if (yas--field-modified-p active-field) "**" "--")
+                (yas-debug-live-range active-field)
+                (buffer-substring-no-properties (yas--field-start 
active-field) (yas--field-end active-field)))))
+    (when-let (exit (yas--snippet-exit snippet))
+      (printf "\tsnippet-exit: %s next: %s\n"
+              (yas-debug-live-marker (yas--exit-marker exit))
+              (yas--exit-next exit)))
+    (dolist (field (yas--snippet-fields snippet))
+      (unless (consp (yas--field-start field))
+        (printf "\tfield: %d %s %s covering \"%s\" next: %s%s\n"
+                (yas--field-number field)
+                (if (yas--field-modified-p field) "**" "--")
+                (yas-debug-live-range field)
+                (buffer-substring-no-properties (yas--field-start field) 
(yas--field-end field))
+                (yas--debug-format-fom-concise (yas--field-next field))
+                (if (yas--field-parent-field field) "(has a parent)" "")))
+      (dolist (mirror (yas--field-mirrors field))
+        (unless (consp (yas--mirror-start mirror))
+          (printf "\t\tmirror: %s covering \"%s\" next: %s\n"
+                  (yas-debug-live-range mirror)
+                  (buffer-substring-no-properties (yas--mirror-start mirror) 
(yas--mirror-end mirror))
+                  (yas--debug-format-fom-concise (yas--mirror-next 
mirror))))))))
+
+(defvar yas-debug-target-buffer nil)
+(defvar-local yas-debug-target-snippets nil)
+(defvar yas-debug-undo nil)
+
+(defun yas-toggle-debug-undo (value)
+  (interactive (list (not yas-debug-undo)))
+  (setq yas-debug-undo value)
+  (yas--message 3 "debug undo %sabled" (if yas-debug-undo "en" "dis")))
+
+(defadvice yas--snippet-parse-create (before yas-debug-target-snippet 
(snippet))
+  (add-to-list 'yas-debug-target-snippets snippet))
+
+(defadvice yas--commit-snippet (after yas-debug-untarget-snippet (snippet))
+  (setq yas-debug-target-snippets
+        (remq snippet yas-debug-target-snippets))
+  (maphash (lambda (k color-ov)
+             (delete-overlay (cdr color-ov)))
+           yas-debug-live-indicators)
+  (clrhash yas-debug-live-indicators))
+
+(defun yas-debug-snippets (&optional outbuf hook)
+  (interactive (list nil t))
+  (condition-case err
+      (yas-debug-with-tracebuf outbuf
+        (unless (buffer-live-p yas-debug-target-buffer)
+          (setq yas-debug-target-buffer nil))
+        (with-current-buffer (or yas-debug-target-buffer (current-buffer))
+          (when yas-debug-target-snippets
+            (setq yas-debug-target-snippets
+                  (cl-delete-if-not #'yas--snippet-p 
yas-debug-target-snippets)))
+          (let ((yas-debug-recently-live-indicators nil))
+            (dolist (snippet (or yas-debug-target-snippets
+                                 (yas-active-snippets)))
+              (printf "snippet %d\n" (yas--snippet-id snippet))
+              (yas-debug-snippet snippet outbuf))
+            (maphash (lambda (loc color-ov)
+                       (unless (memq loc yas-debug-recently-live-indicators)
+                         (delete-overlay (cdr color-ov))
+                         (remhash loc yas-debug-live-indicators)))
+                     yas-debug-live-indicators))
+          (when (and yas-debug-undo (listp buffer-undo-list))
+            (printf "Undo list has %s elements:\n" (length buffer-undo-list))
+            (cl-loop for undo-elem in buffer-undo-list
+                     do (printf "%S\n" undo-elem))))
+        (when hook
+          (setq yas-debug-target-buffer (current-buffer))
+          (ad-enable-advice 'yas--snippet-parse-create 'before 
'yas-debug-target-snippet)
+          (ad-activate 'yas--snippet-parse-create)
+          (ad-enable-advice 'yas--commit-snippet 'after 
'yas-debug-untarget-snippet)
+          (ad-activate 'yas--commit-snippet)
+          (add-hook 'post-command-hook #'yas-debug-snippets)
+          ;; Window management is slapped together, it does what I
+          ;; want when the caller has a single window open.  Good
+          ;; enough for now.
+          (when (eq hook 'create)
+            (require 'edebug)
+            (edebug-instrument-function 'yas--snippet-parse-create)
+            (let ((buf-point (find-function-noselect 
'yas--snippet-parse-create)))
+              (with-current-buffer (car buf-point)
+                (goto-char (cdr buf-point)))))
+          outbuf))
+    ((debug error) (signal (car err) (cdr err)))))
+
+(defun yas-debug-snippet-create ()
+  (yas-debug-snippets nil 'create))
 
 (defun yas-debug-snippet-vars ()
   "Debug snippets, fields, mirrors and the `buffer-undo-list'."
   (interactive)
-  (with-output-to-temp-buffer "*YASnippet trace*"
-    (princ "Interesting YASnippet vars: \n\n")
-
-    (princ (format "\nPost command hook: %s\n" post-command-hook))
-    (princ (format "\nPre  command hook: %s\n" pre-command-hook))
-
-    (princ (format "%s live snippets in total\n" (length 
(yas--snippets-at-point (quote all-snippets)))))
-    (princ (format "%s overlays in buffer:\n\n" (length (overlays-in 
(point-min) (point-max)))))
-    (princ (format "%s live snippets at point:\n\n" (length 
(yas--snippets-at-point))))
-
-
-    (dolist (snippet (yas--snippets-at-point))
-      (princ (format "\tsid: %d control overlay from %d to %d\n"
-                     (yas--snippet-id snippet)
-                     (overlay-start (yas--snippet-control-overlay snippet))
-                     (overlay-end (yas--snippet-control-overlay snippet))))
-      (princ (format "\tactive field: %s from %s to %s covering \"%s\"\n"
-                     (yas--field-number (yas--snippet-active-field snippet))
-                     (marker-position (yas--field-start 
(yas--snippet-active-field snippet)))
-                     (marker-position (yas--field-end 
(yas--snippet-active-field snippet)))
-                     (buffer-substring-no-properties (yas--field-start 
(yas--snippet-active-field snippet)) (yas--field-end (yas--snippet-active-field 
snippet)))))
-      (when (yas--snippet-exit snippet)
-        (princ (format "\tsnippet-exit: at %s next: %s\n"
-                       (yas--exit-marker (yas--snippet-exit snippet))
-                       (yas--exit-next (yas--snippet-exit snippet)))))
-      (dolist (field (yas--snippet-fields snippet))
-        (princ (format "\tfield: %s from %s to %s covering \"%s\" next: %s%s\n"
-                       (yas--field-number field)
-                       (marker-position (yas--field-start field))
-                       (marker-position (yas--field-end field))
-                       (buffer-substring-no-properties (yas--field-start 
field) (yas--field-end field))
-                       (yas--debug-format-fom-concise (yas--field-next field))
-                       (if (yas--field-parent-field field) "(has a parent)" 
"")))
-        (dolist (mirror (yas--field-mirrors field))
-          (princ (format "\t\tmirror: from %s to %s covering \"%s\" next: %s\n"
-                         (marker-position (yas--mirror-start mirror))
-                         (marker-position (yas--mirror-end mirror))
-                         (buffer-substring-no-properties (yas--mirror-start 
mirror) (yas--mirror-end mirror))
-                         (yas--debug-format-fom-concise (yas--mirror-next 
mirror)))))))
-
-    (princ (format "\nUndo is %s and point-max is %s.\n"
-                   (if (eq buffer-undo-list t)
-                       "DISABLED"
-                     "ENABLED")
-                   (point-max)))
+  (yas-debug-with-tracebuf ()
+    (printf "Interesting YASnippet vars: \n\n")
+
+    (printf "\nPost command hook: %s\n" post-command-hook)
+    (printf "\nPre  command hook: %s\n" pre-command-hook)
+
+    (printf "%s live snippets in total\n" (length (yas-active-snippets 
'all-snippets)))
+    (printf "%s overlays in buffer:\n\n" (length (overlays-in (point-min) 
(point-max))))
+    (printf "%s live snippets at point:\n\n" (length (yas-active-snippets)))
+
+    (yas-debug-snippets outbuf)
+
+    (printf "\nUndo is %s and point-max is %s.\n"
+            (if (eq buffer-undo-list t)
+                "DISABLED"
+              "ENABLED")
+            (point-max))
     (unless (eq buffer-undo-list t)
-      (princ (format "Undpolist has %s elements. First 10 elements follow:\n" 
(length buffer-undo-list)))
-      (let ((first-ten (subseq buffer-undo-list 0 (min 19
-                                                       (length 
buffer-undo-list)))))
+      (printf "Undpolist has %s elements. First 10 elements follow:\n"
+              (length buffer-undo-list))
+      (let ((first-ten (cl-subseq buffer-undo-list 0
+                                  (min 19 (length buffer-undo-list)))))
         (dolist (undo-elem first-ten)
-          (princ (format "%2s:  %s\n" (position undo-elem first-ten) 
(truncate-string-to-width (format "%s" undo-elem) 70))))))))
+          (printf "%2s:  %s\n" (cl-position undo-elem first-ten)
+                  (truncate-string-to-width (format "%s" undo-elem) 70)))))
+    (display-buffer tracebuf)))
 
 (defun yas--debug-format-fom-concise (fom)
   (when fom
     (cond ((yas--field-p fom)
            (format "field %s from %d to %d"
                    (yas--field-number fom)
-                   (marker-position (yas--field-start fom))
-                   (marker-position (yas--field-end fom))))
+                   (+ (yas--field-start fom))
+                   (+ (yas--field-end fom))))
           ((yas--mirror-p fom)
            (format "mirror from %d to %d"
-                   (marker-position (yas--mirror-start fom))
-                   (marker-position (yas--mirror-end fom))))
+                   (+ (yas--mirror-start fom))
+                   (+ (yas--mirror-end fom))))
           (t
            (format "snippet exit at %d"
-                   (marker-position (yas--fom-start fom)))))))
+                   (+ (yas--fom-start fom)))))))
+
+(defun yas-debug-process-command-line (&optional options)
+  "Implement command line processing."
+  (setq yas-verbosity 99)
+  (setq yas-triggers-in-field t)
+  (setq debug-on-error t)
+  (let* ((snippet-file nil)
+         (snippet-mode 'fundamental-mode)
+         (snippet-key nil))
+    (unless options
+      (setq options (cl-loop for opt = (pop command-line-args-left)
+                             while (and opt (not (equal opt "--"))
+                                        (string-prefix-p "-" opt))
+                             collect opt)))
+    (when-let (mode (cl-member "-M:" options :test #'string-prefix-p))
+      (setq snippet-mode (intern (concat (substring (car mode) 3) "-mode"))))
+    (when-let (mode (cl-member "-M." options :test #'string-prefix-p))
+      (setq snippet-mode
+            (cdr (cl-assoc (substring (car mode) 2) auto-mode-alist
+                           :test (lambda (ext regexp) (string-match-p regexp 
ext))))))
+    (switch-to-buffer (get-buffer-create "*yas test*"))
+    (funcall snippet-mode)
+    (when-let (snippet-file (cl-member "-S:" options :test #'string-prefix-p))
+      (setq snippet-file (substring (car snippet-file) 3))
+      (if (file-exists-p snippet-file)
+          (with-temp-buffer
+            (insert-file-contents snippet-file)
+            (let ((snippet-deflist (yas--parse-template snippet-file)))
+              (yas-define-snippets snippet-mode (list snippet-deflist))
+              (setq snippet-key (car snippet-deflist))))
+        (yas-reload-all)
+        (let ((template (yas--lookup-snippet-1 snippet-file snippet-mode)))
+          (if template
+              (setq snippet-key (yas--template-key template))
+            (error "No such snippet `%s'" snippet-file)))))
+    (display-buffer (find-file-noselect
+                     (expand-file-name "yasnippet.el" yas--loaddir)))
+    (when-let (verbosity (car (or (member "-v" options) (member "-vv" 
options))))
+      (set-window-buffer
+       (split-window) (yas-debug-snippets
+                       nil (if (equal verbosity "-vv") 'create t))))
+    (yas-minor-mode +1)
+    (when snippet-key (insert snippet-key))))
 
+(when command-line-args-left
+  (yas-debug-process-command-line))
 
 (defun yas-exterminate-package ()
   (interactive)
@@ -106,28 +357,8 @@
                 (when (string-match "yas[-/]" (symbol-name atom))
                   (unintern atom obarray)))))
 
-(defun yas-debug-test (&optional quiet)
-  (interactive "P")
-  (yas-load-directory (or (and (listp yas-snippet-dirs)
-                               (first yas-snippet-dirs))
-                          yas-snippet-dirs
-                          "~/Source/yasnippet/snippets/"))
-  (set-buffer (switch-to-buffer "*YAS TEST*"))
-  (mapc #'yas--commit-snippet (yas--snippets-at-point 'all-snippets))
-  (erase-buffer)
-  (setq buffer-undo-list nil)
-  (setq undo-in-progress nil)
-  (snippet-mode)
-  (yas-minor-mode 1)
-  (let ((abbrev))
-    (setq abbrev "$f")
-    (insert abbrev))
-  (unless quiet
-    (add-hook 'post-command-hook 'yas-debug-snippet-vars 't 'local)))
-
 (provide 'yasnippet-debug)
 ;; Local Variables:
 ;; indent-tabs-mode: nil
-;; byte-compile-warnings: (not cl-functions)
 ;; End:
 ;;; yasnippet-debug.el ends here
diff --git a/packages/yasnippet/yasnippet-tests.el 
b/packages/yasnippet/yasnippet-tests.el
index 6b7a91a..c5a94f5 100644
--- a/packages/yasnippet/yasnippet-tests.el
+++ b/packages/yasnippet/yasnippet-tests.el
@@ -1,6 +1,6 @@
 ;;; yasnippet-tests.el --- some yasnippet tests  -*- lexical-binding: t -*-
 
-;; Copyright (C) 2012, 2013, 2014, 2015  Free Software Foundation, Inc.
+;; Copyright (C) 2012, 2013, 2014, 2015, 2017  Free Software Foundation, Inc.
 
 ;; Author: Jo�o T�vora <address@hidden>
 ;; Keywords: emulations, convenience
@@ -28,6 +28,7 @@
 (require 'ert)
 (require 'ert-x)
 (require 'cl-lib)
+(require 'org)
 
 
 ;;; Snippet mechanics
@@ -90,6 +91,15 @@
       (should (string= (yas--buffer-contents)
                        (concat filled-words "\n"))))))
 
+(ert-deftest auto-fill-with-multiparagraph ()
+  "Test auto-fill protection on snippet spanning multiple paragraphs"
+  (with-temp-buffer
+    (yas-minor-mode +1)
+    (auto-fill-mode +1)
+    (yas-expand-snippet "foo$1\n\n$2bar")
+    (yas-mock-insert " ")
+    (ert-simulate-command '(yas-next-field-or-maybe-expand))
+    (should (looking-at "bar"))))
 
 (ert-deftest primary-field-transformation ()
   (with-temp-buffer
@@ -145,7 +155,7 @@
     (ert-simulate-command '(yas-next-field-or-maybe-expand))
     (ert-simulate-command '(yas-skip-and-clear-or-delete-char))
     (should (looking-at "ble"))
-    (should (null (yas--snippets-at-point)))))
+    (should (null (yas-active-snippets)))))
 
 (ert-deftest ignore-trailing-whitespace ()
   (should (equal
@@ -166,6 +176,41 @@
 ;;     (should (string= (yas--buffer-contents)
 ;;                      "brother from another mother!"))))
 
+(ert-deftest undo-indentation ()
+  "Check undoing works when only line of snippet is indented."
+  (let ((yas-also-auto-indent-first-line t))
+    (yas-with-snippet-dirs
+     '((".emacs.d/snippets" ("emacs-lisp-mode" ("s" . "(setq $0)"))))
+     (with-temp-buffer
+       (emacs-lisp-mode)
+       (yas-reload-all)
+       (yas-minor-mode 1)
+       (insert "(let\n(while s")
+       (setq buffer-undo-list ())
+       (ert-simulate-command '(yas-expand))
+       ;; Need undo barrier, I think command loop puts it normally.
+       (push nil buffer-undo-list)
+       (should (string= (buffer-string) "(let\n    (while (setq )"))
+       (ert-simulate-command '(undo))
+       (should (string= (buffer-string) "(let\n(while s"))))))
+
+(ert-deftest undo-indentation-multiline ()
+  "Check undoing works when first line of multi-line snippet is indented."
+  (yas-with-snippet-dirs
+    '((".emacs.d/snippets" ("js-mode" ("if" . "if ($1) {\n\n}\n"))))
+    (with-temp-buffer
+      (js-mode)
+      (yas-reload-all)
+      (yas-minor-mode 1)
+      (insert "if\nabc = 123456789 + abcdef;")
+      (setq buffer-undo-list ())
+      (goto-char (point-min))
+      (search-forward "if")
+      (ert-simulate-command '(yas-expand))
+      (push nil buffer-undo-list)       ; See test above.
+      (ert-simulate-command '(undo))
+      (should (string= (buffer-string) "if\nabc = 123456789 + abcdef;")))))
+
 (ert-deftest dont-clear-on-partial-deletion-issue-515 ()
   "Ensure fields are not cleared when user doesn't really mean to."
   (with-temp-buffer
@@ -243,6 +288,78 @@ $1   ------------------------")
 XXXXX   ---------------- XXXXX ----
 XXXXX   ------------------------"))))
 
+(ert-deftest single-line-multi-mirror-indentation-2 ()
+  "Like `single-line-multi-mirror-indentation' but 2 mirrors interleaved."
+  ;; See also Github issue #768.
+  (with-temp-buffer
+    (c-mode)
+    (yas-minor-mode 1)
+    (yas-expand-snippet "${1:one} ${2:two};\n$1 $2_;\n$2 $1_;\n")
+    (should (string= (yas--buffer-contents)
+                     "one two;\none two_;\ntwo one_;\n"))))
+
+(ert-deftest indent-org-property ()
+  "Handling of `org-mode' property indentation, see `org-property-format'."
+  ;; This is an interesting case because `org-indent-line' calls
+  ;; `replace-match' for properties.
+  (with-temp-buffer
+    (org-mode)
+    (yas-minor-mode +1)
+    (yas-expand-snippet "* Test ${1:test}\n:PROPERTIES:\n:ID: $1-after\n:END:")
+    (yas-mock-insert "foo bar")
+    (ert-simulate-command '(yas-next-field))
+    (goto-char (point-min))
+    (let ((expected (with-temp-buffer
+                      (insert (format (concat "* Test foo bar\n"
+                                              "  " org-property-format "\n"
+                                              "  " org-property-format "\n"
+                                              "  " org-property-format)
+                                      ":PROPERTIES:" ""
+                                      ":ID:" "foo bar-after"
+                                      ":END:" ""))
+                      (delete-trailing-whitespace)
+                      (buffer-string))))
+      ;; Some org-mode versions leave trailing whitespace, some don't.
+      (delete-trailing-whitespace)
+      (should (equal expected (buffer-string))))))
+
+(ert-deftest indent-cc-mode ()
+  "Handling of cc-mode's indentation."
+  ;; This is an interesting case because cc-mode deletes all the
+  ;; indentation before recreating it.
+  (with-temp-buffer
+    (c++-mode)
+    (yas-minor-mode +1)
+    (yas-expand-snippet "\
+int foo()
+{
+    if ($1) {
+        delete $1;
+        $1 = 0;
+    }
+}")
+    (yas-mock-insert "var")
+    (should (string= "\
+int foo()
+{
+  if (var) {
+    delete var;
+    var = 0;
+  }
+}" (buffer-string)))))
+
+(ert-deftest indent-snippet-mode ()
+  "Handling of snippet-mode indentation."
+  ;; This is an interesting case because newlines match [[:space:]] in
+  ;; snippet-mode.
+  (with-temp-buffer
+    (snippet-mode)
+    (yas-minor-mode +1)
+    (yas-expand-snippet "# -*- mode: snippet -*-\n# name: $1\n# key: $1\n# 
--\n")
+    (yas-mock-insert "foo")
+    (should (string= "# -*- mode: snippet -*-\n# name: foo\n# key: foo\n# --\n"
+                     (buffer-string)))))
+
 (ert-deftest indent-mirrors-on-update ()
   "Check that mirrors are always kept indented."
   (with-temp-buffer
@@ -480,6 +597,88 @@ TODO: correct this bug!"
                      "brother from another mother") ;; no newline should be 
here!
             )))
 
+(ert-deftest snippet-exit-hooks ()
+  (defvar yas--ran-exit-hook)
+  (with-temp-buffer
+    (yas-saving-variables
+     (let ((yas--ran-exit-hook nil)
+           (yas-triggers-in-field t))
+       (yas-with-snippet-dirs
+         '((".emacs.d/snippets"
+            ("emacs-lisp-mode"
+             ("foo" . "\
+# expand-env: ((yas-after-exit-snippet-hook (lambda () (setq 
yas--ran-exit-hook t))))
+# --
+FOO ${1:f1} ${2:f2}")
+             ("sub" . "\
+# expand-env: ((yas-after-exit-snippet-hook (lambda () (setq 
yas--ran-exit-hook 'sub))))
+# --
+SUB"))))
+         (yas-reload-all)
+         (emacs-lisp-mode)
+         (yas-minor-mode +1)
+         (insert "foo")
+         (ert-simulate-command '(yas-expand))
+         (should-not yas--ran-exit-hook)
+         (yas-mock-insert "sub")
+         (ert-simulate-command '(yas-expand))
+         (ert-simulate-command '(yas-next-field))
+         (should-not yas--ran-exit-hook)
+         (ert-simulate-command '(yas-next-field))
+         (should (eq yas--ran-exit-hook t)))))))
+
+(ert-deftest snippet-exit-hooks-bindings ()
+  "Check that `yas-after-exit-snippet-hook' is handled correctly
+in the case of a buffer-local variable and being overwritten by
+the expand-env field."
+  (defvar yas--ran-exit-hook)
+  (with-temp-buffer
+    (yas-saving-variables
+     (let ((yas--ran-exit-hook nil)
+           (yas-triggers-in-field t)
+           (yas-after-exit-snippet-hook nil))
+       (yas-with-snippet-dirs
+         '((".emacs.d/snippets"
+            ("emacs-lisp-mode"
+             ("foo" . "foobar\n")
+             ("baz" . "\
+# expand-env: ((yas-after-exit-snippet-hook (lambda () (setq 
yas--ran-exit-hook 'letenv))))
+# --
+foobaz\n"))))
+         (yas-reload-all)
+         (emacs-lisp-mode)
+         (yas-minor-mode +1)
+         (add-hook 'yas-after-exit-snippet-hook (lambda () (push 'global 
yas--ran-exit-hook)))
+         (add-hook 'yas-after-exit-snippet-hook (lambda () (push 'local 
yas--ran-exit-hook)) nil t)
+         (insert "baz")
+         (ert-simulate-command '(yas-expand))
+         (should (eq 'letenv yas--ran-exit-hook))
+         (insert "foo")
+         (ert-simulate-command '(yas-expand))
+         (should (eq 'global (nth 0 yas--ran-exit-hook)))
+         (should (eq 'local (nth 1 yas--ran-exit-hook))))))))
+
+(ert-deftest snippet-mirror-bindings ()
+  "Check that variables defined with the expand-env field are
+accessible from mirror transformations."
+  (with-temp-buffer
+    (yas-saving-variables
+     (let ((yas-triggers-in-field t)
+           (yas-good-grace nil))
+       (yas-with-snippet-dirs
+         '((".emacs.d/snippets"
+            ("emacs-lisp-mode"
+             ("baz" . "\
+# expand-env: ((func #'upcase))
+# --
+hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat 
\"baz\")}$0"))))
+         (yas-reload-all)
+         (emacs-lisp-mode)
+         (yas-minor-mode +1)
+         (insert "baz")
+         (ert-simulate-command '(yas-expand))
+         (should (string= (yas--buffer-contents) "hello BAZ foobaz\n")))))))
+
 (defvar yas--barbaz)
 (defvar yas--foobarbaz)
 
@@ -523,6 +722,63 @@ TODO: correct this bug!"
          (yas-should-expand '(("foo-barbaz" . "OKfoo-barbazOK")
                               ("foo " . "foo "))))))))
 
+(ert-deftest nested-snippet-expansion-1 ()
+  (with-temp-buffer
+    (yas-minor-mode +1)
+    (let ((yas-triggers-in-field t))
+      (yas-expand-snippet "Parent $1 Snippet")
+      (yas-expand-snippet "(Child $1 $2 Snippet)")
+      (let ((snippets (yas-active-snippets)))
+        (should (= (length snippets) 2))
+        (should (= (length (yas--snippet-fields (nth 0 snippets))) 2))
+        (should (= (length (yas--snippet-fields (nth 1 snippets))) 1))))))
+
+(ert-deftest nested-snippet-expansion-2 ()
+  (let ((yas-triggers-in-field t))
+    (yas-with-snippet-dirs
+      '((".emacs.d/snippets"
+         ("text-mode"
+          ("nest" . "one($1:$1) two($2).$0"))))
+      (yas-reload-all)
+      (text-mode)
+      (yas-minor-mode +1)
+      (insert "nest")
+      (ert-simulate-command '(yas-expand))
+      (yas-mock-insert "nest")
+      (ert-simulate-command '(yas-expand))
+      (yas-mock-insert "x")
+      (ert-simulate-command '(yas-next-field-or-maybe-expand))
+      (yas-mock-insert "y")
+      (ert-simulate-command '(yas-next-field-or-maybe-expand))
+      (ert-simulate-command '(yas-next-field-or-maybe-expand))
+      (yas-mock-insert "z")
+      (ert-simulate-command '(yas-next-field-or-maybe-expand))
+      (should (string= (buffer-string)
+                       "one(one(x:x) two(y).:one(x:x) two(y).) two(z).")))))
+
+(ert-deftest nested-snippet-expansion-3 ()
+  (let ((yas-triggers-in-field t))
+    (yas-with-snippet-dirs
+      '((".emacs.d/snippets"
+         ("text-mode"
+          ("rt" . "\
+\\sqrt${1:$(if (string-equal \"\" yas/text) \"\" \"[\")}${1:}${1:$(if 
(string-equal \"\" yas/text) \"\" \"]\")}{$2}$0"))))
+      (yas-reload-all)
+      (text-mode)
+      (yas-minor-mode +1)
+      (insert "rt")
+      (ert-simulate-command '(yas-expand))
+      (yas-mock-insert "3")
+      (ert-simulate-command '(yas-next-field-or-maybe-expand))
+      (yas-mock-insert "rt")
+      (ert-simulate-command '(yas-next-field-or-maybe-expand))
+      (yas-mock-insert "5")
+      (ert-simulate-command '(yas-next-field-or-maybe-expand))
+      (yas-mock-insert "2")
+      (ert-simulate-command '(yas-next-field-or-maybe-expand))
+      (ert-simulate-command '(yas-next-field-or-maybe-expand))
+      (should (string= (buffer-string) "\\sqrt[3]{\\sqrt[5]{2}}")))))
+
 
 ;;; Loading
 ;;;
@@ -595,11 +851,11 @@ TODO: correct this bug!"
      (text-mode)
      (yas-minor-mode +1)
      (should (equal (yas-lookup-snippet "one") "one"))
-     (should (eq (key-binding "\C-c1") 'yas-expand-from-keymap))
+     (should (eq (yas--key-binding "\C-c1") 'yas-expand-from-keymap))
      (yas-define-snippets
       'text-mode '(("_1" "one!" "won" nil nil nil nil nil "uuid-1")))
      (should (null (yas-lookup-snippet "one" nil 'noerror)))
-     (should (null (key-binding "\C-c1")))
+     (should (null (yas--key-binding "\C-c1")))
      (should (equal (yas-lookup-snippet "won") "one!")))))
 
 (ert-deftest snippet-save ()
@@ -770,6 +1026,7 @@ TODO: correct this bug!"
 ;;; Menu
 ;;;
 (defmacro yas-with-even-more-interesting-snippet-dirs (&rest body)
+  (declare (debug t))
   `(yas-saving-variables
     (yas-with-snippet-dirs
       `((".emacs.d/snippets"
@@ -805,16 +1062,16 @@ TODO: correct this bug!"
   (let ((yas-use-menu t))
     (yas-with-even-more-interesting-snippet-dirs
      (yas-reload-all 'no-jit)
-     (let ((menu (cdr (gethash 'fancy-mode yas--menu-table))))
-       (should (eql 4 (length menu)))
+     (let ((menu-items (yas--collect-menu-items
+                        (gethash 'fancy-mode yas--menu-table))))
+       (should (eql 4 (length menu-items)))
        (dolist (item '("a-guy" "a-beggar"))
-         (should (cl-find item menu :key #'cl-third :test #'string=)))
-       (should-not (cl-find "an-outcast" menu :key #'cl-third :test #'string=))
+         (should (cl-find item menu-items :key #'cl-second :test #'string=)))
+       (should-not (cl-find "an-outcast" menu-items :key #'cl-second :test 
#'string=))
        (dolist (submenu '("sirs" "ladies"))
          (should (keymapp
-                  (cl-fourth
-                   (cl-find submenu menu :key #'cl-third :test #'string=)))))
-       ))))
+                  (cl-third
+                   (cl-find submenu menu-items :key #'cl-second :test 
#'string=)))))))))
 
 (ert-deftest test-group-menus ()
   "Test group-based menus using .yas-make-groups and the group directive"
@@ -889,16 +1146,23 @@ TODO: be meaner"
 ;;; The infamous and problematic tab keybinding
 ;;;
 (ert-deftest test-yas-tab-binding ()
-  (with-temp-buffer
-    (yas-minor-mode -1)
-    (should (not (eq (key-binding (yas--read-keybinding "<tab>")) 
'yas-expand)))
-    (yas-minor-mode 1)
-    (should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand))
-    (yas-expand-snippet "$1 $2 $3")
-    (should (eq (key-binding [(tab)]) 'yas-next-field-or-maybe-expand))
-    (should (eq (key-binding (kbd "TAB")) 'yas-next-field-or-maybe-expand))
-    (should (eq (key-binding [(shift tab)]) 'yas-prev-field))
-    (should (eq (key-binding [backtab]) 'yas-prev-field))))
+  (yas-saving-variables
+   (yas-with-snippet-dirs
+    '((".emacs.d/snippets"
+       ("fundamental-mode"
+        ("foo" . "foobar"))))
+    (yas-reload-all)
+    (with-temp-buffer
+      (yas-minor-mode -1)
+      (insert "foo")
+      (should (not (eq (key-binding (yas--read-keybinding "<tab>")) 
'yas-expand)))
+      (yas-minor-mode 1)
+      (should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand))
+      (yas-expand-snippet "$1 $2 $3")
+      (should (eq (key-binding [(tab)]) 'yas-next-field-or-maybe-expand))
+      (should (eq (key-binding (kbd "TAB")) 'yas-next-field-or-maybe-expand))
+      (should (eq (key-binding [(shift tab)]) 'yas-prev-field))
+      (should (eq (key-binding [backtab]) 'yas-prev-field))))))
 
 (ert-deftest test-rebindings ()
   (let* ((yas-minor-mode-map (copy-keymap yas-minor-mode-map))
@@ -918,11 +1182,58 @@ TODO: be meaner"
       (should (eq (key-binding (kbd "SPC")) 'yas-expand)))))
 
 (ert-deftest test-yas-in-org ()
-  (with-temp-buffer
-    (org-mode)
-    (yas-minor-mode 1)
-    (should (eq (key-binding [(tab)]) 'yas-expand))
-    (should (eq (key-binding (kbd "TAB")) 'yas-expand))))
+  (yas-saving-variables
+   (yas-with-snippet-dirs
+    '((".emacs.d/snippets"
+       ("org-mode"
+        ("foo" . "foobar"))))
+    (yas-reload-all)
+    (with-temp-buffer
+      (org-mode)
+      (yas-minor-mode 1)
+      (insert "foo")
+      (should (eq (key-binding [(tab)]) 'yas-expand))
+      (should (eq (key-binding (kbd "TAB")) 'yas-expand))))))
+
+(ert-deftest yas-org-native-tab-in-source-block ()
+  "Test expansion of snippets in org source blocks."
+  :expected-result (if (fboundp 'org-in-src-block-p)
+                       :passed :failed)
+  (yas-saving-variables
+   (yas-with-snippet-dirs
+    '((".emacs.d/snippets"
+       ("text-mode"
+        ("T" . "${1:one} $1\n${2:two} $2\n<<$0>> done!"))))
+    (let ((text-mode-hook '(yas-minor-mode))
+          (org-src-tab-acts-natively t)
+          ;; Org 8.x requires this in order for
+          ;; `org-src-tab-acts-natively' to have effect.
+          (org-src-fontify-natively t))
+      (yas-reload-all)
+      ;; Org relies on font-lock to identify source blocks.
+      (yas--with-font-locked-temp-buffer
+       (org-mode)
+       (yas-minor-mode 1)
+       (insert "#+BEGIN_SRC text\nT\n#+END_SRC")
+       (if (fboundp 'font-lock-ensure)
+           (font-lock-ensure)
+         (jit-lock-fontify-now))
+       (re-search-backward "^T$") (goto-char (match-end 0))
+       (should (org-in-src-block-p))
+       (ert-simulate-command `(,(key-binding (kbd "TAB"))))
+       (ert-simulate-command `(,(key-binding (kbd "TAB"))))
+       (ert-simulate-command `(,(key-binding (kbd "TAB"))))
+       ;; Check snippet exit location.
+       (should (looking-at ">> done!"))
+       (goto-char (point-min))
+       (forward-line)
+       ;; Check snippet expansion, ignore leading whitespace due to
+       ;; `org-edit-src-content-indentation'.
+       (should (looking-at "\
+[[:space:]]*one one
+[[:space:]]*two two
+[[:space:]]*<<>> done!")))))))
+
 
 (ert-deftest test-yas-activate-extra-modes ()
   "Given a symbol, `yas-activate-extra-mode' should be able to
@@ -964,6 +1275,14 @@ add the snippets associated with the given mode."
                         (yas--buffer-contents)))))
   (yas-exit-all-snippets))
 
+(defun yas--collect-menu-items (menu-keymap)
+  (let ((yas--menu-items ()))
+    (map-keymap (lambda (_binding definition)
+                  (when (eq (car-safe definition) 'menu-item)
+                    (push definition yas--menu-items)))
+                menu-keymap)
+    yas--menu-items))
+
 (defun yas-should-not-expand (keys)
   (dolist (key keys)
     (yas-exit-all-snippets)
@@ -985,6 +1304,13 @@ add the snippets associated with the given mode."
   (let ((interprogram-paste-function (lambda () string)))
     (ert-simulate-command '(yank nil))))
 
+(defun yas--key-binding (key)
+  "Like `key-binding', but override `this-command-keys-vector'.
+This lets `yas--maybe-expand-from-keymap-filter' work as expected."
+  (cl-letf (((symbol-function 'this-command-keys-vector)
+             (lambda () (cl-coerce key 'vector))))
+    (key-binding key)))
+
 (defun yas-make-file-or-dirs (ass)
   (let ((file-or-dir-name (car ass))
         (content (cdr ass)))
diff --git a/packages/yasnippet/yasnippet.el b/packages/yasnippet/yasnippet.el
index a6977d1..834d035 100644
--- a/packages/yasnippet/yasnippet.el
+++ b/packages/yasnippet/yasnippet.el
@@ -1,11 +1,11 @@
 ;;; yasnippet.el --- Yet another snippet extension for Emacs.
 
-;; Copyright (C) 2008-2016 Free Software Foundation, Inc.
+;; Copyright (C) 2008-2017 Free Software Foundation, Inc.
 ;; Authors: pluskid <address@hidden>,
 ;;          João Távora <address@hidden>,
 ;;          Noam Postavsky <address@hidden>
 ;; Maintainer: Noam Postavsky <address@hidden>
-;; Version: 0.11.0
+;; Version: 0.12.0
 ;; X-URL: http://github.com/joaotavora/yasnippet
 ;; Keywords: convenience, emulation
 ;; URL: http://github.com/joaotavora/yasnippet
@@ -152,10 +152,13 @@
   :prefix "yas-"
   :group 'editing)
 
+(defconst yas--loaddir
+  (file-name-directory (or load-file-name buffer-file-name))
+  "Directory that yasnippet was loaded from.")
+
 (defvar yas-installed-snippets-dir nil)
 (setq yas-installed-snippets-dir
-      (when load-file-name
-        (expand-file-name "snippets" (file-name-directory load-file-name))))
+      (expand-file-name "snippets" yas--loaddir))
 
 (defconst yas--default-user-snippets-dir
   (expand-file-name "snippets" user-emacs-directory))
@@ -271,22 +274,20 @@ Otherwise `yas-next-field-or-maybe-expand' just moves on 
to the
 next field"
   :type 'boolean)
 
-(defcustom yas-fallback-behavior 'call-other-command
-  "How to act when `yas-expand' does *not* expand a snippet.
-
-- `call-other-command' means try to temporarily disable YASnippet
-    and call the next command bound to whatever key was used to
-    invoke `yas-expand'.
-
-- nil or the symbol `return-nil' mean do nothing. (and
-  `yas-expand' returns nil)
-
-- A Lisp form (apply COMMAND . ARGS) means interactively call
-  COMMAND. If ARGS is non-nil, call COMMAND non-interactively
-  with ARGS as arguments."
+(defcustom yas-fallback-behavior 'return-nil
+  "This option is obsolete.
+Now that the conditional keybinding `yas-maybe-expand' is
+available, there's no more need for it."
   :type '(choice (const :tag "Call previous command"  call-other-command)
                  (const :tag "Do nothing"             return-nil)))
 
+(make-obsolete-variable
+ 'yas-fallback-behavior
+ "For `call-other-command' behavior bind to the conditional
+command value `yas-maybe-expand', for `return-nil' behavior bind
+directly to `yas-expand'."
+ "0.12")
+
 (defcustom yas-choose-keys-first nil
   "If non-nil, prompt for snippet key first, then for template.
 
@@ -342,9 +343,16 @@ per-snippet basis.  A value of `cua' is considered 
equivalent to
                  (const cua))) ; backwards compat
 
 (defcustom yas-good-grace t
-  "If non-nil, don't raise errors in inline elisp evaluation.
+  "If non-nil, don't raise errors in elisp evaluation.
+
+This affects both the inline elisp in snippets and the hook
+variables such as `yas-after-exit-snippet-hook'.
 
-An error string \"[yas] error\" is returned instead."
+If this variable's value is `inline', an error string \"[yas]
+error\" is returned instead of raising the error.  If this
+variable's value is `hooks', a message is output to according to
+`yas-verbosity-level'.  If this variable's value is t, both are
+active."
   :type 'boolean)
 
 (defcustom yas-visit-from-menu nil
@@ -451,13 +459,17 @@ 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
+(defconst yas-not-string-or-comment-condition
   '(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)
+  "Disables snippet expansion in strings and comments.
+To use, set `yas-buffer-local-condition' to this value.")
+
+(defcustom yas-buffer-local-condition t
   "Snippet expanding condition.
 
 This variable is a Lisp form which is evaluated every time a
@@ -504,17 +516,26 @@ conditions.
               (setq yas-buffer-local-condition
                     \\='(if (python-syntax-comment-or-string-p)
                          \\='(require-snippet-condition . force-in-comment)
-                       t))))
-
-The default value is similar, it filters out potential snippet
-expansions inside comments and string literals, unless the
-snippet itself contains a condition that returns the symbol
-`force-in-comment'.")
+                       t))))"
+  :type
+  `(choice
+    (const :tag "Disable snippet expansion inside strings and comments"
+           ,yas-not-string-or-comment-condition)
+    (const :tag "Expand all snippets regardless of conditions" always)
+    (const :tag "Expand snippets unless their condition is nil" t)
+    (const :tag "Disable all snippet expansion" nil)
+    sexp))
+
+(defcustom yas-overlay-priority 100
+  "Priority to use for yasnippets overlays.
+This is useful to control whether snippet navigation bindings
+override bindings from other packages (e.g., `company-mode')."
+  :type 'integer)
 
 
 ;;; Internal variables
 
-(defconst yas--version "0.11.0")
+(defconst yas--version "0.12.0")
 
 (defvar yas--menu-table (make-hash-table)
   "A hash table of MAJOR-MODE symbols to menu keymaps.")
@@ -546,6 +567,10 @@ snippet itself contains a condition that returns the symbol
 (defvar yas--snippet-id-seed 0
   "Contains the next id for a snippet.")
 
+(defvar yas--original-auto-fill-function nil
+  "The original value of `auto-fill-function'.")
+(make-variable-buffer-local 'yas--original-auto-fill-function)
+
 (defun yas--snippet-next-id ()
   (let ((id yas--snippet-id-seed))
     (cl-incf yas--snippet-id-seed)
@@ -560,10 +585,22 @@ snippet itself contains a condition that returns the 
symbol
 (defvar yas--minor-mode-menu nil
   "Holds the YASnippet menu.")
 
+(defun yas--maybe-expand-key-filter (cmd)
+  (when (let ((yas--condition-cache-timestamp (current-time)))
+          (yas--templates-for-key-at-point))
+    cmd))
+
+(defconst yas-maybe-expand
+  '(menu-item "" yas-expand :filter yas--maybe-expand-key-filter)
+  "A conditional key definition.
+This can be used as a key definition in keymaps to bind a key to
+`yas-expand' only when there is a snippet available to be
+expanded.")
+
 (defvar yas-minor-mode-map
   (let ((map (make-sparse-keymap)))
-    (define-key map [(tab)]     'yas-expand)
-    (define-key map (kbd "TAB") 'yas-expand)
+    (define-key map [(tab)]     yas-maybe-expand)
+    (define-key map (kbd "TAB") yas-maybe-expand)
     (define-key map "\C-c&\C-s" 'yas-insert-snippet)
     (define-key map "\C-c&\C-n" 'yas-new-snippet)
     (define-key map "\C-c&\C-v" 'yas-visit-snippet-file)
@@ -703,10 +740,10 @@ This variable is placed in `emulation-mode-map-alists'.
 
 Its elements looks like (TABLE-NAME . KEYMAP).  They're
 instantiated on `yas-reload-all' but KEYMAP is added to only when
-loading snippets.  `yas--direct-TABLE-NAME' is then a variable set
-buffer-locally when entering `yas-minor-mode'.  KEYMAP binds all
-defined direct keybindings to the command
-`yas-expand-from-keymap' which then which snippet to expand.")
+loading snippets.  `yas--direct-TABLE-NAME' is then a variable
+set buffer-locally when entering `yas-minor-mode'.  KEYMAP binds
+all defined direct keybindings to `yas-maybe-expand-from-keymap'
+which decides on the snippet to expand.")
 
 (defun yas-direct-keymaps-reload ()
   "Force reload the direct keybinding for active snippet tables."
@@ -742,6 +779,12 @@ defined direct keybindings to the command
 (defvar yas-minor-mode-hook nil
   "Hook run when `yas-minor-mode' is turned on.")
 
+(defun yas--auto-fill-wrapper ()
+  (when (and auto-fill-function
+             (not (eq auto-fill-function #'yas--auto-fill)))
+    (setq yas--original-auto-fill-function auto-fill-function)
+    (setq auto-fill-function #'yas--auto-fill)))
+
 ;;;###autoload
 (define-minor-mode yas-minor-mode
   "Toggle YASnippet mode.
@@ -774,12 +817,17 @@ Key bindings:
              (set-default name nil)
              (set (make-local-variable name) t)))
          ;; Perform JIT loads
-         ;;
-         (yas--load-pending-jits))
+         (yas--load-pending-jits)
+         ;; Install auto-fill handler.
+         (yas--auto-fill-wrapper)       ; Now...
+         (add-hook 'auto-fill-mode-hook #'yas--auto-fill-wrapper)) ; or later.
         (t
-         ;; Uninstall the direct keymaps and the post-command hook
-         ;;
+         ;; Uninstall the direct keymaps, post-command hook, and
+         ;; auto-fill handler.
          (remove-hook 'post-command-hook #'yas--post-command-handler t)
+         (remove-hook 'auto-fill-mode-hook #'yas--auto-fill-wrapper)
+         (when (local-variable-p 'yas--original-auto-fill-function)
+           (setq auto-fill-function yas--original-auto-fill-function))
          (setq emulation-mode-map-alists
                (remove 'yas--direct-keymaps emulation-mode-map-alists)))))
 
@@ -907,6 +955,21 @@ Honour `yas-dont-activate-functions', which see."
   (set (make-local-variable 'comment-start-skip) "#+[\t ]*")
   (add-hook 'after-save-hook #'yas-maybe-load-snippet-buffer nil t))
 
+(defun yas-snippet-mode-buffer-p ()
+  "Return non-nil if current buffer should be in `snippet-mode'.
+Meaning it's visiting a file under one of the mode directories in
+`yas-snippet-dirs'."
+  (when buffer-file-name
+    (member
+     (expand-file-name
+      ".."
+      (file-name-directory buffer-file-name))
+     (yas-snippet-dirs))))
+
+;; We're abusing `magic-fallback-mode-alist' here because
+;; `auto-mode-alist' doesn't support function matchers.
+(add-to-list 'magic-fallback-mode-alist
+             `(yas-snippet-mode-buffer-p . snippet-mode))
 
 
 ;;; Internal structs for template management
@@ -976,7 +1039,7 @@ Has the following fields:
   A keymap for the snippets in this table that have direct
   keybindings. This is kept in sync with the keyhash, i.e., all
   the elements of the keyhash that are vectors appear here as
-  bindings to `yas-expand-from-keymap'.
+  bindings to `yas-maybe-expand-from-keymap'.
 
 `yas--table-uuidhash'
 
@@ -1075,6 +1138,10 @@ Has the following fields:
         ;;
         (remhash uuid (yas--table-uuidhash table))))))
 
+(defconst yas-maybe-expand-from-keymap
+  '(menu-item "" yas-expand-from-keymap
+              :filter yas--maybe-expand-from-keymap-filter))
+
 (defun yas--add-template (table template)
   "Store in TABLE the snippet template TEMPLATE.
 
@@ -1093,7 +1160,7 @@ keybinding)."
                             (make-hash-table :test 'equal)
                             (yas--table-hash table))))
       (when (vectorp k)
-        (define-key (yas--table-direct-keymap table) k 
'yas-expand-from-keymap)))
+        (define-key (yas--table-direct-keymap table) k 
yas-maybe-expand-from-keymap)))
 
     ;; Update TABLE's `yas--table-uuidhash'
     (puthash (yas--template-uuid template)
@@ -1296,33 +1363,22 @@ Returns (TEMPLATES START END). This function respects
 
 ;;; Internal functions and macros:
 
-(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))))
-    (if yas-good-grace msg
-      (error "%s" msg))))
-
-(defun yas--eval-lisp (form)
+(defun yas--eval-for-string (form)
   "Evaluate FORM and convert the result to string."
-  (let ((retval (catch 'yas--exception
-                  (condition-case err
-                      (save-excursion
-                        (save-restriction
-                          (save-match-data
-                            (widen)
-                            (let ((result (eval form)))
-                              (when result
-                                (format "%s" result))))))
-                    (error (yas--handle-error err))))))
-    (when (and (consp retval)
-               (eq 'yas--exception (car retval)))
-      (error (cdr retval)))
-    retval))
+  (let ((debug-on-error (and (not (memq yas-good-grace '(t inline)))
+                             debug-on-error)))
+    (condition-case oops
+        (save-excursion
+          (save-restriction
+            (save-match-data
+              (widen)
+              (let ((result (eval form)))
+                (when result
+                  (format "%s" result))))))
+      ((debug error) (cdr oops)))))
 
-(defun yas--eval-lisp-no-saves (form)
-  (condition-case err
-      (eval form)
-    (error (message "%s" (yas--handle-error err)))))
+(defun yas--eval-for-effect (form)
+  (yas--safely-call-fun (apply-partially #'eval form)))
 
 (defun yas--read-lisp (string &optional nil-on-error)
   "Read STRING as a elisp expression and return it.
@@ -1638,7 +1694,7 @@ this is a snippet or a snippet-command.
 
 CONDITION, EXPAND-ENV and KEYBINDING are Lisp forms, they have
 been `yas--read-lisp'-ed and will eventually be
-`yas--eval-lisp'-ed.
+`yas--eval-for-string'-ed.
 
 The remaining elements are strings.
 
@@ -1731,8 +1787,7 @@ With prefix argument USE-JIT do jit-loading of snippets."
         ;;
         (yas--define-parents mode-sym parents)
         (yas--menu-keymap-get-create mode-sym)
-        (let ((fun `(lambda () ;; FIXME: Simulating lexical-binding.
-                      (yas--load-directory-1 ',dir ',mode-sym))))
+        (let ((fun (apply-partially #'yas--load-directory-1 dir mode-sym)))
           (if use-jit
               (yas--schedule-jit mode-sym fun)
             (funcall fun)))
@@ -1876,9 +1931,12 @@ prefix argument."
       (yas-direct-keymaps-reload)
 
       (run-hooks 'yas-after-reload-hook)
-      (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*)" "")))))
+      (yas--message (if errors 2 3)
+                    (if no-jit "Snippets loaded %s."
+                      "Prepared just-in-time loading of snippets %s.")
+                    (if errors
+                        "with some errors. Check *Messages*"
+                      "successfully")))))
 
 (defvar yas-after-reload-hook nil
   "Hooks run after `yas-reload-all'.")
@@ -1930,9 +1988,24 @@ This works by stubbing a few functions, then calling
 
 (defun yas-about ()
   (interactive)
-  (message (concat "yasnippet (version "
-                   yas--version
-                   ") -- pluskid/joaotavora/npostavs")))
+  (message "yasnippet (version %s) -- pluskid/joaotavora/npostavs"
+           (or (ignore-errors (car (let ((default-directory yas--loaddir))
+                                     (process-lines "git" "describe"
+                                                    "--tags" "--dirty"))))
+               (when (and (featurep 'package)
+                          (fboundp 'package-desc-version)
+                          (fboundp 'package-version-join))
+                 (defvar package-alist)
+                 (ignore-errors
+                   (let* ((yas-pkg (cdr (assq 'yasnippet package-alist)))
+                          (version (package-version-join
+                                    (package-desc-version (car yas-pkg)))))
+                     ;; Special case for MELPA's bogus version numbers.
+                     (if (string-match 
"\\`20..[01][0-9][0-3][0-9][.][0-9]\\{3,4\\}\\'"
+                                       version)
+                         (concat yas--version "-snapshot" version)
+                       version))))
+               yas--version)))
 
 
 ;;; Apropos snippet menu:
@@ -2003,7 +2076,7 @@ static in the menu."
   ;; higher passes.
   ;;
   (mapc #'(lambda (item)
-            (when (and (listp (cdr item))
+            (when (and (consp (cdr-safe item))
                        (keymapp (nth 2 (cdr item))))
               (yas--delete-from-keymap (nth 2 (cdr item)) uuid)))
         (cdr keymap))
@@ -2013,9 +2086,10 @@ static in the menu."
   ;; Destructively modify keymap
   ;;
   (setcdr keymap (cl-delete-if (lambda (item)
-                                 (or (null (cdr item))
-                                     (and (keymapp (nth 2 (cdr item)))
-                                          (null (cdr (nth 2 (cdr item)))))))
+                                 (cond ((not (listp item)) nil)
+                                       ((null (cdr item)))
+                                       ((and (keymapp (nth 2 (cdr item)))
+                                             (null (cdr (nth 2 (cdr 
item))))))))
                                (cdr keymap))))
 
 (defun yas-define-menu (mode menu &optional omit-items)
@@ -2053,35 +2127,34 @@ omitted from MODE's menu, even if they're manually 
loaded."
   "Helper for `yas-define-menu'."
   (cl-loop
    for (type name submenu) in (reverse menu)
-   if (or (eq type 'yas-item)
-          (and yas-alias-to-yas/prefix-p
-               (eq type 'yas/item)))
-   do (let ((template (or (gethash name uuidhash)
-                          (puthash name
-                                   (yas--make-template
-                                    :table table
-                                    :perm-group group-list
-                                    :uuid name)
-                                   uuidhash))))
-        (define-key menu-keymap (vector (cl-gensym))
-          (car (yas--template-menu-binding-pair-get-create template :stay))))
-   else if (or (eq type 'yas-submenu)
-               (and yas-alias-to-yas/prefix-p
-                    (eq type 'yas/submenu)))
-   do (let ((subkeymap (make-sparse-keymap)))
-        (define-key menu-keymap (vector (cl-gensym))
-          `(menu-item ,name ,subkeymap))
-        (yas--define-menu-1 table
-                            subkeymap
-                            submenu
-                            uuidhash
-                            (append group-list (list name))))
-   else if (or (eq type 'yas-separator)
-               (and yas-alias-to-yas/prefix-p
-                    (eq type 'yas/separator)))
-   do (define-key menu-keymap (vector (cl-gensym))
-        '(menu-item "----"))
-   else do (yas--message 1 "Don't know anything about menu entry %s" type)))
+   collect (cond
+            ((or (eq type 'yas-item)
+                 (and yas-alias-to-yas/prefix-p
+                      (eq type 'yas/item)))
+             (let ((template (or (gethash name uuidhash)
+                                 (puthash name
+                                          (yas--make-template
+                                           :table table
+                                           :perm-group group-list
+                                           :uuid name)
+                                          uuidhash))))
+               (car (yas--template-menu-binding-pair-get-create
+                     template :stay))))
+            ((or (eq type 'yas-submenu)
+                 (and yas-alias-to-yas/prefix-p
+                      (eq type 'yas/submenu)))
+             (let ((subkeymap (make-sparse-keymap)))
+               (yas--define-menu-1 table subkeymap submenu uuidhash
+                                   (append group-list (list name)))
+               `(menu-item ,name ,subkeymap)))
+            ((or (eq type 'yas-separator)
+                 (and yas-alias-to-yas/prefix-p
+                      (eq type 'yas/separator)))
+             '(menu-item "----"))
+            (t (yas--message 1 "Don't know anything about menu entry %s" type)
+               nil))
+   into menu-entries
+   finally do (push (apply #'vector menu-entries) (cdr menu-keymap))))
 
 (defun yas--define (mode key template &optional name condition group)
   "Define a snippet.  Expanding KEY into TEMPLATE.
@@ -2164,23 +2237,24 @@ object satisfying `yas--field-p' to restrict the 
expansion to."
               (nth 2 templates-and-pos)))
       (yas--fallback))))
 
-(defun yas-expand-from-keymap ()
-  "Directly expand some snippets, searching `yas--direct-keymaps'.
-
-If expansion fails, execute the previous binding for this key"
-  (interactive)
-  (setq yas--condition-cache-timestamp (current-time))
-  (let* ((vec (cl-subseq (this-command-keys-vector)
+(defun yas--maybe-expand-from-keymap-filter (cmd)
+  (let* ((yas--condition-cache-timestamp (current-time))
+         (vec (cl-subseq (this-command-keys-vector)
                          (if current-prefix-arg
                              (length (this-command-keys))
                            0)))
          (templates (cl-mapcan (lambda (table)
                                  (yas--fetch table vec))
                                (yas--get-snippet-tables))))
-    (if templates
-        (yas--expand-or-prompt-for-template templates)
-      (let ((yas-fallback-behavior 'call-other-command))
-        (yas--fallback)))))
+    (if templates (or cmd templates))))
+
+(defun yas-expand-from-keymap ()
+  "Directly expand some snippets, searching `yas--direct-keymaps'."
+  (interactive)
+  (setq yas--condition-cache-timestamp (current-time))
+  (let* ((templates (yas--maybe-expand-from-keymap-filter nil)))
+    (when templates
+      (yas--expand-or-prompt-for-template templates))))
 
 (defun yas--expand-or-prompt-for-template (templates &optional start end)
   "Expand one of TEMPLATES from START to END.
@@ -2824,22 +2898,22 @@ The last element of POSSIBILITIES may be a list of 
strings."
             key)))))
 
 (defun yas-throw (text)
-  "Throw a yas--exception with TEXT as the reason."
-  (throw 'yas--exception (cons 'yas--exception text)))
+  "Signal `yas-exception' with TEXT as the reason."
+  (signal 'yas-exception (list text)))
+(put 'yas-exception 'error-conditions '(error yas-exception))
+(put 'yas-exception 'error-message "[yas] Exception")
 
 (defun yas-verify-value (possibilities)
   "Verify that the current field value is in POSSIBILITIES.
-
-Otherwise throw exception."
-  (when (and yas-moving-away-p
-             (cl-notany (lambda (pos) (string= pos yas-text)) possibilities))
-    (yas-throw (yas--format "Field only allows %s" possibilities))))
+Otherwise signal `yas-exception'."
+  (when (and yas-moving-away-p (cl-notany (lambda (pos) (string= pos 
yas-text)) possibilities))
+    (yas-throw (format "Field only allows %s" possibilities))))
 
 (defun yas-field-value (number)
   "Get the string for field with NUMBER.
 
 Use this in primary and mirror transformations to tget."
-  (let* ((snippet (car (yas--snippets-at-point)))
+  (let* ((snippet (car (yas-active-snippets)))
          (field (and snippet
                      (yas--snippet-find-field snippet number))))
     (when field
@@ -2899,10 +2973,11 @@ Use this in primary and mirror transformations to tget."
 (put 'yas--active-field-overlay 'permanent-local t)
 (put 'yas--field-protection-overlays 'permanent-local t)
 
-(cl-defstruct (yas--snippet (:constructor yas--make-snippet ()))
+(cl-defstruct (yas--snippet (:constructor yas--make-snippet (expand-env)))
   "A snippet.
 
 ..."
+  expand-env
   (fields '())
   (exit nil)
   (id (yas--snippet-next-id) :read-only t)
@@ -2951,6 +3026,35 @@ DEPTH is a count of how many nested mirrors can affect 
this mirror"
   marker
   next)
 
+(defmacro yas--letenv (env &rest body)
+  "Evaluate BODY with bindings from ENV.
+ENV is a list of elements with the form (VAR FORM)."
+  (declare (debug (form body)) (indent 1))
+  `(eval (cl-list* 'let* ,env ',body)))
+
+(defun yas--snippet-map-markers (fun snippet)
+  "Apply FUN to all marker (sub)fields in SNIPPET.
+Update each field with the result of calling FUN."
+  (dolist (field (yas--snippet-fields snippet))
+    (setf (yas--field-start field) (funcall fun (yas--field-start field)))
+    (setf (yas--field-end field)   (funcall fun (yas--field-end field)))
+    (dolist (mirror (yas--field-mirrors field))
+      (setf (yas--mirror-start mirror) (funcall fun (yas--mirror-start 
mirror)))
+      (setf (yas--mirror-end mirror)   (funcall fun (yas--mirror-end 
mirror)))))
+  (let ((snippet-exit (yas--snippet-exit snippet)))
+    (when snippet-exit
+      (setf (yas--exit-marker snippet-exit)
+            (funcall fun (yas--exit-marker snippet-exit))))))
+
+(defun yas--snippet-live-p (snippet)
+  "Return non-nil if SNIPPET hasn't been committed."
+  (catch 'live
+    (yas--snippet-map-markers (lambda (m)
+                                (if (markerp m) m
+                                  (throw 'live nil)))
+                              snippet)
+    t))
+
 (defun yas--apply-transform (field-or-mirror field &optional empty-on-nil-p)
   "Calculate transformed string for FIELD-OR-MIRROR from FIELD.
 
@@ -2969,7 +3073,7 @@ string iff EMPTY-ON-NIL-P is true."
          (transformed (and transform
                            (save-excursion
                              (goto-char start-point)
-                             (let ((ret (yas--eval-lisp transform)))
+                             (let ((ret (yas--eval-for-string transform)))
                                (or ret (and empty-on-nil-p "")))))))
     transformed))
 
@@ -3036,18 +3140,30 @@ through the field's start point"
    (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
-   (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)))))
+(defun yas-active-snippets (&optional beg end)
+  "Return a sorted list of active snippets.
+The most recently-inserted snippets are returned first.
+
+Only snippets overlapping the region BEG ... END are returned.
+Overlapping has the same meaning as described in `overlays-in'.
+If END is omitted, it defaults to (1+ BEG).  If BEG is omitted,
+it defaults to point.  A non-nil, non-buffer position BEG is
+equivalent to a range covering the whole buffer."
+  (unless beg
+    (setq beg (point)))
+  (cond ((not (or (integerp beg) (markerp beg)))
+         (setq beg (point-min) end (point-max)))
+        ((not end)
+         (setq end (1+ beg))))
+  (cl-sort
+   (delete-dups ;; Snippets have multiple overlays.
+    (delq nil
+          (mapcar (lambda (ov) (overlay-get ov 'yas--snippet))
+                  (overlays-in beg end))))
+   #'>= :key #'yas--snippet-id))
+
+(define-obsolete-function-alias 'yas--snippets-at-point
+  'yas-active-snippets "0.12")
 
 (defun yas-next-field-or-maybe-expand ()
   "Try to expand a snippet at a key before point.
@@ -3064,7 +3180,7 @@ Otherwise delegate to `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)))
+  (let ((snippet (car (yas-active-snippets)))
         (active (overlay-get yas--active-field-overlay 'yas--field)))
     (when snippet
       (not (yas--find-next-field arg snippet active)))))
@@ -3084,23 +3200,28 @@ Otherwise delegate to `yas-next-field'."
 If there's none, exit the snippet."
   (interactive)
   (unless arg (setq arg 1))
-  (let* ((snippet (car (yas--snippets-at-point)))
+  (let* ((snippet (car (yas-active-snippets)))
          (active-field (overlay-get yas--active-field-overlay 'yas--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...
-    (if target-field
-        (yas--move-to-field snippet target-field)
-      (yas-exit-snippet snippet))))
+    (yas--letenv (yas--snippet-expand-env snippet)
+      ;; 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...
+      (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."
   (yas--make-move-field-protection-overlays snippet field)
-  (yas--make-move-active-field-overlay snippet field))
+  ;; Only move active field overlays if this is field is from the
+  ;; innermost snippet.
+  (when (eq snippet (car (yas-active-snippets (1- (yas--field-start field))
+                                              (1+ (yas--field-end field)))))
+    (yas--make-move-active-field-overlay snippet field)))
 
 (defun yas--move-to-field (snippet field)
   "Update SNIPPET to move to field FIELD.
@@ -3108,6 +3229,7 @@ If there's none, exit the snippet."
 Also create some protection overlays"
   (goto-char (yas--field-start field))
   (yas--place-overlays snippet field)
+  (overlay-put yas--active-field-overlay 'yas--snippet snippet)
   (overlay-put yas--active-field-overlay 'yas--field field)
   (let ((number (yas--field-number field)))
     ;; check for the special ${0: ...} field
@@ -3133,13 +3255,13 @@ Also create some protection overlays"
 (defun yas-abort-snippet (&optional snippet)
   (interactive)
   (let ((snippet (or snippet
-                     (car (yas--snippets-at-point)))))
+                     (car (yas-active-snippets)))))
     (when snippet
       (setf (yas--snippet-force-exit snippet) t))))
 
 (defun yas-exit-snippet (snippet)
   "Goto exit-marker of SNIPPET."
-  (interactive (list (cl-first (yas--snippets-at-point))))
+  (interactive (list (cl-first (yas-active-snippets))))
   (when snippet
     (setf (yas--snippet-force-exit snippet) t)
     (goto-char (if (yas--snippet-exit snippet)
@@ -3152,7 +3274,7 @@ Also create some protection overlays"
   (mapc #'(lambda (snippet)
             (yas-exit-snippet snippet)
             (yas--check-commit-snippet))
-        (yas--snippets-at-point 'all-snippets)))
+        (yas-active-snippets 'all)))
 
 
 ;;; Some low level snippet-routines:
@@ -3177,7 +3299,8 @@ This renders the snippet as ordinary text."
                (overlay-buffer control-overlay))
       (setq yas-snippet-beg (overlay-start control-overlay))
       (setq yas-snippet-end (overlay-end control-overlay))
-      (delete-overlay control-overlay))
+      (delete-overlay control-overlay)
+      (setf (yas--snippet-control-overlay snippet) nil))
 
     (let ((yas--inhibit-overlay-hooks t))
       (when yas--active-field-overlay
@@ -3208,100 +3331,155 @@ This renders the snippet as ordinary text."
 
   (yas--message 4 "Snippet %s exited." (yas--snippet-id snippet)))
 
-(defun yas--safely-run-hooks (hook-var)
-  (condition-case error
-      (run-hooks hook-var)
-    (error
-     (yas--message 2 "%s error: %s" hook-var (error-message-string error)))))
+(defvar yas--snippets-to-move nil)
+(make-variable-buffer-local 'yas--snippets-to-move)
 
+(defun yas--prepare-snippets-for-move (beg end buf pos)
+  "Gather snippets in BEG..END for moving to POS in BUF."
+  (let ((to-move nil)
+        (snippets (yas-active-snippets beg end))
+        (dst-base-line (with-current-buffer buf
+                         (count-lines (point-min) pos))))
+    (when snippets
+      (dolist (snippet snippets)
+        (yas--snippet-map-markers
+         (lambda (m)
+           (goto-char m)
+           (beginning-of-line)
+           (prog1 (cons (count-lines (point-min) (point))
+                        (yas--snapshot-marker-location m))
+             (set-marker m nil)))
+         snippet)
+        (let ((ctrl-ov (yas--snapshot-overlay-line-location
+                        (yas--snippet-control-overlay snippet))))
+          (push (list ctrl-ov dst-base-line snippet) to-move)
+          (delete-overlay (car ctrl-ov))))
+      (with-current-buffer buf
+        (setq yas--snippets-to-move (nconc to-move yas--snippets-to-move))))))
+
+(defun yas--on-buffer-kill ()
+  ;; Org mode uses temp buffers for fontification and "native tab",
+  ;; move all the snippets to the original org-mode buffer when it's
+  ;; killed.
+  (let ((org-marker nil))
+    (when (and yas-minor-mode
+               (or (bound-and-true-p org-edit-src-from-org-mode)
+                   (bound-and-true-p org-src--from-org-mode))
+               (markerp
+                (setq org-marker
+                      (or (bound-and-true-p org-edit-src-beg-marker)
+                          (bound-and-true-p org-src--beg-marker)))))
+      (yas--prepare-snippets-for-move
+       (point-min) (point-max)
+       (marker-buffer org-marker) org-marker))))
+
+(add-hook 'kill-buffer-hook #'yas--on-buffer-kill)
+
+(defun yas--finish-moving-snippets ()
+  "Finish job started in `yas--prepare-snippets-for-move'."
+  (cl-loop for (ctrl-ov base-line snippet) in yas--snippets-to-move
+           for base-pos = (progn (goto-char (point-min))
+                                 (forward-line base-line) (point))
+           do (yas--snippet-map-markers
+               (lambda (l-m-r-w)
+                 (goto-char base-pos)
+                 (forward-line (nth 0 l-m-r-w))
+                 (save-restriction
+                   (narrow-to-region (line-beginning-position)
+                                     (line-end-position))
+                   (yas--restore-marker-location (cdr l-m-r-w)))
+                 (nth 1 l-m-r-w))
+               snippet)
+           (goto-char base-pos)
+           (yas--restore-overlay-location ctrl-ov)
+           (yas--maybe-move-to-active-field snippet))
+  (setq yas--snippets-to-move nil))
+
+(defun yas--safely-call-fun (fun)
+  "Call FUN and catch any errors."
+  (condition-case error
+      (funcall fun)
+    ((debug error)
+     (yas--message 2 "Error running %s: %s" fun
+                   (error-message-string error)))))
+
+(defun yas--safely-run-hook (hook)
+  "Call HOOK's functions.
+HOOK should be a symbol, a hook variable, as in `run-hooks'."
+  (let ((debug-on-error (and (not (memq yas-good-grace '(t hooks)))
+                             debug-on-error)))
+    (yas--safely-call-fun (apply-partially #'run-hooks hook))))
 
 (defun yas--check-commit-snippet ()
   "Check if point exited the currently active field of the snippet.
 
 If so cleans up the whole snippet up."
-  (let* ((snippets (yas--snippets-at-point 'all-snippets))
+  (let* ((snippets (yas-active-snippets 'all))
          (snippets-left snippets)
-         (snippet-exit-transform))
+         (snippet-exit-transform)
+         ;; Record the custom snippet `yas-after-exit-snippet-hook'
+         ;; set in the expand-env field.
+         (snippet-exit-hook yas-after-exit-snippet-hook))
     (dolist (snippet snippets)
       (let ((active-field (yas--snippet-active-field snippet)))
-        (setq snippet-exit-transform (yas--snippet-force-exit snippet))
-        (cond ((or snippet-exit-transform
-                   (not (and active-field (yas--field-contains-point-p 
active-field))))
-               (setq snippets-left (delete snippet snippets-left))
-               (setf (yas--snippet-force-exit snippet) nil)
-               (yas--commit-snippet snippet))
-              ((and active-field
-                    (or (not yas--active-field-overlay)
-                        (not (overlay-buffer yas--active-field-overlay))))
-               ;;
-               ;; stacked expansion: this case is mainly for recent
-               ;; snippet exits that place us back int the field of
-               ;; another snippet
-               ;;
-               (save-excursion
-                 (yas--move-to-field snippet active-field)
-                 (yas--update-mirrors snippet)))
-              (t
-               nil))))
+        (yas--letenv (yas--snippet-expand-env snippet)
+          ;; Note: the `force-exit' field could be a transform in case of
+          ;; ${0: ...}, see `yas--move-to-field'.
+          (setq snippet-exit-transform (yas--snippet-force-exit snippet))
+          (cond ((or snippet-exit-transform
+                     (not (and active-field (yas--field-contains-point-p 
active-field))))
+                 (setq snippets-left (delete snippet snippets-left))
+                 (setf (yas--snippet-force-exit snippet) nil)
+                 (setq snippet-exit-hook yas-after-exit-snippet-hook)
+                 (yas--commit-snippet snippet))
+                ((and active-field
+                      (or (not yas--active-field-overlay)
+                          (not (overlay-buffer yas--active-field-overlay))))
+                 ;;
+                 ;; stacked expansion: this case is mainly for recent
+                 ;; snippet exits that place us back int the field of
+                 ;; another snippet
+                 ;;
+                 (save-excursion
+                   (yas--move-to-field snippet active-field)
+                   (yas--update-mirrors snippet)))
+                (t
+                 nil)))))
     (unless (or (null snippets) snippets-left)
-      (if snippet-exit-transform
-          (yas--eval-lisp-no-saves snippet-exit-transform))
-      (yas--safely-run-hooks 'yas-after-exit-snippet-hook))))
+      (when snippet-exit-transform
+        (yas--eval-for-effect snippet-exit-transform))
+      (let ((yas-after-exit-snippet-hook snippet-exit-hook))
+        (yas--safely-run-hook 'yas-after-exit-snippet-hook)))))
 
 ;; Apropos markers-to-points:
 ;;
-;; This was found useful for performance reasons, so that an
-;; excessive number of live markers aren't kept around in the
-;; `buffer-undo-list'. However, in `markers-to-points', the
-;; set-to-nil markers can't simply be discarded and replaced with
-;; fresh ones in `points-to-markers'. The original marker that was
-;; just set to nil has to be reused.
+;; This was found useful for performance reasons, so that an excessive
+;; number of live markers aren't kept around in the
+;; `buffer-undo-list'.  We don't reuse the original marker object
+;; because that leaves an unreadable object in the history list and
+;; undo-tree persistence has trouble with that.
 ;;
-;; This shouldn't bring horrible problems with undo/redo, but it
-;; you never know
+;; This shouldn't bring horrible problems with undo/redo, but you
+;; never know.
 ;;
 (defun yas--markers-to-points (snippet)
-  "Convert all markers in SNIPPET to a cons (POINT . MARKER)
-where POINT is the original position of the marker and MARKER is
-the original marker object with the position set to nil."
-  (dolist (field (yas--snippet-fields snippet))
-    (let ((start (marker-position (yas--field-start field)))
-          (end (marker-position (yas--field-end field))))
-      (set-marker (yas--field-start field) nil)
-      (set-marker (yas--field-end field) nil)
-      (setf (yas--field-start field) (cons start (yas--field-start field)))
-      (setf (yas--field-end field) (cons end (yas--field-end field))))
-    (dolist (mirror (yas--field-mirrors field))
-      (let ((start (marker-position (yas--mirror-start mirror)))
-            (end (marker-position (yas--mirror-end mirror))))
-        (set-marker (yas--mirror-start mirror) nil)
-        (set-marker (yas--mirror-end mirror) nil)
-        (setf (yas--mirror-start mirror) (cons start (yas--mirror-start 
mirror)))
-        (setf (yas--mirror-end mirror) (cons end (yas--mirror-end mirror))))))
-  (let ((snippet-exit (yas--snippet-exit snippet)))
-    (when snippet-exit
-      (let ((exit (marker-position (yas--exit-marker snippet-exit))))
-        (set-marker (yas--exit-marker snippet-exit) nil)
-        (setf (yas--exit-marker snippet-exit) (cons exit (yas--exit-marker 
snippet-exit)))))))
+  "Save all markers of SNIPPET as positions."
+  (yas--snippet-map-markers (lambda (m)
+                              (prog1 (marker-position m)
+                                (set-marker m nil)))
+                            snippet))
 
 (defun yas--points-to-markers (snippet)
-  "Convert all cons (POINT . MARKER) in SNIPPET to markers.
+  "Restore SNIPPET's marker positions, saved by `yas--markers-to-points'."
+  (yas--snippet-map-markers #'copy-marker snippet))
 
-This is done by setting MARKER to POINT with `set-marker'."
-  (dolist (field (yas--snippet-fields snippet))
-    (setf (yas--field-start field) (set-marker (cdr (yas--field-start field))
-                                              (car (yas--field-start field))))
-    (setf (yas--field-end field) (set-marker (cdr (yas--field-end field))
-                                            (car (yas--field-end field))))
-    (dolist (mirror (yas--field-mirrors field))
-      (setf (yas--mirror-start mirror) (set-marker (cdr (yas--mirror-start 
mirror))
-                                                  (car (yas--mirror-start 
mirror))))
-      (setf (yas--mirror-end mirror) (set-marker (cdr (yas--mirror-end mirror))
-                                                (car (yas--mirror-end 
mirror))))))
-  (let ((snippet-exit (yas--snippet-exit snippet)))
-    (when snippet-exit
-      (setf (yas--exit-marker snippet-exit) (set-marker (cdr (yas--exit-marker 
snippet-exit))
-                                                       (car (yas--exit-marker 
snippet-exit)))))))
+(defun yas--maybe-move-to-active-field (snippet)
+  "Try to move to SNIPPET's active (or first) field and return it if found."
+  (let ((target-field (or (yas--snippet-active-field snippet)
+                          (car (yas--snippet-fields snippet)))))
+    (when target-field
+      (yas--move-to-field snippet target-field)
+      target-field)))
 
 (defun yas--field-contains-point-p (field &optional point)
   (let ((point (or point
@@ -3328,7 +3506,7 @@ holds the keymap."
                                nil
                                t)))
     (overlay-put overlay 'keymap yas-keymap)
-    (overlay-put overlay 'priority 100)
+    (overlay-put overlay 'priority yas-overlay-priority)
     (overlay-put overlay 'yas--snippet snippet)
     overlay))
 
@@ -3384,7 +3562,7 @@ Move the overlay, or create it if it does not exit."
           (make-overlay (yas--field-start field)
                         (yas--field-end field)
                         nil nil t))
-    (overlay-put yas--active-field-overlay 'priority 100)
+    (overlay-put yas--active-field-overlay 'priority yas-overlay-priority)
     (overlay-put yas--active-field-overlay 'face 'yas-field-highlight-face)
     (overlay-put yas--active-field-overlay 'yas--snippet snippet)
     (overlay-put yas--active-field-overlay 'modification-hooks 
'(yas--on-field-overlay-modification))
@@ -3408,19 +3586,57 @@ 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.
+              ;; If a single change hits multiple overlays of the same
+              ;; snippet, then we delete the snippet the first time,
+              ;; and then subsequent calls get a deleted overlay.
+              ;; Don't delete the snippet again!
+              (not (overlay-buffer overlay))
               (yas--undo-in-progress))
-    (let* ((inhibit-modification-hooks t)
+    (let* ((inhibit-modification-hooks nil)
+           (yas--inhibit-overlay-hooks t)
            (field (overlay-get overlay 'yas--field))
            (snippet (overlay-get yas--active-field-overlay 'yas--snippet)))
-      (save-match-data
-        (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)))))
+      (if (yas--snippet-live-p snippet)
+          (save-match-data
+            (yas--letenv (yas--snippet-expand-env snippet)
+              (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)))
+        (lwarn '(yasnippet zombie) :warning "Killing zombie snippet!")
+        (delete-overlay overlay)))))
+
+(defun yas--auto-fill ()
+  (let* ((orig-point (point))
+         (end (progn (forward-paragraph) (point)))
+         (beg (progn (backward-paragraph) (point)))
+         (snippets (yas-active-snippets beg end))
+         (remarkers nil)
+         (reoverlays nil))
+    (dolist (snippet snippets)
+      (dolist (m (yas--collect-snippet-markers snippet))
+        (when (and (<= beg m) (<= m end))
+          (push (yas--snapshot-marker-location m beg end) remarkers)))
+      (push (yas--snapshot-overlay-location
+             (yas--snippet-control-overlay snippet) beg end)
+            reoverlays))
+    (goto-char orig-point)
+    (let ((yas--inhibit-overlay-hooks t))
+      (funcall yas--original-auto-fill-function))
+    (save-excursion
+      (setq end (progn (forward-paragraph) (point)))
+      (setq beg (progn (backward-paragraph) (point))))
+    (save-excursion
+      (save-restriction
+        (narrow-to-region beg end)
+        (mapc #'yas--restore-marker-location remarkers)
+        (mapc #'yas--restore-overlay-location reoverlays))
+      (mapc #'yas--update-mirrors snippets))))
+
 
 ;;; Apropos protection overlays:
 ;;
@@ -3471,7 +3687,7 @@ Move the overlays, or create them if they do not exit."
               (not after?)
               (= length (- end beg)) ; deletion or insertion
               (yas--undo-in-progress))
-    (let ((snippets (yas--snippets-at-point)))
+    (let ((snippets (yas-active-snippets)))
       (yas--message 2 "Committing snippets. Action would destroy a protection 
overlay.")
       (cl-loop for snippet in snippets
                do (yas--commit-snippet snippet)))))
@@ -3503,7 +3719,15 @@ Move the overlays, or create them if they do not exit."
 ;; running. This would mean a lot of overlay modification hooks
 ;; running, but if managed correctly (including overlay priorities)
 ;; they should account for all situations...
-;;
+
+(defvar yas--first-indent-undo nil
+  "Internal variable for indent undo entries.
+Used to pass info from `yas--indent-region' to `yas-expand-snippet'.")
+(defvar yas--get-indent-undo-pos nil
+  "Record undo info for line beginning at given position.
+We bind this when first creating a snippet.  See also
+`yas--first-indent-undo'.")
+
 (defun yas-expand-snippet (content &optional start end expand-env)
   "Expand snippet CONTENT at current point.
 
@@ -3532,6 +3756,7 @@ considered when expanding the snippet."
          (to-delete (and start
                          end
                          (buffer-substring-no-properties start end)))
+         (yas--first-indent-undo nil)
          snippet)
     (goto-char start)
     (setq yas--indent-original-column (current-column))
@@ -3544,7 +3769,7 @@ considered when expanding the snippet."
     (cond ((listp content)
            ;; x) This is a snippet-command
            ;;
-           (yas--eval-lisp-no-saves content))
+           (yas--eval-for-effect content))
           (t
            ;; x) This is a snippet-snippet :-)
            ;;
@@ -3555,27 +3780,17 @@ considered when expanding the snippet."
            ;;    plain text will get recorded at the end.
            ;;
            ;;    stacked expansion: also shoosh the overlay modification hooks
-           (let ((buffer-undo-list t))
+           (let ((buffer-undo-list t)
+                 (yas--get-indent-undo-pos (line-beginning-position)))
              ;; snippet creation might evaluate users elisp, which
              ;; might generate errors, so we have to be ready to catch
              ;; them mostly to make the undo information
              ;;
              (setq yas--start-column (current-column))
-             (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))
+             (let ((yas--inhibit-overlay-hooks t))
+               (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)))))
-             ;; Invalidate any syntax-propertizing done while 
`syntax-propertize-function' was nil
-             (syntax-ppss-flush-cache start))
+                     (yas--snippet-create expand-env start (point)))))
 
            ;; stacked-expansion: This checks for stacked expansion, save the
            ;; `yas--previous-active-field' and advance its boundary.
@@ -3592,30 +3807,29 @@ considered when expanding the snippet."
            (unless (yas--snippet-fields snippet)
              (yas-exit-snippet snippet))
 
-           ;; Push two undo actions: the deletion of the inserted contents of
-           ;; the new snippet (without the "key") followed by an apply of
-           ;; `yas--take-care-of-redo' on the newly inserted snippet boundaries
-           ;;
-           ;; A small exception, if `yas-also-auto-indent-first-line'
-           ;; is t and `yas--indent' decides to indent the line to a
-           ;; point before the actual expansion point, undo would be
-           ;; messed up. We call the early point "newstart"".  case,
-           ;; and attempt to fix undo.
-           ;;
-           (let ((newstart (overlay-start (yas--snippet-control-overlay 
snippet)))
-                 (end (overlay-end (yas--snippet-control-overlay snippet))))
-             (when (< newstart start)
-               (push (cons (make-string (- start newstart) ? ) newstart) 
buffer-undo-list))
-             (push (cons newstart end) buffer-undo-list)
-             (push `(apply yas--take-care-of-redo ,start ,end ,snippet)
-                   buffer-undo-list))
+           ;; Undo actions from indent of snippet's 1st line.
+           (setq buffer-undo-list
+                 (nconc yas--first-indent-undo buffer-undo-list))
+           ;; Undo action for the expand snippet contents.
+           (push (cons (overlay-start (yas--snippet-control-overlay snippet))
+                       (overlay-end (yas--snippet-control-overlay snippet)))
+                 buffer-undo-list)
+           ;; Follow up with `yas--take-care-of-redo' on the newly
+           ;; inserted snippet boundaries.
+           (push `(apply yas--take-care-of-redo ,start
+                         ,(overlay-end (yas--snippet-control-overlay snippet))
+                         ,snippet)
+                 buffer-undo-list)
+
            ;; Now, schedule a move to the first field
            ;;
            (let ((first-field (car (yas--snippet-fields snippet))))
              (when first-field
                (sit-for 0) ;; fix issue 125
-               (yas--move-to-field snippet first-field)))
-           (yas--message 4 "snippet expanded.")
+               (yas--letenv (yas--snippet-expand-env snippet)
+                 (yas--move-to-field snippet first-field))))
+           (yas--message 4 "snippet %d expanded." (yas--snippet-id snippet))
+           (setq deactivate-mark nil)
            t))))
 
 (defun yas--take-care-of-redo (_beg _end snippet)
@@ -3637,43 +3851,37 @@ to their correct locations *at the time the snippet is 
revived*.
 After revival, push the `yas--take-care-of-redo' in the
 `buffer-undo-list'"
   ;; Reconvert all the points to markers
-  ;;
   (yas--points-to-markers snippet)
   ;; When at least one editable field existed in the zombie snippet,
   ;; try to revive the whole thing...
-  ;;
-  (let ((target-field (or (yas--snippet-active-field snippet)
-                          (car (yas--snippet-fields snippet)))))
-    (when target-field
-      (setf (yas--snippet-control-overlay snippet) (yas--make-control-overlay 
snippet beg end))
-      (overlay-put (yas--snippet-control-overlay snippet) 'yas--snippet 
snippet)
-
-      (yas--move-to-field snippet target-field)
-
-      (push `(apply yas--take-care-of-redo ,beg ,end ,snippet)
-            buffer-undo-list))))
+  (when (yas--maybe-move-to-active-field snippet)
+    (setf (yas--snippet-control-overlay snippet) (yas--make-control-overlay 
snippet beg end))
+    (overlay-put (yas--snippet-control-overlay snippet) 'yas--snippet snippet)
+    (push `(apply yas--take-care-of-redo ,beg ,end ,snippet)
+          buffer-undo-list)))
 
-(defun yas--snippet-create (begin end)
+(defun yas--snippet-create (expand-env begin end)
   "Create a snippet from a template inserted at BEGIN to END.
 
 Returns the newly created snippet."
   (save-restriction
     (narrow-to-region begin end)
-    (let ((snippet (yas--make-snippet)))
-      (goto-char begin)
-      (yas--snippet-parse-create snippet)
+    (let ((snippet (yas--make-snippet expand-env)))
+      (yas--letenv expand-env
+        (goto-char begin)
+        (yas--snippet-parse-create snippet)
 
-      ;; Sort and link each field
-      (yas--snippet-sort-fields snippet)
+        ;; Sort and link each field
+        (yas--snippet-sort-fields snippet)
 
-      ;; Create keymap overlay for snippet
-      (setf (yas--snippet-control-overlay snippet)
-            (yas--make-control-overlay snippet (point-min) (point-max)))
+        ;; Create keymap overlay for snippet
+        (setf (yas--snippet-control-overlay snippet)
+              (yas--make-control-overlay snippet (point-min) (point-max)))
 
-      ;; Move to end
-      (goto-char (point-max))
+        ;; Move to end
+        (goto-char (point-max))
 
-      snippet)))
+        snippet))))
 
 
 ;;; Apropos adjacencies and "fom's":
@@ -3831,41 +4039,29 @@ necessary fields, mirrors and exit points.
 
 Meant to be called in a narrowed buffer, does various passes"
   (let ((parse-start (point)))
-    ;; Reset the yas--dollar-regions
-    ;;
-    (setq yas--dollar-regions nil)
-    ;; protect just the backquotes
-    ;;
-    (yas--protect-escapes nil '(?`))
-    ;; replace all backquoted expressions
-    ;;
-    (goto-char parse-start)
-    (yas--save-backquotes)
-    ;; protect escaped characters
-    ;;
-    (yas--protect-escapes)
-    ;; Parse indent markers: `$>'.
-    (goto-char parse-start)
-    (yas--indent-parse-create)
-    ;; parse fields with {}
-    ;;
-    (goto-char parse-start)
-    (yas--field-parse-create snippet)
-    ;; parse simple mirrors and fields
-    ;;
-    (goto-char parse-start)
-    (yas--simple-mirror-parse-create snippet)
-    ;; parse mirror transforms
-    ;;
-    (goto-char parse-start)
-    (yas--transform-mirror-parse-create snippet)
-    ;; calculate adjacencies of fields and mirrors
-    ;;
+    ;; Avoid major-mode's syntax propertizing function, since we
+    ;; change the syntax-table while calling `scan-sexps'.
+    (let ((syntax-propertize-function nil))
+      (setq yas--dollar-regions nil)  ; Reset the yas--dollar-regions.
+      (yas--protect-escapes nil '(?`))  ; Protect just the backquotes.
+      (goto-char parse-start)
+      (yas--save-backquotes)     ; Replace all backquoted expressions.
+      (yas--protect-escapes)     ; Protect escaped characters.
+      (goto-char parse-start)
+      (yas--indent-parse-create)        ; Parse indent markers: `$>'.
+      (goto-char parse-start)
+      (yas--field-parse-create snippet) ; Parse fields with {}.
+      (goto-char parse-start)
+      (yas--simple-mirror-parse-create snippet) ; Parse simple mirrors & 
fields.
+      (goto-char parse-start)
+      (yas--transform-mirror-parse-create snippet) ; Parse mirror transforms.
+      ;; Invalidate any syntax-propertizing done while
+      ;; `syntax-propertize-function' was nil.
+      (syntax-ppss-flush-cache parse-start))
+    ;; Set "next" links of fields & mirrors.
     (yas--calculate-adjacencies snippet)
-    ;; Delete $-constructs
-    ;;
     (save-restriction
-      (widen)
+      (widen)                           ; Delete $-constructs.
       (yas--delete-regions yas--dollar-regions))
     ;; Make sure to do this insertion *after* deleting the dollar
     ;; regions, otherwise we invalidate the calculated positions of
@@ -3880,55 +4076,158 @@ Meant to be called in a narrowed buffer, does various 
passes"
                 (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 escapes
-    ;;
+    (yas--restore-backquotes)  ; Restore backquoted expression values.
     (goto-char parse-start)
-    (yas--restore-escapes)
-    ;; update mirrors for the first time
-    ;;
-    (yas--update-mirrors snippet)
-    ;; indent the best we can
-    ;;
-    (goto-char parse-start)
-    (yas--indent snippet)))
+    (yas--restore-escapes)        ; Restore escapes.
+    (yas--update-mirrors snippet) ; Update mirrors for the first time.
+    (goto-char parse-start))
+  (yas--indent snippet))                ; Indent the best we can.
+
+;; HACK: Some implementations of `indent-line-function' (called via
+;; `indent-according-to-mode') delete text before they insert (like
+;; cc-mode), some make complicated regexp replacements (looking at
+;; you, org-mode).  To find place where the marker "should" go after
+;; indentation, we create a regexp based on what the line looks like
+;; before, putting a capture group where the marker is.  The regexp
+;; matches any whitespace with [[:space:]]* to allow for the
+;; indentation changing whitespace.  Additionally, we try to preserve
+;; the amount of whitespace *following* the marker, because
+;; indentation generally affects whitespace at the beginning, not the
+;; end.
+;;
+;; Two other cases where we apply a similar strategy:
+;;
+;; 1. Handling `auto-fill-mode', in this case we need to use the
+;; current paragraph instead of line.
+;;
+;; 2. Moving snippets from an `org-src' temp buffer into the main org
+;; buffer, in this case we need to count the line offsets (because org
+;; may add indentation on each line making character positions
+;; unreliable).
+;;
+;; This is all best-effort heuristic stuff, but it should cover 99% of
+;; use-cases.
+
+(defun yas--snapshot-marker-location (marker &optional beg end)
+  "Returns info for restoring MARKER's location after indent.
+The returned value is a list of the form (MARKER REGEXP WS-COUNT)."
+  (unless beg (setq beg (line-beginning-position)))
+  (unless end (setq end (line-end-position)))
+  (let ((before (split-string (buffer-substring-no-properties beg marker)
+                              "[[:space:]\n]+" t))
+        (after (split-string (buffer-substring-no-properties marker end)
+                             "[[:space:]\n]+" t)))
+    (list marker
+          (concat "[[:space:]\n]*"
+                  (mapconcat (lambda (s)
+                               (if (eq s marker) "\\(\\)"
+                                 (regexp-quote s)))
+                             (nconc before (list marker) after)
+                             "[[:space:]\n]*"))
+          (progn (goto-char marker)
+                 (skip-chars-forward "[:space:]\n" end)
+                 (- (point) marker)))))
+
+(defun yas--snapshot-overlay-location (overlay beg end)
+  "Like `yas--snapshot-marker-location' for overlays.
+The returned format is (OVERLAY (RE WS) (RE WS)).  Either of
+the (RE WS) lists may be nil if the start or end, respectively,
+of the overlay is outside the range BEG .. END."
+  (let ((obeg (overlay-start overlay))
+        (oend (overlay-end overlay)))
+    (list overlay
+          (when (and (<= beg obeg) (< obeg end))
+            (cdr (yas--snapshot-marker-location obeg beg end)))
+          (when (and (<= beg oend) (< oend end))
+            (cdr (yas--snapshot-marker-location oend beg end))))))
+
+(defun yas--snapshot-overlay-line-location (overlay)
+  "Return info for restoring OVERLAY's line based location.
+The returned format is (OVERLAY (LINE RE WS) (LINE RE WS))."
+  (let ((loc-beg (progn (goto-char (overlay-start overlay))
+                        (yas--snapshot-marker-location (point))))
+        (loc-end (progn (goto-char (overlay-end overlay))
+                        (yas--snapshot-marker-location (point)))))
+    (setcar loc-beg (count-lines (point-min) (progn (goto-char (car loc-beg))
+                                                    
(line-beginning-position))))
+    (setcar loc-end (count-lines (point-min) (progn (goto-char (car loc-end))
+                                                    
(line-beginning-position))))
+    (list overlay loc-beg loc-end)))
+
+(defun yas--goto-saved-location (regexp ws-count)
+  "Move point to location saved by `yas--snapshot-marker-location'.
+Buffer must be narrowed to BEG..END used to create the snapshot info."
+  (goto-char (point-min))
+  (if (not (looking-at regexp))
+      (lwarn '(yasnippet re-marker) :warning
+             "Couldn't find: %S" regexp)
+    (goto-char (match-beginning 1))
+    (skip-chars-forward "[:space:]\n")
+    (skip-chars-backward "[:space:]\n" (- (point) ws-count))))
+
+(defun yas--restore-marker-location (re-marker)
+  "Restores marker based on info from `yas--snapshot-marker-location'.
+Buffer must be narrowed to BEG..END used to create the snapshot info."
+  (apply #'yas--goto-saved-location (cdr re-marker))
+  (set-marker (car re-marker) (point)))
+
+(defun yas--restore-overlay-location (ov-locations)
+  "Restores marker based on info from `yas--snapshot-marker-location'.
+Buffer must be narrowed to BEG..END used to create the snapshot info."
+  (cl-destructuring-bind (overlay loc-beg loc-end) ov-locations
+    (move-overlay overlay
+                  (if (not loc-beg) (overlay-start overlay)
+                    (apply #'yas--goto-saved-location loc-beg)
+                    (point))
+                  (if (not loc-end) (overlay-end overlay)
+                    (apply #'yas--goto-saved-location loc-end)
+                    (point)))))
+
+
+(defun yas--restore-overlay-line-location (ov-locations)
+  "Restores overlay based on info from `yas--snapshot-overlay-line-location'."
+  (save-restriction
+    (move-overlay (car ov-locations)
+                  (save-excursion
+                    (forward-line (car (nth 1 ov-locations)))
+                    (narrow-to-region (line-beginning-position) 
(line-end-position))
+                    (apply #'yas--goto-saved-location (cdr (nth 1 
ov-locations)))
+                    (point))
+                  (save-excursion
+                    (forward-line (car (nth 2 ov-locations)))
+                    (narrow-to-region (line-beginning-position) 
(line-end-position))
+                    (apply #'yas--goto-saved-location (cdr (nth 2 
ov-locations)))
+                    (point)))))
 
 (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'
-  ;; is available. Some implementations of these functions delete text
-  ;; before they insert. If there happens to be a marker just after
-  ;; the text being deleted, the insertion actually happens after the
-  ;; marker, which misplaces it.
-  ;;
-  ;; This would also happen if we had used overlays with the
-  ;; `front-advance' property set to nil.
-  ;;
-  ;; This is why I have these `trouble-markers', they are the ones at
-  ;; 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 #'/=)))
+  (save-excursion
+    (save-restriction
+      (widen)
+      (let* ((snippet-markers (yas--collect-snippet-markers snippet))
+             (to (set-marker (make-marker) to)))
+        (goto-char from)
+        (cl-loop for bol = (line-beginning-position)
+                 for eol = (line-end-position)
+                 if (/= bol eol) do
+                 ;; Indent each non-empty line.
+                 (let ((remarkers nil))
+                   (dolist (m snippet-markers)
+                     (when (and (<= bol m) (<= m eol))
+                       (push (yas--snapshot-marker-location m bol eol)
+                             remarkers)))
                    (unwind-protect
-                       (indent-according-to-mode)
-                     (dolist (marker trouble-markers)
-                       (set-marker marker (point)))))
+                       (progn (back-to-indentation)
+                              (if (eq yas--get-indent-undo-pos bol)
+                                  (let ((buffer-undo-list nil))
+                                    (indent-according-to-mode)
+                                    (setq yas--first-indent-undo
+                                          (delq nil buffer-undo-list)))
+                                (indent-according-to-mode)))
+                     (save-restriction
+                       (narrow-to-region bol (line-end-position))
+                       (mapc #'yas--restore-marker-location remarkers))))
                  while (and (zerop (forward-line 1))
                             (< (point) to)))))))
 
@@ -3961,16 +4260,7 @@ The SNIPPET's markers are preserved."
 (defun yas--collect-snippet-markers (snippet)
   "Make a list of all the markers used by SNIPPET."
   (let (markers)
-    (dolist (field (yas--snippet-fields snippet))
-      (push (yas--field-start field) markers)
-      (push (yas--field-end field) markers)
-      (dolist (mirror (yas--field-mirrors field))
-        (push (yas--mirror-start mirror) markers)
-        (push (yas--mirror-end mirror) markers)))
-    (let ((snippet-exit (yas--snippet-exit snippet)))
-      (when (and snippet-exit
-                 (marker-buffer (yas--exit-marker snippet-exit)))
-        (push (yas--exit-marker snippet-exit) markers)))
+    (yas--snippet-map-markers (lambda (m) (push m markers) m) snippet)
     markers))
 
 (defun yas--escape-string (escaped)
@@ -4018,9 +4308,9 @@ with their evaluated value into 
`yas--backquote-markers-and-strings'."
                           (delete-region (match-beginning 0) (match-end 0)))
         (let ((before-change-functions
                (cons detect-change before-change-functions)))
-          (setq transformed (yas--eval-lisp (yas--read-lisp
-                                             (yas--restore-escapes
-                                              current-string '(?`))))))
+          (setq transformed (yas--eval-for-string (yas--read-lisp
+                                                   (yas--restore-escapes
+                                                    current-string '(?`))))))
         (goto-char (match-beginning 0))
         (when transformed
           (let ((marker (make-marker))
@@ -4058,7 +4348,8 @@ with their evaluated value into 
`yas--backquote-markers-and-strings'."
   (ignore-errors
     (save-match-data ; `scan-sexps' may modify match data.
       (with-syntax-table (standard-syntax-table)
-        (scan-sexps from count)))))
+        (let ((parse-sexp-lookup-properties nil))
+          (scan-sexps from count))))))
 
 (defun yas--make-marker (pos)
   "Create a marker at POS with nil `marker-insertion-type'."
@@ -4229,44 +4520,42 @@ When multiple expressions are found, only the last one 
counts."
   (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))
-                                       (cl-sort
-                                        (cl-copy-list
-                                         (yas--field-mirrors field))
-                                        #'<
-                                        :key #'yas--mirror-start)))
-                           (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))))))))
+      (cl-loop
+       for (field . mirror)
+       in (cl-sort
+           ;; Make a list of (FIELD . MIRROR).
+           (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 also handles the case where a mirror in
+           ;; a field causes another mirror to need reupdating.
+           #'> :key (lambda (fm) (yas--calculate-mirror-depth (cdr fm))))
+       ;; Before updating a mirror with a parent-field, maybe advance
+       ;; its start (#290).
+       do (let ((parent-field (yas--mirror-parent-field mirror)))
+            (when parent-field
+              (yas--advance-start-maybe mirror (yas--fom-start parent-field))))
+       ;; Update this mirror.
+       do (yas--mirror-update-display mirror field snippet)
+       ;; Delay indenting until we're done all mirrors.  We must do
+       ;; this to avoid losing whitespace between fields that are
+       ;; still empty (i.e., they will be non-empty after updating).
+       when (eq yas-indent-line 'auto)
+       collect (cons (yas--mirror-start mirror) (yas--mirror-end mirror))
+       into indent-regions
+       ;; `yas--place-overlays' is needed since the active field and
+       ;; protected overlays might have been changed because of insertions
+       ;; in `yas--mirror-update-display'.
+       do (let ((active-field (yas--snippet-active-field snippet)))
+            (when active-field (yas--place-overlays snippet active-field)))
+       finally do
+       (let ((yas--inhibit-overlay-hooks t))
+         (cl-loop for (beg . end) in (cl-sort indent-regions #'< :key #'car)
+                  do (yas--indent-region beg end snippet)))))))
 
 (defun yas--mirror-update-display (mirror field snippet)
   "Update MIRROR according to FIELD (and mirror transform)."
@@ -4287,11 +4576,7 @@ When multiple expressions are found, only the last one 
counts."
         (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)))
-      (let ((yas--inhibit-overlay-hooks t))
-        (yas--indent-region (yas--mirror-start mirror)
-                            (yas--mirror-end mirror)
-                            snippet)))))
+        (yas--advance-end-of-parents-maybe mirror-parent-field (point))))))
 
 (defun yas--field-update-display (field)
   "Much like `yas--mirror-update-display', but for fields."
@@ -4316,26 +4601,29 @@ When multiple expressions are found, only the last one 
counts."
 ;;
 (defun yas--post-command-handler ()
   "Handles various yasnippet conditions after each command."
-  (cond ((eq 'undo this-command)
-         ;;
-         ;; After undo revival the correct field is sometimes not
-         ;; restored correctly, this condition handles that
-         ;;
-         (let* ((snippet (car (yas--snippets-at-point)))
-                (target-field
-                 (and snippet
-                      (cl-find-if-not
-                       (lambda (field)
-                         (yas--field-probably-deleted-p snippet field))
-                       (remq nil
-                             (cons (yas--snippet-active-field snippet)
-                                   (yas--snippet-fields snippet)))))))
-           (when target-field
-             (yas--move-to-field snippet target-field))))
-        ((not (yas--undo-in-progress))
-         ;; When not in an undo, check if we must commit the snippet
-         ;; (user exited it).
-         (yas--check-commit-snippet))))
+  (condition-case err
+      (progn (yas--finish-moving-snippets)
+             (cond ((eq 'undo this-command)
+                    ;;
+                    ;; After undo revival the correct field is sometimes not
+                    ;; restored correctly, this condition handles that
+                    ;;
+                    (let* ((snippet (car (yas-active-snippets)))
+                           (target-field
+                            (and snippet
+                                 (cl-find-if-not
+                                  (lambda (field)
+                                    (yas--field-probably-deleted-p snippet 
field))
+                                  (remq nil
+                                        (cons (yas--snippet-active-field 
snippet)
+                                              (yas--snippet-fields 
snippet)))))))
+                      (when target-field
+                        (yas--move-to-field snippet target-field))))
+                   ((not (yas--undo-in-progress))
+                    ;; When not in an undo, check if we must commit the snippet
+                    ;; (user exited it).
+                    (yas--check-commit-snippet))))
+    ((debug error) (signal (car err) (cdr err)))))
 
 ;;; Fancy docs:
 ;;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]