1 ;;; yasnippet.el --- Yet another snippet extension for Emacs
3 ;; Copyright (C) 2008-2019 Free Software Foundation, Inc.
4 ;; Authors: pluskid <pluskid@gmail.com>,
5 ;; João Távora <joaotavora@gmail.com>,
6 ;; Noam Postavsky <npostavs@gmail.com>
7 ;; Maintainer: Noam Postavsky <npostavs@gmail.com>
9 ;; X-URL: http://github.com/joaotavora/yasnippet
10 ;; Keywords: convenience, emulation
11 ;; URL: http://github.com/joaotavora/yasnippet
12 ;; Package-Requires: ((cl-lib "0.5"))
13 ;; EmacsWiki: YaSnippetMode
15 ;; This program is free software: you can redistribute it and/or modify
16 ;; it under the terms of the GNU General Public License as published by
17 ;; the Free Software Foundation, either version 3 of the License, or
18 ;; (at your option) any later version.
20 ;; This program is distributed in the hope that it will be useful,
21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 ;; GNU General Public License for more details.
25 ;; You should have received a copy of the GNU General Public License
26 ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
30 ;; Basic steps to setup:
32 ;; (add-to-list 'load-path
33 ;; "~/path-to-yasnippet")
34 ;; (require 'yasnippet)
35 ;; (yas-global-mode 1)
38 ;; Interesting variables are:
42 ;; The directory where user-created snippets are to be
43 ;; stored. Can also be a list of directories. In that case,
44 ;; when used for bulk (re)loading of snippets (at startup or
45 ;; via `yas-reload-all'), directories appearing earlier in
46 ;; the list override other dir's snippets. Also, the first
47 ;; directory is taken as the default for storing the user's
50 ;; The deprecated `yas/root-directory' aliases this variable
51 ;; for backward-compatibility.
54 ;; Major commands are:
58 ;; Try to expand snippets before point. In `yas-minor-mode',
59 ;; this is normally bound to TAB, but you can customize it in
60 ;; `yas-minor-mode-map'.
62 ;; M-x yas-load-directory
64 ;; Prompts you for a directory hierarchy of snippets to load.
66 ;; M-x yas-activate-extra-mode
68 ;; Prompts you for an extra mode to add snippets for in the
71 ;; M-x yas-insert-snippet
73 ;; Prompts you for possible snippet expansion if that is
74 ;; possible according to buffer-local and snippet-local
75 ;; expansion conditions. With prefix argument, ignore these
78 ;; M-x yas-visit-snippet-file
80 ;; Prompts you for possible snippet expansions like
81 ;; `yas-insert-snippet', but instead of expanding it, takes
82 ;; you directly to the snippet definition's file, if it
85 ;; M-x yas-new-snippet
87 ;; Lets you create a new snippet file in the correct
88 ;; subdirectory of `yas-snippet-dirs', according to the
91 ;; M-x yas-load-snippet-buffer
93 ;; When editing a snippet, this loads the snippet. This is
94 ;; bound to "C-c C-c" while in the `snippet-mode' editing
97 ;; M-x yas-tryout-snippet
99 ;; When editing a snippet, this opens a new empty buffer,
100 ;; sets it to the appropriate major mode and inserts the
101 ;; snippet there, so you can see what it looks like. This is
102 ;; bound to "C-c C-t" while in `snippet-mode'.
104 ;; M-x yas-describe-tables
106 ;; Lists known snippets in a separate buffer. User is
107 ;; prompted as to whether only the currently active tables
108 ;; are to be displayed, or all the tables for all major
111 ;; If you have `dropdown-list' installed, you can optionally use it
112 ;; as the preferred "prompting method", putting in your .emacs file,
115 ;; (require 'dropdown-list)
116 ;; (setq yas-prompt-functions '(yas-dropdown-prompt
118 ;; yas-completing-prompt))
120 ;; Also check out the customization group
122 ;; M-x customize-group RET yasnippet RET
124 ;; If you use the customization group to set variables
125 ;; `yas-snippet-dirs' or `yas-global-mode', make sure the path to
126 ;; "yasnippet.el" is present in the `load-path' *before* the
127 ;; `custom-set-variables' is executed in your .emacs file.
129 ;; For more information and detailed usage, refer to the project page:
130 ;; http://github.com/joaotavora/yasnippet
135 (require 'eldoc) ; Needed for 24.
136 (declare-function cl-progv-after "cl-extra") ; Needed for 23.4.
140 (defvar yas--editing-template)
141 (defvar yas--guessed-modes)
142 (defvar yas--indent-original-column)
143 (defvar yas--scheduled-jit-loads)
145 (defvar yas-selected-text)
146 (defvar yas-verbosity)
147 (defvar yas--current-template)
150 ;;; User customizable variables
152 (defgroup yasnippet nil
153 "Yet Another Snippet extension"
157 (defconst yas--loaddir
158 (file-name-directory (or load-file-name buffer-file-name))
159 "Directory that yasnippet was loaded from.")
161 (defconst yas-installed-snippets-dir (expand-file-name "snippets" yas--loaddir))
162 (make-obsolete-variable 'yas-installed-snippets-dir "\
163 Yasnippet no longer comes with installed snippets" "0.14")
165 (defconst yas--default-user-snippets-dir
166 (expand-file-name "snippets" user-emacs-directory))
168 (defcustom yas-snippet-dirs (list yas--default-user-snippets-dir)
169 "List of top-level snippet directories.
171 Each element, a string or a symbol whose value is a string,
172 designates a top-level directory where per-mode snippet
173 directories can be found.
175 Elements appearing earlier in the list override later elements'
178 The first directory is taken as the default for storing snippet's
179 created with `yas-new-snippet'. "
180 :type '(choice (directory :tag "Single directory")
181 (repeat :tag "List of directories"
182 (choice (directory) (variable))))
183 :set #'(lambda (symbol new)
184 (let ((old (and (boundp symbol)
185 (symbol-value symbol))))
186 (set-default symbol new)
187 (unless (or (not (fboundp 'yas-reload-all))
191 (defun yas-snippet-dirs ()
192 "Return variable `yas-snippet-dirs' as list of strings."
193 (cl-loop for e in (if (listp yas-snippet-dirs)
195 (list yas-snippet-dirs))
197 (cond ((stringp e) e)
200 (stringp (symbol-value e)))
203 (error "[yas] invalid element %s in `yas-snippet-dirs'" e)))))
205 (defcustom yas-new-snippet-default "\
206 # -*- mode: snippet -*-
208 # key: ${2:${1:$(yas--key-from-desc yas-text)}}
210 $0`(yas-escape-text yas-selected-text)`"
211 "Default snippet to use when creating a new snippet.
212 If nil, don't use any snippet."
215 (defcustom yas-prompt-functions '(yas-dropdown-prompt
216 yas-completing-prompt
219 "Functions to prompt for keys, templates, etc interactively.
221 These functions are called with the following arguments:
223 - PROMPT: A string to prompt the user
225 - CHOICES: a list of strings or objects.
227 - optional DISPLAY-FN : A function that, when applied to each of
228 the objects in CHOICES will return a string.
230 The return value of any function you put here should be one of
231 the objects in CHOICES, properly formatted with DISPLAY-FN (if
234 - To signal that your particular style of prompting is
235 unavailable at the moment, you can also have the function return
238 - To signal that the user quit the prompting process, you can
241 (signal \\='quit \"user quit!\")"
242 :type '(repeat function))
244 (defcustom yas-indent-line 'auto
245 "Controls indenting applied to a recent snippet expansion.
247 The following values are possible:
249 - `fixed' Indent the snippet to the current column;
251 - `auto' Indent each line of the snippet with `indent-according-to-mode'
253 Every other value means don't apply any snippet-side indentation
254 after expansion (the manual per-line \"$>\" indentation still
256 :type '(choice (const :tag "Nothing" nothing)
257 (const :tag "Fixed" fixed)
258 (const :tag "Auto" auto)))
260 (defcustom yas-also-auto-indent-first-line nil
261 "Non-nil means also auto indent first line according to mode.
263 Naturally this is only valid when `yas-indent-line' is `auto'."
266 (defcustom yas-also-indent-empty-lines nil
267 "Non-nil means also indent empty lines according to mode."
270 (defcustom yas-snippet-revival t
271 "Non-nil means re-activate snippet fields after undo/redo."
274 (defcustom yas-triggers-in-field nil
275 "If non-nil, allow stacked expansions (snippets inside snippets).
277 Otherwise `yas-next-field-or-maybe-expand' just moves on to the
281 (defcustom yas-fallback-behavior 'return-nil
282 "This option is obsolete.
283 Now that the conditional keybinding `yas-maybe-expand' is
284 available, there's no more need for it."
285 :type '(choice (const :tag "Call previous command" call-other-command)
286 (const :tag "Do nothing" return-nil)))
288 (make-obsolete-variable
289 'yas-fallback-behavior
290 "For `call-other-command' behavior bind to the conditional
291 command value `yas-maybe-expand', for `return-nil' behavior bind
292 directly to `yas-expand'."
295 (defcustom yas-choose-keys-first nil
296 "If non-nil, prompt for snippet key first, then for template.
298 Otherwise prompts for all possible snippet names.
300 This affects `yas-insert-snippet' and `yas-visit-snippet-file'."
303 (defcustom yas-choose-tables-first nil
304 "If non-nil, and multiple eligible snippet tables, prompts user for tables first.
306 Otherwise, user chooses between the merging together of all
309 This affects `yas-insert-snippet', `yas-visit-snippet-file'"
312 (defcustom yas-use-menu 'abbreviate
313 "Display a YASnippet menu in the menu bar.
315 When non-nil, submenus for each snippet table will be listed
316 under the menu \"Yasnippet\".
318 - If set to `abbreviate', only the current major-mode
319 menu and the modes set in `yas--extra-modes' are listed.
321 - If set to `full', every submenu is listed
323 - If set to nil, hide the menu.
325 Any other non-nil value, every submenu is listed."
326 :type '(choice (const :tag "Full" full)
327 (const :tag "Abbreviate" abbreviate)
328 (const :tag "No menu" nil)))
330 (defcustom yas-trigger-symbol (or (and (eq window-system 'mac)
332 (char-to-string ?\x21E5))) ;; little ->| sign
334 "The text that will be used in menu to represent the trigger."
337 (defcustom yas-wrap-around-region nil
338 "What to insert for snippet's $0 field.
340 If set to a character, insert contents of corresponding register.
341 If non-nil insert region contents. This can be overridden on a
342 per-snippet basis. A value of `cua' is considered equivalent to
343 `?0' for backwards compatibility."
344 :type '(choice (character :tag "Insert from register")
345 (const t :tag "Insert region contents")
346 (const nil :tag "Don't insert anything")
347 (const cua))) ; backwards compat
349 (defcustom yas-good-grace t
350 "If non-nil, don't raise errors in elisp evaluation.
352 This affects both the inline elisp in snippets and the hook
353 variables such as `yas-after-exit-snippet-hook'.
355 If this variable's value is `inline', an error string \"[yas]
356 error\" is returned instead of raising the error. If this
357 variable's value is `hooks', a message is output to according to
358 `yas-verbosity-level'. If this variable's value is t, both are
362 (defcustom yas-visit-from-menu nil
363 "If non-nil visit snippets's files from menu, instead of expanding them.
365 This can only work when snippets are loaded from files."
368 (defcustom yas-expand-only-for-last-commands nil
369 "List of `last-command' values to restrict tab-triggering to, or nil.
371 Leave this set at nil (the default) to be able to trigger an
372 expansion simply by placing the cursor after a valid tab trigger,
373 using whichever commands.
375 Optionally, set this to something like (self-insert-command) if
376 you to wish restrict expansion to only happen when the last
377 letter of the snippet tab trigger was typed immediately before
378 the trigger key itself."
379 :type '(repeat function))
381 (defcustom yas-alias-to-yas/prefix-p t
382 "If non-nil make aliases for the old style yas/ prefixed symbols.
383 It must be set to nil before loading yasnippet to take effect."
386 ;; Only two faces, and one of them shouldn't even be used...
388 (defface yas-field-highlight-face
389 '((t (:inherit region)))
390 "The face used to highlight the currently active field of a snippet")
392 (defface yas--field-debug-face
394 "The face used for debugging some overlays normally hidden")
397 ;;; User-visible variables
399 (defconst yas-maybe-skip-and-clear-field
400 '(menu-item "" yas-skip-and-clear-field
401 :filter yas--maybe-clear-field-filter)
402 "A conditional key definition.
403 This can be used as a key definition in keymaps to bind a key to
404 `yas-skip-and-clear-field' only when at the beginning of an
405 unmodified snippet field.")
407 (defconst yas-maybe-clear-field
408 '(menu-item "" yas-clear-field
409 :filter yas--maybe-clear-field-filter)
410 "A conditional key definition.
411 This can be used as a key definition in keymaps to bind a key to
412 `yas-clear-field' only when at the beginning of an
413 unmodified snippet field.")
415 (defun yas-filtered-definition (def)
416 "Return a condition key definition.
417 The condition will respect the value of `yas-keymap-disable-hook'."
419 :filter ,(lambda (cmd) (unless (run-hook-with-args-until-success
420 'yas-keymap-disable-hook)
424 (let ((map (make-sparse-keymap)))
425 (define-key map [(tab)] (yas-filtered-definition 'yas-next-field-or-maybe-expand))
426 (define-key map (kbd "TAB") (yas-filtered-definition 'yas-next-field-or-maybe-expand))
427 (define-key map [(shift tab)] (yas-filtered-definition 'yas-prev-field))
428 (define-key map [backtab] (yas-filtered-definition 'yas-prev-field))
429 (define-key map (kbd "C-g") (yas-filtered-definition 'yas-abort-snippet))
430 ;; Yes, filters can be chained!
431 (define-key map (kbd "C-d") (yas-filtered-definition yas-maybe-skip-and-clear-field))
432 (define-key map (kbd "DEL") (yas-filtered-definition yas-maybe-clear-field))
434 "The active keymap while a snippet expansion is in progress.")
436 (defvar yas-key-syntaxes (list #'yas-try-key-from-whitespace
437 "w_.()" "w_." "w_" "w")
438 "Syntaxes and functions to help look for trigger keys before point.
440 Each element in this list specifies how to skip buffer positions
441 backwards and look for the start of a trigger key.
443 Each element can be either a string or a function receiving the
444 original point as an argument. A string element is simply passed
445 to `skip-syntax-backward' whereas a function element is called
446 with no arguments and should also place point before the original
449 The string between the resulting buffer position and the original
450 point is matched against the trigger keys in the active snippet
453 If no expandable snippets are found, the next element is the list
454 is tried, unless a function element returned the symbol `again',
455 in which case it is called again from the previous position and
456 may once more reposition point.
458 For example, if `yas-key-syntaxes' has the value (\"w\" \"w_\"),
459 trigger keys composed exclusively of \"word\"-syntax characters
460 are looked for first. Failing that, longer keys composed of
461 \"word\" or \"symbol\" syntax are looked for. Therefore,
466 will, according to the \"w\" element first try \"barbaz\". If
467 that isn't a trigger key, \"foo-barbaz\" is tried, respecting the
468 second \"w_\" element. Notice that even if \"baz\" is a trigger
469 key for an active snippet, it won't be expanded, unless a
470 function is added to `yas-key-syntaxes' that eventually places
471 point between \"bar\" and \"baz\".
473 See also Info node `(elisp) Syntax Descriptors'.")
475 (defvar yas-after-exit-snippet-hook
477 "Hooks to run after a snippet exited.
479 The hooks will be run in an environment where some variables bound to
482 `yas-snippet-beg' : The beginning of the region of the snippet.
484 `yas-snippet-end' : Similar to beg.
486 Attention: These hooks are not run when exiting nested/stacked snippet expansion!")
488 (defvar yas-before-expand-snippet-hook
490 "Hooks to run just before expanding a snippet.")
492 (defconst yas-not-string-or-comment-condition
493 '(if (let ((ppss (syntax-ppss)))
494 (or (nth 3 ppss) (nth 4 ppss)))
495 '(require-snippet-condition . force-in-comment)
497 "Disables snippet expansion in strings and comments.
498 To use, set `yas-buffer-local-condition' to this value.")
500 (defcustom yas-buffer-local-condition t
501 "Snippet expanding condition.
503 This variable is a Lisp form which is evaluated every time a
504 snippet expansion is attempted:
506 * If it evaluates to nil, no snippets can be expanded.
508 * If it evaluates to the a cons (require-snippet-condition
511 * Snippets bearing no \"# condition:\" directive are not
514 * Snippets bearing conditions that evaluate to nil (or
515 produce an error) won't be considered.
517 * If the snippet has a condition that evaluates to non-nil
520 * If REQUIREMENT is t, the snippet is considered
522 * If REQUIREMENT is `eq' RESULT, the snippet is
525 * Otherwise, the snippet is not considered.
527 * If it evaluates to the symbol `always', all snippets are
528 considered for expansion, regardless of any conditions.
530 * If it evaluates to t or some other non-nil value
532 * Snippet bearing no conditions, or conditions that
533 evaluate to non-nil, are considered for expansion.
535 * Otherwise, the snippet is not considered.
537 Here's an example preventing snippets from being expanded from
538 inside comments, in `python-mode' only, with the exception of
539 snippets returning the symbol `force-in-comment' in their
542 (add-hook \\='python-mode-hook
544 (setq yas-buffer-local-condition
545 \\='(if (python-syntax-comment-or-string-p)
546 \\='(require-snippet-condition . force-in-comment)
550 (const :tag "Disable snippet expansion inside strings and comments"
551 ,yas-not-string-or-comment-condition)
552 (const :tag "Expand all snippets regardless of conditions" always)
553 (const :tag "Expand snippets unless their condition is nil" t)
554 (const :tag "Disable all snippet expansion" nil)
557 (defcustom yas-keymap-disable-hook nil
558 "The `yas-keymap' bindings are disabled if any function in this list returns non-nil.
559 This is useful to control whether snippet navigation bindings
560 override bindings from other packages (e.g., `company-mode')."
563 (defcustom yas-overlay-priority 100
564 "Priority to use for yasnippets overlays.
565 This is useful to control whether snippet navigation bindings
566 override `keymap' overlay property bindings from other packages."
569 (defcustom yas-inhibit-overlay-modification-protection nil
570 "If nil, changing text outside the active field aborts the snippet.
571 This protection is intended to prevent yasnippet from ending up
572 in an inconsistent state. However, some packages (e.g., the
573 company completion package) may trigger this protection when it
574 is not needed. In that case, setting this variable to non-nil
576 ;; See also `yas--on-protection-overlay-modification'.
580 ;;; Internal variables
582 (defconst yas--version "0.14.0")
584 (defvar yas--menu-table (make-hash-table)
585 "A hash table of MAJOR-MODE symbols to menu keymaps.")
587 (defvar yas--escaped-characters
588 '(?\\ ?` ?\" ?' ?$ ?} ?{ ?\( ?\))
589 "List of characters which *might* need to be escaped.")
591 (defconst yas--field-regexp
592 "${\\([0-9]+:\\)?\\([^}]*\\)}"
593 "A regexp to *almost* recognize a field.")
595 (defconst yas--multi-dollar-lisp-expression-regexp
596 "$+[ \t\n]*\\(([^)]*)\\)"
597 "A regexp to *almost* recognize a \"$(...)\" expression.")
599 (defconst yas--backquote-lisp-expression-regexp
601 "A regexp to recognize a \"\\=`lisp-expression\\=`\" expression." )
603 (defconst yas--transform-mirror-regexp
604 "${\\(?:\\([0-9]+\\):\\)?$\\([ \t\n]*([^}]*\\)"
605 "A regexp to *almost* recognize a mirror with a transform.")
607 (defconst yas--simple-mirror-regexp
609 "A regexp to recognize a simple mirror.")
611 (defvar yas--snippet-id-seed 0
612 "Contains the next id for a snippet.")
614 (defvar yas--original-auto-fill-function nil
615 "The original value of `auto-fill-function'.")
616 (make-variable-buffer-local 'yas--original-auto-fill-function)
618 (defvar yas--watch-auto-fill-backtrace nil)
620 (defun yas--watch-auto-fill (sym newval op _where)
621 (when (and (or (and (eq sym 'yas--original-auto-fill-function)
623 (eq auto-fill-function 'yas--auto-fill))
624 (and (eq sym 'auto-fill-function)
625 (eq newval 'yas--auto-fill)
626 (null yas--original-auto-fill-function)))
627 (null yas--watch-auto-fill-backtrace)
628 (fboundp 'backtrace-frames) ; Suppress compiler warning.
629 ;; If we're about to change `auto-fill-function' too,
630 ;; it's okay (probably).
631 (not (and (eq op 'makunbound)
632 (not (eq (default-value 'auto-fill-function) 'yas--auto-fill))
633 (cl-member 'kill-all-local-variables
634 (backtrace-frames 'yas--watch-auto-fill)
635 :key (lambda (frame) (nth 1 frame))))))
636 (setq yas--watch-auto-fill-backtrace
637 (backtrace-frames 'yas--watch-auto-fill))))
639 ;; Try to get more info on #873/919 (this only works for Emacs 26+).
640 (when (fboundp 'add-variable-watcher)
641 (add-variable-watcher 'yas--original-auto-fill-function
642 #'yas--watch-auto-fill)
643 (add-variable-watcher 'auto-fill-function
644 #'yas--watch-auto-fill))
646 (defun yas--snippet-next-id ()
647 (let ((id yas--snippet-id-seed))
648 (cl-incf yas--snippet-id-seed)
654 (defvar yas--minor-mode-menu nil
655 "Holds the YASnippet menu.")
657 (defvar yas--condition-cache-timestamp nil)
659 (defun yas-maybe-expand-abbrev-key-filter (cmd)
660 "Return CMD if there is an expandable snippet at point.
661 This function is useful as a `:filter' to a conditional key
663 (when (let ((yas--condition-cache-timestamp (current-time)))
664 (yas--templates-for-key-at-point))
667 (define-obsolete-function-alias 'yas--maybe-expand-key-filter
668 #'yas-maybe-expand-abbrev-key-filter "0.14")
670 (defconst yas-maybe-expand
671 '(menu-item "" yas-expand :filter yas-maybe-expand-abbrev-key-filter)
672 "A conditional key definition.
673 This can be used as a key definition in keymaps to bind a key to
674 `yas-expand' only when there is a snippet available to be
677 (defvar yas-minor-mode-map
678 (let ((map (make-sparse-keymap)))
679 (define-key map [(tab)] yas-maybe-expand)
680 (define-key map (kbd "TAB") yas-maybe-expand)
681 (define-key map "\C-c&\C-s" 'yas-insert-snippet)
682 (define-key map "\C-c&\C-n" 'yas-new-snippet)
683 (define-key map "\C-c&\C-v" 'yas-visit-snippet-file)
685 "The keymap used when `yas-minor-mode' is active.")
687 (easy-menu-define yas--minor-mode-menu
689 "Menu used when `yas-minor-mode' is active."
690 '("YASnippet" :visible yas-use-menu
692 ["Expand trigger" yas-expand
693 :help "Possibly expand tab trigger before point"]
694 ["Insert at point..." yas-insert-snippet
695 :help "Prompt for an expandable snippet and expand it at point"]
696 ["New snippet..." yas-new-snippet
697 :help "Create a new snippet in an appropriate directory"]
698 ["Visit snippet file..." yas-visit-snippet-file
699 :help "Prompt for an expandable snippet and find its file"]
701 ("Snippet menu behaviour"
702 ["Visit snippets" (setq yas-visit-from-menu t)
703 :help "Visit snippets from the menu"
704 :active t :style radio :selected yas-visit-from-menu]
705 ["Expand snippets" (setq yas-visit-from-menu nil)
706 :help "Expand snippets from the menu"
707 :active t :style radio :selected (not yas-visit-from-menu)]
709 ["Show all known modes" (setq yas-use-menu 'full)
710 :help "Show one snippet submenu for each loaded table"
711 :active t :style radio :selected (eq yas-use-menu 'full)]
712 ["Abbreviate according to current mode" (setq yas-use-menu 'abbreviate)
713 :help "Show only snippet submenus for the current active modes"
714 :active t :style radio :selected (eq yas-use-menu 'abbreviate)])
716 ["Auto" (setq yas-indent-line 'auto)
717 :help "Indent each line of the snippet with `indent-according-to-mode'"
718 :active t :style radio :selected (eq yas-indent-line 'auto)]
719 ["Fixed" (setq yas-indent-line 'fixed)
720 :help "Indent the snippet to the current column"
721 :active t :style radio :selected (eq yas-indent-line 'fixed)]
722 ["None" (setq yas-indent-line 'none)
723 :help "Don't apply any particular snippet indentation after expansion"
724 :active t :style radio :selected (not (member yas-indent-line '(fixed auto)))]
726 ["Also auto indent first line" (setq yas-also-auto-indent-first-line
727 (not yas-also-auto-indent-first-line))
728 :help "When auto-indenting also, auto indent the first line menu"
729 :active (eq yas-indent-line 'auto)
730 :style toggle :selected yas-also-auto-indent-first-line]
733 ["System X-widget" (setq yas-prompt-functions
735 (remove #'yas-x-prompt
736 yas-prompt-functions)))
737 :help "Use your windowing system's (gtk, mac, windows, etc...) default menu"
738 :active t :style radio :selected (eq (car yas-prompt-functions)
740 ["Dropdown-list" (setq yas-prompt-functions
741 (cons #'yas-dropdown-prompt
742 (remove #'yas-dropdown-prompt
743 yas-prompt-functions)))
744 :help "Use a special dropdown list"
745 :active t :style radio :selected (eq (car yas-prompt-functions)
746 #'yas-dropdown-prompt)]
747 ["Ido" (setq yas-prompt-functions
748 (cons #'yas-ido-prompt
749 (remove #'yas-ido-prompt
750 yas-prompt-functions)))
751 :help "Use an ido-style minibuffer prompt"
752 :active t :style radio :selected (eq (car yas-prompt-functions)
754 ["Completing read" (setq yas-prompt-functions
755 (cons #'yas-completing-prompt
756 (remove #'yas-completing-prompt
757 yas-prompt-functions)))
758 :help "Use a normal minibuffer prompt"
759 :active t :style radio :selected (eq (car yas-prompt-functions)
760 #'yas-completing-prompt)]
763 ["Wrap region in exit marker"
764 (setq yas-wrap-around-region
765 (not yas-wrap-around-region))
766 :help "If non-nil automatically wrap the selected text in the $0 snippet exit"
767 :style toggle :selected yas-wrap-around-region]
768 ["Allow stacked expansions "
769 (setq yas-triggers-in-field
770 (not yas-triggers-in-field))
771 :help "If non-nil allow snippets to be triggered inside other snippet fields"
772 :style toggle :selected yas-triggers-in-field]
773 ["Revive snippets on undo "
774 (setq yas-snippet-revival
775 (not yas-snippet-revival))
776 :help "If non-nil allow snippets to become active again after undo"
777 :style toggle :selected yas-snippet-revival]
780 (not yas-good-grace))
781 :help "If non-nil don't raise errors in bad embedded elisp in snippets"
782 :style toggle :selected yas-good-grace]
785 ["Load snippets..." yas-load-directory
786 :help "Load snippets from a specific directory"]
787 ["Reload everything" yas-reload-all
788 :help "Cleanup stuff, reload snippets, rebuild menus"]
790 :help "Display some information about YASnippet"]))
792 (define-obsolete-variable-alias 'yas-extra-modes 'yas--extra-modes "0.9.1")
793 (defvar yas--extra-modes nil
794 "An internal list of modes for which to also lookup snippets.
796 This variable probably makes more sense as buffer-local, so
797 ensure your use `make-local-variable' when you set it.")
799 (defvar yas--tables (make-hash-table)
800 "A hash table of mode symbols to `yas--table' objects.")
802 (defvar yas--parents (make-hash-table)
803 "A hash table of mode symbols do lists of direct parent mode symbols.
805 This list is populated when reading the \".yas-parents\" files
806 found when traversing snippet directories with
807 `yas-load-directory'.
809 There might be additional parenting information stored in the
810 `derived-mode-parent' property of some mode symbols, but that is
813 (defvar yas--direct-keymaps (list)
814 "Keymap alist supporting direct snippet keybindings.
816 This variable is placed in `emulation-mode-map-alists'.
818 Its elements looks like (TABLE-NAME . KEYMAP). They're
819 instantiated on `yas-reload-all' but KEYMAP is added to only when
820 loading snippets. `yas--direct-TABLE-NAME' is then a variable
821 set buffer-locally when entering `yas-minor-mode'. KEYMAP binds
822 all defined direct keybindings to `yas-maybe-expand-from-keymap'
823 which decides on the snippet to expand.")
825 (defun yas-direct-keymaps-reload ()
826 "Force reload the direct keybinding for active snippet tables."
828 (setq yas--direct-keymaps nil)
829 (maphash #'(lambda (name table)
830 (push (cons (intern (format "yas--direct-%s" name))
831 (yas--table-direct-keymap table))
832 yas--direct-keymaps))
835 (defun yas--modes-to-activate (&optional mode)
836 "Compute list of mode symbols that are active for `yas-expand' and friends."
837 (defvar yas--dfs) ;We rely on dynbind. We could use `letrec' instead!
838 (let* ((explored (if mode (list mode) ; Building up list in reverse.
839 (cons major-mode (reverse yas--extra-modes))))
842 (cl-loop for neighbour
843 in (cl-list* (or (get mode 'derived-mode-parent)
844 ;; Consider `fundamental-mode'
845 ;; as ultimate ancestor.
847 ;; NOTE: `fboundp' check is redundant
849 (and (fboundp mode) (symbol-function mode))
850 (gethash mode yas--parents))
852 (not (memq neighbour explored))
854 do (push neighbour explored)
855 (funcall yas--dfs neighbour)))))
856 (mapc yas--dfs explored)
857 (nreverse explored)))
859 (defvar yas-minor-mode-hook nil
860 "Hook run when `yas-minor-mode' is turned on.")
862 (defun yas--auto-fill-wrapper ()
863 (when (and auto-fill-function
864 (not (eq auto-fill-function #'yas--auto-fill)))
865 (setq yas--original-auto-fill-function auto-fill-function)
866 (setq auto-fill-function #'yas--auto-fill)))
869 (define-minor-mode yas-minor-mode
870 "Toggle YASnippet mode.
872 When YASnippet mode is enabled, `yas-expand', normally bound to
873 the TAB key, expands snippets of code depending on the major
876 With no argument, this command toggles the mode.
877 positive prefix argument turns on the mode.
878 Negative prefix argument turns off the mode.
881 \\{yas-minor-mode-map}"
882 :lighter " yas" ;; The indicator for the mode line.
883 (cond ((and yas-minor-mode (featurep 'yasnippet))
884 ;; Install the direct keymaps in `emulation-mode-map-alists'
885 ;; (we use `add-hook' even though it's not technically a hook,
886 ;; but it works). Then define variables named after modes to
887 ;; index `yas--direct-keymaps'.
889 ;; Also install the post-command-hook.
891 (cl-pushnew 'yas--direct-keymaps emulation-mode-map-alists)
892 (add-hook 'post-command-hook #'yas--post-command-handler nil t)
893 ;; Set the `yas--direct-%s' vars for direct keymap expansion
895 (dolist (mode (yas--modes-to-activate))
896 (let ((name (intern (format "yas--direct-%s" mode))))
897 (set-default name nil)
898 (set (make-local-variable name) t)))
900 (yas--load-pending-jits)
901 ;; Install auto-fill handler.
902 (yas--auto-fill-wrapper) ; Now...
903 (add-hook 'auto-fill-mode-hook #'yas--auto-fill-wrapper)) ; or later.
905 ;; Uninstall the direct keymaps, post-command hook, and
906 ;; auto-fill handler.
907 (remove-hook 'post-command-hook #'yas--post-command-handler t)
908 (remove-hook 'auto-fill-mode-hook #'yas--auto-fill-wrapper)
909 (when (local-variable-p 'yas--original-auto-fill-function)
910 (setq auto-fill-function yas--original-auto-fill-function))
911 (setq emulation-mode-map-alists
912 (remove 'yas--direct-keymaps emulation-mode-map-alists)))))
914 (defun yas-activate-extra-mode (mode)
915 "Activates the snippets for the given `mode' in the buffer.
917 The function can be called in the hook of a minor mode to
918 activate snippets associated with that mode."
922 (maphash (lambda (k _)
923 (setq modes (cons (list k) modes)))
925 (setq symbol (completing-read
926 "Activate mode: " modes nil t))
928 (when (not (string= "" symbol))
931 (add-to-list (make-local-variable 'yas--extra-modes) mode)
932 (yas--load-pending-jits)))
934 (defun yas-deactivate-extra-mode (mode)
935 "Deactivates the snippets for the given `mode' in the buffer."
939 "Deactivate mode: " (mapcar #'list yas--extra-modes) nil t))))
940 (set (make-local-variable 'yas--extra-modes)
944 (defun yas-temp-buffer-p (&optional buffer)
945 (eq (aref (buffer-name buffer) 0) ?\s))
947 (define-obsolete-variable-alias 'yas-dont-activate
948 'yas-dont-activate-functions "0.9.2")
949 (defvar yas-dont-activate-functions (list #'minibufferp #'yas-temp-buffer-p)
950 "Special hook to control which buffers `yas-global-mode' affects.
951 Functions are called with no argument, and should return non-nil to prevent
952 `yas-global-mode' from enabling yasnippet in this buffer.
954 In Emacsen < 24, this variable is buffer-local. Because
955 `yas-minor-mode-on' is called by `yas-global-mode' after
956 executing the buffer's major mode hook, setting this variable
957 there is an effective way to define exceptions to the \"global\"
958 activation behaviour.
960 In Emacsen >= 24, only the global value is used. To define
961 per-mode exceptions to the \"global\" activation behaviour, call
962 `yas-minor-mode' with a negative argument directily in the major
964 (unless (> emacs-major-version 23)
966 (make-variable-buffer-local 'yas-dont-activate)))
969 (defun yas-minor-mode-on ()
970 "Turn on YASnippet minor mode.
972 Honour `yas-dont-activate-functions', which see."
975 ;; The old behavior used for Emacs<24 was to set
976 ;; `yas-dont-activate-functions' to t buffer-locally.
977 (not (or (listp yas-dont-activate-functions)
978 (functionp yas-dont-activate-functions)))
979 (run-hook-with-args-until-success 'yas-dont-activate-functions))
983 (define-globalized-minor-mode yas-global-mode yas-minor-mode yas-minor-mode-on)
985 (defun yas--global-mode-reload-with-jit-maybe ()
986 "Run `yas-reload-all' when `yas-global-mode' is on."
987 (when yas-global-mode (yas-reload-all)))
989 (add-hook 'yas-global-mode-hook #'yas--global-mode-reload-with-jit-maybe)
994 (defvar yas--font-lock-keywords
995 (append '(("^#.*$" . font-lock-comment-face))
997 (let ((prog-mode-hook nil)
998 (emacs-lisp-mode-hook nil))
999 (ignore-errors (emacs-lisp-mode)))
1000 (font-lock-set-defaults)
1001 (if (eq t (car-safe font-lock-keywords))
1002 ;; They're "compiled", so extract the source.
1003 (cadr font-lock-keywords)
1004 font-lock-keywords))
1005 '(("\\$\\([0-9]+\\)"
1006 (0 font-lock-keyword-face)
1007 (1 font-lock-string-face t))
1008 ("\\${\\([0-9]+\\):?"
1009 (0 font-lock-keyword-face)
1010 (1 font-lock-warning-face t))
1011 ("\\(\\$(\\)" 1 font-lock-preprocessor-face)
1013 (0 font-lock-keyword-face)))))
1015 (defvar snippet-mode-map
1016 (let ((map (make-sparse-keymap)))
1017 (easy-menu-define nil
1019 "Menu used when snippet-mode is active."
1021 (mapcar #'(lambda (ent)
1023 (define-key map (nth 2 ent) (nth 1 ent)))
1024 (vector (nth 0 ent) (nth 1 ent) t))
1025 '(("Load this snippet" yas-load-snippet-buffer "\C-c\C-l")
1026 ("Load and quit window" yas-load-snippet-buffer-and-close "\C-c\C-c")
1027 ("Try out this snippet" yas-tryout-snippet "\C-c\C-t")))))
1029 "The keymap used when `snippet-mode' is active.")
1033 ;;;###autoload(autoload 'snippet-mode "yasnippet" "A mode for editing yasnippets" t nil)
1035 (if (fboundp 'prog-mode)
1036 ;; `prog-mode' is new in 24.1.
1037 (define-derived-mode snippet-mode prog-mode "Snippet"
1038 "A mode for editing yasnippets"
1039 (setq font-lock-defaults '(yas--font-lock-keywords))
1040 (set (make-local-variable 'require-final-newline) nil)
1041 (set (make-local-variable 'comment-start) "#")
1042 (set (make-local-variable 'comment-start-skip) "#+[\t ]*")
1043 (add-hook 'after-save-hook #'yas-maybe-load-snippet-buffer nil t))
1044 (define-derived-mode snippet-mode fundamental-mode "Snippet"
1045 "A mode for editing yasnippets"
1046 (setq font-lock-defaults '(yas--font-lock-keywords))
1047 (set (make-local-variable 'require-final-newline) nil)
1048 (set (make-local-variable 'comment-start) "#")
1049 (set (make-local-variable 'comment-start-skip) "#+[\t ]*")
1050 (add-hook 'after-save-hook #'yas-maybe-load-snippet-buffer nil t))))
1052 (defun yas-snippet-mode-buffer-p ()
1053 "Return non-nil if current buffer should be in `snippet-mode'.
1054 Meaning it's visiting a file under one of the mode directories in
1055 `yas-snippet-dirs'."
1056 (when buffer-file-name
1057 (cl-member buffer-file-name (yas-snippet-dirs)
1058 :test #'file-in-directory-p)))
1060 ;; We're abusing `magic-fallback-mode-alist' here because
1061 ;; `auto-mode-alist' doesn't support function matchers.
1062 (add-to-list 'magic-fallback-mode-alist
1063 `(yas-snippet-mode-buffer-p . snippet-mode))
1066 ;;; Internal structs for template management
1068 (cl-defstruct (yas--template
1069 (:constructor yas--make-template)
1070 ;; Handles `yas-define-snippets' format, plus the
1071 ;; initial TABLE argument.
1073 yas--define-snippets-2
1076 &optional xname condition group
1077 expand-env load-file xkeybinding xuuid save-file
1080 ;; A little redundant: we always get a name
1081 ;; from `yas--parse-template' except when
1082 ;; there isn't a file.
1083 (and load-file (file-name-nondirectory load-file))
1084 (and save-file (file-name-nondirectory save-file))
1086 (keybinding (yas--read-keybinding xkeybinding))
1087 (uuid (or xuuid name))
1088 (old (gethash uuid (yas--table-uuidhash table)))
1090 (and old (yas--template-menu-binding-pair old)))
1092 (and old (yas--template-perm-group old))))))
1093 "A template for a snippet."
1104 group ;; as dictated by the #group: directive or .yas-make-groups
1105 perm-group ;; as dictated by `yas-define-menu'
1109 (cl-defstruct (yas--table (:constructor yas--make-snippet-table (name)))
1110 "A table to store snippets for a particular mode.
1112 Has the following fields:
1116 A symbol name normally corresponding to a major mode, but can
1117 also be a pseudo major-mode to be used in
1118 `yas-activate-extra-mode', for example.
1122 A hash table (KEY . NAMEHASH), known as the \"keyhash\". KEY is
1123 a string or a vector, where the former is the snippet's trigger
1124 and the latter means it's a direct keybinding. NAMEHASH is yet
1125 another hash of (NAME . TEMPLATE) where NAME is the snippet's
1126 name and TEMPLATE is a `yas--template' object.
1128 `yas--table-direct-keymap'
1130 A keymap for the snippets in this table that have direct
1131 keybindings. This is kept in sync with the keyhash, i.e., all
1132 the elements of the keyhash that are vectors appear here as
1133 bindings to `yas-maybe-expand-from-keymap'.
1135 `yas--table-uuidhash'
1137 A hash table mapping snippets uuid's to the same `yas--template'
1138 objects. A snippet uuid defaults to the snippet's name."
1140 (hash (make-hash-table :test 'equal))
1141 (uuidhash (make-hash-table :test 'equal))
1143 (direct-keymap (make-sparse-keymap)))
1145 (defun yas--get-template-by-uuid (mode uuid)
1146 "Find the snippet template in MODE by its UUID."
1147 (let* ((table (gethash mode yas--tables mode)))
1149 (gethash uuid (yas--table-uuidhash table)))))
1151 ;; Apropos storing/updating in TABLE, this works in two steps:
1153 ;; 1. `yas--remove-template-by-uuid' removes any
1154 ;; keyhash-namehash-template mappings from TABLE, grabbing the
1155 ;; snippet by its uuid. Also removes mappings from TABLE's
1156 ;; `yas--table-direct-keymap' (FIXME: and should probably take care
1157 ;; of potentially stale menu bindings right?.)
1159 ;; 2. `yas--add-template' adds this all over again.
1161 ;; Create a new or add to an existing keyhash-namehash mapping.
1163 ;; For reference on understanding this, consider three snippet
1166 ;; A: # name: The Foo
1168 ;; # binding: C-c M-l
1170 ;; B: # name: Mrs Foo
1173 ;; C: # name: The Bar
1174 ;; # binding: C-c M-l
1179 ;; keyhash namehashes(3) yas--template structs(4)
1180 ;; -----------------------------------------------------
1183 ;; "foo" ---> "The Foo" ---> [yas--template A] |
1184 ;; "Mrs Foo" ---> [yas--template B] |
1186 ;; [C-c M-l] ---> "The Foo" -------------------------/
1187 ;; "The Bar" ---> [yas--template C]
1189 ;; "baz" ---> "Baz" ---> [yas--template D]
1191 ;; Additionally, since uuid defaults to the name, we have a
1192 ;; `yas--table-uuidhash' for TABLE
1194 ;; uuidhash yas--template structs
1195 ;; -------------------------------
1196 ;; "The Foo" ---> [yas--template A]
1197 ;; "Mrs Foo" ---> [yas--template B]
1198 ;; "The Bar" ---> [yas--template C]
1199 ;; "Baz" ---> [yas--template D]
1201 ;; FIXME: the more I look at this data-structure the more I think I'm
1202 ;; stupid. There has to be an easier way (but beware lots of code
1203 ;; depends on this).
1205 (defun yas--remove-template-by-uuid (table uuid)
1206 "Remove from TABLE a template identified by UUID."
1207 (let ((template (gethash uuid (yas--table-uuidhash table))))
1209 (let* ((name (yas--template-name template))
1211 ;; Remove the name from each of the targeted namehashes
1213 (maphash #'(lambda (k v)
1214 (let ((template (gethash name v)))
1216 (equal uuid (yas--template-uuid template)))
1218 (when (zerop (hash-table-count v))
1219 (push k empty-keys)))))
1220 (yas--table-hash table))
1221 ;; Remove the namehash themselves if they've become empty
1223 (dolist (key empty-keys)
1225 (define-key (yas--table-direct-keymap table) key nil))
1226 (remhash key (yas--table-hash table)))
1228 ;; Finally, remove the uuid from the uuidhash
1230 (remhash uuid (yas--table-uuidhash table))))))
1232 (defconst yas-maybe-expand-from-keymap
1233 '(menu-item "" yas-expand-from-keymap
1234 :filter yas--maybe-expand-from-keymap-filter))
1236 (defun yas--add-template (table template)
1237 "Store in TABLE the snippet template TEMPLATE.
1239 KEY can be a string (trigger key) of a vector (direct
1241 (let ((name (yas--template-name template))
1242 (key (yas--template-key template))
1243 (keybinding (yas--template-keybinding template))
1244 (_menu-binding-pair (yas--template-menu-binding-pair-get-create template)))
1245 (dolist (k (remove nil (list key keybinding)))
1249 (yas--table-hash table))
1251 (make-hash-table :test 'equal)
1252 (yas--table-hash table))))
1254 (define-key (yas--table-direct-keymap table) k yas-maybe-expand-from-keymap)))
1256 ;; Update TABLE's `yas--table-uuidhash'
1257 (puthash (yas--template-uuid template)
1259 (yas--table-uuidhash table))))
1261 (defun yas--update-template (table template)
1262 "Add or update TEMPLATE in TABLE.
1264 Also takes care of adding and updating to the associated menu.
1266 ;; Remove from table by uuid
1268 (yas--remove-template-by-uuid table (yas--template-uuid template))
1269 ;; Add to table again
1271 (yas--add-template table template)
1272 ;; Take care of the menu
1274 (yas--update-template-menu table template)
1277 (defun yas--update-template-menu (table template)
1278 "Update every menu-related for TEMPLATE."
1279 (let ((menu-binding-pair (yas--template-menu-binding-pair-get-create template))
1280 (key (yas--template-key template))
1281 (keybinding (yas--template-keybinding template)))
1282 ;; The snippet might have changed name or keys, so update
1283 ;; user-visible strings
1285 (unless (eq (cdr menu-binding-pair) :none)
1286 ;; the menu item name
1288 (setf (cl-cadar menu-binding-pair) (yas--template-name template))
1289 ;; the :keys information (also visible to the user)
1290 (setf (cl-getf (cdr (car menu-binding-pair)) :keys)
1291 (or (and keybinding (key-description keybinding))
1292 (and key (concat key yas-trigger-symbol))))))
1293 (unless (yas--template-menu-managed-by-yas-define-menu template)
1295 (yas--menu-keymap-get-create (yas--table-mode table)
1296 (mapcar #'yas--table-mode
1297 (yas--table-parents table))))
1298 (group (yas--template-group template)))
1299 ;; Remove from menu keymap
1301 (cl-assert menu-keymap)
1302 (yas--delete-from-keymap menu-keymap (yas--template-uuid template))
1304 ;; Add necessary subgroups as necessary.
1306 (dolist (subgroup group)
1307 (let ((subgroup-keymap (lookup-key menu-keymap (vector (make-symbol subgroup)))))
1308 (unless (and subgroup-keymap
1309 (keymapp subgroup-keymap))
1310 (setq subgroup-keymap (make-sparse-keymap))
1311 (define-key menu-keymap (vector (make-symbol subgroup))
1312 `(menu-item ,subgroup ,subgroup-keymap)))
1313 (setq menu-keymap subgroup-keymap)))
1315 ;; Add this entry to the keymap
1317 (define-key menu-keymap
1318 (vector (make-symbol (yas--template-uuid template)))
1319 (car (yas--template-menu-binding-pair template))))))
1321 (defun yas--namehash-templates-alist (namehash)
1322 "Return NAMEHASH as an alist."
1324 (maphash #'(lambda (k v)
1325 (push (cons k v) alist))
1329 (defun yas--fetch (table key)
1330 "Fetch templates in TABLE by KEY.
1332 Return a list of cons (NAME . TEMPLATE) where NAME is a
1333 string and TEMPLATE is a `yas--template' structure."
1334 (let* ((keyhash (yas--table-hash table))
1335 (namehash (and keyhash (gethash key keyhash))))
1337 (yas--filter-templates-by-condition (yas--namehash-templates-alist namehash)))))
1340 ;;; Filtering/condition logic
1342 (defun yas--eval-condition (condition)
1349 (yas--message 1 "Error in condition evaluation: %s" (error-message-string err))
1353 (defun yas--filter-templates-by-condition (templates)
1354 "Filter the templates using the applicable condition.
1356 TEMPLATES is a list of cons (NAME . TEMPLATE) where NAME is a
1357 string and TEMPLATE is a `yas--template' structure.
1359 This function implements the rules described in
1360 `yas-buffer-local-condition'. See that variables documentation."
1361 (let ((requirement (yas--require-template-specific-condition-p)))
1362 (if (eq requirement 'always)
1364 (cl-remove-if-not (lambda (pair)
1365 (yas--template-can-expand-p
1366 (yas--template-condition (cdr pair)) requirement))
1369 (defun yas--require-template-specific-condition-p ()
1370 "Decide if this buffer requests/requires snippet-specific
1371 conditions to filter out potential expansions."
1372 (if (eq 'always yas-buffer-local-condition)
1374 (let ((local-condition (or (and (consp yas-buffer-local-condition)
1375 (yas--eval-condition yas-buffer-local-condition))
1376 yas-buffer-local-condition)))
1377 (when local-condition
1378 (if (eq local-condition t)
1380 (and (consp local-condition)
1381 (eq 'require-snippet-condition (car local-condition))
1382 (symbolp (cdr local-condition))
1383 (cdr local-condition)))))))
1385 (defun yas--template-can-expand-p (condition requirement)
1386 "Evaluate CONDITION and REQUIREMENT and return a boolean."
1387 (let* ((result (or (null condition)
1388 (yas--eval-condition condition))))
1389 (cond ((eq requirement t)
1392 (eq requirement result)))))
1394 (defun yas--table-templates (table)
1397 (maphash #'(lambda (_key namehash)
1398 (maphash #'(lambda (name template)
1399 (push (cons name template) acc))
1401 (yas--table-hash table))
1402 (maphash #'(lambda (uuid template)
1403 (push (cons uuid template) acc))
1404 (yas--table-uuidhash table))
1405 (yas--filter-templates-by-condition acc))))
1407 (defun yas--templates-for-key-at-point ()
1408 "Find `yas--template' objects for any trigger keys preceding point.
1409 Returns (TEMPLATES START END). This function respects
1410 `yas-key-syntaxes', which see."
1412 (let ((original (point))
1413 (methods yas-key-syntaxes)
1418 (unless (eq method (car methods))
1419 ;; TRICKY: `eq'-ness test means we can only be here if
1420 ;; `method' is a function that returned `again', and hence
1421 ;; don't revert back to original position as per
1422 ;; `yas-key-syntaxes'.
1423 (goto-char original))
1424 (setq method (car methods))
1425 (cond ((stringp method)
1426 (skip-syntax-backward method)
1427 (setq methods (cdr methods)))
1429 (unless (eq (funcall method original)
1431 (setq methods (cdr methods))))
1433 (setq methods (cdr methods))
1434 (yas--warning "Invalid element `%s' in `yas-key-syntaxes'" method)))
1435 (let ((possible-key (buffer-substring-no-properties (point) original)))
1437 (goto-char original)
1439 (cl-mapcan (lambda (table)
1440 (yas--fetch table possible-key))
1441 (yas--get-snippet-tables))))))
1443 (list templates (point) original)))))
1445 (defun yas--table-all-keys (table)
1446 "Get trigger keys of all active snippets in TABLE."
1448 (maphash #'(lambda (key namehash)
1449 (when (yas--filter-templates-by-condition (yas--namehash-templates-alist namehash))
1451 (yas--table-hash table))
1454 (defun yas--table-mode (table)
1455 (intern (yas--table-name table)))
1458 ;;; Internal functions and macros:
1460 (defun yas--remove-misc-free-from-undo (old-undo-list)
1461 "Tries to work around Emacs Bug#30931.
1462 Helper function for `yas--save-restriction-and-widen'."
1463 ;; If Bug#30931 is unfixed, we get (#<Lisp_Misc_Free> . INTEGER)
1464 ;; entries in the undo list. If we call `type-of' on the
1465 ;; Lisp_Misc_Free object then Emacs aborts, so try to find it by
1466 ;; checking that its type is none of the expected ones.
1467 (when (consp buffer-undo-list)
1468 (let* ((prev buffer-undo-list)
1470 (while (and (consp undo-list)
1471 ;; Only check new entries.
1472 (not (eq undo-list old-undo-list)))
1473 (let ((entry (pop undo-list)))
1475 (let ((head (car entry)))
1476 (unless (or (stringp head)
1480 (not (integerp (cdr entry))))
1481 ;; (message "removing misc free %S" entry)
1482 (setcdr prev undo-list)))))
1483 (setq prev undo-list)))))
1485 (defmacro yas--save-restriction-and-widen (&rest body)
1486 "Equivalent to (save-restriction (widen) BODY).
1487 Also tries to work around Emacs Bug#30931."
1488 (declare (debug (body)) (indent 0))
1489 ;; Disable garbage collection, since it could cause an abort.
1490 `(let ((gc-cons-threshold most-positive-fixnum)
1491 (old-undo-list buffer-undo-list))
1492 (prog1 (save-restriction
1495 (yas--remove-misc-free-from-undo old-undo-list))))
1497 (defun yas--eval-for-string (form)
1498 "Evaluate FORM and convert the result to string."
1499 (let ((debug-on-error (and (not (memq yas-good-grace '(t inline)))
1501 (condition-case oops
1503 (yas--save-restriction-and-widen
1505 (let ((result (eval form)))
1507 (format "%s" result))))))
1508 ((debug error) (error-message-string oops)))))
1510 (defun yas--eval-for-effect (form)
1511 (yas--safely-call-fun (apply-partially #'eval form)))
1513 (defun yas--read-lisp (string &optional nil-on-error)
1514 "Read STRING as a elisp expression and return it.
1516 In case STRING in an invalid expression and NIL-ON-ERROR is nil,
1517 return an expression that when evaluated will issue an error."
1520 (error (and (not nil-on-error)
1521 `(error (error-message-string ,err))))))
1523 (defun yas--read-keybinding (keybinding)
1524 "Read KEYBINDING as a snippet keybinding, return a vector."
1525 (when (and keybinding
1526 (not (string-match "keybinding" keybinding)))
1528 (let ((res (or (and (string-match "^\\[.*\\]$" keybinding)
1530 (read-kbd-macro keybinding 'need-vector))))
1533 (yas--message 2 "warning: keybinding \"%s\" invalid since %s."
1534 keybinding (error-message-string err))
1537 (defun yas--table-get-create (mode)
1538 "Get or create the snippet table corresponding to MODE."
1539 (let ((table (gethash mode
1542 (setq table (yas--make-snippet-table (symbol-name mode)))
1543 (puthash mode table yas--tables)
1544 (push (cons (intern (format "yas--direct-%s" mode))
1545 (yas--table-direct-keymap table))
1546 yas--direct-keymaps))
1549 (defun yas--get-snippet-tables (&optional mode)
1550 "Get snippet tables for MODE.
1552 MODE defaults to the current buffer's `major-mode'.
1554 Return a list of `yas--table' objects. The list of modes to
1555 consider is returned by `yas--modes-to-activate'"
1557 (mapcar #'(lambda (name)
1558 (gethash name yas--tables))
1559 (yas--modes-to-activate mode))))
1561 (defun yas--menu-keymap-get-create (mode &optional parents)
1562 "Get or create the menu keymap for MODE and its PARENTS.
1564 This may very well create a plethora of menu keymaps and arrange
1565 them all in `yas--menu-table'"
1566 (let* ((menu-keymap (or (gethash mode yas--menu-table)
1567 (puthash mode (make-sparse-keymap) yas--menu-table))))
1568 (mapc #'yas--menu-keymap-get-create parents)
1569 (define-key yas--minor-mode-menu (vector mode)
1570 `(menu-item ,(symbol-name mode) ,menu-keymap
1571 :visible (yas--show-menu-p ',mode)))
1575 ;;; Template-related and snippet loading functions
1577 (defun yas--parse-template (&optional file)
1578 "Parse the template in the current buffer.
1580 Optional FILE is the absolute file name of the file being
1583 Optional GROUP is the group where the template is to go,
1584 otherwise we attempt to calculate it from FILE.
1586 Return a snippet-definition, i.e. a list
1588 (KEY TEMPLATE NAME CONDITION GROUP VARS LOAD-FILE KEYBINDING UUID)
1590 If the buffer contains a line of \"# --\" then the contents above
1591 this line are ignored. Directives can set most of these with the syntax:
1593 # directive-name : directive-value
1595 Here's a list of currently recognized directives:
1606 (goto-char (point-min))
1607 (let* ((type 'snippet)
1609 (file-name-nondirectory file)))
1615 (yas--calculate-group file)))
1619 (if (re-search-forward "^# --\\s-*\n" nil t)
1620 (progn (setq template
1621 (buffer-substring-no-properties (point)
1623 (setq bound (point))
1624 (goto-char (point-min))
1625 (while (re-search-forward "^# *\\([^ ]+?\\) *: *\\(.*?\\)[[:space:]]*$" bound t)
1626 (when (string= "uuid" (match-string-no-properties 1))
1627 (setq uuid (match-string-no-properties 2)))
1628 (when (string= "type" (match-string-no-properties 1))
1629 (setq type (if (string= "command" (match-string-no-properties 2))
1632 (when (string= "key" (match-string-no-properties 1))
1633 (setq key (match-string-no-properties 2)))
1634 (when (string= "name" (match-string-no-properties 1))
1635 (setq name (match-string-no-properties 2)))
1636 (when (string= "condition" (match-string-no-properties 1))
1637 (setq condition (yas--read-lisp (match-string-no-properties 2))))
1638 (when (string= "group" (match-string-no-properties 1))
1639 (setq group (match-string-no-properties 2)))
1640 (when (string= "expand-env" (match-string-no-properties 1))
1641 (setq expand-env (yas--read-lisp (match-string-no-properties 2)
1643 (when (string= "binding" (match-string-no-properties 1))
1644 (setq binding (match-string-no-properties 2)))))
1646 (buffer-substring-no-properties (point-min) (point-max))))
1647 (unless (or key binding)
1648 (setq key (and file (file-name-nondirectory file))))
1649 (when (eq type 'command)
1650 (setq template (yas--read-lisp (concat "(progn" template ")"))))
1652 (setq group (split-string group "\\.")))
1653 (list key template name condition group expand-env file binding uuid)))
1655 (defun yas--calculate-group (file)
1656 "Calculate the group for snippet file path FILE."
1657 (let* ((dominating-dir (locate-dominating-file file
1658 ".yas-make-groups"))
1659 (extra-path (and dominating-dir
1660 (file-relative-name file dominating-dir)))
1661 (extra-dir (and extra-path
1662 (file-name-directory extra-path)))
1663 (group (and extra-dir
1664 (replace-regexp-in-string "/"
1666 (directory-file-name extra-dir)))))
1669 (defun yas--subdirs (directory &optional filep)
1670 "Return subdirs or files of DIRECTORY according to FILEP."
1671 (cl-remove-if (lambda (file)
1672 (or (string-match "\\`\\."
1673 (file-name-nondirectory file))
1674 (string-match "\\`#.*#\\'"
1675 (file-name-nondirectory file))
1676 (string-match "~\\'"
1677 (file-name-nondirectory file))
1679 (file-directory-p file)
1680 (not (file-directory-p file)))))
1681 (directory-files directory t)))
1683 (defun yas--make-menu-binding (template)
1684 (let ((mode (yas--table-mode (yas--template-table template))))
1685 `(lambda () (interactive) (yas--expand-or-visit-from-menu ',mode ,(yas--template-uuid template)))))
1687 (defun yas--expand-or-visit-from-menu (mode uuid)
1688 (let* ((table (yas--table-get-create mode))
1689 (yas--current-template (and table
1690 (gethash uuid (yas--table-uuidhash table)))))
1691 (when yas--current-template
1692 (if yas-visit-from-menu
1693 (yas--visit-snippet-file-1 yas--current-template)
1694 (let ((where (if (region-active-p)
1695 (cons (region-beginning) (region-end))
1696 (cons (point) (point)))))
1697 (yas-expand-snippet yas--current-template
1698 (car where) (cdr where)))))))
1700 (defun yas--key-from-desc (text)
1701 "Return a yasnippet key from a description string TEXT."
1702 (replace-regexp-in-string "\\(\\w+\\).*" "\\1" text))
1705 ;;; Popping up for keys and templates
1707 (defun yas--prompt-for-template (templates &optional prompt)
1708 "Interactively choose a template from the list TEMPLATES.
1710 TEMPLATES is a list of `yas--template'.
1712 Optional PROMPT sets the prompt to use."
1715 (sort templates #'(lambda (t1 t2)
1716 (< (length (yas--template-name t1))
1717 (length (yas--template-name t2))))))
1718 (cl-some (lambda (fn)
1719 (funcall fn (or prompt "Choose a snippet: ")
1721 #'yas--template-name))
1722 yas-prompt-functions)))
1724 (defun yas--prompt-for-keys (keys &optional prompt)
1725 "Interactively choose a template key from the list KEYS.
1727 Optional PROMPT sets the prompt to use."
1729 (cl-some (lambda (fn)
1730 (funcall fn (or prompt "Choose a snippet key: ") keys))
1731 yas-prompt-functions)))
1733 (defun yas--prompt-for-table (tables &optional prompt)
1734 "Interactively choose a table from the list TABLES.
1736 Optional PROMPT sets the prompt to use."
1738 (cl-some (lambda (fn)
1739 (funcall fn (or prompt "Choose a snippet table: ")
1742 yas-prompt-functions)))
1744 (defun yas-x-prompt (prompt choices &optional display-fn)
1745 "Display choices in a x-window prompt."
1746 (when (and window-system choices)
1747 ;; Let window position be recalculated to ensure that
1748 ;; `posn-at-point' returns non-nil.
1752 (if (fboundp 'posn-at-point)
1753 (let ((x-y (posn-x-y (posn-at-point (point)))))
1754 (list (list (+ (car x-y) 10)
1759 ,@(cl-mapcar (lambda (c d) `(,(concat " " d) . ,c))
1761 (if display-fn (mapcar display-fn choices)
1765 (defun yas-maybe-ido-prompt (prompt choices &optional display-fn)
1766 (when (bound-and-true-p ido-mode)
1767 (yas-ido-prompt prompt choices display-fn)))
1769 (defun yas-ido-prompt (prompt choices &optional display-fn)
1771 (yas-completing-prompt prompt choices display-fn #'ido-completing-read))
1773 (defun yas-dropdown-prompt (_prompt choices &optional display-fn)
1774 (when (fboundp 'dropdown-list)
1775 (let* ((formatted-choices
1776 (if display-fn (mapcar display-fn choices) choices))
1777 (n (dropdown-list formatted-choices)))
1778 (if n (nth n choices)
1781 (defun yas-completing-prompt (prompt choices &optional display-fn completion-fn)
1782 (let* ((formatted-choices
1783 (if display-fn (mapcar display-fn choices) choices))
1784 (chosen (funcall (or completion-fn #'completing-read)
1785 prompt formatted-choices
1786 nil 'require-match nil nil)))
1787 (if (eq choices formatted-choices)
1789 (nth (or (cl-position chosen formatted-choices :test #'string=) 0)
1792 (defun yas-no-prompt (_prompt choices &optional _display-fn)
1796 ;;; Defining snippets
1797 ;; This consists of creating and registering `yas--template' objects in the
1801 (defvar yas--creating-compiled-snippets nil)
1803 (defun yas--define-snippets-1 (snippet snippet-table)
1804 "Helper for `yas-define-snippets'."
1805 ;; Update the appropriate table. Also takes care of adding the
1806 ;; key indicators in the templates menu entry, if any.
1807 (yas--update-template
1808 snippet-table (apply #'yas--define-snippets-2 snippet-table snippet)))
1810 (defun yas-define-snippets (mode snippets)
1811 "Define SNIPPETS for MODE.
1813 SNIPPETS is a list of snippet definitions, each taking the
1816 (KEY TEMPLATE NAME CONDITION GROUP EXPAND-ENV LOAD-FILE KEYBINDING UUID SAVE-FILE)
1818 Within these, only KEY and TEMPLATE are actually mandatory.
1820 TEMPLATE might be a Lisp form or a string, depending on whether
1821 this is a snippet or a snippet-command.
1823 CONDITION, EXPAND-ENV and KEYBINDING are Lisp forms, they have
1824 been `yas--read-lisp'-ed and will eventually be
1825 `yas--eval-for-string'-ed.
1827 The remaining elements are strings.
1829 FILE is probably of very little use if you're programatically
1832 UUID is the snippet's \"unique-id\". Loading a second snippet
1833 file with the same uuid would replace the previous snippet.
1835 You can use `yas--parse-template' to return such lists based on
1836 the current buffers contents."
1837 (if yas--creating-compiled-snippets
1838 (let ((print-length nil))
1839 (insert ";;; Snippet definitions:\n;;;\n")
1840 (dolist (snippet snippets)
1841 ;; Fill in missing elements with nil.
1842 (setq snippet (append snippet (make-list (- 10 (length snippet)) nil)))
1843 ;; Move LOAD-FILE to SAVE-FILE because we will load from the
1844 ;; compiled file, not LOAD-FILE.
1845 (let ((load-file (nth 6 snippet)))
1846 (setcar (nthcdr 6 snippet) nil)
1847 (setcar (nthcdr 9 snippet) load-file)))
1848 (insert (pp-to-string
1849 `(yas-define-snippets ',mode ',snippets)))
1852 (let ((snippet-table (yas--table-get-create mode))
1854 (dolist (snippet snippets)
1855 (setq template (yas--define-snippets-1 snippet
1860 ;;; Loading snippets from files
1862 (defun yas--template-get-file (template)
1863 "Return TEMPLATE's LOAD-FILE or SAVE-FILE."
1864 (or (yas--template-load-file template)
1865 (let ((file (yas--template-save-file template)))
1867 (yas--message 3 "%s has no load file, using save file, %s, instead."
1868 (yas--template-name template) file))
1871 (defun yas--load-yas-setup-file (file)
1872 (if (not yas--creating-compiled-snippets)
1874 (load file 'noerror (<= yas-verbosity 4))
1875 (let ((elfile (concat file ".el")))
1876 (when (file-exists-p elfile)
1877 (insert ";;; contents of the .yas-setup.el support file:\n;;;\n")
1878 (insert-file-contents elfile)
1879 (goto-char (point-max))))))
1881 (defun yas--define-parents (mode parents)
1882 "Add PARENTS to the list of MODE's parents."
1883 (puthash mode (cl-remove-duplicates
1885 (gethash mode yas--parents)))
1888 (defun yas-load-directory (top-level-dir &optional use-jit interactive)
1889 "Load snippets in directory hierarchy TOP-LEVEL-DIR.
1891 Below TOP-LEVEL-DIR each directory should be a mode name.
1893 With prefix argument USE-JIT do jit-loading of snippets."
1895 (list (read-directory-name "Select the root directory: " nil nil t)
1896 current-prefix-arg t))
1897 (unless yas-snippet-dirs
1898 (setq yas-snippet-dirs top-level-dir))
1899 (let ((impatient-buffers))
1900 (dolist (dir (yas--subdirs top-level-dir))
1901 (let* ((major-mode-and-parents (yas--compute-major-mode-and-parents
1902 (concat dir "/dummy")))
1903 (mode-sym (car major-mode-and-parents))
1904 (parents (cdr major-mode-and-parents)))
1905 ;; Attention: The parents and the menus are already defined
1906 ;; here, even if the snippets are later jit-loaded.
1908 ;; * We need to know the parents at this point since entering a
1909 ;; given mode should jit load for its parents
1910 ;; immediately. This could be reviewed, the parents could be
1911 ;; discovered just-in-time-as well
1913 ;; * We need to create the menus here to support the `full'
1914 ;; option to `yas-use-menu' (all known snippet menus are shown to the user)
1916 (yas--define-parents mode-sym parents)
1917 (yas--menu-keymap-get-create mode-sym)
1918 (let ((fun (apply-partially #'yas--load-directory-1 dir mode-sym)))
1920 (yas--schedule-jit mode-sym fun)
1922 ;; Look for buffers that are already in `mode-sym', and so
1923 ;; need the new snippets immediately...
1926 (cl-loop for buffer in (buffer-list)
1927 do (with-current-buffer buffer
1928 (when (eq major-mode mode-sym)
1929 (yas--message 4 "Discovered there was already %s in %s" buffer mode-sym)
1930 (push buffer impatient-buffers)))))))
1931 ;; ...after TOP-LEVEL-DIR has been completely loaded, call
1932 ;; `yas--load-pending-jits' in these impatient buffers.
1934 (cl-loop for buffer in impatient-buffers
1935 do (with-current-buffer buffer (yas--load-pending-jits))))
1937 (yas--message 3 "Loaded snippets from %s." top-level-dir)))
1939 (defun yas--load-directory-1 (directory mode-sym)
1940 "Recursively load snippet templates from DIRECTORY."
1941 (if yas--creating-compiled-snippets
1942 (let ((output-file (expand-file-name ".yas-compiled-snippets.el"
1944 (with-temp-file output-file
1945 (insert (format ";;; Compiled snippets and support files for `%s'\n"
1947 (yas--load-directory-2 directory mode-sym)
1948 (insert (format ";;; Do not edit! File generated at %s\n"
1949 (current-time-string)))))
1951 (unless (file-exists-p (expand-file-name ".yas-skip" directory))
1952 (unless (and (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror (<= yas-verbosity 3))
1953 (progn (yas--message 4 "Loaded compiled snippets from %s" directory) t))
1954 (yas--message 4 "Loading snippet files from %s" directory)
1955 (yas--load-directory-2 directory mode-sym)))))
1957 (defun yas--load-directory-2 (directory mode-sym)
1958 ;; Load .yas-setup.el files wherever we find them
1960 (yas--load-yas-setup-file (expand-file-name ".yas-setup" directory))
1961 (let* ((default-directory directory)
1963 ;; load the snippet files
1966 (dolist (file (yas--subdirs directory 'no-subdirs-just-files))
1967 (when (file-readable-p file)
1968 ;; Erase the buffer instead of passing non-nil REPLACE to
1969 ;; `insert-file-contents' (avoids Emacs bug #23659).
1971 (insert-file-contents file)
1972 (push (yas--parse-template file)
1975 (yas-define-snippets mode-sym
1977 ;; now recurse to a lower level
1979 (dolist (subdir (yas--subdirs directory))
1980 (yas--load-directory-2 subdir
1983 (defun yas--load-snippet-dirs (&optional nojit)
1984 "Reload the directories listed in `yas-snippet-dirs' or
1985 prompt the user to select one."
1987 (if (null yas-snippet-dirs)
1988 (call-interactively 'yas-load-directory)
1989 (when (member yas--default-user-snippets-dir yas-snippet-dirs)
1990 (make-directory yas--default-user-snippets-dir t))
1991 (dolist (directory (reverse (yas-snippet-dirs)))
1992 (cond ((file-directory-p directory)
1993 (yas-load-directory directory (not nojit))
1995 (yas--message 4 "Loaded %s" directory)
1996 (yas--message 4 "Prepared just-in-time loading for %s" directory)))
1998 (push (yas--message 1 "Check your `yas-snippet-dirs': %s is not a directory" directory) errors)))))
2001 (defun yas-reload-all (&optional no-jit interactive)
2002 "Reload all snippets and rebuild the YASnippet menu.
2004 When NO-JIT is non-nil force immediate reload of all known
2005 snippets under `yas-snippet-dirs', otherwise use just-in-time
2008 When called interactively, use just-in-time loading when given a
2010 (interactive (list (not current-prefix-arg) t))
2013 (snippet-editing-buffers
2014 (cl-remove-if-not (lambda (buffer)
2015 (with-current-buffer buffer
2016 yas--editing-template))
2018 ;; Warn if there are buffers visiting snippets, since reloading will break
2019 ;; any on-line editing of those buffers.
2021 (when snippet-editing-buffers
2023 (if (y-or-n-p "Some buffers editing live snippets, close them and proceed with reload? ")
2024 (mapc #'kill-buffer snippet-editing-buffers)
2025 (yas--message 1 "Aborted reload...")
2027 ;; in a non-interactive use, at least set
2028 ;; `yas--editing-template' to nil, make it guess it next time around
2029 (mapc #'(lambda (buffer)
2030 (with-current-buffer buffer
2031 (kill-local-variable 'yas--editing-template)))
2034 ;; Empty all snippet tables and parenting info
2036 (setq yas--tables (make-hash-table))
2037 (setq yas--parents (make-hash-table))
2039 ;; Before killing `yas--menu-table' use its keys to cleanup the
2040 ;; mode menu parts of `yas--minor-mode-menu' (thus also cleaning
2041 ;; up `yas-minor-mode-map', which points to it)
2043 (maphash #'(lambda (menu-symbol _keymap)
2044 (define-key yas--minor-mode-menu (vector menu-symbol) nil))
2046 ;; Now empty `yas--menu-table' as well
2047 (setq yas--menu-table (make-hash-table))
2049 ;; Cancel all pending 'yas--scheduled-jit-loads'
2051 (setq yas--scheduled-jit-loads (make-hash-table))
2053 ;; Reload the directories listed in `yas-snippet-dirs' or prompt
2054 ;; the user to select one.
2056 (setq errors (yas--load-snippet-dirs no-jit))
2057 ;; Reload the direct keybindings
2059 (yas-direct-keymaps-reload)
2061 (run-hooks 'yas-after-reload-hook)
2063 (cl-every (lambda (table) (= (hash-table-count table) 0))
2064 (list yas--scheduled-jit-loads
2065 yas--parents yas--tables))))
2066 (yas--message (if (or no-snippets errors) 2 3)
2067 (if no-jit "Snippets loaded %s."
2068 "Prepared just-in-time loading of snippets %s.")
2070 "with some errors. Check *Messages*")
2072 "(but no snippets found)")
2074 "successfully")))))))
2076 (defvar yas-after-reload-hook nil
2077 "Hooks run after `yas-reload-all'.")
2079 (defun yas--load-pending-jits ()
2080 (dolist (mode (yas--modes-to-activate))
2081 (let ((funs (reverse (gethash mode yas--scheduled-jit-loads))))
2082 ;; must reverse to maintain coherence with `yas-snippet-dirs'
2084 (yas--message 4 "Loading for `%s', just-in-time: %s!" mode fun)
2086 (remhash mode yas--scheduled-jit-loads))))
2088 (defun yas-escape-text (text)
2089 "Escape TEXT for snippet."
2091 (replace-regexp-in-string "[\\$]" "\\\\\\&" text)))
2094 ;;; Snippet compilation function
2096 (defun yas-compile-directory (top-level-dir)
2097 "Create .yas-compiled-snippets.el files under subdirs of TOP-LEVEL-DIR.
2099 This works by stubbing a few functions, then calling
2100 `yas-load-directory'."
2101 (interactive "DTop level snippet directory?")
2102 (let ((yas--creating-compiled-snippets t))
2103 (yas-load-directory top-level-dir nil)))
2105 (defun yas-recompile-all ()
2106 "Compile every dir in `yas-snippet-dirs'."
2108 (mapc #'yas-compile-directory (yas-snippet-dirs)))
2114 (defvar yas--scheduled-jit-loads (make-hash-table)
2115 "Alist of mode-symbols to forms to be evaled when `yas-minor-mode' kicks in.")
2117 (defun yas--schedule-jit (mode fun)
2118 (push fun (gethash mode yas--scheduled-jit-loads)))
2122 ;;; Some user level functions
2126 (message "yasnippet (version %s) -- pluskid/joaotavora/npostavs"
2127 (or (ignore-errors (car (let ((default-directory yas--loaddir))
2128 (process-lines "git" "describe"
2129 "--tags" "--dirty"))))
2130 (when (and (featurep 'package)
2131 (fboundp 'package-desc-version)
2132 (fboundp 'package-version-join))
2133 (defvar package-alist)
2135 (let* ((yas-pkg (cdr (assq 'yasnippet package-alist)))
2136 (version (package-version-join
2137 (package-desc-version (car yas-pkg)))))
2138 ;; Special case for MELPA's bogus version numbers.
2139 (if (string-match "\\`20..[01][0-9][0-3][0-9][.][0-9]\\{3,4\\}\\'"
2141 (concat yas--version "-snapshot" version)
2146 ;;; Apropos snippet menu:
2148 ;; The snippet menu keymaps are stored by mode in hash table called
2149 ;; `yas--menu-table'. They are linked to the main menu in
2150 ;; `yas--menu-keymap-get-create' and are initially created empty,
2151 ;; reflecting the table hierarchy.
2153 ;; They can be populated in two mutually exclusive ways: (1) by
2154 ;; reading `yas--template-group', which in turn is populated by the "#
2155 ;; group:" directives of the snippets or the ".yas-make-groups" file
2156 ;; or (2) by using a separate `yas-define-menu' call, which declares a
2157 ;; menu structure based on snippets uuids.
2159 ;; Both situations are handled in `yas--update-template-menu', which
2160 ;; uses the predicate `yas--template-menu-managed-by-yas-define-menu'
2161 ;; that can tell between the two situations.
2165 ;; * if `yas-define-menu' is used it must run before
2166 ;; `yas-define-snippets' and the UUIDS must match, otherwise we get
2167 ;; duplicate entries. The `yas--template' objects are created in
2168 ;; `yas-define-menu', holding nothing but the menu entry,
2169 ;; represented by a pair of ((menu-item NAME :keys KEYS) TYPE) and
2170 ;; stored in `yas--template-menu-binding-pair'. The (menu-item ...)
2171 ;; part is then stored in the menu keymap itself which make the item
2172 ;; appear to the user. These limitations could probably be revised.
2174 ;; * The `yas--template-perm-group' slot is only used in
2175 ;; `yas-describe-tables'.
2177 (defun yas--template-menu-binding-pair-get-create (template &optional type)
2178 "Get TEMPLATE's menu binding or assign it a new one.
2180 TYPE may be `:stay', signaling this menu binding should be
2181 static in the menu."
2182 (or (yas--template-menu-binding-pair template)
2183 (let (;; (key (yas--template-key template))
2184 ;; (keybinding (yas--template-keybinding template))
2186 (setf (yas--template-menu-binding-pair template)
2187 (cons `(menu-item ,(or (yas--template-name template)
2188 (yas--template-uuid template))
2189 ,(yas--make-menu-binding template)
2192 (defun yas--template-menu-managed-by-yas-define-menu (template)
2193 "Non-nil if TEMPLATE's menu entry was included in a `yas-define-menu' call."
2194 (cdr (yas--template-menu-binding-pair template)))
2197 (defun yas--show-menu-p (mode)
2198 (cond ((eq yas-use-menu 'abbreviate)
2200 (mapcar #'yas--table-mode
2201 (yas--get-snippet-tables))))
2204 (defun yas--delete-from-keymap (keymap uuid)
2205 "Recursively delete items with UUID from KEYMAP and its submenus."
2207 ;; XXX: This used to skip any submenus named \"parent mode\"
2209 ;; First of all, recursively enter submenus, i.e. the tree is
2210 ;; searched depth first so that stale submenus can be found in the
2213 (mapc #'(lambda (item)
2214 (when (and (consp (cdr-safe item))
2215 (keymapp (nth 2 (cdr item))))
2216 (yas--delete-from-keymap (nth 2 (cdr item)) uuid)))
2218 ;; Set the uuid entry to nil
2220 (define-key keymap (vector (make-symbol uuid)) nil)
2221 ;; Destructively modify keymap
2223 (setcdr keymap (cl-delete-if (lambda (item)
2224 (cond ((not (listp item)) nil)
2226 ((and (keymapp (nth 2 (cdr item)))
2227 (null (cdr (nth 2 (cdr item))))))))
2230 (defun yas-define-menu (mode menu &optional omit-items)
2231 "Define a snippet menu for MODE according to MENU, omitting OMIT-ITEMS.
2233 MENU is a list, its elements can be:
2235 - (yas-item UUID) : Creates an entry the snippet identified with
2236 UUID. The menu entry for a snippet thus identified is
2237 permanent, i.e. it will never move (be reordered) in the menu.
2239 - (yas-separator) : Creates a separator
2241 - (yas-submenu NAME SUBMENU) : Creates a submenu with NAME,
2242 SUBMENU has the same form as MENU. NAME is also added to the
2243 list of groups of the snippets defined thereafter.
2245 OMIT-ITEMS is a list of snippet uuids that will always be
2246 omitted from MODE's menu, even if they're manually loaded."
2247 (let* ((table (yas--table-get-create mode))
2248 (hash (yas--table-uuidhash table)))
2249 (yas--define-menu-1 table
2250 (yas--menu-keymap-get-create mode)
2253 (dolist (uuid omit-items)
2254 (let ((template (or (gethash uuid hash)
2256 (yas--make-template :table table
2259 (setf (yas--template-menu-binding-pair template) (cons nil :none))))))
2261 (defun yas--define-menu-1 (table menu-keymap menu uuidhash &optional group-list)
2262 "Helper for `yas-define-menu'."
2264 for (type name submenu) in (reverse menu)
2266 ((or (eq type 'yas-item)
2267 (and yas-alias-to-yas/prefix-p
2268 (eq type 'yas/item)))
2269 (let ((template (or (gethash name uuidhash)
2273 :perm-group group-list
2276 (car (yas--template-menu-binding-pair-get-create
2278 ((or (eq type 'yas-submenu)
2279 (and yas-alias-to-yas/prefix-p
2280 (eq type 'yas/submenu)))
2281 (let ((subkeymap (make-sparse-keymap)))
2282 (yas--define-menu-1 table subkeymap submenu uuidhash
2283 (append group-list (list name)))
2284 `(menu-item ,name ,subkeymap)))
2285 ((or (eq type 'yas-separator)
2286 (and yas-alias-to-yas/prefix-p
2287 (eq type 'yas/separator)))
2288 '(menu-item "----"))
2289 (t (yas--message 1 "Don't know anything about menu entry %s" type)
2292 finally do (push (apply #'vector menu-entries) (cdr menu-keymap))))
2294 (defun yas--define (mode key template &optional name condition group)
2295 "Define a snippet. Expanding KEY into TEMPLATE.
2297 NAME is a description to this template. Also update the menu if
2298 `yas-use-menu' is t. CONDITION is the condition attached to
2299 this snippet. If you attach a condition to a snippet, then it
2300 will only be expanded when the condition evaluated to non-nil."
2301 (yas-define-snippets mode
2302 (list (list key template name condition group))))
2304 (defun yas-hippie-try-expand (first-time?)
2305 "Integrate with hippie expand.
2307 Just put this function in `hippie-expand-try-functions-list'."
2308 (when yas-minor-mode
2309 (if (not first-time?)
2310 (let ((yas-fallback-behavior 'return-nil))
2316 ;;; Apropos condition-cache:
2321 (defmacro yas-define-condition-cache (func doc &rest body)
2322 "Define a function FUNC with doc DOC and body BODY.
2323 BODY is executed at most once every snippet expansion attempt, to check
2324 expansion conditions.
2326 It doesn't make any sense to call FUNC programatically."
2327 `(defun ,func () ,(if (and doc
2330 "\n\nFor use in snippets' conditions. Within each
2331 snippet-expansion routine like `yas-expand', computes actual
2332 value for the first time then always returns a cached value.")
2333 (setq body (cons doc body))
2335 (let ((timestamp-and-value (get ',func 'yas--condition-cache)))
2336 (if (equal (car timestamp-and-value) yas--condition-cache-timestamp)
2337 (cdr timestamp-and-value)
2338 (let ((new-value (progn
2341 (put ',func 'yas--condition-cache (cons yas--condition-cache-timestamp new-value))
2344 (defalias 'yas-expand 'yas-expand-from-trigger-key)
2345 (defun yas-expand-from-trigger-key (&optional field)
2346 "Expand a snippet before point.
2348 If no snippet expansion is possible, fall back to the behaviour
2349 defined in `yas-fallback-behavior'.
2351 Optional argument FIELD is for non-interactive use and is an
2352 object satisfying `yas--field-p' to restrict the expansion to."
2354 (setq yas--condition-cache-timestamp (current-time))
2355 (let (templates-and-pos)
2356 (unless (and yas-expand-only-for-last-commands
2357 (not (member last-command yas-expand-only-for-last-commands)))
2358 (setq templates-and-pos (if field
2360 (narrow-to-region (yas--field-start field)
2361 (yas--field-end field))
2362 (yas--templates-for-key-at-point))
2363 (yas--templates-for-key-at-point))))
2364 (if templates-and-pos
2365 (yas--expand-or-prompt-for-template
2366 (nth 0 templates-and-pos)
2367 ;; Delete snippet key and active region when expanding.
2368 (min (if (use-region-p) (region-beginning) most-positive-fixnum)
2369 (nth 1 templates-and-pos))
2370 (max (if (use-region-p) (region-end) most-negative-fixnum)
2371 (nth 2 templates-and-pos)))
2374 (defun yas--maybe-expand-from-keymap-filter (cmd)
2375 "Check whether a snippet may be expanded.
2376 If there are expandable snippets, return CMD (this is useful for
2377 conditional keybindings) or the list of expandable snippet
2378 template objects if CMD is nil (this is useful as a more general predicate)."
2379 (let* ((yas--condition-cache-timestamp (current-time))
2380 (vec (cl-subseq (this-command-keys-vector)
2381 (if current-prefix-arg
2382 (length (this-command-keys))
2384 (templates (cl-mapcan (lambda (table)
2385 (yas--fetch table vec))
2386 (yas--get-snippet-tables))))
2387 (if templates (or cmd templates))))
2389 (defun yas-expand-from-keymap ()
2390 "Directly expand some snippets, searching `yas--direct-keymaps'."
2392 (setq yas--condition-cache-timestamp (current-time))
2393 (let* ((templates (yas--maybe-expand-from-keymap-filter nil)))
2395 (yas--expand-or-prompt-for-template templates))))
2397 (defun yas--expand-or-prompt-for-template (templates &optional start end)
2398 "Expand one of TEMPLATES from START to END.
2400 Prompt the user if TEMPLATES has more than one element, else
2401 expand immediately. Common gateway for
2402 `yas-expand-from-trigger-key' and `yas-expand-from-keymap'."
2403 (let ((yas--current-template
2404 (or (and (cl-rest templates) ;; more than one
2405 (yas--prompt-for-template (mapcar #'cdr templates)))
2407 (when yas--current-template
2408 (yas-expand-snippet yas--current-template start end))))
2410 ;; Apropos the trigger key and the fallback binding:
2412 ;; When `yas-minor-mode-map' binds <tab>, that correctly overrides
2413 ;; org-mode's <tab>, for example and searching for fallbacks correctly
2414 ;; returns `org-cycle'. However, most other modes bind "TAB". TODO,
2415 ;; improve this explanation.
2417 (defun yas--fallback ()
2418 "Fallback after expansion has failed.
2420 Common gateway for `yas-expand-from-trigger-key' and
2421 `yas-expand-from-keymap'."
2422 (cond ((eq yas-fallback-behavior 'return-nil)
2425 ((eq yas-fallback-behavior 'yas--fallback)
2426 (error (concat "yasnippet fallback loop!\n"
2427 "This can happen when you bind `yas-expand' "
2428 "outside of the `yas-minor-mode-map'.")))
2429 ((eq yas-fallback-behavior 'call-other-command)
2430 (let* ((yas-fallback-behavior 'yas--fallback)
2431 ;; Also bind `yas-minor-mode' to prevent fallback
2432 ;; loops when other extensions use mechanisms similar
2433 ;; to `yas--keybinding-beyond-yasnippet'. (github #525
2436 (yas-minor-mode nil)
2437 (beyond-yasnippet (yas--keybinding-beyond-yasnippet)))
2438 (yas--message 4 "Falling back to %s" beyond-yasnippet)
2439 (cl-assert (or (null beyond-yasnippet) (commandp beyond-yasnippet)))
2440 (setq this-command beyond-yasnippet)
2441 (when beyond-yasnippet
2442 (call-interactively beyond-yasnippet))))
2443 ((and (listp yas-fallback-behavior)
2444 (cdr yas-fallback-behavior)
2445 (eq 'apply (car yas-fallback-behavior)))
2446 (let ((command-or-fn (cadr yas-fallback-behavior))
2447 (args (cddr yas-fallback-behavior))
2448 (yas-fallback-behavior 'yas--fallback)
2449 (yas-minor-mode nil))
2451 (apply command-or-fn args)
2452 (when (commandp command-or-fn)
2453 (setq this-command command-or-fn)
2454 (call-interactively command-or-fn)))))
2456 ;; also return nil if all the other fallbacks have failed
2459 (defun yas--keybinding-beyond-yasnippet ()
2460 "Get current keys's binding as if YASsnippet didn't exist."
2461 (let* ((yas-minor-mode nil)
2462 (yas--direct-keymaps nil)
2463 (keys (this-single-command-keys)))
2464 (or (key-binding keys t)
2465 (key-binding (yas--fallback-translate-input keys) t))))
2467 (defun yas--fallback-translate-input (keys)
2468 "Emulate `read-key-sequence', at least what I think it does.
2470 Keys should be an untranslated key vector. Returns a translated
2471 vector of keys. FIXME not thoroughly tested."
2474 (while (< i (length keys))
2476 (translated local-function-key-map))
2477 (while (and (< j (length keys))
2479 (keymapp translated))
2480 (setq translated (cdr (assoc (aref keys j) (remove 'keymap translated)))
2482 (setq retval (vconcat retval (cond ((symbolp translated)
2484 ((vectorp translated)
2487 (substring keys i j)))))
2492 ;;; Utils for snippet development:
2494 (defun yas--all-templates (tables)
2495 "Get `yas--template' objects in TABLES, applicable for buffer and point.
2497 Honours `yas-choose-tables-first', `yas-choose-keys-first' and
2498 `yas-buffer-local-condition'"
2499 (when yas-choose-tables-first
2500 (setq tables (list (yas--prompt-for-table tables))))
2502 (if yas-choose-keys-first
2503 (let ((key (yas--prompt-for-keys
2504 (cl-mapcan #'yas--table-all-keys tables))))
2506 (cl-mapcan (lambda (table)
2507 (yas--fetch table key))
2509 (cl-remove-duplicates (cl-mapcan #'yas--table-templates tables)
2512 (defun yas--lookup-snippet-1 (name mode)
2513 "Get the snippet called NAME in MODE's tables."
2514 (let ((yas-choose-tables-first nil) ; avoid prompts
2515 (yas-choose-keys-first nil))
2516 (cl-find name (yas--all-templates
2517 (yas--get-snippet-tables mode))
2518 :key #'yas--template-name :test #'string=)))
2520 (defun yas-lookup-snippet (name &optional mode noerror)
2521 "Get the snippet named NAME in MODE's tables.
2523 MODE defaults to the current buffer's `major-mode'. If NOERROR
2524 is non-nil, then don't signal an error if there isn't any snippet
2527 Honours `yas-buffer-local-condition'."
2529 ((yas--lookup-snippet-1 name mode))
2531 (t (error "No snippet named: %s" name))))
2533 (defun yas-insert-snippet (&optional no-condition)
2534 "Choose a snippet to expand, pop-up a list of choices according
2535 to `yas-prompt-functions'.
2537 With prefix argument NO-CONDITION, bypass filtering of snippets
2540 (setq yas--condition-cache-timestamp (current-time))
2541 (let* ((yas-buffer-local-condition (or (and no-condition
2543 yas-buffer-local-condition))
2544 (templates (yas--all-templates (yas--get-snippet-tables)))
2545 (yas--current-template (and templates
2546 (or (and (cl-rest templates) ;; more than one template for same key
2547 (yas--prompt-for-template templates))
2549 (where (if (region-active-p)
2550 (cons (region-beginning) (region-end))
2551 (cons (point) (point)))))
2552 (if yas--current-template
2553 (yas-expand-snippet yas--current-template (car where) (cdr where))
2554 (yas--message 1 "No snippets can be inserted here!"))))
2556 (defun yas-visit-snippet-file ()
2557 "Choose a snippet to edit, selection like `yas-insert-snippet'.
2559 Only success if selected snippet was loaded from a file. Put the
2560 visited file in `snippet-mode'."
2562 (let* ((yas-buffer-local-condition 'always)
2563 (templates (yas--all-templates (yas--get-snippet-tables)))
2564 (template (and templates
2565 (or (yas--prompt-for-template templates
2566 "Choose a snippet template to edit: ")
2570 (yas--visit-snippet-file-1 template)
2571 (message "No snippets tables active!"))))
2573 (defun yas--visit-snippet-file-1 (template)
2574 "Helper for `yas-visit-snippet-file'."
2575 (let ((file (yas--template-get-file template)))
2576 (cond ((and file (file-readable-p file))
2577 (find-file-other-window file)
2579 (set (make-local-variable 'yas--editing-template) template))
2581 (message "Original file %s no longer exists!" file))
2583 (switch-to-buffer (format "*%s*"(yas--template-name template)))
2584 (let ((type 'snippet))
2585 (when (listp (yas--template-content template))
2586 (insert (format "# type: command\n"))
2587 (setq type 'command))
2588 (insert (format "# key: %s\n" (yas--template-key template)))
2589 (insert (format "# name: %s\n" (yas--template-name template)))
2590 (when (yas--template-keybinding template)
2591 (insert (format "# binding: %s\n" (yas--template-keybinding template))))
2592 (when (yas--template-expand-env template)
2593 (insert (format "# expand-env: %s\n" (yas--template-expand-env template))))
2594 (when (yas--template-condition template)
2595 (insert (format "# condition: %s\n" (yas--template-condition template))))
2597 (insert (if (eq type 'command)
2598 (pp-to-string (yas--template-content template))
2599 (yas--template-content template))))
2601 (set (make-local-variable 'yas--editing-template) template)
2602 (set (make-local-variable 'default-directory)
2603 (car (cdr (car (yas--guess-snippet-directories (yas--template-table template))))))))))
2605 (defun yas--guess-snippet-directories-1 (table)
2606 "Guess possible snippet subdirectories for TABLE."
2607 (cons (file-name-as-directory (yas--table-name table))
2608 (cl-mapcan #'yas--guess-snippet-directories-1
2609 (yas--table-parents table))))
2611 (defun yas--guess-snippet-directories (&optional table)
2612 "Try to guess suitable directories based on the current active
2613 tables (or optional TABLE).
2615 Returns a list of elements (TABLE . DIRS) where TABLE is a
2616 `yas--table' object and DIRS is a list of all possible directories
2617 where snippets of table might exist."
2618 (let ((main-dir (car (or (yas-snippet-dirs)
2619 (setq yas-snippet-dirs
2620 (list yas--default-user-snippets-dir)))))
2621 (tables (if table (list table)
2622 (yas--get-snippet-tables))))
2623 ;; HACK! the snippet table created here is actually registered!
2625 ;; The major mode is probably the best guess, put it first.
2626 (let ((major-mode-table (yas--table-get-create major-mode)))
2627 (cl-callf2 delq major-mode-table tables)
2628 (push major-mode-table tables)))
2630 (mapcar #'(lambda (table)
2632 (mapcar #'(lambda (subdir)
2633 (expand-file-name subdir main-dir))
2634 (yas--guess-snippet-directories-1 table))))
2637 (defun yas--make-directory-maybe (table-and-dirs &optional main-table-string)
2638 "Return a dir inside TABLE-AND-DIRS, prompts for creation if none exists."
2639 (or (cl-some (lambda (dir) (when (file-directory-p dir) dir))
2640 (cdr table-and-dirs))
2641 (let ((candidate (cl-first (cdr table-and-dirs))))
2642 (unless (file-writable-p (file-name-directory candidate))
2643 (error (yas--format "%s is not writable." candidate)))
2644 (if (y-or-n-p (format "Guessed directory (%s) for%s%s table \"%s\" does not exist! Create? "
2646 (if (gethash (yas--table-mode (car table-and-dirs))
2650 (or main-table-string
2652 (yas--table-name (car table-and-dirs))))
2654 (make-directory candidate 'also-make-parents)
2655 ;; create the .yas-parents file here...
2658 ;; NOTE: Using the traditional "*new snippet*" stops whitespace mode
2659 ;; from activating (it doesn't like the leading "*").
2660 (defconst yas-new-snippet-buffer-name "+new-snippet+")
2662 (defun yas-new-snippet (&optional no-template)
2663 "Pops a new buffer for writing a snippet.
2665 Expands a snippet-writing snippet, unless the optional prefix arg
2666 NO-TEMPLATE is non-nil."
2668 (let ((guessed-directories (yas--guess-snippet-directories))
2669 (yas-selected-text (or yas-selected-text
2670 (and (region-active-p)
2671 (buffer-substring-no-properties
2672 (region-beginning) (region-end))))))
2674 (switch-to-buffer yas-new-snippet-buffer-name)
2676 (kill-all-local-variables)
2679 (set (make-local-variable 'yas--guessed-modes)
2680 (mapcar (lambda (d) (yas--table-mode (car d)))
2681 guessed-directories))
2682 (set (make-local-variable 'default-directory)
2683 (car (cdr (car guessed-directories))))
2684 (if (and (not no-template) yas-new-snippet-default)
2685 (yas-expand-snippet yas-new-snippet-default))))
2687 (defun yas--compute-major-mode-and-parents (file)
2688 "Given FILE, find the nearest snippet directory for a given mode.
2690 Returns a list (MODE-SYM PARENTS), the mode's symbol and a list
2691 representing one or more of the mode's parents.
2693 Note that MODE-SYM need not be the symbol of a real major mode,
2694 neither do the elements of PARENTS."
2695 (let* ((file-dir (and file
2696 (directory-file-name
2697 (or (cl-some (lambda (special)
2698 (locate-dominating-file file special))
2702 (directory-file-name (file-name-directory file))))))
2703 (parents-file-name (concat file-dir "/.yas-parents"))
2704 (major-mode-name (and file-dir
2705 (file-name-nondirectory file-dir)))
2706 (major-mode-sym (or (and major-mode-name
2707 (intern major-mode-name))))
2708 (parents (when (file-readable-p parents-file-name)
2712 (insert-file-contents parents-file-name)
2713 (buffer-substring-no-properties (point-min)
2715 (when major-mode-sym
2716 (cons major-mode-sym (remove major-mode-sym parents)))))
2718 (defvar yas--editing-template nil
2719 "Supporting variable for `yas-load-snippet-buffer' and `yas--visit-snippet'.")
2721 (defvar yas--current-template nil
2722 "Holds the current template being expanded into a snippet.")
2724 (defvar yas--guessed-modes nil
2725 "List of guessed modes supporting `yas-load-snippet-buffer'.")
2727 (defun yas--read-table ()
2728 "Ask user for a snippet table, help with some guessing."
2729 (let ((prompt (if (and (featurep 'ido)
2731 'ido-completing-read 'completing-read)))
2732 (unless yas--guessed-modes
2733 (set (make-local-variable 'yas--guessed-modes)
2734 (or (yas--compute-major-mode-and-parents buffer-file-name))))
2736 (funcall prompt (format "Choose or enter a table (yas guesses %s): "
2737 (if yas--guessed-modes
2738 (cl-first yas--guessed-modes)
2740 (mapcar #'symbol-name yas--guessed-modes)
2745 (if (cl-first yas--guessed-modes)
2746 (symbol-name (cl-first yas--guessed-modes)))))))
2748 (defun yas-load-snippet-buffer (table &optional interactive)
2749 "Parse and load current buffer's snippet definition into TABLE.
2750 TABLE is a symbol name passed to `yas--table-get-create'. When
2751 called interactively, prompt for the table name.
2752 Return the `yas--template' object created"
2753 (interactive (list (yas--read-table) t))
2755 ;; We have `yas--editing-template', this buffer's content comes from a
2756 ;; template which is already loaded and neatly positioned,...
2758 (yas--editing-template
2759 (yas--define-snippets-1 (yas--parse-template (yas--template-load-file yas--editing-template))
2760 (yas--template-table yas--editing-template)))
2761 ;; Try to use `yas--guessed-modes'. If we don't have that use the
2762 ;; value from `yas--compute-major-mode-and-parents'
2765 (unless yas--guessed-modes
2766 (set (make-local-variable 'yas--guessed-modes) (or (yas--compute-major-mode-and-parents buffer-file-name))))
2767 (let* ((table (yas--table-get-create table)))
2768 (set (make-local-variable 'yas--editing-template)
2769 (yas--define-snippets-1 (yas--parse-template buffer-file-name)
2772 (yas--message 3 "Snippet \"%s\" loaded for %s."
2773 (yas--template-name yas--editing-template)
2774 (yas--table-name (yas--template-table yas--editing-template))))
2775 yas--editing-template)
2777 (defun yas-maybe-load-snippet-buffer ()
2778 "Added to `after-save-hook' in `snippet-mode'."
2779 (let* ((mode (intern (file-name-sans-extension
2780 (file-name-nondirectory
2781 (directory-file-name default-directory)))))
2783 (apply #'yas--define-snippets-2 (yas--table-get-create mode)
2784 (yas--parse-template buffer-file-name)))
2785 (uuid (yas--template-uuid current-snippet)))
2786 (unless (equal current-snippet
2787 (if uuid (yas--get-template-by-uuid mode uuid)
2788 (yas--lookup-snippet-1
2789 (yas--template-name current-snippet) mode)))
2790 (yas-load-snippet-buffer mode t))))
2792 (defun yas-load-snippet-buffer-and-close (table &optional kill)
2793 "Load and save the snippet, then `quit-window' if saved.
2794 Loading is performed by `yas-load-snippet-buffer'. If the
2795 snippet is new, ask the user whether (and where) to save it. If
2796 the snippet already has a file, just save it.
2798 The prefix argument KILL is passed to `quit-window'.
2800 Don't use this from a Lisp program, call `yas-load-snippet-buffer'
2801 and `kill-buffer' instead."
2802 (interactive (list (yas--read-table) current-prefix-arg))
2803 (let ((template (yas-load-snippet-buffer table t)))
2804 (when (and (buffer-modified-p)
2806 (format "[yas] Loaded for %s. Also save snippet buffer?"
2807 (yas--table-name (yas--template-table template)))))
2808 (let ((default-directory (car (cdr (car (yas--guess-snippet-directories
2809 (yas--template-table template))))))
2810 (default-file-name (yas--template-name template)))
2811 (unless (or buffer-file-name (not default-file-name))
2812 (setq buffer-file-name
2813 (read-file-name "File to save snippet in: "
2814 nil nil nil default-file-name))
2815 (rename-buffer (file-name-nondirectory buffer-file-name) t))
2817 (quit-window kill)))
2819 (declare-function yas-debug-snippets "yasnippet-debug")
2821 (defun yas-tryout-snippet (&optional debug)
2822 "Test current buffer's snippet template in other buffer.
2823 DEBUG is for debugging the YASnippet engine itself."
2825 (let* ((major-mode-and-parent (yas--compute-major-mode-and-parents buffer-file-name))
2826 (parsed (yas--parse-template))
2827 (test-mode (or (and (car major-mode-and-parent)
2828 (fboundp (car major-mode-and-parent))
2829 (car major-mode-and-parent))
2830 (cl-first yas--guessed-modes)
2831 (intern (read-from-minibuffer (yas--format "Please input a mode: ")))))
2832 (yas--current-template
2835 (yas--make-template :table nil ;; no tables for ephemeral snippets
2837 :content (nth 1 parsed)
2838 :name (nth 2 parsed)
2839 :expand-env (nth 5 parsed)))))
2840 (cond (yas--current-template
2842 (format "*testing snippet: %s*"
2843 (yas--template-name yas--current-template))))
2844 (kill-buffer (get-buffer-create buffer-name))
2845 (switch-to-buffer (get-buffer-create buffer-name))
2846 (setq buffer-undo-list nil)
2847 (condition-case nil (funcall test-mode) (error nil))
2849 (setq buffer-read-only nil)
2850 (yas-expand-snippet yas--current-template
2851 (point-min) (point-max))
2853 (require 'yasnippet-debug nil t))
2854 (yas-debug-snippets "*YASnippet trace*" 'snippet-navigation)
2855 (display-buffer "*YASnippet trace*"))))
2857 (yas--message 1 "Cannot test snippet for unknown major mode")))))
2859 (defun yas-active-keys ()
2860 "Return all active trigger keys for current buffer and point."
2861 (cl-remove-duplicates
2862 (cl-remove-if-not #'stringp (cl-mapcan #'yas--table-all-keys
2863 (yas--get-snippet-tables)))
2866 (defun yas--template-fine-group (template)
2867 (car (last (or (yas--template-group template)
2868 (yas--template-perm-group template)))))
2870 (defun yas-describe-table-by-namehash ()
2871 "Display snippet tables by NAMEHASH."
2873 (with-current-buffer (get-buffer-create "*YASnippet Tables by NAMEHASH*")
2874 (let ((inhibit-read-only t))
2876 (insert "YASnippet tables by NAMEHASH: \n")
2878 (lambda (_mode table)
2879 (insert (format "\nSnippet table `%s':\n\n" (yas--table-name table)))
2882 (insert (format " key %s maps snippets: %s\n" key
2884 (maphash #'(lambda (k _v)
2886 (gethash key (yas--table-hash table)))
2888 (yas--table-hash table)))
2892 (display-buffer (current-buffer))))
2894 (defun yas-describe-tables (&optional with-nonactive)
2895 "Display snippets for each table."
2897 (let ((original-buffer (current-buffer))
2898 (tables (yas--get-snippet-tables)))
2899 (with-current-buffer (get-buffer-create "*YASnippet Tables*")
2900 (let ((inhibit-read-only t))
2901 (when with-nonactive
2902 (maphash #'(lambda (_k v)
2903 (cl-pushnew v tables))
2906 (insert "YASnippet tables:\n")
2907 (dolist (table tables)
2908 (yas--describe-pretty-table table original-buffer))
2909 (yas--create-snippet-xrefs))
2912 (display-buffer (current-buffer)))))
2914 (defun yas--describe-pretty-table (table &optional original-buffer)
2915 (insert (format "\nSnippet table `%s'"
2916 (yas--table-name table)))
2917 (if (yas--table-parents table)
2918 (insert (format " parents: %s\n"
2919 (mapcar #'yas--table-name
2920 (yas--table-parents table))))
2922 (insert (make-string 100 ?-) "\n")
2923 (insert "group state name key binding\n")
2924 (let ((groups-hash (make-hash-table :test #'equal)))
2925 (maphash #'(lambda (_k v)
2926 (let ((group (or (yas--template-fine-group v)
2928 (when (yas--template-name v)
2930 (cons v (gethash group groups-hash))
2932 (yas--table-uuidhash table))
2934 #'(lambda (group templates)
2935 (setq group (truncate-string-to-width group 25 0 ? "..."))
2936 (insert (make-string 100 ?-) "\n")
2937 (dolist (p templates)
2938 (let* ((name (truncate-string-to-width (propertize (format "\\\\snippet `%s'" (yas--template-name p))
2942 (setq group (make-string (length group) ? ))))
2943 (condition-string (let ((condition (yas--template-condition p)))
2946 (with-current-buffer original-buffer
2947 (if (yas--eval-condition condition)
2951 (key-description-string (key-description (yas--template-keybinding p)))
2952 (template-key-padding (if (string= key-description-string "") nil ? )))
2954 condition-string " "
2955 name (if (string-match "\\.\\.\\.$" name)
2958 (truncate-string-to-width (or (yas--template-key p) "")
2959 15 0 template-key-padding "...")
2960 (or template-key-padding "")
2961 (truncate-string-to-width key-description-string
2968 ;;; User convenience functions, for using in `yas-key-syntaxes'
2970 (defun yas-try-key-from-whitespace (_start-point)
2971 "As `yas-key-syntaxes' element, look for whitespace delimited key.
2973 A newline will be considered whitespace even if the mode syntax
2974 marks it as something else (typically comment ender)."
2975 (skip-chars-backward "^[:space:]\n"))
2977 (defun yas-shortest-key-until-whitespace (_start-point)
2978 "Like `yas-longest-key-from-whitespace' but take the shortest key."
2979 (when (/= (skip-chars-backward "^[:space:]\n" (1- (point))) 0)
2982 (defun yas-longest-key-from-whitespace (start-point)
2983 "As `yas-key-syntaxes' element, look for longest key between point and whitespace.
2985 A newline will be considered whitespace even if the mode syntax
2986 marks it as something else (typically comment ender)."
2987 (if (= (point) start-point)
2988 (yas-try-key-from-whitespace start-point)
2990 (unless (<= start-point (1+ (point)))
2995 ;;; User convenience functions, for using in snippet definitions
2997 (defvar yas-modified-p nil
2998 "Non-nil if field has been modified by user or transformation.")
3000 (defvar yas-moving-away-p nil
3001 "Non-nil if user is about to exit field.")
3003 (defvar yas-text nil
3004 "Contains current field text.")
3006 (defun yas-substr (str pattern &optional subexp)
3007 "Search PATTERN in STR and return SUBEXPth match.
3009 If found, the content of subexp group SUBEXP (default 0) is
3010 returned, or else the original STR will be returned."
3011 (let ((grp (or subexp 0)))
3013 (if (string-match pattern str)
3014 (match-string-no-properties grp str)
3017 (defun yas-choose-value (&rest possibilities)
3018 "Prompt for a string in POSSIBILITIES and return it.
3020 The last element of POSSIBILITIES may be a list of strings."
3021 (unless (or yas-moving-away-p
3023 (let* ((last-link (last possibilities))
3024 (last-elem (car last-link)))
3025 (when (listp last-elem)
3026 (setcar last-link (car last-elem))
3027 (setcdr last-link (cdr last-elem))))
3028 (cl-some (lambda (fn)
3029 (funcall fn "Choose: " possibilities))
3030 yas-prompt-functions)))
3032 (defun yas-completing-read (&rest args)
3033 "A snippet-aware version of `completing-read'.
3034 This can be used to query the user for the initial value of a
3035 snippet field. The arguments are the same as `completing-read'.
3037 \(fn PROMPT COLLECTION &optional PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF INHERIT-INPUT-METHOD)"
3038 (unless (or yas-moving-away-p
3040 (apply #'completing-read args)))
3042 (defun yas--auto-next ()
3043 "Helper for `yas-auto-next'."
3045 do (progn (remove-hook 'post-command-hook #'yas--auto-next t)
3047 ;; The transform in the next field may have requested auto-next as
3048 ;; well. Call it ourselves, since the command loop itself won't
3049 ;; recheck the value of post-command-hook while running it.
3050 while (memq #'yas--auto-next post-command-hook)))
3052 (defmacro yas-auto-next (&rest body)
3053 "Automatically advance to next field after eval'ing BODY."
3054 (declare (indent 0) (debug t))
3055 `(unless yas-moving-away-p
3057 (add-hook 'post-command-hook #'yas--auto-next nil t))))
3059 (defun yas-key-to-value (alist)
3060 (unless (or yas-moving-away-p
3062 (let ((key (read-key-sequence "")))
3064 (or (cdr (cl-find key alist :key #'car :test #'string=))
3067 (defun yas-throw (text)
3068 "Signal `yas-exception' with TEXT as the reason."
3069 (signal 'yas-exception (list text)))
3070 (put 'yas-exception 'error-conditions '(error yas-exception))
3071 (put 'yas-exception 'error-message "[yas] Exception")
3073 (defun yas-verify-value (possibilities)
3074 "Verify that the current field value is in POSSIBILITIES.
3075 Otherwise signal `yas-exception'."
3076 (when (and yas-moving-away-p (not (member yas-text possibilities)))
3077 (yas-throw (format "Field only allows %s" possibilities))))
3079 (defun yas-field-value (number)
3080 "Get the string for field with NUMBER.
3082 Use this in primary and mirror transformations to get the text of
3084 (let* ((snippet (car (yas-active-snippets)))
3086 (yas--snippet-find-field snippet number))))
3088 (yas--field-text-for-display field))))
3091 "Return `yas-text' if that exists and is non-empty, else nil."
3093 (not (string= "" yas-text)))
3096 (defun yas-selected-text ()
3097 "Return `yas-selected-text' if that exists and is non-empty, else nil."
3098 (if (and yas-selected-text
3099 (not (string= "" yas-selected-text)))
3102 (defun yas--get-field-once (number &optional transform-fn)
3103 (unless yas-modified-p
3105 (funcall transform-fn (yas-field-value number))
3106 (yas-field-value number))))
3108 (defun yas-default-from-field (number)
3109 (unless yas-modified-p
3110 (yas-field-value number)))
3112 (defun yas-inside-string ()
3113 "Return non-nil if the point is inside a string according to font-lock."
3114 (equal 'font-lock-string-face (get-char-property (1- (point)) 'face)))
3116 (defun yas-unimplemented (&optional missing-feature)
3117 (if yas--current-template
3118 (if (y-or-n-p (format "This snippet is unimplemented (missing %s) Visit the snippet definition? "
3121 (yas--visit-snippet-file-1 yas--current-template))
3122 (message "No implementation. Missing %s" (or missing-feature "something"))))
3125 ;;; Snippet expansion and field management
3127 (defvar yas--active-field-overlay nil
3128 "Overlays the currently active field.")
3130 (defvar yas--active-snippets nil
3131 "List of currently active snippets")
3132 (make-variable-buffer-local 'yas--active-snippets)
3134 (defvar yas--field-protection-overlays nil
3135 "Two overlays protect the current active field.")
3137 (defvar yas-selected-text nil
3138 "The selected region deleted on the last snippet expansion.")
3140 (defvar yas--start-column nil
3141 "The column where the snippet expansion started.")
3143 (make-variable-buffer-local 'yas--active-field-overlay)
3144 (make-variable-buffer-local 'yas--field-protection-overlays)
3145 (put 'yas--active-field-overlay 'permanent-local t)
3146 (put 'yas--field-protection-overlays 'permanent-local t)
3148 (cl-defstruct (yas--snippet (:constructor yas--make-snippet (expand-env)))
3155 (id (yas--snippet-next-id) :read-only t)
3156 (control-overlay nil)
3158 ;; stacked expansion: the `previous-active-field' slot saves the
3159 ;; active field where the child expansion took place
3160 previous-active-field
3163 (cl-defstruct (yas--field (:constructor yas--make-field (number start end parent-field)))
3166 NUMBER is the field number.
3167 START and END are mostly buffer markers, but see \"apropos markers-to-points\".
3168 PARENT-FIELD is a `yas--field' this field is nested under, or nil.
3169 MIRRORS is a list of `yas--mirror's
3170 TRANSFORM is a lisp form.
3171 MODIFIED-P is a boolean set to true once user inputs text.
3172 NEXT is another `yas--field' or `yas--mirror' or `yas--exit'.
3183 (cl-defstruct (yas--mirror (:constructor yas--make-mirror (start end transform)))
3186 START and END are mostly buffer markers, but see \"apropos markers-to-points\".
3187 TRANSFORM is a lisp form.
3188 PARENT-FIELD is a `yas--field' this mirror is nested under, or nil.
3189 NEXT is another `yas--field' or `yas--mirror' or `yas--exit'
3190 DEPTH is a count of how many nested mirrors can affect this mirror"
3197 (cl-defstruct (yas--exit (:constructor yas--make-exit (marker)))
3201 (defmacro yas--letenv (env &rest body)
3202 "Evaluate BODY with bindings from ENV.
3203 ENV is a lisp expression that evaluates to list of elements with
3204 the form (VAR FORM), where VAR is a symbol and FORM is a lisp
3205 expression that evaluates to its value."
3206 (declare (debug (form body)) (indent 1))
3207 (let ((envvar (make-symbol "envvar")))
3208 `(let ((,envvar ,env))
3210 (mapcar #'car ,envvar)
3211 (mapcar (lambda (v-f) (eval (cadr v-f))) ,envvar)
3214 (defun yas--snippet-map-markers (fun snippet)
3215 "Apply FUN to all marker (sub)fields in SNIPPET.
3216 Update each field with the result of calling FUN."
3217 (dolist (field (yas--snippet-fields snippet))
3218 (setf (yas--field-start field) (funcall fun (yas--field-start field)))
3219 (setf (yas--field-end field) (funcall fun (yas--field-end field)))
3220 (dolist (mirror (yas--field-mirrors field))
3221 (setf (yas--mirror-start mirror) (funcall fun (yas--mirror-start mirror)))
3222 (setf (yas--mirror-end mirror) (funcall fun (yas--mirror-end mirror)))))
3223 (let ((snippet-exit (yas--snippet-exit snippet)))
3225 (setf (yas--exit-marker snippet-exit)
3226 (funcall fun (yas--exit-marker snippet-exit))))))
3228 (defun yas--snippet-live-p (snippet)
3229 "Return non-nil if SNIPPET hasn't been committed."
3231 (yas--snippet-map-markers (lambda (m)
3237 (defun yas--apply-transform (field-or-mirror field &optional empty-on-nil-p)
3238 "Calculate transformed string for FIELD-OR-MIRROR from FIELD.
3240 If there is no transform for ht field, return nil.
3242 If there is a transform but it returns nil, return the empty
3243 string iff EMPTY-ON-NIL-P is true."
3244 (let* ((yas-text (yas--field-text-for-display field))
3245 (yas-modified-p (yas--field-modified-p field))
3246 (transform (if (yas--mirror-p field-or-mirror)
3247 (yas--mirror-transform field-or-mirror)
3248 (yas--field-transform field-or-mirror)))
3249 (start-point (if (yas--mirror-p field-or-mirror)
3250 (yas--mirror-start field-or-mirror)
3251 (yas--field-start field-or-mirror)))
3252 (transformed (and transform
3254 (goto-char start-point)
3255 (let ((ret (yas--eval-for-string transform)))
3256 (or ret (and empty-on-nil-p "")))))))
3259 (defsubst yas--replace-all (from to &optional text)
3260 "Replace all occurrences from FROM to TO.
3262 With optional string TEXT do it in that string."
3264 (replace-regexp-in-string (regexp-quote from) to text t t)
3265 (goto-char (point-min))
3266 (while (search-forward from nil t)
3267 (replace-match to t t text))))
3269 (defun yas--snippet-find-field (snippet number)
3270 (cl-find-if (lambda (field)
3271 (eq number (yas--field-number field)))
3272 (yas--snippet-fields snippet)))
3274 (defun yas--snippet-sort-fields (snippet)
3275 "Sort the fields of SNIPPET in navigation order."
3276 (setf (yas--snippet-fields snippet)
3277 (sort (yas--snippet-fields snippet)
3278 #'yas--snippet-field-compare)))
3280 (defun yas--snippet-field-compare (field1 field2)
3281 "Compare FIELD1 and FIELD2.
3283 The field with a number is sorted first. If they both have a
3284 number, compare through the number. If neither have, compare
3285 through the field's start point"
3286 (let ((n1 (yas--field-number field1))
3287 (n2 (yas--field-number field2)))
3290 (or (zerop n2) (and (not (zerop n1))
3295 (< (yas--field-start field1)
3296 (yas--field-start field2))))))
3298 (defun yas--field-probably-deleted-p (snippet field)
3299 "Guess if SNIPPET's FIELD should be skipped."
3301 ;; field must be zero length
3303 (zerop (- (yas--field-start field) (yas--field-end field)))
3304 ;; field must have been modified
3306 (yas--field-modified-p field)
3309 ;; 1) it's a nested field
3311 (yas--field-parent-field field)
3312 ;; 2) ends just before the snippet end
3314 (and (eq field (car (last (yas--snippet-fields snippet))))
3315 (= (yas--field-start field) (overlay-end (yas--snippet-control-overlay snippet)))))
3316 ;; the field numbered 0, just before the exit marker, should
3319 (not (and (yas--field-number field)
3320 (zerop (yas--field-number field))))))
3322 (defun yas-active-snippets (&optional beg end)
3323 "Return a sorted list of active snippets.
3324 The most recently-inserted snippets are returned first.
3326 Only snippets overlapping the region BEG ... END are returned.
3327 Overlapping has the same meaning as described in `overlays-in'.
3328 If END is omitted, it defaults to (1+ BEG). If BEG is omitted,
3329 it defaults to point. A non-nil, non-buffer position BEG is
3330 equivalent to a range covering the whole buffer."
3333 (cond ((not (or (integerp beg) (markerp beg)))
3334 (setq beg (point-min) end (point-max)))
3336 (setq end (1+ beg))))
3337 (if (and (eq beg (point-min))
3338 (eq end (point-max)))
3339 yas--active-snippets
3340 ;; Note: don't use `mapcar' here, since it would allocate in
3341 ;; proportion to the amount of overlays, even though the list of
3342 ;; active snippets should be very small.
3343 (let ((snippets nil))
3344 (dolist (ov (overlays-in beg end))
3345 (let ((snippet (overlay-get ov 'yas--snippet)))
3346 ;; Snippets have multiple overlays, so check for dups.
3347 (when (and snippet (not (memq snippet snippets)))
3348 (push snippet snippets))))
3349 (cl-sort snippets #'>= :key #'yas--snippet-id))))
3351 (define-obsolete-function-alias 'yas--snippets-at-point
3352 'yas-active-snippets "0.12")
3354 (defun yas-next-field-or-maybe-expand ()
3355 "Try to expand a snippet at a key before point.
3357 Otherwise delegate to `yas-next-field'."
3359 (if yas-triggers-in-field
3360 (let ((yas-fallback-behavior 'return-nil)
3361 (active-field (overlay-get yas--active-field-overlay 'yas--field)))
3363 (unless (yas-expand-from-trigger-key active-field)
3367 (defun yas-next-field-will-exit-p (&optional arg)
3368 "Return non-nil if (yas-next-field ARG) would exit the current snippet."
3369 (let ((snippet (car (yas-active-snippets)))
3370 (active (overlay-get yas--active-field-overlay 'yas--field)))
3372 (not (yas--find-next-field arg snippet active)))))
3374 (defun yas--find-next-field (n snippet active)
3375 "Return the Nth field after the ACTIVE one in SNIPPET."
3376 (let ((live-fields (cl-remove-if
3378 (and (not (eq field active))
3379 (yas--field-probably-deleted-p snippet field)))
3380 (yas--snippet-fields snippet))))
3381 (nth (abs n) (memq active (if (>= n 0) live-fields (reverse live-fields))))))
3383 (defun yas-next-field (&optional arg)
3384 "Navigate to the ARGth next field.
3386 If there's none, exit the snippet."
3388 (unless arg (setq arg 1))
3389 (let* ((active-field (overlay-get yas--active-field-overlay 'yas--field))
3390 (snippet (car (yas-active-snippets (yas--field-start active-field)
3391 (yas--field-end active-field))))
3392 (target-field (yas--find-next-field arg snippet active-field)))
3393 (yas--letenv (yas--snippet-expand-env snippet)
3394 ;; Apply transform to active field.
3396 (let ((yas-moving-away-p t))
3397 (when (yas--field-update-display active-field)
3398 (yas--update-mirrors snippet))))
3399 ;; Now actually move...
3401 (yas--move-to-field snippet target-field)
3402 (yas-exit-snippet snippet)))))
3404 (defun yas--place-overlays (snippet field)
3405 "Correctly place overlays for SNIPPET's FIELD."
3406 (yas--make-move-field-protection-overlays snippet field)
3407 ;; Only move active field overlays if this is field is from the
3408 ;; innermost snippet.
3409 (when (eq snippet (car (yas-active-snippets (1- (yas--field-start field))
3410 (1+ (yas--field-end field)))))
3411 (yas--make-move-active-field-overlay snippet field)))
3413 (defun yas--move-to-field (snippet field)
3414 "Update SNIPPET to move to field FIELD.
3416 Also create some protection overlays"
3417 (goto-char (yas--field-start field))
3418 (yas--place-overlays snippet field)
3419 (overlay-put yas--active-field-overlay 'yas--snippet snippet)
3420 (overlay-put yas--active-field-overlay 'yas--field field)
3421 (let ((number (yas--field-number field)))
3422 ;; check for the special ${0: ...} field
3423 (if (and number (zerop number))
3425 (set-mark (yas--field-end field))
3426 (setf (yas--snippet-force-exit snippet)
3427 (or (yas--field-transform field)
3429 ;; make this field active
3430 (setf (yas--snippet-active-field snippet) field)
3431 ;; primary field transform: first call to snippet transform
3432 (unless (yas--field-modified-p field)
3433 (if (yas--field-update-display field)
3434 (yas--update-mirrors snippet)
3435 (setf (yas--field-modified-p field) nil))))))
3437 (defun yas-prev-field ()
3438 "Navigate to prev field. If there's none, exit the snippet."
3440 (yas-next-field -1))
3442 (defun yas-abort-snippet (&optional snippet)
3444 (let ((snippet (or snippet
3445 (car (yas-active-snippets)))))
3447 (setf (yas--snippet-force-exit snippet) t))))
3449 (defun yas-exit-snippet (snippet)
3450 "Goto exit-marker of SNIPPET."
3451 (interactive (list (cl-first (yas-active-snippets))))
3453 (setf (yas--snippet-force-exit snippet) t)
3454 (goto-char (if (yas--snippet-exit snippet)
3455 (yas--exit-marker (yas--snippet-exit snippet))
3456 (overlay-end (yas--snippet-control-overlay snippet))))))
3458 (defun yas-exit-all-snippets ()
3459 "Exit all snippets."
3461 (mapc #'(lambda (snippet)
3462 (yas-exit-snippet snippet)
3463 (yas--check-commit-snippet))
3464 (yas-active-snippets 'all)))
3467 ;;; Some low level snippet-routines:
3469 (defvar yas--inhibit-overlay-hooks nil
3470 "Bind this temporarily to non-nil to prevent running `yas--on-*-modification'.")
3472 (defvar yas-snippet-beg nil "Beginning position of the last snippet committed.")
3473 (defvar yas-snippet-end nil "End position of the last snippet committed.")
3475 (defun yas--commit-snippet (snippet)
3476 "Commit SNIPPET, but leave point as it is.
3478 This renders the snippet as ordinary text."
3480 (let ((control-overlay (yas--snippet-control-overlay snippet)))
3482 ;; Save the end of the moribund snippet in case we need to revive it
3483 ;; its original expansion.
3485 (when (and control-overlay
3486 (overlay-buffer control-overlay))
3487 (setq yas-snippet-beg (overlay-start control-overlay))
3488 (setq yas-snippet-end (overlay-end control-overlay))
3489 (delete-overlay control-overlay)
3490 (setf (yas--snippet-control-overlay snippet) nil))
3492 (let ((yas--inhibit-overlay-hooks t))
3493 (when yas--active-field-overlay
3494 (delete-overlay yas--active-field-overlay))
3495 (when yas--field-protection-overlays
3496 (mapc #'delete-overlay yas--field-protection-overlays)))
3498 ;; stacked expansion: if the original expansion took place from a
3499 ;; field, make sure we advance it here at least to
3500 ;; `yas-snippet-end'...
3502 (let ((previous-field (yas--snippet-previous-active-field snippet)))
3503 (when (and yas-snippet-end previous-field)
3504 (yas--advance-end-maybe-previous-fields
3505 previous-field yas-snippet-end (cdr yas--active-snippets))))
3507 ;; Convert all markers to points,
3509 (yas--markers-to-points snippet)
3511 ;; It's no longer an active snippet.
3512 (cl-callf2 delq snippet yas--active-snippets)
3514 ;; Take care of snippet revival on undo.
3515 (if (and yas-snippet-revival (listp buffer-undo-list))
3516 (push `(apply yas--snippet-revive ,yas-snippet-beg ,yas-snippet-end ,snippet)
3518 ;; Dismember the snippet... this is useful if we get called
3519 ;; again from `yas--take-care-of-redo'....
3520 (setf (yas--snippet-fields snippet) nil)))
3522 (yas--message 4 "Snippet %s exited." (yas--snippet-id snippet)))
3524 (defvar yas--snippets-to-move nil)
3525 (make-variable-buffer-local 'yas--snippets-to-move)
3527 (defun yas--prepare-snippets-for-move (beg end buf pos)
3528 "Gather snippets in BEG..END for moving to POS in BUF."
3530 (snippets (yas-active-snippets beg end))
3531 (dst-base-line (with-current-buffer buf
3532 (count-lines (point-min) pos))))
3534 (dolist (snippet snippets)
3535 (yas--snippet-map-markers
3537 (prog1 (cons m (yas--snapshot-line-location m))
3538 (set-marker m nil)))
3540 (let ((ctrl-ov (yas--snapshot-overlay-line-location
3541 (yas--snippet-control-overlay snippet))))
3542 (push (list ctrl-ov dst-base-line snippet) to-move)
3543 (delete-overlay (car ctrl-ov))))
3544 (with-current-buffer buf
3545 (cl-callf2 nconc to-move yas--snippets-to-move)))))
3547 (defun yas--on-buffer-kill ()
3548 ;; Org mode uses temp buffers for fontification and "native tab",
3549 ;; move all the snippets to the original org-mode buffer when it's
3551 (let ((org-marker nil)
3553 (when (and yas-minor-mode
3554 (or (bound-and-true-p org-edit-src-from-org-mode)
3555 (bound-and-true-p org-src--from-org-mode))
3558 (or (bound-and-true-p org-edit-src-beg-marker)
3559 (bound-and-true-p org-src--beg-marker))))
3560 ;; If the org source buffer is killed before the temp
3561 ;; fontification one, org-marker might point nowhere.
3562 (setq org-buffer (marker-buffer org-marker)))
3563 (yas--prepare-snippets-for-move
3564 (point-min) (point-max)
3565 org-buffer org-marker))))
3567 (add-hook 'kill-buffer-hook #'yas--on-buffer-kill)
3569 (defun yas--finish-moving-snippets ()
3570 "Finish job started in `yas--prepare-snippets-for-move'."
3571 (cl-loop for (ctrl-ov base-line snippet) in yas--snippets-to-move
3572 for base-pos = (progn (goto-char (point-min))
3573 (forward-line base-line) (point))
3574 do (yas--snippet-map-markers
3575 (lambda (saved-location)
3576 (let ((m (pop saved-location)))
3577 (set-marker m (yas--goto-saved-line-location
3578 base-pos saved-location))
3581 (goto-char base-pos)
3582 (yas--restore-overlay-line-location base-pos ctrl-ov)
3583 (yas--maybe-move-to-active-field snippet)
3584 (push snippet yas--active-snippets))
3585 (setq yas--snippets-to-move nil))
3587 (defun yas--safely-call-fun (fun)
3588 "Call FUN and catch any errors."
3589 (condition-case error
3592 (yas--message 2 "Error running %s: %s" fun
3593 (error-message-string error)))))
3595 (defun yas--safely-run-hook (hook)
3596 "Call HOOK's functions.
3597 HOOK should be a symbol, a hook variable, as in `run-hooks'."
3598 (let ((debug-on-error (and (not (memq yas-good-grace '(t hooks)))
3600 (yas--safely-call-fun (apply-partially #'run-hooks hook))))
3602 (defun yas--check-commit-snippet ()
3603 "Check if point exited the currently active field of the snippet.
3605 If so cleans up the whole snippet up."
3606 (let* ((snippet-exit-transform nil)
3607 (exited-snippets-p nil)
3608 ;; Record the custom snippet `yas-after-exit-snippet-hook'
3609 ;; set in the expand-env field.
3610 (snippet-exit-hook yas-after-exit-snippet-hook))
3611 (dolist (snippet yas--active-snippets)
3612 (let ((active-field (yas--snippet-active-field snippet)))
3613 (yas--letenv (yas--snippet-expand-env snippet)
3614 ;; Note: the `force-exit' field could be a transform in case of
3615 ;; ${0: ...}, see `yas--move-to-field'.
3616 (setq snippet-exit-transform (yas--snippet-force-exit snippet))
3617 (cond ((or snippet-exit-transform
3618 (not (and active-field (yas--field-contains-point-p active-field))))
3619 (setf (yas--snippet-force-exit snippet) nil)
3620 (setq snippet-exit-hook yas-after-exit-snippet-hook)
3621 (yas--commit-snippet snippet)
3622 (setq exited-snippets-p t))
3624 (or (not yas--active-field-overlay)
3625 (not (overlay-buffer yas--active-field-overlay))))
3627 ;; stacked expansion: this case is mainly for recent
3628 ;; snippet exits that place us back int the field of
3632 (yas--move-to-field snippet active-field)
3633 (yas--update-mirrors snippet)))
3636 (unless (or yas--active-snippets (not exited-snippets-p))
3637 (when snippet-exit-transform
3638 (yas--eval-for-effect snippet-exit-transform))
3639 (let ((yas-after-exit-snippet-hook snippet-exit-hook))
3640 (yas--safely-run-hook 'yas-after-exit-snippet-hook)))))
3642 ;; Apropos markers-to-points:
3644 ;; This was found useful for performance reasons, so that an excessive
3645 ;; number of live markers aren't kept around in the
3646 ;; `buffer-undo-list'. We don't reuse the original marker object
3647 ;; because that leaves an unreadable object in the history list and
3648 ;; undo-tree persistence has trouble with that.
3650 ;; This shouldn't bring horrible problems with undo/redo, but you
3653 (defun yas--markers-to-points (snippet)
3654 "Save all markers of SNIPPET as positions."
3655 (yas--snippet-map-markers (lambda (m)
3656 (prog1 (marker-position m)
3657 (set-marker m nil)))
3660 (defun yas--points-to-markers (snippet)
3661 "Restore SNIPPET's marker positions, saved by `yas--markers-to-points'."
3662 (yas--snippet-map-markers #'copy-marker snippet))
3664 (defun yas--maybe-move-to-active-field (snippet)
3665 "Try to move to SNIPPET's active (or first) field and return it if found."
3666 (let ((target-field (or (yas--snippet-active-field snippet)
3667 (car (yas--snippet-fields snippet)))))
3669 (yas--move-to-field snippet target-field)
3672 (defun yas--field-contains-point-p (field &optional point)
3673 (let ((point (or point
3675 (and (>= point (yas--field-start field))
3676 (<= point (yas--field-end field)))))
3678 (defun yas--field-text-for-display (field)
3679 "Return the propertized display text for field FIELD."
3680 (buffer-substring (yas--field-start field) (yas--field-end field)))
3682 (defun yas--undo-in-progress ()
3683 "True if some kind of undo is in progress."
3684 (or undo-in-progress
3685 (eq this-command 'undo)
3686 (eq this-command 'redo)))
3688 (defun yas--make-control-overlay (snippet start end)
3689 "Create the control overlay that surrounds the snippet and
3691 (let ((overlay (make-overlay start
3696 (overlay-put overlay 'keymap yas-keymap)
3697 (overlay-put overlay 'priority yas-overlay-priority)
3698 (overlay-put overlay 'yas--snippet snippet)
3701 (defun yas-current-field ()
3702 "Return the currently active field."
3703 (and yas--active-field-overlay
3704 (overlay-buffer yas--active-field-overlay)
3705 (overlay-get yas--active-field-overlay 'yas--field)))
3707 (defun yas--maybe-clear-field-filter (cmd)
3708 "Return CMD if at start of unmodified snippet field.
3709 Use as a `:filter' argument for a conditional keybinding."
3710 (let ((field (yas-current-field)))
3712 (not (yas--field-modified-p field))
3713 (eq (point) (marker-position (yas--field-start field))))
3716 (defun yas-skip-and-clear-field (&optional field)
3717 "Clears unmodified FIELD if at field start, skips to next tab."
3719 (yas--skip-and-clear (or field (yas-current-field)))
3722 (defun yas-clear-field (&optional field)
3723 "Clears unmodified FIELD if at field start."
3725 (yas--skip-and-clear (or field (yas-current-field))))
3727 (defun yas-skip-and-clear-or-delete-char (&optional field)
3728 "Clears unmodified field if at field start, skips to next tab.
3730 Otherwise deletes a character normally by calling `delete-char'."
3732 (declare (obsolete "Bind to `yas-maybe-skip-and-clear-field' instead." "0.13"))
3733 (cond ((yas--maybe-clear-field-filter t)
3734 (yas--skip-and-clear (or field (yas-current-field)))
3736 (t (call-interactively 'delete-char))))
3738 (defun yas--skip-and-clear (field &optional from)
3739 "Deletes the region of FIELD and sets it's modified state to t.
3740 If given, FROM indicates position to start at instead of FIELD's beginning."
3741 ;; Just before skipping-and-clearing the field, mark its children
3742 ;; fields as modified, too. If the children have mirrors-in-fields
3743 ;; this prevents them from updating erroneously (we're skipping and
3746 (yas--mark-this-and-children-modified field)
3747 (unless (= (yas--field-start field) (yas--field-end field))
3748 (delete-region (or from (yas--field-start field)) (yas--field-end field))))
3750 (defun yas--mark-this-and-children-modified (field)
3751 (setf (yas--field-modified-p field) t)
3752 (let ((fom (yas--field-next field)))
3754 (yas--fom-parent-field fom))
3755 (when (and (eq (yas--fom-parent-field fom) field)
3757 (yas--mark-this-and-children-modified fom))
3758 (setq fom (yas--fom-next fom)))))
3760 (defun yas--make-move-active-field-overlay (snippet field)
3761 "Place the active field overlay in SNIPPET's FIELD.
3763 Move the overlay, or create it if it does not exit."
3764 (if (and yas--active-field-overlay
3765 (overlay-buffer yas--active-field-overlay))
3766 (move-overlay yas--active-field-overlay
3767 (yas--field-start field)
3768 (yas--field-end field))
3769 (setq yas--active-field-overlay
3770 (make-overlay (yas--field-start field)
3771 (yas--field-end field)
3773 (overlay-put yas--active-field-overlay 'priority yas-overlay-priority)
3774 (overlay-put yas--active-field-overlay 'face 'yas-field-highlight-face)
3775 (overlay-put yas--active-field-overlay 'yas--snippet snippet)
3776 (overlay-put yas--active-field-overlay 'modification-hooks '(yas--on-field-overlay-modification))
3777 (overlay-put yas--active-field-overlay 'insert-in-front-hooks
3778 '(yas--on-field-overlay-modification))
3779 (overlay-put yas--active-field-overlay 'insert-behind-hooks
3780 '(yas--on-field-overlay-modification))))
3782 (defun yas--skip-and-clear-field-p (field beg _end length)
3783 "Tell if newly modified FIELD should be cleared and skipped.
3784 BEG, END and LENGTH like overlay modification hooks."
3785 (and (= length 0) ; A 0 pre-change length indicates insertion.
3786 (= beg (yas--field-start field)) ; Insertion at field start?
3787 (not (yas--field-modified-p field))))
3790 (defun yas--merge-and-drop-dups (list1 list2 cmp key)
3791 ;; `delete-consecutive-dups' + `cl-merge'.
3792 (funcall (if (fboundp 'delete-consecutive-dups)
3793 #'delete-consecutive-dups ; 24.4
3795 (cl-merge 'list list1 list2 cmp :key key)))
3797 (defvar yas--before-change-modified-snippets nil)
3798 (make-variable-buffer-local 'yas--before-change-modified-snippets)
3800 (defun yas--gather-active-snippets (overlay beg end then-delete)
3801 ;; Add active snippets in BEG..END into an OVERLAY keyed entry of
3802 ;; `yas--before-change-modified-snippets'. Return accumulated list.
3803 ;; If THEN-DELETE is non-nil, delete the entry.
3804 (let ((new (yas-active-snippets beg end))
3805 (old (assq overlay yas--before-change-modified-snippets)))
3806 (prog1 (cond ((and new old)
3808 (yas--merge-and-drop-dups
3810 ;; Sort like `yas-active-snippets'.
3811 #'>= #'yas--snippet-id)))
3812 (new (unless then-delete
3813 ;; Don't add new entry if we're about to
3814 ;; remove it anyway.
3815 (push (cons overlay new)
3816 yas--before-change-modified-snippets))
3821 (cl-callf2 delq old yas--before-change-modified-snippets)))))
3823 (defvar yas--todo-snippet-indent nil nil)
3824 (make-variable-buffer-local 'yas--todo-snippet-indent)
3826 (defun yas--on-field-overlay-modification (overlay after? beg end &optional length)
3827 "Clears the field and updates mirrors, conditionally.
3829 Only clears the field if it hasn't been modified and point is at
3830 field start. This hook does nothing if an undo is in progress."
3831 (unless (or yas--inhibit-overlay-hooks
3832 (not (overlayp yas--active-field-overlay)) ; Avoid Emacs bug #21824.
3833 ;; If a single change hits multiple overlays of the same
3834 ;; snippet, then we delete the snippet the first time,
3835 ;; and then subsequent calls get a deleted overlay.
3836 ;; Don't delete the snippet again!
3837 (not (overlay-buffer overlay))
3838 (yas--undo-in-progress))
3839 (let* ((inhibit-modification-hooks nil)
3840 (yas--inhibit-overlay-hooks t)
3841 (field (overlay-get overlay 'yas--field))
3842 (snippet (overlay-get yas--active-field-overlay 'yas--snippet)))
3843 (if (yas--snippet-live-p snippet)
3846 (yas--letenv (yas--snippet-expand-env snippet)
3847 (when (yas--skip-and-clear-field-p field beg end length)
3848 ;; We delete text starting from the END of insertion.
3849 (yas--skip-and-clear field end))
3850 (setf (yas--field-modified-p field) t)
3851 ;; Adjust any pending active fields in case of stacked
3853 (yas--advance-end-maybe-previous-fields
3854 field (overlay-end overlay)
3855 (yas--gather-active-snippets overlay beg end t))
3856 ;; Update fields now, but delay auto indentation until
3857 ;; post-command. We don't want to run indentation on
3858 ;; the intermediate state where field text might be
3859 ;; removed (and hence the field could be deleted along
3860 ;; with leading indentation).
3861 (let ((yas-indent-line nil))
3863 (yas--field-update-display field))
3864 (yas--update-mirrors snippet))
3865 (unless (or (not (eq yas-indent-line 'auto))
3866 (memq snippet yas--todo-snippet-indent))
3867 (push snippet yas--todo-snippet-indent))))
3868 ;; Remember active snippets to use for after the change.
3869 (yas--gather-active-snippets overlay beg end nil))
3870 (lwarn '(yasnippet zombie) :warning "Killing zombie snippet!")
3871 (delete-overlay overlay)))))
3873 (defun yas--do-todo-snippet-indent ()
3874 ;; Do pending indentation of snippet fields, called from
3875 ;; `yas--post-command-handler'.
3876 (when yas--todo-snippet-indent
3878 (cl-loop for snippet in yas--todo-snippet-indent
3879 do (yas--indent-mirrors-of-snippet
3880 snippet (yas--snippet-field-mirrors snippet)))
3881 (setq yas--todo-snippet-indent nil))))
3883 (defun yas--auto-fill ()
3884 ;; Preserve snippet markers during auto-fill.
3885 (let* ((orig-point (point))
3886 (end (progn (forward-paragraph) (point)))
3887 (beg (progn (backward-paragraph) (point)))
3888 (snippets (yas-active-snippets beg end))
3891 (dolist (snippet snippets)
3892 (dolist (m (yas--collect-snippet-markers snippet))
3893 (when (and (<= beg m) (<= m end))
3894 (push (cons m (yas--snapshot-location m beg end)) remarkers)))
3895 (push (yas--snapshot-overlay-location
3896 (yas--snippet-control-overlay snippet) beg end)
3898 (goto-char orig-point)
3899 (let ((yas--inhibit-overlay-hooks t))
3900 (if yas--original-auto-fill-function
3901 (funcall yas--original-auto-fill-function)
3902 ;; Shouldn't happen, gather more info about it (see #873/919).
3903 (let ((yas--fill-fun-values `((t ,(default-value 'yas--original-auto-fill-function))))
3904 (fill-fun-values `((t ,(default-value 'auto-fill-function))))
3905 ;; Listing 2 buffers with the same value is enough
3907 (save-current-buffer
3908 (dolist (buf (let ((bufs (buffer-list)))
3909 ;; List the current buffer first.
3910 (setq bufs (cons (current-buffer)
3911 (remq (current-buffer) bufs)))))
3913 (let* ((yf-cell (assq yas--original-auto-fill-function
3914 yas--fill-fun-values))
3915 (af-cell (assq auto-fill-function fill-fun-values)))
3916 (when (local-variable-p 'yas--original-auto-fill-function)
3917 (if yf-cell (setcdr yf-cell (cons buf (cdr yf-cell)))
3918 (push (list yas--original-auto-fill-function buf) yas--fill-fun-values)))
3919 (when (local-variable-p 'auto-fill-function)
3920 (if af-cell (setcdr af-cell (cons buf (cdr af-cell)))
3921 (push (list auto-fill-function buf) fill-fun-values))))))
3922 (lwarn '(yasnippet auto-fill bug) :error
3923 "`yas--original-auto-fill-function' unexpectedly nil in %S! Disabling auto-fill.
3925 `auto-fill-function': %S\n%s"
3926 (current-buffer) yas--fill-fun-values fill-fun-values
3927 (if (fboundp 'backtrace--print-frame)
3928 (with-output-to-string
3929 (mapc (lambda (frame)
3930 (apply #'backtrace--print-frame frame))
3931 yas--watch-auto-fill-backtrace))
3933 ;; Try to avoid repeated triggering of this bug.
3935 ;; Don't pop up more than once in a session (still log though).
3936 (defvar warning-suppress-types) ; `warnings' is autoloaded by `lwarn'.
3937 (add-to-list 'warning-suppress-types '(yasnippet auto-fill bug)))))
3939 (setq end (progn (forward-paragraph) (point)))
3940 (setq beg (progn (backward-paragraph) (point))))
3943 (narrow-to-region beg end)
3944 (dolist (remarker remarkers)
3945 (set-marker (car remarker)
3946 (yas--goto-saved-location (cdr remarker))))
3947 (mapc #'yas--restore-overlay-location reoverlays))
3948 (mapc (lambda (snippet)
3949 (yas--letenv (yas--snippet-expand-env snippet)
3950 (yas--update-mirrors snippet)))
3954 ;;; Apropos protection overlays:
3956 ;; These exist for nasty users who will try to delete parts of the
3957 ;; snippet outside the active field. Actual protection happens in
3958 ;; `yas--on-protection-overlay-modification'.
3960 ;; As of github #537 this no longer inhibits the command by issuing an
3961 ;; error: all the snippets at point, including nested snippets, are
3962 ;; automatically commited and the current command can proceed.
3964 (defun yas--make-move-field-protection-overlays (snippet field)
3965 "Place protection overlays surrounding SNIPPET's FIELD.
3967 Move the overlays, or create them if they do not exit."
3968 (let ((start (yas--field-start field))
3969 (end (yas--field-end field)))
3970 ;; First check if the (1+ end) is contained in the buffer,
3971 ;; otherwise we'll have to do a bit of cheating and silently
3972 ;; insert a newline. the `(1+ (buffer-size))' should prevent this
3973 ;; when using stacked expansion
3975 (when (< (buffer-size) end)
3977 (let ((yas--inhibit-overlay-hooks t))
3978 (goto-char (point-max))
3980 ;; go on to normal overlay creation/moving
3982 (cond ((and yas--field-protection-overlays
3983 (cl-every #'overlay-buffer yas--field-protection-overlays))
3984 (move-overlay (nth 0 yas--field-protection-overlays)
3986 (move-overlay (nth 1 yas--field-protection-overlays) end (1+ end)))
3988 (setq yas--field-protection-overlays
3989 (list (make-overlay (1- start) start nil t nil)
3990 (make-overlay end (1+ end) nil t nil)))
3991 (dolist (ov yas--field-protection-overlays)
3992 (overlay-put ov 'face 'yas--field-debug-face)
3993 (overlay-put ov 'yas--snippet snippet)
3994 ;; (overlay-put ov 'evaporate t)
3995 (overlay-put ov 'modification-hooks '(yas--on-protection-overlay-modification)))))))
3997 (defun yas--on-protection-overlay-modification (_overlay after? beg end &optional length)
3998 "Commit the snippet if the protection overlay is being killed."
3999 (unless (or yas--inhibit-overlay-hooks
4000 yas-inhibit-overlay-modification-protection
4002 (= length (- end beg)) ; deletion or insertion
4003 (yas--undo-in-progress))
4004 (let ((snippets (yas-active-snippets)))
4005 (yas--message 2 "Committing snippets. Action would destroy a protection overlay.")
4006 (cl-loop for snippet in snippets
4007 do (yas--commit-snippet snippet)))))
4009 (add-to-list 'debug-ignored-errors "^Exit the snippet first!$")
4012 ;;; Snippet expansion and "stacked" expansion:
4014 ;; Stacked expansion is when you try to expand a snippet when already
4015 ;; inside a snippet expansion.
4017 ;; The parent snippet does not run its fields modification hooks
4018 ;; (`yas--on-field-overlay-modification' and
4019 ;; `yas--on-protection-overlay-modification') while the child snippet
4020 ;; is active. This means, among other things, that the mirrors of the
4021 ;; parent snippet are not updated, this only happening when one exits
4022 ;; the child snippet.
4024 ;; Unfortunately, this also puts some ugly (and not fully-tested)
4025 ;; bits of code in `yas-expand-snippet' and
4026 ;; `yas--commit-snippet'. I've tried to mark them with "stacked
4029 ;; This was thought to be safer in an undo/redo perspective, but
4030 ;; maybe the correct implementation is to make the globals
4031 ;; `yas--active-field-overlay' and `yas--field-protection-overlays' be
4032 ;; snippet-local and be active even while the child snippet is
4033 ;; running. This would mean a lot of overlay modification hooks
4034 ;; running, but if managed correctly (including overlay priorities)
4035 ;; they should account for all situations...
4037 (defun yas-expand-snippet (snippet &optional start end expand-env)
4038 "Expand SNIPPET at current point.
4040 Text between START and END will be deleted before inserting
4041 template. EXPAND-ENV is a list of (SYM VALUE) let-style dynamic
4042 bindings considered when expanding the snippet. If omitted, use
4043 SNIPPET's expand-env field.
4045 SNIPPET may be a snippet structure (e.g., as returned by
4046 `yas-lookup-snippet'), or just a snippet body (which is a string
4047 for normal snippets, and a list for command snippets)."
4048 (cl-assert (and yas-minor-mode
4049 (memq 'yas--post-command-handler post-command-hook))
4051 "[yas] `yas-expand-snippet' needs properly setup `yas-minor-mode'")
4052 (run-hooks 'yas-before-expand-snippet-hook)
4055 (let ((field (and yas--active-field-overlay
4056 (overlay-buffer yas--active-field-overlay)
4057 (overlay-get yas--active-field-overlay 'yas--field))))
4058 (and field (yas--skip-and-clear-field-p
4059 field (point) (point) 0)
4061 (start (cond (start)
4065 (yas--field-start clear-field))
4071 (yas--field-end clear-field))
4073 (to-delete (and (> end start)
4074 (buffer-substring-no-properties start end)))
4076 (cond (yas-selected-text)
4077 ((and (region-active-p)
4081 (setq yas--indent-original-column (current-column))
4082 ;; Delete the region to delete, this *does* get undo-recorded.
4084 (delete-region start end))
4086 (let ((content (if (yas--template-p snippet)
4087 (yas--template-content snippet)
4089 (when (and (not expand-env) (yas--template-p snippet))
4090 (setq expand-env (yas--template-expand-env snippet)))
4091 (cond ((listp content)
4092 ;; x) This is a snippet-command.
4093 (yas--eval-for-effect content))
4095 ;; x) This is a snippet-snippet :-)
4096 (setq yas--start-column (current-column))
4097 ;; Stacked expansion: also shoosh the overlay modification hooks.
4098 (let ((yas--inhibit-overlay-hooks t))
4100 (yas--snippet-create content expand-env start (point))))
4102 ;; Stacked-expansion: This checks for stacked expansion, save the
4103 ;; `yas--previous-active-field' and advance its boundary.
4104 (let ((existing-field (and yas--active-field-overlay
4105 (overlay-buffer yas--active-field-overlay)
4106 (overlay-get yas--active-field-overlay 'yas--field))))
4107 (when existing-field
4108 (setf (yas--snippet-previous-active-field snippet) existing-field)
4109 (yas--advance-end-maybe-previous-fields
4110 existing-field (overlay-end yas--active-field-overlay)
4111 (cdr yas--active-snippets))))
4113 ;; Exit the snippet immediately if no fields.
4114 (unless (yas--snippet-fields snippet)
4115 (yas-exit-snippet snippet))
4117 ;; Now, schedule a move to the first field.
4118 (let ((first-field (car (yas--snippet-fields snippet))))
4120 (sit-for 0) ;; fix issue 125
4121 (yas--letenv (yas--snippet-expand-env snippet)
4122 (yas--move-to-field snippet first-field))
4123 (when (and (eq (yas--field-number first-field) 0)
4124 (> (length (yas--field-text-for-display
4127 ;; Keep region for ${0:exit text}.
4128 (setq deactivate-mark nil))))
4129 (yas--message 4 "snippet %d expanded." (yas--snippet-id snippet))
4132 (defun yas--take-care-of-redo (snippet)
4133 "Commits SNIPPET, which in turn pushes an undo action for reviving it.
4135 Meant to exit in the `buffer-undo-list'."
4136 ;; slightly optimize: this action is only needed for snippets with
4137 ;; at least one field
4138 (when (yas--snippet-fields snippet)
4139 (yas--commit-snippet snippet)))
4141 (defun yas--snippet-revive (beg end snippet)
4142 "Revives SNIPPET and creates a control overlay from BEG to END.
4144 BEG and END are, we hope, the original snippets boundaries.
4145 All the markers/points exiting existing inside SNIPPET should point
4146 to their correct locations *at the time the snippet is revived*.
4148 After revival, push the `yas--take-care-of-redo' in the
4150 ;; Reconvert all the points to markers
4151 (yas--points-to-markers snippet)
4152 ;; When at least one editable field existed in the zombie snippet,
4153 ;; try to revive the whole thing...
4154 (when (yas--maybe-move-to-active-field snippet)
4155 (setf (yas--snippet-control-overlay snippet) (yas--make-control-overlay snippet beg end))
4156 (overlay-put (yas--snippet-control-overlay snippet) 'yas--snippet snippet)
4157 (push snippet yas--active-snippets)
4158 (when (listp buffer-undo-list)
4159 (push `(apply yas--take-care-of-redo ,snippet)
4160 buffer-undo-list))))
4162 (defun yas--snippet-create (content expand-env begin end)
4163 "Create a snippet from a template inserted at BEGIN to END.
4165 Returns the newly created snippet."
4167 (let ((snippet (yas--make-snippet expand-env)))
4168 (yas--letenv expand-env
4169 ;; Put a single undo action for the expanded snippet's
4171 (let ((buffer-undo-list t))
4173 ;; Call before and after change functions manually,
4174 ;; otherwise cc-mode's cache can get messed up. Don't use
4175 ;; `inhibit-modification-hooks' for that, that blocks
4176 ;; overlay and text property hooks as well! FIXME: Maybe
4177 ;; use `combine-change-calls'? (Requires Emacs 27+ though.)
4178 (run-hook-with-args 'before-change-functions begin end)
4179 (let ((before-change-functions nil)
4180 (after-change-functions nil))
4181 ;; Some versions of cc-mode (might be the one with Emacs
4182 ;; 24.3 only) fail when inserting snippet content in a
4183 ;; narrowed buffer, so make sure to insert before
4186 (narrow-to-region begin (point))
4187 (goto-char (point-min))
4188 (yas--snippet-parse-create snippet))
4189 (run-hook-with-args 'after-change-functions
4190 (point-min) (point-max)
4192 (when (listp buffer-undo-list)
4193 (push (cons (point-min) (point-max))
4196 ;; Indent, collecting undo information normally.
4197 (yas--indent snippet)
4199 ;; Follow up with `yas--take-care-of-redo' on the newly
4200 ;; inserted snippet boundaries.
4201 (when (listp buffer-undo-list)
4202 (push `(apply yas--take-care-of-redo ,snippet)
4205 ;; Sort and link each field
4206 (yas--snippet-sort-fields snippet)
4208 ;; Create keymap overlay for snippet
4209 (setf (yas--snippet-control-overlay snippet)
4210 (yas--make-control-overlay snippet (point-min) (point-max)))
4213 (goto-char (point-max))
4215 (push snippet yas--active-snippets)
4219 ;;; Apropos adjacencies and "fom's":
4221 ;; Once the $-constructs bits like "$n" and "${:n" are deleted in the
4222 ;; recently expanded snippet, we might actually have many fields,
4223 ;; mirrors (and the snippet exit) in the very same position in the
4224 ;; buffer. Therefore we need to single-link the
4225 ;; fields-or-mirrors-or-exit (which I have abbreviated to "fom")
4226 ;; according to their original positions in the buffer.
4228 ;; Then we have operation `yas--advance-end-maybe' and
4229 ;; `yas--advance-start-maybe', which conditionally push the starts and
4230 ;; ends of these foms down the chain.
4232 ;; This allows for like the printf with the magic ",":
4234 ;; printf ("${1:%s}\\n"${1:$(if (string-match "%" text) "," "\);")} \
4235 ;; $2${1:$(if (string-match "%" text) "\);" "")}$0
4237 (defun yas--fom-start (fom)
4238 (cond ((yas--field-p fom)
4239 (yas--field-start fom))
4240 ((yas--mirror-p fom)
4241 (yas--mirror-start fom))
4243 (yas--exit-marker fom))))
4245 (defun yas--fom-end (fom)
4246 (cond ((yas--field-p fom)
4247 (yas--field-end fom))
4248 ((yas--mirror-p fom)
4249 (yas--mirror-end fom))
4251 (yas--exit-marker fom))))
4253 (defun yas--fom-next (fom)
4254 (cond ((yas--field-p fom)
4255 (yas--field-next fom))
4256 ((yas--mirror-p fom)
4257 (yas--mirror-next fom))
4259 (yas--exit-next fom))))
4261 (defun yas--fom-parent-field (fom)
4262 (cond ((yas--field-p fom)
4263 (yas--field-parent-field fom))
4264 ((yas--mirror-p fom)
4265 (yas--mirror-parent-field fom))
4269 (defun yas--calculate-adjacencies (snippet)
4270 "Calculate adjacencies for fields or mirrors of SNIPPET.
4272 This is according to their relative positions in the buffer, and
4273 has to be called before the $-constructs are deleted."
4274 (let* ((fom-set-next-fom
4275 (lambda (fom nextfom)
4276 (cond ((yas--field-p fom)
4277 (setf (yas--field-next fom) nextfom))
4278 ((yas--mirror-p fom)
4279 (setf (yas--mirror-next fom) nextfom))
4281 (setf (yas--exit-next fom) nextfom)))))
4284 (if (= (yas--fom-start fom2) (yas--fom-start fom1))
4285 (yas--mirror-p fom2)
4286 (>= (yas--fom-start fom2) (yas--fom-start fom1)))))
4287 (link-foms fom-set-next-fom))
4288 ;; make some yas--field, yas--mirror and yas--exit soup
4290 (when (yas--snippet-exit snippet)
4291 (push (yas--snippet-exit snippet) soup))
4292 (dolist (field (yas--snippet-fields snippet))
4294 (dolist (mirror (yas--field-mirrors field))
4295 (push mirror soup)))
4297 (sort soup compare-fom-begs))
4299 (cl-reduce link-foms soup)))))
4301 (defun yas--calculate-simple-fom-parentage (snippet fom)
4302 "Discover if FOM is parented by some field in SNIPPET.
4304 Use the tightest containing field if more than one field contains
4305 the mirror. Intended to be called *before* the dollar-regions are
4307 (let ((min (point-min))
4309 (dolist (field (remq fom (yas--snippet-fields snippet)))
4310 (when (and (<= (yas--field-start field) (yas--fom-start fom))
4311 (<= (yas--fom-end fom) (yas--field-end field))
4312 (< min (yas--field-start field))
4313 (< (yas--field-end field) max))
4314 (setq min (yas--field-start field)
4315 max (yas--field-end field))
4316 (cond ((yas--field-p fom)
4317 (setf (yas--field-parent-field fom) field))
4318 ((yas--mirror-p fom)
4319 (setf (yas--mirror-parent-field fom) field))
4320 (t ; it's an exit, so noop
4323 (defun yas--advance-end-maybe (fom newend)
4324 "Maybe advance FOM's end to NEWEND if it needs it.
4328 * call `yas--advance-start-maybe' on FOM's next fom.
4330 * in case FOM is field call `yas--advance-end-maybe' on its parent
4333 Also, if FOM is an exit-marker, always call
4334 `yas--advance-start-maybe' on its next fom. This is because
4335 exit-marker have identical start and end markers."
4336 (cond ((and fom (< (yas--fom-end fom) newend))
4337 (set-marker (yas--fom-end fom) newend)
4338 (yas--advance-start-maybe (yas--fom-next fom) newend)
4339 (yas--advance-end-of-parents-maybe (yas--fom-parent-field fom) newend))
4341 (yas--advance-start-maybe (yas--fom-next fom) newend))))
4343 (defun yas--advance-end-maybe-previous-fields (field end snippets)
4344 "Call `yas--advance-end-maybe' on FIELD, and previous fields on SNIPPETS."
4345 (dolist (snippet snippets)
4346 (cl-assert (memq field (yas--snippet-fields snippet)))
4347 (yas--advance-end-maybe field end)
4348 (setq field (yas--snippet-previous-active-field snippet))))
4350 (defun yas--advance-start-maybe (fom newstart)
4351 "Maybe advance FOM's start to NEWSTART if it needs it.
4353 If it does, also call `yas--advance-end-maybe' on FOM."
4354 (when (and fom (< (yas--fom-start fom) newstart))
4355 (set-marker (yas--fom-start fom) newstart)
4356 (yas--advance-end-maybe fom newstart)))
4358 (defun yas--advance-end-of-parents-maybe (field newend)
4359 "Like `yas--advance-end-maybe' but for parent fields.
4361 Only works for fields and doesn't care about the start of the
4362 next FOM. Works its way up recursively for parents of parents."
4364 (< (yas--field-end field) newend))
4365 (set-marker (yas--field-end field) newend)
4366 (yas--advance-end-of-parents-maybe (yas--field-parent-field field) newend)))
4368 (defvar yas--dollar-regions nil
4369 "When expanding the snippet the \"parse-create\" functions add
4370 cons cells to this var.")
4372 (defvar yas--indent-markers nil
4373 "List of markers for manual indentation.")
4375 (defun yas--snippet-parse-create (snippet)
4376 "Parse a recently inserted snippet template, creating all
4377 necessary fields, mirrors and exit points.
4379 Meant to be called in a narrowed buffer, does various passes"
4380 (let ((saved-quotes nil)
4381 (parse-start (point)))
4382 ;; Avoid major-mode's syntax propertizing function, since we
4383 ;; change the syntax-table while calling `scan-sexps'.
4384 (let ((syntax-propertize-function nil))
4385 (setq yas--dollar-regions nil) ; Reset the yas--dollar-regions.
4386 (yas--protect-escapes nil '(?`)) ; Protect just the backquotes.
4387 (goto-char parse-start)
4388 (setq saved-quotes (yas--save-backquotes)) ; `expressions`.
4389 (yas--protect-escapes) ; Protect escaped characters.
4390 (goto-char parse-start)
4391 (yas--indent-parse-create) ; Parse indent markers: `$>'.
4392 (goto-char parse-start)
4393 (yas--field-parse-create snippet) ; Parse fields with {}.
4394 (goto-char parse-start)
4395 (yas--simple-fom-create snippet) ; Parse simple mirrors & fields.
4396 (goto-char parse-start)
4397 (yas--transform-mirror-parse-create snippet) ; Parse mirror transforms.
4398 ;; Invalidate any syntax-propertizing done while
4399 ;; `syntax-propertize-function' was nil.
4400 (syntax-ppss-flush-cache parse-start))
4401 ;; Set "next" links of fields & mirrors.
4402 (yas--calculate-adjacencies snippet)
4403 (yas--save-restriction-and-widen ; Delete $-constructs.
4404 (yas--delete-regions yas--dollar-regions))
4405 ;; Make sure to do this insertion *after* deleting the dollar
4406 ;; regions, otherwise we invalidate the calculated positions of
4407 ;; all the fields following $0.
4408 (let ((exit (yas--snippet-exit snippet)))
4409 (goto-char (if exit (yas--exit-marker exit) (point-max))))
4410 (when (eq yas-wrap-around-region 'cua)
4411 (setq yas-wrap-around-region ?0))
4412 (cond ((and yas-wrap-around-region yas-selected-text)
4413 (insert yas-selected-text))
4414 ((and (characterp yas-wrap-around-region)
4415 (get-register yas-wrap-around-region))
4416 (insert (prog1 (get-register yas-wrap-around-region)
4417 (set-register yas-wrap-around-region nil)))))
4418 (yas--restore-backquotes saved-quotes) ; Restore `expression` values.
4419 (goto-char parse-start)
4420 (yas--restore-escapes) ; Restore escapes.
4421 (yas--update-mirrors snippet) ; Update mirrors for the first time.
4422 (goto-char parse-start)))
4424 ;; HACK: Some implementations of `indent-line-function' (called via
4425 ;; `indent-according-to-mode') delete text before they insert (like
4426 ;; cc-mode), some make complicated regexp replacements (looking at
4427 ;; you, org-mode). To find place where the marker "should" go after
4428 ;; indentation, we create a regexp based on what the line looks like
4429 ;; before, putting a capture group where the marker is. The regexp
4430 ;; matches any whitespace with [[:space:]]* to allow for the
4431 ;; indentation changing whitespace. Additionally, we try to preserve
4432 ;; the amount of whitespace *following* the marker, because
4433 ;; indentation generally affects whitespace at the beginning, not the
4436 ;; Two other cases where we apply a similar strategy:
4438 ;; 1. Handling `auto-fill-mode', in this case we need to use the
4439 ;; current paragraph instead of line.
4441 ;; 2. Moving snippets from an `org-src' temp buffer into the main org
4442 ;; buffer, in this case we need to count the relative line number
4443 ;; (because org may add indentation on each line making character
4444 ;; positions unreliable).
4447 ;; (LOCATION) = (REGEXP WS-COUNT)
4448 ;; MARKER -> (MARKER . (LOCATION))
4449 ;; OVERLAY -> (OVERLAY LOCATION-BEG LOCATION-END)
4451 ;; For `org-src' temp buffer, add a line number to format:
4452 ;; (LINE-LOCATION) = (LINE . (LOCATION))
4453 ;; MARKER@LINE -> (MARKER . (LINE-LOCATION))
4454 ;; OVERLAY@LINE -> (OVERLAY LINE-LOCATION-BEG LINE-LOCATION-END)
4456 ;; This is all best-effort heuristic stuff, but it should cover 99% of
4459 (defun yas--snapshot-location (position &optional beg end)
4460 "Returns info for restoring POSITIONS's location after indent.
4461 The returned value is a list of the form (REGEXP WS-COUNT).
4462 POSITION may be either a marker or just a buffer position. The
4463 REGEXP matches text between BEG..END which default to the current
4465 (goto-char position)
4466 (unless beg (setq beg (line-beginning-position)))
4467 (unless end (setq end (line-end-position)))
4468 (let ((before (split-string (buffer-substring-no-properties beg position)
4469 "[[:space:]\n]+" t))
4470 (after (split-string (buffer-substring-no-properties position end)
4471 "[[:space:]\n]+" t)))
4472 (list (concat "[[:space:]\n]*"
4473 (mapconcat (lambda (s)
4474 (if (eq s position) "\\(\\)"
4476 (nconc before (list position) after)
4478 (progn (skip-chars-forward "[:space:]\n" end)
4479 (- (point) position)))))
4481 (defun yas--snapshot-line-location (position &optional beg end)
4482 "Like `yas--snapshot-location', but return also line number.
4483 Returned format is (LINE REGEXP WS-COUNT)."
4484 (goto-char position)
4485 (cons (count-lines (point-min) (line-beginning-position))
4486 (yas--snapshot-location position beg end)))
4488 (defun yas--snapshot-overlay-location (overlay beg end)
4489 "Like `yas--snapshot-location' for overlays.
4490 The returned format is (OVERLAY (RE WS) (RE WS)). Either of
4491 the (RE WS) lists may be nil if the start or end, respectively,
4492 of the overlay is outside the range BEG .. END."
4493 (let ((obeg (overlay-start overlay))
4494 (oend (overlay-end overlay)))
4496 (when (and (<= beg obeg) (< obeg end))
4497 (yas--snapshot-location obeg beg end))
4498 (when (and (<= beg oend) (< oend end))
4499 (yas--snapshot-location oend beg end)))))
4501 (defun yas--snapshot-overlay-line-location (overlay)
4502 "Return info for restoring OVERLAY's line based location.
4503 The returned format is (OVERLAY (LINE RE WS) (LINE RE WS))."
4505 (yas--snapshot-line-location (overlay-start overlay))
4506 (yas--snapshot-line-location (overlay-end overlay))))
4508 (defun yas--goto-saved-location (re-count)
4509 "Move to and return point saved by `yas--snapshot-location'.
4510 Buffer must be narrowed to BEG..END used to create the snapshot info."
4511 (let ((regexp (pop re-count))
4512 (ws-count (pop re-count)))
4513 (goto-char (point-min))
4514 (if (not (looking-at regexp))
4515 (lwarn '(yasnippet re-marker) :warning
4516 "Couldn't find: %S" regexp)
4517 (goto-char (match-beginning 1))
4518 (skip-chars-forward "[:space:]\n")
4519 (skip-chars-backward "[:space:]\n" (- (point) ws-count)))
4522 (defun yas--restore-overlay-location (ov-locations)
4523 "Restores marker based on info from `yas--snapshot-overlay-location'.
4524 Buffer must be narrowed to BEG..END used to create the snapshot info."
4525 (cl-destructuring-bind (overlay loc-beg loc-end) ov-locations
4526 (move-overlay overlay
4527 (if (not loc-beg) (overlay-start overlay)
4528 (yas--goto-saved-location loc-beg))
4529 (if (not loc-end) (overlay-end overlay)
4530 (yas--goto-saved-location loc-end)))))
4532 (defun yas--goto-saved-line-location (base-pos l-re-count)
4533 "Move to and return point saved by `yas--snapshot-line-location'.
4534 Additionally requires BASE-POS to tell where the line numbers are
4536 (goto-char base-pos)
4537 (forward-line (pop l-re-count))
4539 (narrow-to-region (line-beginning-position)
4540 (line-end-position))
4541 (yas--goto-saved-location l-re-count)))
4543 (defun yas--restore-overlay-line-location (base-pos ov-locations)
4544 "Restores marker based on info from `yas--snapshot-overlay-line-location'."
4545 (cl-destructuring-bind (overlay beg-l-r-w end-l-r-w)
4547 (move-overlay overlay
4548 (yas--goto-saved-line-location base-pos beg-l-r-w)
4549 (yas--goto-saved-line-location base-pos end-l-r-w))))
4551 (defun yas--indent-region (from to snippet)
4552 "Indent the lines between FROM and TO with `indent-according-to-mode'.
4553 The SNIPPET's markers are preserved."
4555 (yas--save-restriction-and-widen
4556 (let* ((snippet-markers (yas--collect-snippet-markers snippet))
4557 (to (set-marker (make-marker) to)))
4559 (cl-loop for bol = (line-beginning-position)
4560 for eol = (line-end-position)
4561 if (or yas-also-indent-empty-lines
4564 ;; Indent each non-empty line.
4565 (let ((remarkers nil))
4566 (dolist (m snippet-markers)
4567 (when (and (<= bol m) (<= m eol))
4568 (push (cons m (yas--snapshot-location m bol eol))
4571 (progn (back-to-indentation)
4572 (indent-according-to-mode))
4574 (narrow-to-region bol (line-end-position))
4575 (dolist (remarker remarkers)
4576 (set-marker (car remarker)
4577 (yas--goto-saved-location (cdr remarker)))))))
4578 while (and (zerop (forward-line 1))
4579 (< (point) to)))))))
4581 (defvar yas--indent-original-column nil)
4582 (defun yas--indent (snippet)
4583 ;; Indent lines that had indent markers (`$>') on them.
4585 (dolist (marker yas--indent-markers)
4586 (unless (eq yas-indent-line 'auto)
4588 (yas--indent-region (line-beginning-position)
4591 ;; Finished with this marker.
4592 (set-marker marker nil))
4593 (setq yas--indent-markers nil))
4594 ;; Now do stuff for `fixed' and `auto'.
4596 ;; We need to be at end of line, so that `forward-line' will only
4597 ;; report 0 if it actually moves over a newline.
4599 (cond ((eq yas-indent-line 'fixed)
4600 (when (= (forward-line 1) 0)
4601 (let ((indent-line-function
4603 ;; We need to be at beginning of line in order to
4604 ;; indent existing whitespace correctly.
4606 (indent-to-column yas--indent-original-column))))
4607 (yas--indent-region (line-beginning-position)
4610 ((eq yas-indent-line 'auto)
4611 (when (or yas-also-auto-indent-first-line
4612 (= (forward-line 1) 0))
4613 (yas--indent-region (line-beginning-position)
4617 (defun yas--collect-snippet-markers (snippet)
4618 "Make a list of all the markers used by SNIPPET."
4620 (yas--snippet-map-markers (lambda (m) (push m markers) m) snippet)
4623 (defun yas--escape-string (escaped)
4624 (concat "YASESCAPE" (format "%d" escaped) "PROTECTGUARD"))
4626 (defun yas--protect-escapes (&optional text escaped)
4627 "Protect all escaped characters with their numeric ASCII value.
4629 With optional string TEXT do it in string instead of buffer."
4630 (let ((changed-text text)
4631 (text-provided-p text))
4632 (mapc #'(lambda (escaped)
4634 (yas--replace-all (concat "\\" (char-to-string escaped))
4635 (yas--escape-string escaped)
4636 (when text-provided-p changed-text))))
4637 (or escaped yas--escaped-characters))
4640 (defun yas--restore-escapes (&optional text escaped)
4641 "Restore all escaped characters from their numeric ASCII value.
4643 With optional string TEXT do it in string instead of the buffer."
4644 (let ((changed-text text)
4645 (text-provided-p text))
4646 (mapc #'(lambda (escaped)
4648 (yas--replace-all (yas--escape-string escaped)
4649 (char-to-string escaped)
4650 (when text-provided-p changed-text))))
4651 (or escaped yas--escaped-characters))
4654 (defun yas--save-backquotes ()
4655 "Save all \"\\=`(lisp-expression)\\=`\"-style expressions.
4656 Return a list of (MARKER . STRING) entires for each backquoted
4658 (let* ((saved-quotes nil)
4659 (yas--snippet-buffer (current-buffer))
4660 (yas--change-detected nil)
4661 (detect-change (lambda (_beg _end)
4662 (when (eq (current-buffer) yas--snippet-buffer)
4663 (setq yas--change-detected t)))))
4664 (while (re-search-forward yas--backquote-lisp-expression-regexp nil t)
4665 (let ((current-string (match-string-no-properties 1)) transformed)
4666 (yas--save-restriction-and-widen
4667 (delete-region (match-beginning 0) (match-end 0)))
4668 (let ((before-change-functions
4669 (cons detect-change before-change-functions)))
4670 (setq transformed (yas--eval-for-string (yas--read-lisp
4671 (yas--restore-escapes
4672 current-string '(?`))))))
4673 (goto-char (match-beginning 0))
4675 (let ((marker (make-marker)))
4676 (yas--save-restriction-and-widen
4677 (insert "Y") ;; quite horrendous, I love it :)
4678 (set-marker marker (point))
4680 (push (cons marker transformed) saved-quotes)))))
4681 (when yas--change-detected
4682 (lwarn '(yasnippet backquote-change) :warning
4683 "`%s' modified buffer in a backquote expression.
4684 To hide this warning, add (yasnippet backquote-change) to `warning-suppress-types'."
4685 (if yas--current-template
4686 (yas--template-name yas--current-template)
4690 (defun yas--restore-backquotes (saved-quotes)
4691 "Replace markers in SAVED-QUOTES with their values.
4692 SAVED-QUOTES is the in format returned by `yas--save-backquotes'."
4693 (cl-loop for (marker . string) in saved-quotes do
4696 (yas--save-restriction-and-widen
4700 (set-marker marker nil))))
4702 (defun yas--scan-sexps (from count)
4704 (save-match-data ; `scan-sexps' may modify match data.
4705 ;; Parse using the syntax table corresponding to the yasnippet syntax.
4706 (with-syntax-table (standard-syntax-table)
4707 ;; And ignore syntax-table properties that may have been placed by the
4708 ;; major mode since these aren't related to the yasnippet syntax.
4709 (let ((parse-sexp-lookup-properties nil))
4710 (scan-sexps from count))))))
4712 (defun yas--make-marker (pos)
4713 "Create a marker at POS with nil `marker-insertion-type'."
4714 (let ((marker (set-marker (make-marker) pos)))
4715 (set-marker-insertion-type marker nil)
4718 (defun yas--indent-parse-create ()
4719 "Parse the \"$>\" indentation markers just inserted."
4720 (setq yas--indent-markers ())
4721 (while (search-forward "$>" nil t)
4722 (delete-region (match-beginning 0) (match-end 0))
4723 ;; Mark the beginning of the line.
4724 (push (yas--make-marker (line-beginning-position))
4725 yas--indent-markers))
4726 (setq yas--indent-markers (nreverse yas--indent-markers)))
4728 (defun yas--scan-for-field-end ()
4729 (while (progn (re-search-forward "\\${\\|}")
4730 (when (eq (char-before) ?\{)
4732 (yas--scan-for-field-end))))
4735 (defun yas--field-parse-create (snippet &optional parent-field)
4736 "Parse most field expressions in SNIPPET, except for the simple one \"$n\".
4738 The following count as a field:
4740 * \"${n: text}\", for a numbered field with default text, as long as N is not 0;
4742 * \"${n: text$(expression)}, the same with a Lisp expression;
4743 this is caught with the curiously named `yas--multi-dollar-lisp-expression-regexp'
4745 * the same as above but unnumbered, (no N:) and number is calculated automatically.
4747 When multiple expressions are found, only the last one counts."
4750 (while (re-search-forward yas--field-regexp nil t)
4751 (let* ((brace-scan (save-match-data
4752 (goto-char (match-beginning 2))
4753 (yas--scan-for-field-end)))
4754 ;; if the `brace-scan' didn't reach a brace, we have a
4755 ;; snippet with invalid escaping, probably a closing
4756 ;; brace escaped with two backslashes (github#979). But
4757 ;; be lenient, because we can.
4758 (real-match-end-0 (if (eq ?} (char-before brace-scan))
4761 (number (and (match-string-no-properties 1)
4762 (string-to-number (match-string-no-properties 1))))
4763 (brand-new-field (and real-match-end-0
4764 ;; break if on "$(" immediately
4765 ;; after the ":", this will be
4766 ;; caught as a mirror with
4768 (not (string-match-p "\\`\\$[ \t\n]*("
4769 (match-string-no-properties 2)))
4770 ;; allow ${0: some exit text}
4771 ;; (not (and number (zerop number)))
4772 (yas--make-field number
4773 (yas--make-marker (match-beginning 2))
4774 (yas--make-marker (1- real-match-end-0))
4776 (when brand-new-field
4777 (goto-char real-match-end-0)
4778 (push (cons (1- real-match-end-0) real-match-end-0)
4779 yas--dollar-regions)
4780 (push (cons (match-beginning 0) (match-beginning 2))
4781 yas--dollar-regions)
4782 (push brand-new-field (yas--snippet-fields snippet))
4785 (narrow-to-region (yas--field-start brand-new-field) (yas--field-end brand-new-field))
4786 (goto-char (point-min))
4787 (yas--field-parse-create snippet brand-new-field)))))))
4788 ;; if we entered from a parent field, now search for the
4789 ;; `yas--multi-dollar-lisp-expression-regexp'. This is used for
4790 ;; primary field transformations
4794 (while (re-search-forward yas--multi-dollar-lisp-expression-regexp nil t)
4795 (let* ((real-match-end-1 (yas--scan-sexps (match-beginning 1) 1)))
4796 ;; commit the primary field transformation if:
4798 ;; 1. we don't find it in yas--dollar-regions (a subnested
4799 ;; field) might have already caught it.
4801 ;; 2. we really make sure we have either two '$' or some
4802 ;; text and a '$' after the colon ':'. This is a FIXME: work
4803 ;; my regular expressions and end these ugly hacks.
4805 (when (and real-match-end-1
4806 (not (member (cons (match-beginning 0)
4808 yas--dollar-regions))
4810 (char-before (1- (match-beginning 1))))))
4811 (let ((lisp-expression-string (buffer-substring-no-properties (match-beginning 1)
4813 (setf (yas--field-transform parent-field)
4814 (yas--read-lisp (yas--restore-escapes lisp-expression-string))))
4815 (push (cons (match-beginning 0) real-match-end-1)
4816 yas--dollar-regions)))))))
4818 (defun yas--transform-mirror-parse-create (snippet)
4819 "Parse the \"${n:$(lisp-expression)}\" mirror transformations in SNIPPET."
4820 (while (re-search-forward yas--transform-mirror-regexp nil t)
4821 (let* ((real-match-end-0 (yas--scan-sexps (1+ (match-beginning 0)) 1))
4822 (number (string-to-number (match-string-no-properties 1)))
4824 (not (zerop number))
4825 (yas--snippet-find-field snippet number)))
4827 (and real-match-end-0
4829 (yas--make-mirror (yas--make-marker (match-beginning 0))
4830 (yas--make-marker (match-beginning 0))
4832 (yas--restore-escapes
4833 (buffer-substring-no-properties (match-beginning 2)
4834 (1- real-match-end-0))))))))
4835 (when brand-new-mirror
4836 (push brand-new-mirror
4837 (yas--field-mirrors field))
4838 (yas--calculate-simple-fom-parentage snippet brand-new-mirror)
4839 (push (cons (match-beginning 0) real-match-end-0) yas--dollar-regions)))))
4841 (defun yas--simple-fom-create (snippet)
4842 "Parse the simple \"$n\" fields/mirrors/exitmarkers in SNIPPET."
4843 (while (re-search-forward yas--simple-mirror-regexp nil t)
4844 (let ((number (string-to-number (match-string-no-properties 1))))
4845 (cond ((zerop number)
4846 (setf (yas--snippet-exit snippet)
4847 (yas--make-exit (yas--make-marker (match-end 0))))
4848 (push (cons (match-beginning 0) (yas--exit-marker (yas--snippet-exit snippet)))
4849 yas--dollar-regions))
4851 (let ((field (yas--snippet-find-field snippet number))
4855 (setq fom (yas--make-mirror
4856 (yas--make-marker (match-beginning 0))
4857 (yas--make-marker (match-beginning 0))
4859 (yas--field-mirrors field))
4861 (setq fom (yas--make-field number
4862 (yas--make-marker (match-beginning 0))
4863 (yas--make-marker (match-beginning 0))
4865 (yas--snippet-fields snippet)))
4866 (yas--calculate-simple-fom-parentage snippet fom))
4867 (push (cons (match-beginning 0) (match-end 0))
4868 yas--dollar-regions))))))
4870 (defun yas--delete-regions (regions)
4871 "Sort disjuct REGIONS by start point, then delete from the back."
4872 (mapc #'(lambda (reg)
4873 (delete-region (car reg) (cdr reg)))
4876 (>= (car r1) (car r2))))))
4878 (defun yas--calculate-mirror-depth (mirror &optional traversed)
4879 (let* ((parent (yas--mirror-parent-field mirror))
4880 (parents-mirrors (and parent
4881 (yas--field-mirrors parent))))
4882 (or (yas--mirror-depth mirror)
4883 (setf (yas--mirror-depth mirror)
4884 (cond ((memq mirror traversed) 0)
4885 ((and parent parents-mirrors)
4887 #'max parents-mirrors
4889 (yas--calculate-mirror-depth
4890 m (cons mirror traversed))))))
4894 (defun yas--snippet-field-mirrors (snippet)
4895 ;; Make a list of (FIELD . MIRROR).
4897 (cl-mapcan (lambda (field)
4898 (mapcar (lambda (mirror)
4899 (cons field mirror))
4900 (yas--field-mirrors field)))
4901 (yas--snippet-fields snippet))
4902 ;; Then sort this list so that entries with mirrors with
4903 ;; parent fields appear before. This was important for
4904 ;; fixing #290, and also handles the case where a mirror in
4905 ;; a field causes another mirror to need reupdating.
4906 #'> :key (lambda (fm) (yas--calculate-mirror-depth (cdr fm)))))
4908 (defun yas--indent-mirrors-of-snippet (snippet &optional f-ms)
4909 ;; Indent mirrors of SNIPPET. F-MS is the return value of
4910 ;; (yas--snippet-field-mirrors SNIPPET).
4911 (when (eq yas-indent-line 'auto)
4912 (let ((yas--inhibit-overlay-hooks t))
4913 (cl-loop for (beg . end) in
4914 (cl-sort (mapcar (lambda (f-m)
4915 (let ((mirror (cdr f-m)))
4916 (cons (yas--mirror-start mirror)
4917 (yas--mirror-end mirror))))
4919 (yas--snippet-field-mirrors snippet)))
4921 do (yas--indent-region beg end snippet)))))
4923 (defun yas--update-mirrors (snippet)
4924 "Update all the mirrors of SNIPPET."
4925 (yas--save-restriction-and-widen
4927 (let ((f-ms (yas--snippet-field-mirrors snippet)))
4929 for (field . mirror) in f-ms
4930 ;; Before updating a mirror with a parent-field, maybe advance
4931 ;; its start (#290).
4932 do (let ((parent-field (yas--mirror-parent-field mirror)))
4934 (yas--advance-start-maybe mirror (yas--fom-start parent-field))))
4935 ;; Update this mirror.
4936 do (yas--mirror-update-display mirror field)
4937 ;; `yas--place-overlays' is needed since the active field and
4938 ;; protected overlays might have been changed because of insertions
4939 ;; in `yas--mirror-update-display'.
4940 do (let ((active-field (yas--snippet-active-field snippet)))
4941 (when active-field (yas--place-overlays snippet active-field))))
4942 ;; Delay indenting until we're done all mirrors. We must do
4943 ;; this to avoid losing whitespace between fields that are
4944 ;; still empty (i.e., they will be non-empty after updating).
4945 (yas--indent-mirrors-of-snippet snippet f-ms)))))
4947 (defun yas--mirror-update-display (mirror field)
4948 "Update MIRROR according to FIELD (and mirror transform)."
4950 (let* ((mirror-parent-field (yas--mirror-parent-field mirror))
4951 (reflection (and (not (and mirror-parent-field
4952 (yas--field-modified-p mirror-parent-field)))
4953 (or (yas--apply-transform mirror field 'empty-on-nil)
4954 (yas--field-text-for-display field)))))
4955 (when (and reflection
4956 (not (string= reflection (buffer-substring-no-properties (yas--mirror-start mirror)
4957 (yas--mirror-end mirror)))))
4958 (goto-char (yas--mirror-start mirror))
4959 (let ((yas--inhibit-overlay-hooks t))
4960 (insert reflection))
4961 (if (> (yas--mirror-end mirror) (point))
4962 (delete-region (point) (yas--mirror-end mirror))
4963 (set-marker (yas--mirror-end mirror) (point))
4964 (yas--advance-start-maybe (yas--mirror-next mirror) (point))
4965 ;; super-special advance
4966 (yas--advance-end-of-parents-maybe mirror-parent-field (point))))))
4968 (defun yas--field-update-display (field)
4969 "Much like `yas--mirror-update-display', but for fields."
4970 (when (yas--field-transform field)
4971 (let ((transformed (and (not (eq (yas--field-number field) 0))
4972 (yas--apply-transform field field))))
4973 (when (and transformed
4974 (not (string= transformed (buffer-substring-no-properties (yas--field-start field)
4975 (yas--field-end field)))))
4976 (setf (yas--field-modified-p field) t)
4977 (goto-char (yas--field-start field))
4978 (let ((yas--inhibit-overlay-hooks t))
4979 (insert transformed)
4980 (if (> (yas--field-end field) (point))
4981 (delete-region (point) (yas--field-end field))
4982 (set-marker (yas--field-end field) (point))
4983 (yas--advance-start-maybe (yas--field-next field) (point)))
4987 ;;; Post-command hook:
4989 (defun yas--post-command-handler ()
4990 "Handles various yasnippet conditions after each command."
4991 (when (and yas--watch-auto-fill-backtrace
4992 (fboundp 'backtrace--print-frame)
4993 (null yas--original-auto-fill-function)
4994 (eq auto-fill-function 'yas--auto-fill))
4995 (lwarn '(yasnippet auto-fill bug) :error
4996 "`yas--original-auto-fill-function' unexpectedly nil! Please report this backtrace\n%S"
4997 (with-output-to-string
4998 (mapc #'backtrace--print-frame
4999 yas--watch-auto-fill-backtrace)))
5000 ;; Don't pop up more than once in a session (still log though).
5001 (defvar warning-suppress-types) ; `warnings' is autoloaded by `lwarn'.
5002 (add-to-list 'warning-suppress-types '(yasnippet auto-fill bug)))
5003 (yas--do-todo-snippet-indent)
5005 (progn (yas--finish-moving-snippets)
5006 (cond ((eq 'undo this-command)
5008 ;; After undo revival the correct field is sometimes not
5009 ;; restored correctly, this condition handles that
5011 (let* ((snippet (car (yas-active-snippets)))
5016 (yas--field-probably-deleted-p snippet field))
5018 (cons (yas--snippet-active-field snippet)
5019 (yas--snippet-fields snippet)))))))
5021 (yas--move-to-field snippet target-field))))
5022 ((not (yas--undo-in-progress))
5023 ;; When not in an undo, check if we must commit the snippet
5024 ;; (user exited it).
5025 (yas--check-commit-snippet))))
5026 ((debug error) (signal (car err) (cdr err)))))
5030 ;; The docstrings for some functions are generated dynamically
5031 ;; depending on the context.
5033 (put 'yas-expand 'function-documentation
5034 '(yas--expand-from-trigger-key-doc t))
5035 (defun yas--expand-from-trigger-key-doc (context)
5036 "A doc synthesizer for `yas--expand-from-trigger-key-doc'."
5037 (let* ((yas-fallback-behavior (and context yas-fallback-behavior))
5038 (fallback-description
5039 (cond ((eq yas-fallback-behavior 'call-other-command)
5040 (let* ((fallback (yas--keybinding-beyond-yasnippet)))
5042 (format "call command `%s'."
5043 (pp-to-string fallback)))
5044 "do nothing (`yas-expand' doesn't override\nanything).")))
5045 ((eq yas-fallback-behavior 'return-nil)
5047 (t "defer to `yas-fallback-behavior' (which see)."))))
5048 (concat "Expand a snippet before point. If no snippet
5049 expansion is possible, "
5050 fallback-description
5051 "\n\nOptional argument FIELD is for non-interactive use and is an
5052 object satisfying `yas--field-p' to restrict the expansion to.")))
5054 (put 'yas-expand-from-keymap 'function-documentation
5055 '(yas--expand-from-keymap-doc t))
5056 (defun yas--expand-from-keymap-doc (context)
5057 "A doc synthesizer for `yas--expand-from-keymap-doc'."
5058 (add-hook 'temp-buffer-show-hook #'yas--snippet-description-finish-runonce)
5059 (concat "Expand/run snippets from keymaps, possibly falling back to original binding.\n"
5060 (when (and context (eq this-command 'describe-key))
5061 (let* ((vec (this-single-command-keys))
5062 (templates (cl-mapcan (lambda (table)
5063 (yas--fetch table vec))
5064 (yas--get-snippet-tables)))
5065 (yas--direct-keymaps nil)
5066 (fallback (key-binding vec)))
5067 (concat "In this case, "
5069 (concat "these snippets are bound to this key:\n"
5070 (yas--template-pretty-list templates)
5071 "\n\nIf none of these expands, "))
5073 (format "fallback `%s' will be called." (pp-to-string fallback)))
5074 "no fallback keybinding is called."))))))
5076 (defun yas--template-pretty-list (templates)
5078 (yas-buffer-local-condition 'always))
5079 (dolist (plate templates)
5080 (setq acc (concat acc "\n*) "
5081 (propertize (concat "\\\\snippet `" (car plate) "'")
5082 'yasnippet (cdr plate)))))
5085 (define-button-type 'help-snippet-def
5086 :supertype 'help-xref
5087 'help-function (lambda (template) (yas--visit-snippet-file-1 template))
5088 'help-echo (purecopy "mouse-2, RET: find snippets's definition"))
5090 (defun yas--snippet-description-finish-runonce ()
5091 "Final adjustments for the help buffer when snippets are concerned."
5092 (yas--create-snippet-xrefs)
5093 (remove-hook 'temp-buffer-show-hook
5094 #'yas--snippet-description-finish-runonce))
5096 (defun yas--create-snippet-xrefs ()
5098 (goto-char (point-min))
5099 (while (search-forward-regexp "\\\\\\\\snippet[ \s\t]+`\\([^']+\\)'" nil t)
5100 (let ((template (get-text-property (match-beginning 1)
5103 (help-xref-button 1 'help-snippet-def template)
5104 (delete-region (match-end 1) (match-end 0))
5105 (delete-region (match-beginning 0) (match-beginning 1)))))))
5107 ;;; Eldoc configuration.
5108 (eldoc-add-command 'yas-next-field-or-maybe-expand
5109 'yas-next-field 'yas-prev-field
5110 'yas-expand 'yas-expand-from-keymap
5111 'yas-expand-from-trigger-key)
5115 (defvar yas-verbosity 3
5116 "Log level for `yas--message' 4 means trace most anything, 0 means nothing.")
5118 (defun yas--message (level message &rest args)
5119 "When LEVEL is at or below `yas-verbosity', log MESSAGE and ARGS."
5120 (when (>= yas-verbosity level)
5121 (message "%s" (apply #'yas--format message args))))
5123 (defun yas--warning (format-control &rest format-args)
5124 (let ((msg (apply #'format format-control format-args)))
5125 (display-warning 'yasnippet msg :warning)
5126 (yas--message 1 msg)))
5128 (defun yas--format (format-control &rest format-args)
5129 (apply #'format (concat "[yas] " format-control) format-args))
5134 (defvar unload-function-defs-list) ; loadhist.el
5136 (defun yasnippet-unload-function ()
5137 "Disable minor modes when calling `unload-feature'."
5138 ;; Disable `yas-minor-mode' everywhere it's enabled.
5139 (yas-global-mode -1)
5140 (save-current-buffer
5141 (dolist (buffer (buffer-list))
5143 (when yas-minor-mode
5144 (yas-minor-mode -1))))
5145 ;; Remove symbol properties of all our functions, this avoids
5146 ;; Bug#25088 in Emacs 25.1, where the compiler macro on
5147 ;; `cl-defstruct' created functions hang around in the symbol plist
5148 ;; and cause errors when loading again (we don't *need* to clean
5149 ;; *all* symbol plists, but it's easier than being precise).
5150 (dolist (def unload-function-defs-list)
5151 (when (eq (car-safe def) 'defun)
5152 (setplist (cdr def) nil)))
5153 ;; Return nil so that `unload-feature' will take of undefining
5154 ;; functions, and changing any buffers using `snippet-mode'.
5158 ;;; Backward compatibility to yasnippet <= 0.7
5160 (defun yas-initialize ()
5161 "For backward compatibility, enable `yas-minor-mode' globally."
5162 (declare (obsolete "Use (yas-global-mode 1) instead." "0.8"))
5163 (yas-global-mode 1))
5165 (defvar yas--backported-syms '(;; `defcustom's
5168 yas-prompt-functions
5170 yas-also-auto-indent-first-line
5172 yas-triggers-in-field
5173 yas-fallback-behavior
5174 yas-choose-keys-first
5175 yas-choose-tables-first
5178 yas-wrap-around-region
5181 yas-expand-only-for-last-commands
5182 yas-field-highlight-face
5184 ;; these vars can be customized as well
5190 yas-after-exit-snippet-hook
5191 yas-before-expand-snippet-hook
5192 yas-buffer-local-condition
5195 ;; prompting functions
5200 yas-completing-prompt
5203 ;; interactive functions
5208 yas-direct-keymaps-reload
5212 yas-compile-directory
5215 yas-expand-from-trigger-key
5216 yas-expand-from-keymap
5218 yas-visit-snippet-file
5220 yas-load-snippet-buffer
5223 yas-next-field-or-maybe-expand
5228 yas-exit-all-snippets
5229 yas-skip-and-clear-or-delete-char
5232 ;; symbols that I "exported" for use
5233 ;; in snippets and hookage
5250 yas-default-from-field
5253 yas-define-condition-cache
5254 yas-hippie-try-expand
5256 ;; debug definitions
5257 ;; yas-debug-snippet-vars
5258 ;; yas-exterminate-package
5261 ;; testing definitions
5262 ;; yas-should-expand
5263 ;; yas-should-not-expand
5265 ;; yas-make-file-or-dirs
5267 ;; yas-saving-variables
5268 ;; yas-call-with-snippet-dirs
5269 ;; yas-with-snippet-dirs
5271 "Backported yasnippet symbols.
5273 They are mapped to \"yas/*\" variants.")
5275 (when yas-alias-to-yas/prefix-p
5276 (dolist (sym yas--backported-syms)
5277 (let ((backported (intern (replace-regexp-in-string "\\`yas-" "yas/" (symbol-name sym)))))
5279 (make-obsolete-variable backported sym "yasnippet 0.8")
5280 (defvaralias backported sym))
5282 (make-obsolete backported sym "yasnippet 0.8")
5283 (defalias backported sym))))
5284 (make-obsolete 'yas/root-directory 'yas-snippet-dirs "yasnippet 0.8")
5285 (defvaralias 'yas/root-directory 'yas-snippet-dirs))
5287 (defvar yas--exported-syms
5289 (mapatoms (lambda (atom)
5290 (if (and (or (and (boundp atom)
5291 (not (get atom 'byte-obsolete-variable)))
5293 (not (get atom 'byte-obsolete-info))))
5294 (string-match-p "\\`yas-[^-]" (symbol-name atom)))
5295 (push atom exported))))
5297 "Exported yasnippet symbols.
5299 i.e. the ones with \"yas-\" single dash prefix. I will try to
5300 keep them in future yasnippet versions and other elisp libraries
5301 can more or less safely rely upon them.")
5304 (provide 'yasnippet)
5307 ;; indent-tabs-mode: nil
5309 ;;; yasnippet.el ends here