summaryrefslogtreecommitdiff
path: root/.emacs.d/lisp/yasnippet.el
diff options
context:
space:
mode:
Diffstat (limited to '.emacs.d/lisp/yasnippet.el')
-rw-r--r--.emacs.d/lisp/yasnippet.el479
1 files changed, 269 insertions, 210 deletions
diff --git a/.emacs.d/lisp/yasnippet.el b/.emacs.d/lisp/yasnippet.el
index b3c5c90..69b880a 100644
--- a/.emacs.d/lisp/yasnippet.el
+++ b/.emacs.d/lisp/yasnippet.el
@@ -157,16 +157,14 @@
157 (file-name-directory (or load-file-name buffer-file-name)) 157 (file-name-directory (or load-file-name buffer-file-name))
158 "Directory that yasnippet was loaded from.") 158 "Directory that yasnippet was loaded from.")
159 159
160(defvar yas-installed-snippets-dir nil) 160(defconst yas-installed-snippets-dir (expand-file-name "snippets" yas--loaddir))
161(setq yas-installed-snippets-dir 161(make-obsolete-variable 'yas-installed-snippets-dir "\
162 (expand-file-name "snippets" yas--loaddir)) 162Yasnippet no longer comes with installed snippets" "0.13")
163 163
164(defconst yas--default-user-snippets-dir 164(defconst yas--default-user-snippets-dir
165 (expand-file-name "snippets" user-emacs-directory)) 165 (expand-file-name "snippets" user-emacs-directory))
166 166
167(defcustom yas-snippet-dirs (remove nil 167(defcustom yas-snippet-dirs (list yas--default-user-snippets-dir)
168 (list yas--default-user-snippets-dir
169 'yas-installed-snippets-dir))
170 "List of top-level snippet directories. 168 "List of top-level snippet directories.
171 169
172Each element, a string or a symbol whose value is a string, 170Each element, a string or a symbol whose value is a string,
@@ -398,18 +396,26 @@ It must be set to nil before loading yasnippet to take effect."
398 396
399;;; User-visible variables 397;;; User-visible variables
400 398
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.
403This 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
405unmodified snippey field.")
406
401(defvar yas-keymap (let ((map (make-sparse-keymap))) 407(defvar yas-keymap (let ((map (make-sparse-keymap)))
402 (define-key map [(tab)] 'yas-next-field-or-maybe-expand) 408 (define-key map [(tab)] 'yas-next-field-or-maybe-expand)
403 (define-key map (kbd "TAB") 'yas-next-field-or-maybe-expand) 409 (define-key map (kbd "TAB") 'yas-next-field-or-maybe-expand)
404 (define-key map [(shift tab)] 'yas-prev-field) 410 (define-key map [(shift tab)] 'yas-prev-field)
405 (define-key map [backtab] 'yas-prev-field) 411 (define-key map [backtab] 'yas-prev-field)
406 (define-key map (kbd "C-g") 'yas-abort-snippet) 412 (define-key map (kbd "C-g") 'yas-abort-snippet)
407 (define-key map (kbd "C-d") 'yas-skip-and-clear-or-delete-char) 413 (define-key map (kbd "C-d") yas-maybe-skip-and-clear-field)
408 map) 414 map)
409 "The active keymap while a snippet expansion is in progress.") 415 "The active keymap while a snippet expansion is in progress.")
410 416
411(defvar yas-key-syntaxes (list "w" "w_" "w_." "w_.()" 417(defvar yas-key-syntaxes (list #'yas-try-key-from-whitespace
412 #'yas-try-key-from-whitespace) 418 "w_.()" "w_." "w_" "w")
413 "Syntaxes and functions to help look for trigger keys before point. 419 "Syntaxes and functions to help look for trigger keys before point.
414 420
415Each element in this list specifies how to skip buffer positions 421Each element in this list specifies how to skip buffer positions
@@ -953,14 +959,25 @@ Honour `yas-dont-activate-functions', which see."
953 "The keymap used when `snippet-mode' is active.") 959 "The keymap used when `snippet-mode' is active.")
954 960
955 961
956;;;###autoload 962
957(define-derived-mode snippet-mode text-mode "Snippet" 963;;;###autoload(autoload 'snippet-mode "yasnippet" "A mode for editing yasnippets" t nil)
958 "A mode for editing yasnippets" 964(eval-and-compile
959 (setq font-lock-defaults '(yas--font-lock-keywords)) 965 (if (fboundp 'prog-mode)
960 (set (make-local-variable 'require-final-newline) nil) 966 ;; `prog-mode' is new in 24.1.
961 (set (make-local-variable 'comment-start) "#") 967 (define-derived-mode snippet-mode prog-mode "Snippet"
962 (set (make-local-variable 'comment-start-skip) "#+[\t ]*") 968 "A mode for editing yasnippets"
963 (add-hook 'after-save-hook #'yas-maybe-load-snippet-buffer nil t)) 969 (setq font-lock-defaults '(yas--font-lock-keywords))
970 (set (make-local-variable 'require-final-newline) nil)
971 (set (make-local-variable 'comment-start) "#")
972 (set (make-local-variable 'comment-start-skip) "#+[\t ]*")
973 (add-hook 'after-save-hook #'yas-maybe-load-snippet-buffer nil t))
974 (define-derived-mode snippet-mode fundamental-mode "Snippet"
975 "A mode for editing yasnippets"
976 (setq font-lock-defaults '(yas--font-lock-keywords))
977 (set (make-local-variable 'require-final-newline) nil)
978 (set (make-local-variable 'comment-start) "#")
979 (set (make-local-variable 'comment-start-skip) "#+[\t ]*")
980 (add-hook 'after-save-hook #'yas-maybe-load-snippet-buffer nil t))))
964 981
965(defun yas-snippet-mode-buffer-p () 982(defun yas-snippet-mode-buffer-p ()
966 "Return non-nil if current buffer should be in `snippet-mode'. 983 "Return non-nil if current buffer should be in `snippet-mode'.
@@ -1493,7 +1510,7 @@ Here's a list of currently recognized directives:
1493 expand-env 1510 expand-env
1494 binding 1511 binding
1495 uuid) 1512 uuid)
1496 (if (re-search-forward "^# --\n" nil t) 1513 (if (re-search-forward "^# --\\s-*\n" nil t)
1497 (progn (setq template 1514 (progn (setq template
1498 (buffer-substring-no-properties (point) 1515 (buffer-substring-no-properties (point)
1499 (point-max))) 1516 (point-max)))
@@ -1938,12 +1955,19 @@ prefix argument."
1938 (yas-direct-keymaps-reload) 1955 (yas-direct-keymaps-reload)
1939 1956
1940 (run-hooks 'yas-after-reload-hook) 1957 (run-hooks 'yas-after-reload-hook)
1941 (yas--message (if errors 2 3) 1958 (let ((no-snippets
1942 (if no-jit "Snippets loaded %s." 1959 (cl-every (lambda (table) (= (hash-table-count table) 0))
1943 "Prepared just-in-time loading of snippets %s.") 1960 (list yas--scheduled-jit-loads
1944 (if errors 1961 yas--parents yas--tables))))
1945 "with some errors. Check *Messages*" 1962 (yas--message (if (or no-snippets errors) 2 3)
1946 "successfully"))))) 1963 (if no-jit "Snippets loaded %s."
1964 "Prepared just-in-time loading of snippets %s.")
1965 (cond (errors
1966 "with some errors. Check *Messages*")
1967 (no-snippets
1968 "(but no snippets found)")
1969 (t
1970 "successfully")))))))
1947 1971
1948(defvar yas-after-reload-hook nil 1972(defvar yas-after-reload-hook nil
1949 "Hooks run after `yas-reload-all'.") 1973 "Hooks run after `yas-reload-all'.")
@@ -2388,18 +2412,17 @@ Honours `yas-choose-tables-first', `yas-choose-keys-first' and
2388 :key #'yas--template-name :test #'string=))) 2412 :key #'yas--template-name :test #'string=)))
2389 2413
2390(defun yas-lookup-snippet (name &optional mode noerror) 2414(defun yas-lookup-snippet (name &optional mode noerror)
2391 "Get the snippet content for the snippet NAME in MODE's tables. 2415 "Get the snippet named NAME in MODE's tables.
2392 2416
2393MODE defaults to the current buffer's `major-mode'. If NOERROR 2417MODE defaults to the current buffer's `major-mode'. If NOERROR
2394is non-nil, then don't signal an error if there isn't any snippet 2418is non-nil, then don't signal an error if there isn't any snippet
2395called NAME. 2419called NAME.
2396 2420
2397Honours `yas-buffer-local-condition'." 2421Honours `yas-buffer-local-condition'."
2398 (let ((snippet (yas--lookup-snippet-1 name mode))) 2422 (cond
2399 (cond 2423 ((yas--lookup-snippet-1 name mode))
2400 (snippet (yas--template-content snippet)) 2424 (noerror nil)
2401 (noerror nil) 2425 (t (error "No snippet named: %s" name))))
2402 (t (error "No snippet named: %s" name)))))
2403 2426
2404(defun yas-insert-snippet (&optional no-condition) 2427(defun yas-insert-snippet (&optional no-condition)
2405 "Choose a snippet to expand, pop-up a list of choices according 2428 "Choose a snippet to expand, pop-up a list of choices according
@@ -2495,10 +2518,11 @@ where snippets of table might exist."
2495 (tables (if table (list table) 2518 (tables (if table (list table)
2496 (yas--get-snippet-tables)))) 2519 (yas--get-snippet-tables))))
2497 ;; HACK! the snippet table created here is actually registered! 2520 ;; HACK! the snippet table created here is actually registered!
2498 ;; 2521 (unless table
2499 (unless (or table (gethash major-mode yas--tables)) 2522 ;; The major mode is probably the best guess, put it first.
2500 (push (yas--table-get-create major-mode) 2523 (let ((major-mode-table (yas--table-get-create major-mode)))
2501 tables)) 2524 (cl-callf2 delq major-mode-table tables)
2525 (push major-mode-table tables)))
2502 2526
2503 (mapcar #'(lambda (table) 2527 (mapcar #'(lambda (table)
2504 (cons table 2528 (cons table
@@ -2689,8 +2713,11 @@ and `kill-buffer' instead."
2689 (save-buffer))) 2713 (save-buffer)))
2690 (quit-window kill))) 2714 (quit-window kill)))
2691 2715
2716(declare-function yas-debug-snippets "yasnippet-debug")
2717
2692(defun yas-tryout-snippet (&optional debug) 2718(defun yas-tryout-snippet (&optional debug)
2693 "Test current buffer's snippet template in other buffer." 2719 "Test current buffer's snippet template in other buffer.
2720DEBUG is for debugging the YASnippet engine itself."
2694 (interactive "P") 2721 (interactive "P")
2695 (let* ((major-mode-and-parent (yas--compute-major-mode-and-parents buffer-file-name)) 2722 (let* ((major-mode-and-parent (yas--compute-major-mode-and-parents buffer-file-name))
2696 (parsed (yas--parse-template)) 2723 (parsed (yas--parse-template))
@@ -2720,9 +2747,9 @@ and `kill-buffer' instead."
2720 (point-max) 2747 (point-max)
2721 (yas--template-expand-env yas--current-template)) 2748 (yas--template-expand-env yas--current-template))
2722 (when (and debug 2749 (when (and debug
2723 (require 'yasnippet-debug nil t) 2750 (require 'yasnippet-debug nil t))
2724 (fboundp 'yas-debug-snippet-vars)) 2751 (yas-debug-snippets "*YASnippet trace*" 'snippet-navigation)
2725 (add-hook 'post-command-hook #'yas-debug-snippet-vars nil t)))) 2752 (display-buffer "*YASnippet trace*"))))
2726 (t 2753 (t
2727 (yas--message 1 "Cannot test snippet for unknown major mode"))))) 2754 (yas--message 1 "Cannot test snippet for unknown major mode")))))
2728 2755
@@ -3527,22 +3554,37 @@ holds the keymap."
3527 (overlay-put overlay 'yas--snippet snippet) 3554 (overlay-put overlay 'yas--snippet snippet)
3528 overlay)) 3555 overlay))
3529 3556
3557(defun yas-current-field ()
3558 "Return the currently active field."
3559 (and yas--active-field-overlay
3560 (overlay-buffer yas--active-field-overlay)
3561 (overlay-get yas--active-field-overlay 'yas--field)))
3562
3563(defun yas--maybe-clear-field-filter (cmd)
3564 "Return CMD if at start of unmodified snippet field.
3565Use as a `:filter' argument for a conditional keybinding."
3566 (let ((field (yas-current-field)))
3567 (when (and field
3568 (not (yas--field-modified-p field))
3569 (eq (point) (marker-position (yas--field-start field))))
3570 cmd)))
3571
3572(defun yas-skip-and-clear-field (&optional field)
3573 "Clears unmodified FIELD if at field start, skips to next tab."
3574 (interactive)
3575 (yas--skip-and-clear (or field (yas-current-field)))
3576 (yas-next-field 1))
3577
3530(defun yas-skip-and-clear-or-delete-char (&optional field) 3578(defun yas-skip-and-clear-or-delete-char (&optional field)
3531 "Clears unmodified field if at field start, skips to next tab. 3579 "Clears unmodified field if at field start, skips to next tab.
3532 3580
3533Otherwise deletes a character normally by calling `delete-char'." 3581Otherwise deletes a character normally by calling `delete-char'."
3534 (interactive) 3582 (interactive)
3535 (let ((field (or field 3583 (declare (obsolete "Bind to `yas-maybe-skip-and-clear-field' instead." "0.13"))
3536 (and yas--active-field-overlay 3584 (cond ((yas--maybe-clear-field-filter t)
3537 (overlay-buffer yas--active-field-overlay) 3585 (yas--skip-and-clear (or field (yas-current-field)))
3538 (overlay-get yas--active-field-overlay 'yas--field))))) 3586 (yas-next-field 1))
3539 (cond ((and field 3587 (t (call-interactively 'delete-char))))
3540 (not (yas--field-modified-p field))
3541 (eq (point) (marker-position (yas--field-start field))))
3542 (yas--skip-and-clear field)
3543 (yas-next-field 1))
3544 (t
3545 (call-interactively 'delete-char)))))
3546 3588
3547(defun yas--skip-and-clear (field &optional from) 3589(defun yas--skip-and-clear (field &optional from)
3548 "Deletes the region of FIELD and sets it's modified state to t. 3590 "Deletes the region of FIELD and sets it's modified state to t.
@@ -3740,124 +3782,100 @@ Move the overlays, or create them if they do not exit."
3740;; running, but if managed correctly (including overlay priorities) 3782;; running, but if managed correctly (including overlay priorities)
3741;; they should account for all situations... 3783;; they should account for all situations...
3742 3784
3743(defvar yas--first-indent-undo nil 3785(defun yas-expand-snippet (snippet &optional start end expand-env)
3744 "Internal variable for indent undo entries. 3786 "Expand SNIPPET at current point.
3745Used to pass info from `yas--indent-region' to `yas-expand-snippet'.")
3746(defvar yas--get-indent-undo-pos nil
3747 "Record undo info for line beginning at given position.
3748We bind this when first creating a snippet. See also
3749`yas--first-indent-undo'.")
3750
3751(defun yas-expand-snippet (content &optional start end expand-env)
3752 "Expand snippet CONTENT at current point.
3753 3787
3754Text between START and END will be deleted before inserting 3788Text between START and END will be deleted before inserting
3755template. EXPAND-ENV is a list of (SYM VALUE) let-style dynamic bindings 3789template. EXPAND-ENV is a list of (SYM VALUE) let-style dynamic
3756considered when expanding the snippet." 3790bindings considered when expanding the snippet. If omitted, use
3791SNIPPET's expand-env field.
3792
3793SNIPPET may be a snippet structure (e.g., as returned by
3794`yas-lookup-snippet'), or just a snippet body (which is a string
3795for normal snippets, and a list for command snippets)."
3757 (cl-assert (and yas-minor-mode 3796 (cl-assert (and yas-minor-mode
3758 (memq 'yas--post-command-handler post-command-hook)) 3797 (memq 'yas--post-command-handler post-command-hook))
3759 nil 3798 nil
3760 "[yas] `yas-expand-snippet' needs properly setup `yas-minor-mode'") 3799 "[yas] `yas-expand-snippet' needs properly setup `yas-minor-mode'")
3761 (run-hooks 'yas-before-expand-snippet-hook) 3800 (run-hooks 'yas-before-expand-snippet-hook)
3762 3801
3763 ;; 3802 (let* ((clear-field
3764 (let* ((yas-selected-text (or yas-selected-text 3803 (let ((field (and yas--active-field-overlay
3765 (and (region-active-p) 3804 (overlay-buffer yas--active-field-overlay)
3766 (buffer-substring-no-properties (region-beginning) 3805 (overlay-get yas--active-field-overlay 'yas--field))))
3767 (region-end))))) 3806 (and field (yas--skip-and-clear-field-p
3768 (start (or start 3807 field (point) (point) 0)
3769 (and (region-active-p) 3808 field)))
3770 (region-beginning)) 3809 (start (cond (start)
3771 (point))) 3810 ((region-active-p)
3772 (end (or end 3811 (region-beginning))
3773 (and (region-active-p) 3812 (clear-field
3774 (region-end)) 3813 (yas--field-start clear-field))
3775 (point))) 3814 (t (point))))
3776 (to-delete (and start 3815 (end (cond (end)
3777 end 3816 ((region-active-p)
3817 (region-end))
3818 (clear-field
3819 (yas--field-end clear-field))
3820 (t (point))))
3821 (to-delete (and (> end start)
3778 (buffer-substring-no-properties start end))) 3822 (buffer-substring-no-properties start end)))
3779 (yas--first-indent-undo nil) 3823 (yas-selected-text
3780 snippet) 3824 (cond (yas-selected-text)
3825 ((and (region-active-p)
3826 (not clear-field))
3827 to-delete))))
3781 (goto-char start) 3828 (goto-char start)
3782 (setq yas--indent-original-column (current-column)) 3829 (setq yas--indent-original-column (current-column))
3783 ;; Delete the region to delete, this *does* get undo-recorded. 3830 ;; Delete the region to delete, this *does* get undo-recorded.
3784 ;; 3831 (when to-delete
3785 (when (and to-delete
3786 (> end start))
3787 (delete-region start end)) 3832 (delete-region start end))
3788 3833
3789 (cond ((listp content) 3834 (let ((content (if (yas--template-p snippet)
3790 ;; x) This is a snippet-command 3835 (yas--template-content snippet)
3791 ;; 3836 snippet)))
3792 (yas--eval-for-effect content)) 3837 (when (and (not expand-env) (yas--template-p snippet))
3793 (t 3838 (setq expand-env (yas--template-expand-env snippet)))
3794 ;; x) This is a snippet-snippet :-) 3839 (cond ((listp content)
3795 ;; 3840 ;; x) This is a snippet-command.
3796 ;; Narrow the region down to the content, shoosh the 3841 (yas--eval-for-effect content))
3797 ;; `buffer-undo-list', and create the snippet, the new 3842 (t
3798 ;; snippet updates its mirrors once, so we are left with 3843 ;; x) This is a snippet-snippet :-)
3799 ;; some plain text. The undo action for deleting this
3800 ;; plain text will get recorded at the end.
3801 ;;
3802 ;; stacked expansion: also shoosh the overlay modification hooks
3803 (let ((buffer-undo-list t)
3804 (yas--get-indent-undo-pos (line-beginning-position)))
3805 ;; snippet creation might evaluate users elisp, which
3806 ;; might generate errors, so we have to be ready to catch
3807 ;; them mostly to make the undo information
3808 ;;
3809 (setq yas--start-column (current-column)) 3844 (setq yas--start-column (current-column))
3845 ;; Stacked expansion: also shoosh the overlay modification hooks.
3810 (let ((yas--inhibit-overlay-hooks t)) 3846 (let ((yas--inhibit-overlay-hooks t))
3811 (insert content)
3812 (setq snippet 3847 (setq snippet
3813 (yas--snippet-create expand-env start (point))))) 3848 (yas--snippet-create content expand-env start (point))))
3814 3849
3815 ;; stacked-expansion: This checks for stacked expansion, save the 3850 ;; Stacked-expansion: This checks for stacked expansion, save the
3816 ;; `yas--previous-active-field' and advance its boundary. 3851 ;; `yas--previous-active-field' and advance its boundary.
3817 ;; 3852 (let ((existing-field (and yas--active-field-overlay
3818 (let ((existing-field (and yas--active-field-overlay 3853 (overlay-buffer yas--active-field-overlay)
3819 (overlay-buffer yas--active-field-overlay) 3854 (overlay-get yas--active-field-overlay 'yas--field))))
3820 (overlay-get yas--active-field-overlay 'yas--field)))) 3855 (when existing-field
3821 (when existing-field 3856 (setf (yas--snippet-previous-active-field snippet) existing-field)
3822 (setf (yas--snippet-previous-active-field snippet) existing-field) 3857 (yas--advance-end-maybe existing-field (overlay-end yas--active-field-overlay))))
3823 (yas--advance-end-maybe existing-field (overlay-end yas--active-field-overlay))))
3824 3858
3825 ;; Exit the snippet immediately if no fields 3859 ;; Exit the snippet immediately if no fields.
3826 ;; 3860 (unless (yas--snippet-fields snippet)
3827 (unless (yas--snippet-fields snippet) 3861 (yas-exit-snippet snippet))
3828 (yas-exit-snippet snippet))
3829 3862
3830 ;; Undo actions from indent of snippet's 1st line. 3863 ;; Now, schedule a move to the first field.
3831 (setq buffer-undo-list 3864 (let ((first-field (car (yas--snippet-fields snippet))))
3832 (nconc yas--first-indent-undo buffer-undo-list)) 3865 (when first-field
3833 ;; Undo action for the expand snippet contents. 3866 (sit-for 0) ;; fix issue 125
3834 (push (cons (overlay-start (yas--snippet-control-overlay snippet)) 3867 (yas--letenv (yas--snippet-expand-env snippet)
3835 (overlay-end (yas--snippet-control-overlay snippet))) 3868 (yas--move-to-field snippet first-field))
3836 buffer-undo-list) 3869 (when (and (eq (yas--field-number first-field) 0)
3837 ;; Follow up with `yas--take-care-of-redo' on the newly 3870 (> (length (yas--field-text-for-display
3838 ;; inserted snippet boundaries. 3871 first-field))
3839 (push `(apply yas--take-care-of-redo ,start 3872 0))
3840 ,(overlay-end (yas--snippet-control-overlay snippet)) 3873 ;; Keep region for ${0:exit text}.
3841 ,snippet) 3874 (setq deactivate-mark nil))))
3842 buffer-undo-list) 3875 (yas--message 4 "snippet %d expanded." (yas--snippet-id snippet))
3876 t)))))
3843 3877
3844 ;; Now, schedule a move to the first field 3878(defun yas--take-care-of-redo (snippet)
3845 ;;
3846 (let ((first-field (car (yas--snippet-fields snippet))))
3847 (when first-field
3848 (sit-for 0) ;; fix issue 125
3849 (yas--letenv (yas--snippet-expand-env snippet)
3850 (yas--move-to-field snippet first-field))
3851 (when (and (eq (yas--field-number first-field) 0)
3852 (> (length (yas--field-text-for-display
3853 first-field))
3854 0))
3855 ;; Keep region for ${0:exit text}.
3856 (setq deactivate-mark nil))))
3857 (yas--message 4 "snippet %d expanded." (yas--snippet-id snippet))
3858 t))))
3859
3860(defun yas--take-care-of-redo (_beg _end snippet)
3861 "Commits SNIPPET, which in turn pushes an undo action for reviving it. 3879 "Commits SNIPPET, which in turn pushes an undo action for reviving it.
3862 3880
3863Meant to exit in the `buffer-undo-list'." 3881Meant to exit in the `buffer-undo-list'."
@@ -3882,19 +3900,37 @@ After revival, push the `yas--take-care-of-redo' in the
3882 (when (yas--maybe-move-to-active-field snippet) 3900 (when (yas--maybe-move-to-active-field snippet)
3883 (setf (yas--snippet-control-overlay snippet) (yas--make-control-overlay snippet beg end)) 3901 (setf (yas--snippet-control-overlay snippet) (yas--make-control-overlay snippet beg end))
3884 (overlay-put (yas--snippet-control-overlay snippet) 'yas--snippet snippet) 3902 (overlay-put (yas--snippet-control-overlay snippet) 'yas--snippet snippet)
3885 (push `(apply yas--take-care-of-redo ,beg ,end ,snippet) 3903 (push `(apply yas--take-care-of-redo ,snippet)
3886 buffer-undo-list))) 3904 buffer-undo-list)))
3887 3905
3888(defun yas--snippet-create (expand-env begin end) 3906(defun yas--snippet-create (content expand-env begin end)
3889 "Create a snippet from a template inserted at BEGIN to END. 3907 "Create a snippet from a template inserted at BEGIN to END.
3890 3908
3891Returns the newly created snippet." 3909Returns the newly created snippet."
3892 (save-restriction 3910 (save-restriction
3893 (narrow-to-region begin end)
3894 (let ((snippet (yas--make-snippet expand-env))) 3911 (let ((snippet (yas--make-snippet expand-env)))
3895 (yas--letenv expand-env 3912 (yas--letenv expand-env
3896 (goto-char begin) 3913 ;; Put a single undo action for the expanded snippet's
3897 (yas--snippet-parse-create snippet) 3914 ;; content.
3915 (let ((buffer-undo-list t))
3916 ;; Some versions of cc-mode fail when inserting snippet
3917 ;; content in a narrowed buffer.
3918 (goto-char begin)
3919 (insert content)
3920 (setq end (+ end (length content)))
3921 (narrow-to-region begin end)
3922 (goto-char (point-min))
3923 (yas--snippet-parse-create snippet))
3924 (push (cons (point-min) (point-max))
3925 buffer-undo-list)
3926
3927 ;; Indent, collecting undo information normally.
3928 (yas--indent snippet)
3929
3930 ;; Follow up with `yas--take-care-of-redo' on the newly
3931 ;; inserted snippet boundaries.
3932 (push `(apply yas--take-care-of-redo ,snippet)
3933 buffer-undo-list)
3898 3934
3899 ;; Sort and link each field 3935 ;; Sort and link each field
3900 (yas--snippet-sort-fields snippet) 3936 (yas--snippet-sort-fields snippet)
@@ -3991,22 +4027,27 @@ has to be called before the $-constructs are deleted."
3991 (when soup 4027 (when soup
3992 (cl-reduce link-foms soup))))) 4028 (cl-reduce link-foms soup)))))
3993 4029
3994(defun yas--calculate-mirrors-in-fields (snippet mirror) 4030(defun yas--calculate-simple-fom-parentage (snippet fom)
3995 "Attempt to assign a parent field of SNIPPET to the mirror MIRROR. 4031 "Discover if FOM is parented by some field in SNIPPET.
3996 4032
3997Use the tightest containing field if more than one field contains 4033Use the tightest containing field if more than one field contains
3998the mirror. Intended to be called *before* the dollar-regions are 4034the mirror. Intended to be called *before* the dollar-regions are
3999deleted." 4035deleted."
4000 (let ((min (point-min)) 4036 (let ((min (point-min))
4001 (max (point-max))) 4037 (max (point-max)))
4002 (dolist (field (yas--snippet-fields snippet)) 4038 (dolist (field (remq fom (yas--snippet-fields snippet)))
4003 (when (and (<= (yas--field-start field) (yas--mirror-start mirror)) 4039 (when (and (<= (yas--field-start field) (yas--fom-start fom))
4004 (<= (yas--mirror-end mirror) (yas--field-end field)) 4040 (<= (yas--fom-end fom) (yas--field-end field))
4005 (< min (yas--field-start field)) 4041 (< min (yas--field-start field))
4006 (< (yas--field-end field) max)) 4042 (< (yas--field-end field) max))
4007 (setq min (yas--field-start field) 4043 (setq min (yas--field-start field)
4008 max (yas--field-end field)) 4044 max (yas--field-end field))
4009 (setf (yas--mirror-parent-field mirror) field))))) 4045 (cond ((yas--field-p fom)
4046 (setf (yas--field-parent-field fom) field))
4047 ((yas--mirror-p fom)
4048 (setf (yas--mirror-parent-field fom) field))
4049 (t ; it's an exit, so noop
4050 nil ))))))
4010 4051
4011(defun yas--advance-end-maybe (fom newend) 4052(defun yas--advance-end-maybe (fom newend)
4012 "Maybe advance FOM's end to NEWEND if it needs it. 4053 "Maybe advance FOM's end to NEWEND if it needs it.
@@ -4050,11 +4091,6 @@ next FOM. Works its way up recursively for parents of parents."
4050 "When expanding the snippet the \"parse-create\" functions add 4091 "When expanding the snippet the \"parse-create\" functions add
4051cons cells to this var.") 4092cons cells to this var.")
4052 4093
4053(defvar yas--backquote-markers-and-strings nil
4054 "List of (MARKER . STRING) marking where the values from
4055backquoted Lisp expressions should be inserted at the end of
4056expansion.")
4057
4058(defvar yas--indent-markers nil 4094(defvar yas--indent-markers nil
4059 "List of markers for manual indentation.") 4095 "List of markers for manual indentation.")
4060 4096
@@ -4063,21 +4099,22 @@ expansion.")
4063necessary fields, mirrors and exit points. 4099necessary fields, mirrors and exit points.
4064 4100
4065Meant to be called in a narrowed buffer, does various passes" 4101Meant to be called in a narrowed buffer, does various passes"
4066 (let ((parse-start (point))) 4102 (let ((saved-quotes nil)
4103 (parse-start (point)))
4067 ;; Avoid major-mode's syntax propertizing function, since we 4104 ;; Avoid major-mode's syntax propertizing function, since we
4068 ;; change the syntax-table while calling `scan-sexps'. 4105 ;; change the syntax-table while calling `scan-sexps'.
4069 (let ((syntax-propertize-function nil)) 4106 (let ((syntax-propertize-function nil))
4070 (setq yas--dollar-regions nil) ; Reset the yas--dollar-regions. 4107 (setq yas--dollar-regions nil) ; Reset the yas--dollar-regions.
4071 (yas--protect-escapes nil '(?`)) ; Protect just the backquotes. 4108 (yas--protect-escapes nil '(?`)) ; Protect just the backquotes.
4072 (goto-char parse-start) 4109 (goto-char parse-start)
4073 (yas--save-backquotes) ; Replace all backquoted expressions. 4110 (setq saved-quotes (yas--save-backquotes)) ; `expressions`.
4074 (yas--protect-escapes) ; Protect escaped characters. 4111 (yas--protect-escapes) ; Protect escaped characters.
4075 (goto-char parse-start) 4112 (goto-char parse-start)
4076 (yas--indent-parse-create) ; Parse indent markers: `$>'. 4113 (yas--indent-parse-create) ; Parse indent markers: `$>'.
4077 (goto-char parse-start) 4114 (goto-char parse-start)
4078 (yas--field-parse-create snippet) ; Parse fields with {}. 4115 (yas--field-parse-create snippet) ; Parse fields with {}.
4079 (goto-char parse-start) 4116 (goto-char parse-start)
4080 (yas--simple-mirror-parse-create snippet) ; Parse simple mirrors & fields. 4117 (yas--simple-fom-create snippet) ; Parse simple mirrors & fields.
4081 (goto-char parse-start) 4118 (goto-char parse-start)
4082 (yas--transform-mirror-parse-create snippet) ; Parse mirror transforms. 4119 (yas--transform-mirror-parse-create snippet) ; Parse mirror transforms.
4083 ;; Invalidate any syntax-propertizing done while 4120 ;; Invalidate any syntax-propertizing done while
@@ -4101,12 +4138,11 @@ Meant to be called in a narrowed buffer, does various passes"
4101 (get-register yas-wrap-around-region)) 4138 (get-register yas-wrap-around-region))
4102 (insert (prog1 (get-register yas-wrap-around-region) 4139 (insert (prog1 (get-register yas-wrap-around-region)
4103 (set-register yas-wrap-around-region nil))))) 4140 (set-register yas-wrap-around-region nil)))))
4104 (yas--restore-backquotes) ; Restore backquoted expression values. 4141 (yas--restore-backquotes saved-quotes) ; Restore `expression` values.
4105 (goto-char parse-start) 4142 (goto-char parse-start)
4106 (yas--restore-escapes) ; Restore escapes. 4143 (yas--restore-escapes) ; Restore escapes.
4107 (yas--update-mirrors snippet) ; Update mirrors for the first time. 4144 (yas--update-mirrors snippet) ; Update mirrors for the first time.
4108 (goto-char parse-start)) 4145 (goto-char parse-start)))
4109 (yas--indent snippet)) ; Indent the best we can.
4110 4146
4111;; HACK: Some implementations of `indent-line-function' (called via 4147;; HACK: Some implementations of `indent-line-function' (called via
4112;; `indent-according-to-mode') delete text before they insert (like 4148;; `indent-according-to-mode') delete text before they insert (like
@@ -4246,12 +4282,7 @@ The SNIPPET's markers are preserved."
4246 remarkers))) 4282 remarkers)))
4247 (unwind-protect 4283 (unwind-protect
4248 (progn (back-to-indentation) 4284 (progn (back-to-indentation)
4249 (if (eq yas--get-indent-undo-pos bol) 4285 (indent-according-to-mode))
4250 (let ((buffer-undo-list nil))
4251 (indent-according-to-mode)
4252 (setq yas--first-indent-undo
4253 (delq nil buffer-undo-list)))
4254 (indent-according-to-mode)))
4255 (save-restriction 4286 (save-restriction
4256 (narrow-to-region bol (line-end-position)) 4287 (narrow-to-region bol (line-end-position))
4257 (mapc #'yas--restore-marker-location remarkers)))) 4288 (mapc #'yas--restore-marker-location remarkers))))
@@ -4322,9 +4353,11 @@ With optional string TEXT do it in string instead of the buffer."
4322 changed-text)) 4353 changed-text))
4323 4354
4324(defun yas--save-backquotes () 4355(defun yas--save-backquotes ()
4325 "Save all the \"\\=`(lisp-expression)\\=`\"-style expressions 4356 "Save all \"\\=`(lisp-expression)\\=`\"-style expressions.
4326with their evaluated value into `yas--backquote-markers-and-strings'." 4357Return a list of (MARKER . STRING) entires for each backquoted
4327 (let* ((yas--snippet-buffer (current-buffer)) 4358Lisp expression."
4359 (let* ((saved-quotes nil)
4360 (yas--snippet-buffer (current-buffer))
4328 (yas--change-detected nil) 4361 (yas--change-detected nil)
4329 (detect-change (lambda (_beg _end) 4362 (detect-change (lambda (_beg _end)
4330 (when (eq (current-buffer) yas--snippet-buffer) 4363 (when (eq (current-buffer) yas--snippet-buffer)
@@ -4347,29 +4380,28 @@ with their evaluated value into `yas--backquote-markers-and-strings'."
4347 (insert "Y") ;; quite horrendous, I love it :) 4380 (insert "Y") ;; quite horrendous, I love it :)
4348 (set-marker marker (point)) 4381 (set-marker marker (point))
4349 (insert "Y")) 4382 (insert "Y"))
4350 (push (cons marker transformed) yas--backquote-markers-and-strings))))) 4383 (push (cons marker transformed) saved-quotes)))))
4351 (when yas--change-detected 4384 (when yas--change-detected
4352 (lwarn '(yasnippet backquote-change) :warning 4385 (lwarn '(yasnippet backquote-change) :warning
4353 "`%s' modified buffer in a backquote expression. 4386 "`%s' modified buffer in a backquote expression.
4354 To hide this warning, add (yasnippet backquote-change) to `warning-suppress-types'." 4387 To hide this warning, add (yasnippet backquote-change) to `warning-suppress-types'."
4355 (if yas--current-template 4388 (if yas--current-template
4356 (yas--template-name yas--current-template) 4389 (yas--template-name yas--current-template)
4357 "Snippet"))))) 4390 "Snippet")))
4391 saved-quotes))
4358 4392
4359(defun yas--restore-backquotes () 4393(defun yas--restore-backquotes (saved-quotes)
4360 "Replace markers in `yas--backquote-markers-and-strings' with their values." 4394 "Replace markers in SAVED-QUOTES with their values.
4361 (while yas--backquote-markers-and-strings 4395SAVED-QUOTES is the in format returned by `yas--save-backquotes'."
4362 (let* ((marker-and-string (pop yas--backquote-markers-and-strings)) 4396 (cl-loop for (marker . string) in saved-quotes do
4363 (marker (car marker-and-string)) 4397 (save-excursion
4364 (string (cdr marker-and-string))) 4398 (goto-char marker)
4365 (save-excursion 4399 (save-restriction
4366 (goto-char marker) 4400 (widen)
4367 (save-restriction 4401 (delete-char -1)
4368 (widen) 4402 (insert string)
4369 (delete-char -1) 4403 (delete-char 1))
4370 (insert string) 4404 (set-marker marker nil))))
4371 (delete-char 1))
4372 (set-marker marker nil)))))
4373 4405
4374(defun yas--scan-sexps (from count) 4406(defun yas--scan-sexps (from count)
4375 (ignore-errors 4407 (ignore-errors
@@ -4488,10 +4520,10 @@ When multiple expressions are found, only the last one counts."
4488 (when brand-new-mirror 4520 (when brand-new-mirror
4489 (push brand-new-mirror 4521 (push brand-new-mirror
4490 (yas--field-mirrors field)) 4522 (yas--field-mirrors field))
4491 (yas--calculate-mirrors-in-fields snippet brand-new-mirror) 4523 (yas--calculate-simple-fom-parentage snippet brand-new-mirror)
4492 (push (cons (match-beginning 0) real-match-end-0) yas--dollar-regions))))) 4524 (push (cons (match-beginning 0) real-match-end-0) yas--dollar-regions)))))
4493 4525
4494(defun yas--simple-mirror-parse-create (snippet) 4526(defun yas--simple-fom-create (snippet)
4495 "Parse the simple \"$n\" fields/mirrors/exitmarkers in SNIPPET." 4527 "Parse the simple \"$n\" fields/mirrors/exitmarkers in SNIPPET."
4496 (while (re-search-forward yas--simple-mirror-regexp nil t) 4528 (while (re-search-forward yas--simple-mirror-regexp nil t)
4497 (let ((number (string-to-number (match-string-no-properties 1)))) 4529 (let ((number (string-to-number (match-string-no-properties 1))))
@@ -4501,20 +4533,22 @@ When multiple expressions are found, only the last one counts."
4501 (push (cons (match-beginning 0) (yas--exit-marker (yas--snippet-exit snippet))) 4533 (push (cons (match-beginning 0) (yas--exit-marker (yas--snippet-exit snippet)))
4502 yas--dollar-regions)) 4534 yas--dollar-regions))
4503 (t 4535 (t
4504 (let ((field (yas--snippet-find-field snippet number))) 4536 (let ((field (yas--snippet-find-field snippet number))
4537 (fom))
4505 (if field 4538 (if field
4506 (let ((brand-new-mirror (yas--make-mirror 4539 (push
4507 (yas--make-marker (match-beginning 0)) 4540 (setq fom (yas--make-mirror
4508 (yas--make-marker (match-beginning 0)) 4541 (yas--make-marker (match-beginning 0))
4509 nil))) 4542 (yas--make-marker (match-beginning 0))
4510 (push brand-new-mirror 4543 nil))
4511 (yas--field-mirrors field)) 4544 (yas--field-mirrors field))
4512 (yas--calculate-mirrors-in-fields snippet brand-new-mirror)) 4545 (push
4513 (push (yas--make-field number 4546 (setq fom (yas--make-field number
4514 (yas--make-marker (match-beginning 0)) 4547 (yas--make-marker (match-beginning 0))
4515 (yas--make-marker (match-beginning 0)) 4548 (yas--make-marker (match-beginning 0))
4516 nil) 4549 nil))
4517 (yas--snippet-fields snippet)))) 4550 (yas--snippet-fields snippet)))
4551 (yas--calculate-simple-fom-parentage snippet fom))
4518 (push (cons (match-beginning 0) (match-end 0)) 4552 (push (cons (match-beginning 0) (match-end 0))
4519 yas--dollar-regions)))))) 4553 yas--dollar-regions))))))
4520 4554
@@ -4737,7 +4771,7 @@ object satisfying `yas--field-p' to restrict the expansion to.")))
4737 "Log level for `yas--message' 4 means trace most anything, 0 means nothing.") 4771 "Log level for `yas--message' 4 means trace most anything, 0 means nothing.")
4738 4772
4739(defun yas--message (level message &rest args) 4773(defun yas--message (level message &rest args)
4740 "When LEVEL is at or below `yas-verbosity-level', log MESSAGE and ARGS." 4774 "When LEVEL is at or below `yas-verbosity', log MESSAGE and ARGS."
4741 (when (>= yas-verbosity level) 4775 (when (>= yas-verbosity level)
4742 (message "%s" (apply #'yas--format message args)))) 4776 (message "%s" (apply #'yas--format message args))))
4743 4777
@@ -4805,6 +4839,31 @@ and return the directory. Return nil if not found."
4805 (directory-file-name file)))) 4839 (directory-file-name file))))
4806 (setq file nil)))) 4840 (setq file nil))))
4807 root)))) 4841 root))))
4842
4843;;; Unloading
4844
4845(defvar unload-function-defs-list) ; loadhist.el
4846
4847(defun yasnippet-unload-function ()
4848 "Disable minor modes when calling `unload-feature'."
4849 ;; Disable `yas-minor-mode' everywhere it's enabled.
4850 (yas-global-mode -1)
4851 (save-current-buffer
4852 (dolist (buffer (buffer-list))
4853 (set-buffer buffer)
4854 (when yas-minor-mode
4855 (yas-minor-mode -1))))
4856 ;; Remove symbol properties of all our functions, this avoids
4857 ;; Bug#25088 in Emacs 25.1, where the compiler macro on
4858 ;; `cl-defstruct' created functions hang around in the symbol plist
4859 ;; and cause errors when loading again (we don't *need* to clean
4860 ;; *all* symbol plists, but it's easier than being precise).
4861 (dolist (def unload-function-defs-list)
4862 (when (eq (car-safe def) 'defun)
4863 (setplist (cdr def) nil)))
4864 ;; Return nil so that `unload-feature' will take of undefining
4865 ;; functions, and changing any buffers using `snippet-mode'.
4866 nil)
4808 4867
4809 4868
4810;;; Backward compatibility to yasnippet <= 0.7 4869;;; Backward compatibility to yasnippet <= 0.7