;;; yasnippet.el --- Yet another snippet extension for Emacs.
-;; Copyright (C) 2008-2013, 2015 Free Software Foundation, Inc.
-;; Authors: pluskid <pluskid@gmail.com>, João Távora <joaotavora@gmail.com>, Noam Postavsky <npostavs@gmail.com>
+;; Copyright (C) 2008-2016 Free Software Foundation, Inc.
+;; Authors: pluskid <pluskid@gmail.com>,
+;; João Távora <joaotavora@gmail.com>,
+;; Noam Postavsky <npostavs@gmail.com>
;; Maintainer: Noam Postavsky <npostavs@gmail.com>
-;; Version: 0.8.1
-;; Package-version: 0.8.0
+;; Version: 0.9.1
;; X-URL: http://github.com/capitaomorte/yasnippet
;; Keywords: convenience, emulation
;; URL: http://github.com/capitaomorte/yasnippet
+;; Package-Requires: ((cl-lib "0.5"))
;; EmacsWiki: YaSnippetMode
;; This program is free software: you can redistribute it and/or modify
(defvar yas-installed-snippets-dir nil)
(setq yas-installed-snippets-dir
(when load-file-name
- (concat (file-name-directory load-file-name) "snippets")))
+ (expand-file-name "snippets" (file-name-directory load-file-name))))
(defconst yas--default-user-snippets-dir
- (concat user-emacs-directory "snippets"))
+ (expand-file-name "snippets" user-emacs-directory))
(defcustom yas-snippet-dirs (remove nil
(list yas--default-user-snippets-dir
The first directory is taken as the default for storing snippet's
created with `yas-new-snippet'. "
- :type '(choice (string :tag "Single directory (string)")
- (repeat :args (string) :tag "List of directories (strings)"))
+ :type '(choice (directory :tag "Single directory")
+ (repeat :tag "List of directories"
+ (choice (directory) (variable))))
:group 'yasnippet
:require 'yasnippet
:set #'(lambda (symbol new)
(defvaralias 'yas/root-directory 'yas-snippet-dirs)
(defcustom yas-new-snippet-default "\
-# -*- mode: snippet; require-final-newline: nil -*-
+# -*- mode: snippet -*-
# name: $1
-# key: ${2:${1:$(yas--key-from-desc yas-text)}}${3:
-# binding: ${4:direct-keybinding}}
+# key: ${2:${1:$(yas--key-from-desc yas-text)}}
# --
$0"
"Default snippet to use when creating a new snippet.
:type 'string
:group 'yasnippet)
-(defcustom yas-prompt-functions '(yas-x-prompt
- yas-dropdown-prompt
+(defcustom yas-prompt-functions '(yas-dropdown-prompt
yas-completing-prompt
yas-maybe-ido-prompt
yas-no-prompt)
conditions.
(add-hook 'python-mode-hook
- '(lambda ()
+ (lambda ()
(setq yas-buffer-local-condition
'(if (python-in-string/comment)
'(require-snippet-condition . force-in-comment)
\f
;;; Internal variables
-(defvar yas--version "0.8.0beta")
+(defvar yas--version "0.9.1")
(defvar yas--menu-table (make-hash-table)
"A hash table of MAJOR-MODE symbols to menu keymaps.")
This variable probably makes more sense as buffer-local, so
ensure your use `make-local-variable' when you set it.")
-(define-obsolete-variable-alias 'yas-extra-modes 'yas--extra-modes "0.8.1")
+(define-obsolete-variable-alias 'yas-extra-modes 'yas--extra-modes "0.9.1")
(defvar yas--tables (make-hash-table)
"A hash table of mode symbols to `yas--table' objects.")
yas--tables))
(defun yas--modes-to-activate (&optional mode)
- "Compute list of mode symbols that are active for `yas-expand'
-and friends."
+ "Compute list of mode symbols that are active for `yas-expand' and friends."
+ (defvar yas--dfs) ;We rely on dynbind. We could use `letrec' instead!
(let* ((explored (if mode (list mode) ; Building up list in reverse.
(cons major-mode (reverse yas--extra-modes))))
- (dfs
+ (yas--dfs
(lambda (mode)
(cl-loop for neighbour
in (cl-list* (get mode 'derived-mode-parent)
- (ignore-errors (symbol-function mode))
+ ;; NOTE: `fboundp' check is redundant
+ ;; since Emacs 24.4.
+ (and (fboundp mode) (symbol-function mode))
(gethash mode yas--parents))
when (and neighbour
(not (memq neighbour explored))
(symbolp neighbour))
do (push neighbour explored)
- (funcall dfs neighbour)))))
- (mapcar dfs explored)
+ (funcall yas--dfs neighbour)))))
+ (mapc yas--dfs explored)
(nreverse explored)))
(defvar yas-minor-mode-hook nil
;;
;; Also install the post-command-hook.
;;
- (add-hook 'emulation-mode-map-alists 'yas--direct-keymaps)
- (add-hook 'post-command-hook 'yas--post-command-handler nil t)
+ (cl-pushnew 'yas--direct-keymaps emulation-mode-map-alists)
+ (add-hook 'post-command-hook #'yas--post-command-handler nil t)
;; Set the `yas--direct-%s' vars for direct keymap expansion
;;
(dolist (mode (yas--modes-to-activate))
(t
;; Uninstall the direct keymaps and the post-command hook
;;
- (remove-hook 'post-command-hook 'yas--post-command-handler t)
- (remove-hook 'emulation-mode-map-alists 'yas--direct-keymaps))))
+ (remove-hook 'post-command-hook #'yas--post-command-handler t)
+ (setq emulation-mode-map-alists
+ (remove 'yas--direct-keymaps emulation-mode-map-alists)))))
(defun yas-activate-extra-mode (mode)
"Activates the snippets for the given `mode' in the buffer.
(remove mode
yas--extra-modes)))
-(defvar yas-dont-activate '(minibufferp)
- "If non-nil don't let `yas-global-mode' affect some buffers.
+(define-obsolete-variable-alias 'yas-dont-activate
+ 'yas-dont-activate-functions "0.9.2")
+(defvar yas-dont-activate-functions (list #'minibufferp)
+ "Special hook to control which buffers `yas-global-mode' affects.
+Functions are called with no argument, and should return non-nil to prevent
+`yas-global-mode' from enabling yasnippet in this buffer.
-If a function of zero arguments, then its result is used.
-
-If a list of functions, then all functions must return nil to
-activate yas for this buffer.
-
-In Emacsen <= 23, this variable is buffer-local. Because
+In Emacsen < 24, this variable is buffer-local. Because
`yas-minor-mode-on' is called by `yas-global-mode' after
executing the buffer's major mode hook, setting this variable
there is an effective way to define exceptions to the \"global\"
activation behaviour.
-In Emacsen > 23, only the global value is used. To define
+In Emacsen >= 24, only the global value is used. To define
per-mode exceptions to the \"global\" activation behaviour, call
`yas-minor-mode' with a negative argument directily in the major
mode's hook.")
(defun yas-minor-mode-on ()
"Turn on YASnippet minor mode.
-Honour `yas-dont-activate', which see."
+Honour `yas-dont-activate-functions', which see."
(interactive)
- ;; Check `yas-dont-activate'
- (unless (cond ((functionp yas-dont-activate)
- (funcall yas-dont-activate))
- ((consp yas-dont-activate)
- (some #'funcall yas-dont-activate))
- (yas-dont-activate))
+ (unless (or
+ ;; The old behavior used for Emacs<24 was to set
+ ;; `yas-dont-activate-functions' to t buffer-locally.
+ (not (or (listp yas-dont-activate-functions)
+ (functionp yas-dont-activate-functions)))
+ (run-hook-with-args-until-success 'yas-dont-activate-functions))
(yas-minor-mode 1)))
;;;###autoload
"Run `yas-reload-all' when `yas-global-mode' is on."
(when yas-global-mode (yas-reload-all)))
-(add-hook 'yas-global-mode-hook 'yas--global-mode-reload-with-jit-maybe)
+(add-hook 'yas-global-mode-hook #'yas--global-mode-reload-with-jit-maybe)
\f
;;; Major mode stuff
(defvar yas--font-lock-keywords
(append '(("^#.*$" . font-lock-comment-face))
- lisp-font-lock-keywords-2
+ (with-temp-buffer
+ (ignore-errors (emacs-lisp-mode))
+ (font-lock-set-defaults)
+ (if (eq t (car-safe font-lock-keywords))
+ ;; They're "compiled", so extract the source.
+ (cadr font-lock-keywords)
+ font-lock-keywords))
'(("$\\([0-9]+\\)"
(0 font-lock-keyword-face)
(1 font-lock-string-face t))
("${\\([0-9]+\\):?"
(0 font-lock-keyword-face)
(1 font-lock-warning-face t))
- ("${" . font-lock-keyword-face)
- ("$[0-9]+?" . font-lock-preprocessor-face)
("\\(\\$(\\)" 1 font-lock-preprocessor-face)
("}"
(0 font-lock-keyword-face)))))
"The keymap used when `snippet-mode' is active.")
+;;;###autoload
(define-derived-mode snippet-mode text-mode "Snippet"
"A mode for editing yasnippets"
(setq font-lock-defaults '(yas--font-lock-keywords))
(let* ((dominating-dir (locate-dominating-file file
".yas-make-groups"))
(extra-path (and dominating-dir
- (replace-regexp-in-string (concat "^"
- (expand-file-name dominating-dir))
- ""
- (expand-file-name file))))
+ (file-relative-name file dominating-dir)))
(extra-dir (and extra-path
(file-name-directory extra-path)))
(group (and extra-dir
(defun yas--subdirs (directory &optional filep)
"Return subdirs or files of DIRECTORY according to FILEP."
- (remove-if (lambda (file)
- (or (string-match "^\\."
- (file-name-nondirectory file))
- (string-match "^#.*#$"
- (file-name-nondirectory file))
- (string-match "~$"
- (file-name-nondirectory file))
- (if filep
- (file-directory-p file)
- (not (file-directory-p file)))))
- (directory-files directory t)))
+ (cl-remove-if (lambda (file)
+ (or (string-match "\\`\\."
+ (file-name-nondirectory file))
+ (string-match "\\`#.*#\\'"
+ (file-name-nondirectory file))
+ (string-match "~\\'"
+ (file-name-nondirectory file))
+ (if filep
+ (file-directory-p file)
+ (not (file-directory-p file)))))
+ (directory-files directory t)))
(defun yas--make-menu-binding (template)
(let ((mode (yas--table-mode (yas--template-table template))))
(insert (format ";;; Do not edit! File generated at %s\n"
(current-time-string)))))
;; Normal case.
- (unless (file-exists-p (concat directory "/" ".yas-skip"))
+ (unless (file-exists-p (expand-file-name ".yas-skip" directory))
(unless (and (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror (<= yas-verbosity 3))
(progn (yas--message 2 "Loaded compiled snippets from %s" directory) t))
(yas--message 2 "Loading snippet files from %s" directory)
"Reload the directories listed in `yas-snippet-dirs' or
prompt the user to select one."
(let (errors)
- (if yas-snippet-dirs
- (when (member yas--default-user-snippets-dir yas-snippet-dirs)
- (make-directory yas--default-user-snippets-dir t))
- (dolist (directory (reverse (yas-snippet-dirs)))
- (cond ((file-directory-p directory)
- (yas-load-directory directory (not nojit))
- (if nojit
- (yas--message 3 "Loaded %s" directory)
- (yas--message 3 "Prepared just-in-time loading for %s" directory)))
- (t
- (push (yas--message 0 "Check your `yas-snippet-dirs': %s is not a directory" directory) errors))))
- (call-interactively 'yas-load-directory))
+ (if (null yas-snippet-dirs)
+ (call-interactively 'yas-load-directory)
+ (when (member yas--default-user-snippets-dir yas-snippet-dirs)
+ (make-directory yas--default-user-snippets-dir t))
+ (dolist (directory (reverse (yas-snippet-dirs)))
+ (cond ((file-directory-p directory)
+ (yas-load-directory directory (not nojit))
+ (if nojit
+ (yas--message 3 "Loaded %s" directory)
+ (yas--message 3 "Prepared just-in-time loading for %s" directory)))
+ (t
+ (push (yas--message 0 "Check your `yas-snippet-dirs': %s is not a directory" directory) errors)))))
errors))
(defun yas-reload-all (&optional no-jit interactive)
\f
;;; Apropos snippet menu:
;;
-;; The snippet menu keymaps are store by mode in hash table called
+;; The snippet menu keymaps are stored by mode in hash table called
;; `yas--menu-table'. They are linked to the main menu in
;; `yas--menu-keymap-get-create' and are initially created empty,
;; reflecting the table hierarchy.
;; duplicate entries. The `yas--template' objects are created in
;; `yas-define-menu', holding nothing but the menu entry,
;; represented by a pair of ((menu-item NAME :keys KEYS) TYPE) and
-;; stored in `yas--template-menu-binding-pair'. The (menu-item ...)
+;; stored in `yas--template-menu-binding-pair'. The (menu-item ...)
;; part is then stored in the menu keymap itself which make the item
-;; appear to the user. These limitations could probably be revised.
+;; appear to the user. These limitations could probably be revised.
;;
;; * The `yas--template-perm-group' slot is only used in
;; `yas-describe-tables'.
(yas--templates-for-key-at-point))
(yas--templates-for-key-at-point))))
(if templates-and-pos
- (yas--expand-or-prompt-for-template (first templates-and-pos)
- (second templates-and-pos)
- (third templates-and-pos))
+ (yas--expand-or-prompt-for-template (nth 0 templates-and-pos)
+ (nth 1 templates-and-pos)
+ (nth 2 templates-and-pos))
(yas--fallback))))
(defun yas-expand-from-keymap ()
Returns a list of elements (TABLE . DIRS) where TABLE is a
`yas--table' object and DIRS is a list of all possible directories
where snippets of table might exist."
- (let ((main-dir (replace-regexp-in-string
- "/+$" ""
- (or (first (or (yas-snippet-dirs)
- (setq yas-snippet-dirs (list yas--default-user-snippets-dir)))))))
- (tables (or (and table
- (list table))
- (yas--get-snippet-tables))))
+ (let ((main-dir (car (or (yas-snippet-dirs)
+ (setq yas-snippet-dirs
+ (list yas--default-user-snippets-dir)))))
+ (tables (if table (list table)
+ (yas--get-snippet-tables))))
;; HACK! the snippet table created here is actually registered!
;;
(unless (or table (gethash major-mode yas--tables))
(mapcar #'(lambda (table)
(cons table
(mapcar #'(lambda (subdir)
- (concat main-dir "/" subdir))
+ (expand-file-name subdir main-dir))
(yas--guess-snippet-directories-1 table))))
tables)))
(when chosen
(let ((default-file-name (or (and file (file-name-nondirectory file))
(yas--template-name yas--editing-template))))
- (write-file (concat chosen "/"
- (read-from-minibuffer (format "File name to create in %s? " chosen)
- default-file-name)))
+ (write-file (expand-file-name
+ (read-file-name (format "File name to create in %s? " chosen)
+ chosen default-file-name)
+ chosen))
(setf (yas--template-load-file yas--editing-template) buffer-file-name))))))
(when buffer-file-name
(save-buffer)
(and parsed
(fboundp test-mode)
(yas--make-template :table nil ;; no tables for ephemeral snippets
- :key (first parsed)
- :content (second parsed)
- :name (third parsed)
- :expand-env (sixth parsed)))))
+ :key (nth 0 parsed)
+ :content (nth 1 parsed)
+ :name (nth 2 parsed)
+ :expand-env (nth 5 parsed)))))
(cond (yas--current-template
(let ((buffer-name (format "*testing snippet: %s*" (yas--template-name yas--current-template))))
(kill-buffer (get-buffer-create buffer-name))
(setq buffer-read-only nil)
(erase-buffer)
(cond ((not by-name-hash)
- (insert "YASnippet tables: \n")
+ (insert "YASnippet tables:\n")
(while (and table-lists
continue)
(dolist (table (car table-lists))
(setq group (truncate-string-to-width group 25 0 ? "..."))
(insert (make-string 100 ?-) "\n")
(dolist (p templates)
- (let ((name (truncate-string-to-width (propertize (format "\\\\snippet `%s'" (yas--template-name p))
- 'yasnippet p)
- 50 0 ? "..."))
- (group (prog1 group
- (setq group (make-string (length group) ? ))))
- (condition-string (let ((condition (yas--template-condition p)))
- (if (and condition
- original-buffer)
- (with-current-buffer original-buffer
- (if (yas--eval-condition condition)
- "(y)"
- "(s)"))
- "(a)"))))
- (insert group " ")
- (insert condition-string " ")
- (insert name
- (if (string-match "\\.\\.\\.$" name)
- "'"
- " ")
- " ")
- (insert (truncate-string-to-width (or (yas--template-key p) "")
- 15 0 ? "...") " ")
- (insert (truncate-string-to-width (key-description (yas--template-keybinding p))
- 15 0 ? "...") " ")
- (insert "\n"))))
+ (let* ((name (truncate-string-to-width (propertize (format "\\\\snippet `%s'" (yas--template-name p))
+ 'yasnippet p)
+ 50 0 ? "..."))
+ (group (prog1 group
+ (setq group (make-string (length group) ? ))))
+ (condition-string (let ((condition (yas--template-condition p)))
+ (if (and condition
+ original-buffer)
+ (with-current-buffer original-buffer
+ (if (yas--eval-condition condition)
+ "(y)"
+ "(s)"))
+ "(a)")))
+ (key-description-string (key-description (yas--template-keybinding p)))
+ (template-key-padding (if (string= key-description-string "") nil ? )))
+ (insert group " "
+ condition-string " "
+ name (if (string-match "\\.\\.\\.$" name)
+ "'" " ")
+ " "
+ (truncate-string-to-width (or (yas--template-key p) "")
+ 15 0 template-key-padding "...")
+ (or template-key-padding "")
+ (truncate-string-to-width key-description-string
+ 15 0 nil "...")
+ "\n"))))
groups-hash)))
(yas-next-field))))
(yas-next-field)))
+(defun yas--find-next-field (n snippet active)
+ "Return the Nth field after the ACTIVE one in SNIPPET."
+ (let ((live-fields (cl-remove-if
+ (lambda (field)
+ (and (not (eq field active))
+ (yas--field-probably-deleted-p snippet field)))
+ (yas--snippet-fields snippet))))
+ (if (>= n 0) (nth n (memq active live-fields))
+ (car (last (memq active (reverse live-fields)) (- n))))))
+
(defun yas-next-field (&optional arg)
"Navigate to the ARGth next field.
If there's none, exit the snippet."
(interactive)
- (let* ((arg (or arg
- 1))
- (snippet (first (yas--snippets-at-point)))
+ (unless arg (setq arg 1))
+ (let* ((snippet (car (yas--snippets-at-point)))
(active-field (overlay-get yas--active-field-overlay 'yas--field))
- (live-fields (remove-if #'(lambda (field)
- (and (not (eq field active-field))
- (yas--field-probably-deleted-p snippet field)))
- (yas--snippet-fields snippet)))
- (active-field-pos (position active-field live-fields))
- (target-pos (and active-field-pos (+ arg active-field-pos)))
- (target-field (and target-pos (nth target-pos live-fields))))
- ;; First check if we're moving out of a field with a transform
- ;;
- (when (and active-field
- (yas--field-transform active-field))
+ (target-field (yas--find-next-field arg snippet active-field)))
+ ;; First check if we're moving out of a field with a transform.
+ (when (and active-field (yas--field-transform active-field))
(let* ((yas-moving-away-p t)
(yas-text (yas--field-text-for-display active-field))
(yas-modified-p (yas--field-modified-p active-field)))
;; primary field transform: exit call to field-transform
(yas--eval-lisp (yas--field-transform active-field))))
;; Now actually move...
- (cond ((and target-pos (>= target-pos (length live-fields)))
- (yas-exit-snippet snippet))
- (target-field
- (yas--move-to-field snippet target-field))
- (t
- nil))))
+ (if target-field
+ (yas--move-to-field snippet target-field)
+ (yas-exit-snippet snippet))))
(defun yas--place-overlays (snippet field)
"Correctly place overlays for SNIPPET's FIELD."
(t
(call-interactively 'delete-char)))))
-(defun yas--skip-and-clear (field)
- "Deletes the region of FIELD and sets it's modified state to t."
+(defun yas--skip-and-clear (field &optional from)
+ "Deletes the region of FIELD and sets it's modified state to t.
+If given, FROM indicates position to start at instead of FIELD's beginning."
;; Just before skipping-and-clearing the field, mark its children
;; fields as modified, too. If the children have mirrors-in-fields
;; this prevents them from updating erroneously (we're skipping and
;; deleting!).
;;
(yas--mark-this-and-children-modified field)
- (delete-region (yas--field-start field) (yas--field-end field)))
+ (unless (= (yas--field-start field) (yas--field-end field))
+ (delete-region (or from (yas--field-start field)) (yas--field-end field))))
(defun yas--mark-this-and-children-modified (field)
(setf (yas--field-modified-p field) t)
(overlay-put yas--active-field-overlay 'insert-behind-hooks
'(yas--on-field-overlay-modification))))
-(defun yas--on-field-overlay-modification (overlay after? _beg _end &optional _length)
+(defun yas--skip-and-clear-field-p (field beg _end length)
+ "Tell if newly modified FIELD should be cleared and skipped.
+BEG, END and LENGTH like overlay modification hooks."
+ (and (= length 0) ; A 0 pre-change length indicates insertion.
+ (= beg (yas--field-start field)) ; Insertion at field start?
+ (not (yas--field-modified-p field))))
+
+(defun yas--on-field-overlay-modification (overlay after? beg end &optional length)
"Clears the field and updates mirrors, conditionally.
Only clears the field if it hasn't been modified and point is at
field start. This hook does nothing if an undo is in progress."
- (unless (or yas--inhibit-overlay-hooks
+ (unless (or (not after?)
+ yas--inhibit-overlay-hooks
(not (overlayp yas--active-field-overlay)) ; Avoid Emacs bug #21824.
(yas--undo-in-progress))
- (let* ((field (overlay-get overlay 'yas--field))
+ (let* ((inhibit-modification-hooks t)
+ (field (overlay-get overlay 'yas--field))
(snippet (overlay-get yas--active-field-overlay 'yas--snippet)))
- (cond (after?
- (yas--advance-end-maybe field (overlay-end overlay))
- (save-excursion
- (yas--field-update-display field))
- (yas--update-mirrors snippet))
- (field
- (when (and (eq this-command 'self-insert-command)
- (not (yas--field-modified-p field))
- (= (point) (yas--field-start field)))
- (yas--skip-and-clear field))
- (setf (yas--field-modified-p field) t))))))
+ (when (yas--skip-and-clear-field-p field beg end length)
+ ;; We delete text starting from the END of insertion.
+ (yas--skip-and-clear field end))
+ (setf (yas--field-modified-p field) t)
+ (yas--advance-end-maybe field (overlay-end overlay))
+ (save-excursion
+ (yas--field-update-display field))
+ (yas--update-mirrors snippet))))
\f
;;; Apropos protection overlays:
;;
;; (overlay-put ov 'evaporate t)
(overlay-put ov 'modification-hooks '(yas--on-protection-overlay-modification)))))))
-(defun yas--on-protection-overlay-modification (_overlay after? _beg _end &optional _length)
- "Signals a snippet violation, then issues error.
-
-The error should be ignored in `debug-ignored-errors'"
+(defun yas--on-protection-overlay-modification (_overlay after? beg end &optional length)
+ "Commit the snippet if the protection overlay is being killed."
(unless (or yas--inhibit-overlay-hooks
- after?
+ (not after?)
+ (= length (- end beg)) ; deletion or insertion
(yas--undo-in-progress))
(let ((snippets (yas--snippets-at-point)))
(yas--message 3 "Comitting snippets. Action would destroy a protection overlay.")
(defun yas--update-mirrors (snippet)
"Update all the mirrors of SNIPPET."
- (save-excursion
- (dolist (field-and-mirror (sort
- ;; make a list of ((F1 . M1) (F1 . M2) (F2 . M3) (F2 . M4) ...)
- ;; where F is the field that M is mirroring
- ;;
- (mapcan #'(lambda (field)
- (mapcar #'(lambda (mirror)
- (cons field mirror))
- (yas--field-mirrors field)))
- (yas--snippet-fields snippet))
- ;; then sort this list so that entries with mirrors with parent
- ;; fields appear before. This was important for fixing #290, and
- ;; luckily also handles the case where a mirror in a field causes
- ;; another mirror to need reupdating
- ;;
- #'(lambda (field-and-mirror1 field-and-mirror2)
- (> (yas--calculate-mirror-depth (cdr field-and-mirror1))
- (yas--calculate-mirror-depth (cdr field-and-mirror2))))))
- (let* ((field (car field-and-mirror))
- (mirror (cdr field-and-mirror))
- (parent-field (yas--mirror-parent-field mirror)))
- ;; before updating a mirror with a parent-field, maybe advance
- ;; its start (#290)
- ;;
- (when parent-field
- (yas--advance-start-maybe mirror (yas--fom-start parent-field)))
- ;; update this mirror
- ;;
- (yas--mirror-update-display mirror field)
- ;; `yas--place-overlays' is needed if the active field and
- ;; protected overlays have been changed because of insertions
- ;; in `yas--mirror-update-display'
- ;;
- (when (eq field (yas--snippet-active-field snippet))
- (yas--place-overlays snippet field))))))
+ (save-restriction
+ (widen)
+ (save-excursion
+ (dolist (field-and-mirror
+ (sort
+ ;; make a list of ((F1 . M1) (F1 . M2) (F2 . M3) (F2 . M4) ...)
+ ;; where F is the field that M is mirroring
+ ;;
+ (cl-mapcan #'(lambda (field)
+ (mapcar #'(lambda (mirror)
+ (cons field mirror))
+ (yas--field-mirrors field)))
+ (yas--snippet-fields snippet))
+ ;; then sort this list so that entries with mirrors with parent
+ ;; fields appear before. This was important for fixing #290, and
+ ;; luckily also handles the case where a mirror in a field causes
+ ;; another mirror to need reupdating
+ ;;
+ #'(lambda (field-and-mirror1 field-and-mirror2)
+ (> (yas--calculate-mirror-depth (cdr field-and-mirror1))
+ (yas--calculate-mirror-depth (cdr field-and-mirror2))))))
+ (let* ((field (car field-and-mirror))
+ (mirror (cdr field-and-mirror))
+ (parent-field (yas--mirror-parent-field mirror)))
+ ;; before updating a mirror with a parent-field, maybe advance
+ ;; its start (#290)
+ ;;
+ (when parent-field
+ (yas--advance-start-maybe mirror (yas--fom-start parent-field)))
+ ;; update this mirror
+ ;;
+ (yas--mirror-update-display mirror field)
+ ;; `yas--place-overlays' is needed if the active field and
+ ;; protected overlays have been changed because of insertions
+ ;; in `yas--mirror-update-display'
+ ;;
+ (when (eq field (yas--snippet-active-field snippet))
+ (yas--place-overlays snippet field)))))))
(defun yas--mirror-update-display (mirror field)
"Update MIRROR according to FIELD (and mirror transform)."
'(yas--expand-from-keymap-doc t))
(defun yas--expand-from-keymap-doc (context)
"A doc synthesizer for `yas--expand-from-keymap-doc'."
- (add-hook 'temp-buffer-show-hook 'yas--snippet-description-finish-runonce)
+ (add-hook 'temp-buffer-show-hook #'yas--snippet-description-finish-runonce)
(concat "Expand/run snippets from keymaps, possibly falling back to original binding.\n"
(when (and context (eq this-command 'describe-key))
(let* ((vec (this-single-command-keys))
(defun yas--snippet-description-finish-runonce ()
"Final adjustments for the help buffer when snippets are concerned."
(yas--create-snippet-xrefs)
- (remove-hook 'temp-buffer-show-hook 'yas--snippet-description-finish-runonce))
+ (remove-hook 'temp-buffer-show-hook
+ #'yas--snippet-description-finish-runonce))
(defun yas--create-snippet-xrefs ()
(save-excursion
'yasnippet)))
(when template
(help-xref-button 1 'help-snippet-def template)
- (kill-region (match-end 1) (match-end 0))
- (kill-region (match-beginning 0) (match-beginning 1)))))))
+ (delete-region (match-end 1) (match-end 0))
+ (delete-region (match-beginning 0) (match-beginning 1)))))))
\f
;;; Utils
They are mapped to \"yas/*\" variants.")
(dolist (sym yas--backported-syms)
- (let ((backported (intern (replace-regexp-in-string "^yas-" "yas/" (symbol-name sym)))))
+ (let ((backported (intern (replace-regexp-in-string "\\`yas-" "yas/" (symbol-name sym)))))
(when (boundp sym)
(make-obsolete-variable backported sym "yasnippet 0.8")
(defvaralias backported sym))
(not (get atom 'byte-obsolete-variable)))
(and (fboundp atom)
(not (get atom 'byte-obsolete-info))))
- (string-match-p "^yas-[^-]" (symbol-name atom)))
+ (string-match-p "\\`yas-[^-]" (symbol-name atom)))
(push atom exported))))
exported)
"Exported yasnippet symbols.