;; Authors: pluskid <pluskid@gmail.com>, joaotavora <joaotavora@gmail.com>
;; Version: 0.7.0
;; Package-version: 0.7.0
-;; X-URL: http://code.google.com/p/yasnippet/
+;; X-URL: http://github.com/capitaomorte/yasnippet
;; Keywords: convenience, emulation
-;; URL: http://code.google.com/p/yasnippet/
+;; URL: http://github.com/capitaomorte/yasnippet
;; EmacsWiki: YaSnippetMode
;; This file is free software; you can redistribute it and/or modify
;; Basic steps to setup:
;;
-;; 1. In your .emacs file:
-;; (add-to-list 'load-path "/dir/to/yasnippet.el")
-;; (require 'yasnippet)
-;; 2. Place the `snippets' directory somewhere. E.g: ~/.emacs.d/snippets
-;; 3. In your .emacs file
-;; (setq yas/snippet-dirs "~/.emacs/snippets")
-;; (yas/load-directory yas/snippet-dirs)
-;; 4. To enable the YASnippet menu and tab-trigger expansion
-;; M-x yas/minor-mode
-;; 5. To globally enable the minor mode in *all* buffers
-;; M-x yas/global-mode
+;; (add-to-list 'load-path
+;; "~/.emacs.d/plugins/yasnippet")
+;; (require 'yasnippet)
+;; (yas/global-mode 1)
;;
-;; Steps 4. and 5. are optional, you don't have to use the minor
-;; mode to use YASnippet.
;;
;; Interesting variables are:
;;
;; `custom-set-variables' is executed in your .emacs file.
;;
;; For more information and detailed usage, refer to the project page:
-;; http://code.google.com/p/yasnippet/
+;; http://github.com/capitaomorte/yasnippet
;;; Code:
(require 'cl)
-(require 'assoc)
(require 'easymenu)
(require 'help-mode)
(equal old new))
(yas/reload-all)))))
(defun yas/snippet-dirs ()
+ "Returns `yas/snippet-dirs' (which see) as a list."
(if (listp yas/snippet-dirs) yas/snippet-dirs (list yas/snippet-dirs)))
(defvaralias 'yas/root-directory 'yas/snippet-dirs)
t)
"Snippet expanding condition.
-This variable is a lisp form:
+This variable is a lisp form which is evaluated everytime a
+snippet expansion is attemped:
* If it evaluates to nil, no snippets can be expanded.
"A list of mode which is well known but not part of emacs.")
(defvar yas/escaped-characters
- '(?\\ ?` ?' ?$ ?} ?{ ?\( ?\))
+ '(?\\ ?` ?\" ?' ?$ ?} ?{ ?\( ?\))
"List of characters which *might* need to be escaped.")
(defconst yas/field-regexp
(define-key yas/minor-mode-map (read-kbd-macro yas/trigger-key) 'yas/expand)))
(defvar yas/tables (make-hash-table)
- "A hash table of MAJOR-MODE symbols to `yas/table' objects.")
+ "A hash table of mode symbols to `yas/table' objects.")
+
+(defvar yas/parents (make-hash-table)
+ "A hash table of mode symbols do lists of direct parent mode symbols.
+
+This list is populated when reading the \".yas-parents\" files
+found when traversing snippet directories with
+`yas/load-directory'.
+
+There might be additionalal parenting information stored in the
+`derived-mode-parent' property of some mode symbols, but that is
+not recorded here.")
(defvar yas/direct-keymaps (list)
"Keymap alist supporting direct snippet keybindings.
-This variable is is placed `emulation-mode-map-alists'.
+This variable is is placed in `emulation-mode-map-alists'.
-Its elements looks like (TABLE-NAME . KEYMAP) and are
-calculated when loading snippets. TABLE-NAME is a variable
-set buffer-locally when entering `yas/minor-mode'. KEYMAP binds
-all defined direct keybindings to the command
-`yas/expand-from-keymap', which acts similarly to `yas/expand'")
+Its elements looks like (TABLE-NAME . KEYMAP). They're
+instantiated on `yas/reload-all' but KEYMAP is added to only when
+loading snippets. `yas//direct-TABLE-NAME' is then a variable set
+buffer-locally when entering `yas/minor-mode'. KEYMAP binds all
+defined direct keybindings to the command
+`yas/expand-from-keymap' which then which snippet to expand.")
(defun yas/direct-keymaps-reload ()
"Force reload the direct keybinding for active snippet tables."
(interactive)
(setq yas/direct-keymaps nil)
(maphash #'(lambda (name table)
- (mapc #'(lambda (table)
- (push (cons (intern (format "yas//direct-%s" name))
- (yas/table-direct-keymap table))
- yas/direct-keymaps))
- (cons table (yas/table-get-all-parents table))))
+ (push (cons (intern (format "yas//direct-%s" name))
+ (yas/table-direct-keymap table))
+ yas/direct-keymaps))
yas/tables))
-(defun yas/direct-keymaps-set-vars ()
+(defun yas/modes-to-activate ()
+ "Compute list of mode symbols that are active for `yas/expand'
+and friends."
(let ((modes-to-activate (list major-mode))
(mode major-mode))
(while (setq mode (get mode 'derived-mode-parent))
(push mode modes-to-activate))
(dolist (mode (yas/extra-modes))
(push mode modes-to-activate))
- (dolist (mode modes-to-activate)
- (let ((name (intern (format "yas//direct-%s" mode))))
- (set-default name nil)
- (set (make-local-variable name) t)))))
+ (remove-duplicates
+ (append modes-to-activate
+ (mapcan #'(lambda (mode)
+ (yas/all-parents mode))
+ modes-to-activate)))))
(defvar yas/minor-mode-hook nil
"Hook run when yas/minor-mode is turned on")
(define-minor-mode yas/minor-mode
"Toggle YASnippet mode.
-When YASnippet mode is enabled, the `tas/trigger-key' key expands
+When YASnippet mode is enabled, the `yas/trigger-key' key expands
snippets of code depending on the mode.
With no argument, this command toggles the mode.
;;
(add-hook 'emulation-mode-map-alists 'yas/direct-keymaps)
(add-hook 'post-command-hook 'yas/post-command-handler nil t)
- (add-hook 'yas/minor-mode-hook 'yas/direct-keymaps-set-vars-runonce 'append))
+ ;; Set the `yas//direct-%s' vars for direct keymap expansion
+ ;;
+ (dolist (mode (yas/modes-to-activate))
+ (let ((name (intern (format "yas//direct-%s" mode))))
+ (set-default name nil)
+ (set (make-local-variable name) t)))
+ ;; Perform JIT loads
+ ;;
+ (yas/load-pending-jits))
(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))))
-(defun yas/direct-keymaps-set-vars-runonce ()
- (yas/direct-keymaps-set-vars)
- (remove-hook 'yas/minor-mode-hook 'yas/direct-keymaps-set-vars-runonce))
(defvar yas/dont-activate nil
"If non-nil don't let `yas/minor-mode-on' active yas for this buffer.
:group 'yasnippet
:require 'yasnippet)
-(add-hook 'yas/global-mode-hook 'yas/reload-all-maybe)
-(defun yas/reload-all-maybe ()
- (if yas/global-mode
- (yas/reload-all)))
+(defadvice yas/global-mode (before yas/reload-with-jit (arg) activate)
+ (cond ((and arg
+ (numberp arg)
+ (> arg 1))
+ ;; explicitly enabling
+ (yas/reload-all))
+ ((not yas/global-mode)
+ ;; toggling
+ (yas/reload-all))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Major mode stuff
(define-derived-mode snippet-mode text-mode "Snippet"
"A mode for editing yasnippets"
- (set-syntax-table (standard-syntax-table))
(setq font-lock-defaults '(yas/font-lock-keywords))
(set (make-local-variable 'require-final-newline) nil)
- (use-local-map snippet-mode-map))
+ (set (make-local-variable 'comment-start) "#")
+ (set (make-local-variable 'comment-start-skip) "#+[\t ]*"))
\f
(defstruct (yas/template (:constructor yas/make-blank-template))
"A template for a snippet."
- table
key
content
name
keybinding
uuid
menu-binding-pair
- group ;; as dictated by the #group: directive or .yas-make-groups
+ group ;; as dictated by the #group: directive or .yas-make-groups
perm-group ;; as dictated by `yas/define-menu'
+ table
)
(defun yas/populate-template (template &rest args)
another hash of (NAME . TEMPLATE) where NAME is the snippet's
name and TEMPLATE is a `yas/template' object.
-`yas/table-parents'
-
- A list of tables considered parents of this table: i.e. when
- searching for expansions they are searched as well.
-
`yas/table-direct-keymap'
A keymap for the snippets in this table that have direct
;;
(remhash uuid (yas/table-uuidhash table))))))
-
(defun yas/add-template (table template)
"Store in TABLE the snippet template TEMPLATE.
(let ((name (yas/template-name template))
(key (yas/template-key template))
(keybinding (yas/template-keybinding template))
- (menu-binding (car (yas/template-menu-binding-pair template))))
+ (menu-binding-pair (yas/snippet-menu-binding-pair-get-create template)))
(dolist (k (remove nil (list key keybinding)))
(puthash name
template
(when (vectorp k)
(define-key (yas/table-direct-keymap table) k 'yas/expand-from-keymap)))
- (when menu-binding
- (setf (getf (cdr menu-binding) :keys)
- (or (and keybinding (key-description keybinding))
- (and key (concat key yas/trigger-symbol))))
- (setcar (cdr menu-binding)
- name))
+ ;; Update trigger & keybinding in the menu-binding pair
+ ;;
+ (setf (getf (cdr (car menu-binding-pair)) :keys)
+ (or (and keybinding (key-description keybinding))
+ (and key (concat key yas/trigger-symbol))))
(puthash (yas/template-uuid template) template (yas/table-uuidhash table))))
-(defun yas/update-template (snippet-table template)
- "Add or update TEMPLATE in SNIPPET-TABLE.
+(defun yas/update-template (table template)
+ "Add or update TEMPLATE in TABLE.
-Also takes care of adding and updaring to the associated menu."
+Also takes care of adding and updating to the associated menu."
;; Remove from table by uuid
;;
- (yas/remove-template-by-uuid snippet-table (yas/template-uuid template))
+ (yas/remove-template-by-uuid table (yas/template-uuid template))
;; Add to table again
;;
- (yas/add-template snippet-table template)
+ (yas/add-template table template)
;; Take care of the menu
;;
- (let ((keymap (yas/menu-keymap-get-create snippet-table))
+ (let ((keymap (yas/menu-keymap-get-create table))
(group (yas/template-group template)))
(when (and yas/use-menu
keymap
(yas/delete-from-keymap keymap (yas/template-uuid template))
;; Add necessary subgroups as necessary.
- ;;
+ ;;
(dolist (subgroup group)
(let ((subgroup-keymap (lookup-key keymap (vector (make-symbol subgroup)))))
(unless (and subgroup-keymap
(define-key keymap (vector (make-symbol subgroup))
`(menu-item ,subgroup ,subgroup-keymap)))
(setq keymap subgroup-keymap)))
-
+
;; Add this entry to the keymap
- ;;
+ ;;
(let ((menu-binding-pair (yas/snippet-menu-binding-pair-get-create template)))
(define-key keymap (vector (make-symbol (yas/template-uuid template))) (car menu-binding-pair))))))
(save-match-data
(eval condition))))
(error (progn
- (message (format "[yas] error in condition evaluation: %s"
- (error-message-string err)))
+ (yas/message 1 "Error in condition evaluation: %s" (error-message-string err))
nil))))
(t
(eq requirement result)))))
-(defun yas/table-get-all-parents (table)
- "Returns a list of all parent tables of TABLE"
- (let ((parents (yas/table-parents table)))
- (when parents
- (append (copy-list parents)
- (mapcan #'yas/table-get-all-parents parents)))))
+(defun yas/all-parents (mode)
+ "Returns a list of all parent modes of MODE"
+ (let ((parents (gethash mode yas/parents)))
+ (append parents
+ (mapcan #'yas/all-parents parents))))
(defun yas/table-templates (table)
(when table
(when result
(format "%s" result))))))
(error (if yas/good-grace
- (format "[yas] elisp error! %s" (error-message-string err))
- (error (format "[yas] elisp error: %s"
+ (yas/format "elisp error! %s" (error-message-string err))
+ (error (yas/format "elisp error: %s"
(error-message-string err)))))))))
(when (and (consp retval)
(eq 'yas/exception (car retval)))
(condition-case err
(eval form)
(error (if yas/good-grace
- (format "[yas] elisp error! %s" (error-message-string err))
- (error (format "[yas] elisp error: %s"
+ (yas/format "elisp error! %s" (error-message-string err))
+ (error (yas/format "elisp error: %s"
(error-message-string err)))))))
(defun yas/read-lisp (string &optional nil-on-error)
(condition-case err
(read string)
(error (and (not nil-on-error)
- `(error (error-message-string err))))))
+ `(error (error-message-string ,err))))))
(defun yas/read-keybinding (keybinding)
"Read KEYBINDING as a snippet keybinding, return a vector."
(read-kbd-macro keybinding 'need-vector))))
res)
(error
- (message "[yas] warning: keybinding \"%s\" invalid since %s."
+ (yas/message 3 "warning: keybinding \"%s\" invalid since %s."
keybinding (error-message-string err))
nil))))
(defvaralias 'yas/mode-symbol 'yas/extra-modes)
(defun yas/table-get-create (mode)
- "Get the snippet table corresponding to MODE.
-
-Optional DIRECTORY gets recorded as the default directory to
-search for snippet files if the retrieved/created table didn't
-already have such a property."
+ "Get or create the snippet table corresponding to MODE."
(let ((table (gethash mode
yas/tables)))
(unless table
(setq table (yas/make-snippet-table (symbol-name mode)))
(puthash mode table yas/tables)
- (aput 'yas/direct-keymaps (intern (format "yas//direct-%s" mode))
- (yas/table-direct-keymap table)))
+ (push (cons (intern (format "yas//direct-%s" mode))
+ (yas/table-direct-keymap table))
+ yas/direct-keymaps))
table))
-(defun yas/get-snippet-tables (&optional mode-symbol dont-search-parents)
+(defun yas/get-snippet-tables ()
"Get snippet tables for current buffer.
-Return a list of 'yas/table' objects indexed by mode.
-
-The modes are tried in this order: optional MODE-SYMBOL, then
-`yas/extra-modes', then `major-mode' then, unless
-DONT-SEARCH-PARENTS is non-nil, the guessed parent mode of either
-MODE-SYMBOL or `major-mode'.
-
-Guessing is done by looking up the MODE-SYMBOL's
-`derived-mode-parent' property, see also `derived-mode-p'."
- (let ((mode-tables
- (remove nil
- (mapcar #'(lambda (mode)
- (gethash mode yas/tables))
- (remove nil (append (list mode-symbol)
- (yas/extra-modes)
- (list major-mode
- (and (not dont-search-parents)
- (get major-mode
- 'derived-mode-parent)))))))))
- (remove-duplicates
- (append mode-tables
- (mapcan #'yas/table-get-all-parents mode-tables)))))
+Return a list of `yas/table' objects. The list of modes to
+consider is returned by `yas/modes-to-activate'"
+ (remove nil
+ (mapcar #'(lambda (mode-name)
+ (gethash mode-name yas/tables))
+ (yas/modes-to-activate))))
(defun yas/menu-keymap-get-create (table)
"Get or create the main menu keymap correspondong to MODE.
(setq binding (match-string-no-properties 2)))))
(setq template
(buffer-substring-no-properties (point-min) (point-max))))
+ (unless (or key binding)
+ (setq key (and file (file-name-nondirectory file))))
(when (eq type 'command)
(setq template (yas/read-lisp (concat "(progn" template ")"))))
(when group
(directory-file-name extra-dir)))))
group))
-(defun yas/subdirs (directory &optional file?)
- "Return subdirs or files of DIRECTORY according to FILE?."
+(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))
(file-name-nondirectory file))
(string-match "~$"
(file-name-nondirectory file))
- (if file?
+ (if filep
(file-directory-p file)
(not (file-directory-p file)))))
(directory-files directory t)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Popping up for keys and templates
;;
+(defvar yas/x-pretty-prompt-templates nil
+ "If non-nil, attempt to prompt for templates like TextMate.")
+
+
(defun yas/prompt-for-template (templates &optional prompt)
"Interactively choose a template from the list TEMPLATES.
(or chosen
(keyboard-quit)))))
-(defvar yas/x-pretty-prompt-templates nil
- "If non-nil, attempt to prompt for templates like TextMate.")
(defun yas/x-pretty-prompt-templates (prompt templates)
"Display TEMPLATES, grouping neatly by table name."
- (let ((pretty-alist (list))
+ (let ((organized (make-hash-table :test #'equal))
menu
more-than-one-table
prefix)
(dolist (tl templates)
- (aput 'pretty-alist (yas/template-table tl) (cons tl (aget pretty-alist (yas/template-table tl)))))
- (setq more-than-one-table (> (length pretty-alist) 1))
+ (puthash (yas/template-table tl)
+ (cons tl
+ (gethash (yas/template-table tl) organized))
+ organized))
+ (setq more-than-one-table (> (hash-table-count organized) 1))
(setq prefix (if more-than-one-table
" " ""))
- (dolist (table-and-templates pretty-alist)
- (when (cdr table-and-templates)
- (if more-than-one-table
- (push (yas/table-name (car table-and-templates)) menu))
- (dolist (template (cdr table-and-templates))
- (push (cons (concat prefix (yas/template-name template))
- template) menu))))
+ (if more-than-one-table
+ (maphash #'(lambda (table templates)
+ (push (yas/table-name table) menu)
+ (dolist (tl templates)
+ (push (cons (concat prefix (yas/template-name tl)) tl) menu))) organized)
+ (setq menu (mapcar #'(lambda (tl) (cons (concat prefix (yas/template-name tl)) tl)) templates)))
+
(setq menu (nreverse menu))
(or (x-popup-menu (if (fboundp 'posn-at-point)
(let ((x-y (posn-x-y (posn-at-point (point)))))
(keyboard-quit))))
(defun yas/ido-prompt (prompt choices &optional display-fn)
- (when (featurep 'ido)
+ (when (fboundp 'ido-completing-read)
(yas/completing-prompt prompt choices display-fn #'ido-completing-read)))
(eval-when-compile (require 'dropdown-list nil t))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Loading snippets from files
;;
-(defun yas/load-directory-1 (directory &optional mode-sym parents)
- "Recursively load snippet templates from DIRECTORY."
+(defun yas/load-yas-setup-file (file)
+ (load file 'noerror))
- ;; Load .yas-setup.el files wherever we find them
- ;;
- (let ((file (concat directory "/" ".yas-setup")))
- (when (or (file-readable-p (concat file ".el"))
- (file-readable-p (concat file ".elc")))
- (load file)))
+(defun yas/load-directory (top-level-dir &optional use-jit)
+ "Load snippets in directory hierarchy TOP-LEVEL-DIR.
- ;;
- ;;
- (unless (file-exists-p (concat directory "/" ".yas-skip"))
- (let* ((major-mode-and-parents (if mode-sym
- (cons mode-sym parents)
- (yas/compute-major-mode-and-parents (concat directory
- "/dummy"))))
- (default-directory directory)
- (snippet-defs nil))
- ;; load the snippet files
- ;;
- (with-temp-buffer
- (dolist (file (yas/subdirs directory 'no-subdirs-just-files))
- (when (file-readable-p file)
- (insert-file-contents file nil nil nil t)
- (push (yas/parse-template file)
- snippet-defs))))
- (when (or snippet-defs
- (cdr major-mode-and-parents))
- (yas/define-snippets (car major-mode-and-parents)
- snippet-defs
- (cdr major-mode-and-parents)))
- ;; now recurse to a lower level
- ;;
- (dolist (subdir (yas/subdirs directory))
- (yas/load-directory-1 subdir
- (car major-mode-and-parents)
- (cdr major-mode-and-parents))))))
-
-(defun yas/load-directory (directory)
- "Load snippet definition from a directory hierarchy.
-
-Below the top-level directory, each directory is a mode
-name. And under each subdirectory, each file is a definition
-of a snippet. The file name is the trigger key and the
-content of the file is the template."
+Below TOP-LEVEL-DIR each directory should be a mode name.
+
+Optional USE-JIT use jit-loading of snippets."
(interactive "DSelect the root directory: ")
- (unless (file-directory-p directory)
- (error "%s is not a directory" directory))
(unless yas/snippet-dirs
- (setq yas/snippet-dirs directory))
- (dolist (dir (yas/subdirs directory))
- (yas/load-directory-1 dir))
+ (setq yas/snippet-dirs top-level-dir))
+ (dolist (dir (yas/subdirs top-level-dir))
+ (let* ((major-mode-and-parents (yas/compute-major-mode-and-parents
+ (concat dir "/dummy")))
+ (mode-sym (car major-mode-and-parents))
+ (parents (cdr major-mode-and-parents)))
+ (yas/define-parents mode-sym parents)
+ (let ((form `(yas/load-directory-1 ,dir
+ ',mode-sym
+ ',parents)))
+ (if use-jit
+ (yas/schedule-jit mode-sym form)
+ (eval form)))))
(when (interactive-p)
- (message "[yas] Loaded snippets from %s." directory)))
+ (yas/message 3 "Loaded snippets from %s." top-level-dir)))
+
+(defun yas/load-directory-1 (directory mode-sym parents &optional no-compiled-snippets)
+ "Recursively load snippet templates from DIRECTORY."
+ (unless (file-exists-p (concat directory "/" ".yas-skip"))
+ (if (and (not no-compiled-snippets)
+ (load (expand-file-name ".yas-compiled-snippets" directory) 'noerror (<= yas/verbosity 2)))
+ (yas/message 2 "Loading much faster .yas-compiled-snippets from %s" directory)
+ (yas/load-directory-2 directory mode-sym))))
-(defun yas/load-snippet-dirs ()
+(defun yas/load-directory-2 (directory mode-sym)
+ ;; Load .yas-setup.el files wherever we find them
+ ;;
+ (yas/load-yas-setup-file (expand-file-name ".yas-setup" directory))
+ (let* ((default-directory directory)
+ (snippet-defs nil))
+ ;; load the snippet files
+ ;;
+ (with-temp-buffer
+ (dolist (file (yas/subdirs directory 'no-subdirs-just-files))
+ (when (file-readable-p file)
+ (insert-file-contents file nil nil nil t)
+ (push (yas/parse-template file)
+ snippet-defs))))
+ (when snippet-defs
+ (yas/define-snippets mode-sym
+ snippet-defs))
+ ;; now recurse to a lower level
+ ;;
+ (dolist (subdir (yas/subdirs directory))
+ (yas/load-directory-2 subdir
+ mode-sym))))
+
+(defun yas/load-snippet-dirs (&optional nojit)
"Reload the directories listed in `yas/snippet-dirs' or
prompt the user to select one."
- (if yas/snippet-dirs
- (dolist (directory (reverse (yas/snippet-dirs)))
- (yas/load-directory directory))
- (call-interactively 'yas/load-directory)))
-
-(defun yas/reload-all (&optional interactive)
- "Reload all snippets and rebuild the YASnippet menu. "
+ (let (errors)
+ (if yas/snippet-dirs
+ (dolist (directory (reverse (yas/snippet-dirs)))
+ (cond ((file-directory-p directory)
+ (yas/load-directory directory (not nojit))
+ (yas/message 3 "Loaded %s" directory))
+ (t
+ (push (yas/message 0 "Check your `yas/snippet-dirs': %s is not a directory" directory) errors))))
+ (call-interactively 'yas/load-directory))
+ errors))
+
+(defun yas/reload-all (&optional no-jit)
+ "Reload all snippets and rebuild the YASnippet menu.
+
+Behaviour is affected by `yas/no-jit', which see."
(interactive "p")
- (let ((errors))
- ;; Empty all snippet tables and all menu tables
- ;;
- (setq yas/tables (make-hash-table))
- (setq yas/menu-table (make-hash-table))
+ (catch 'abort
+ (let ((errors)
+ (snippet-editing-buffers
+ (remove-if-not #'(lambda (buffer)
+ (with-current-buffer buffer yas/editing-template))
+ (buffer-list))))
+ ;; Warn if there are buffers visiting snippets, since reloading will break
+ ;; any on-line editing of those buffers.
+ ;;
+ (if snippet-editing-buffers
+ (if (y-or-n-p "Some buffers editing live snippets, close them and proceed with reload?")
+ (mapcar #'kill-buffer snippet-editing-buffers)
+ (yas/message 1 "Aborted reload...")
+ (throw 'abort nil)))
- ;; Init the `yas/minor-mode-map', taking care not to break the
- ;; menu....
- ;;
- (setf (cdr yas/minor-mode-map)
- (cdr (yas/init-minor-keymap)))
+ ;; Empty all snippet tables, parenting info and all menu tables
+ ;;
+ (setq yas/tables (make-hash-table))
+ (setq yas/parents (make-hash-table))
+ (setq yas/menu-table (make-hash-table))
- ;; Reload the directories listed in `yas/snippet-dirs' or prompt
- ;; the user to select one.
- ;;
- (condition-case oops
- (yas/load-snippet-dirs)
- (error (push oops errors)
- (message "[yas] Check your `yas/snippet-dirs': %s" (second oops))))
- ;; Reload the direct keybindings
- ;;
- (yas/direct-keymaps-reload)
- (message "[yas] Reloaded everything...%s." (if errors " (some errors, check *Messages*)" ""))))
+ ;; Cancel all pending 'yas/scheduled-jit-loads'
+ ;;
+ (setq yas/scheduled-jit-loads (make-hash-table))
+
+ ;; Init the `yas/minor-mode-map', taking care not to break the
+ ;; menu....
+ ;;
+ (setf (cdr yas/minor-mode-map)
+ (cdr (yas/init-minor-keymap)))
+
+ ;; Reload the directories listed in `yas/snippet-dirs' or prompt
+ ;; the user to select one.
+ ;;
+ (setq errors (yas/load-snippet-dirs no-jit))
+ ;; Reload the direct keybindings
+ ;;
+ (yas/direct-keymaps-reload)
+ ;; Reload the trigger-key (shoudn't be needed, but see issue #237)
+ ;;
+ (yas/trigger-key-reload)
+
+ (yas/message 3 "Reloaded everything...%s." (if errors " (some errors, check *Messages*)" "")))))
+
+(defun yas/load-pending-jits ()
+ (when yas/minor-mode
+ (dolist (mode (yas/modes-to-activate))
+ (let ((forms (gethash mode yas/scheduled-jit-loads)))
+ (dolist (form forms)
+ (yas/message 3 "Loading snippets for %s, just in time: %s!" mode form)
+ (eval form))
+ (remhash mode yas/scheduled-jit-loads)))))
+
+;; (when (<= emacs-major-version 22)
+;; (add-hook 'after-change-major-mode-hook 'yas/load-pending-jits))
(defun yas/quote-string (string)
"Escape and quote STRING.
t)
"\""))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Yasnippet Bundle
+;;; Snippet compilation function
(defun yas/initialize ()
"For backward compatibility, enable `yas/minor-mode' globally"
(yas/global-mode 1))
-(defun yas/compile-bundle
- (&optional yasnippet yasnippet-bundle snippet-roots code dropdown)
- "Compile snippets in SNIPPET-ROOTS to a single bundle file.
-
-YASNIPPET is the yasnippet.el file path.
-
-YASNIPPET-BUNDLE is the output file of the compile result.
+(defun yas/compile-directory (top-level-dir)
+ "Create .yas-compiled-snippets.el files under subdirs of TOP-LEVEL-DIR.
+
+This works by stubbing a few functions, then calling
+`yas/load-directory'."
+ (interactive "DTop level snippet directory?")
+ (flet ((yas/load-yas-setup-file
+ (file)
+ (let ((elfile (concat file ".el")))
+ (when (file-exists-p elfile)
+ (insert ";;; .yas-setup.el support file if any:\n;;;\n")
+ (insert-file-contents elfile)
+ (end-of-buffer)
+ )))
+ (yas/define-snippets
+ (mode snippets)
+ (insert ";;; Snippet definitions:\n;;;\n")
+ (let ((literal-snippets (list))
+ (print-length nil))
+ (dolist (snippet snippets)
+ (let ((key (first snippet))
+ (template-content (second snippet))
+ (name (third snippet))
+ (condition (fourth snippet))
+ (group (fifth snippet))
+ (expand-env (sixth snippet))
+ (file nil) ;; (seventh snippet)) ;; omit on purpose
+ (binding (eighth snippet))
+ (uuid (ninth snippet)))
+ (push `(,key
+ ,template-content
+ ,name
+ ,condition
+ ,group
+ ,expand-env
+ ,file
+ ,binding
+ ,uuid)
+ literal-snippets)))
+ (insert (pp-to-string `(yas/define-snippets ',mode ',literal-snippets)))
+ (insert "\n\n")))
+ (yas/load-directory-1
+ (dir mode parents &rest ignore)
+ (let ((output-file (concat (file-name-as-directory dir) ".yas-compiled-snippets.el")))
+ (with-temp-file output-file
+ (insert (format ";;; Compiled snippets and support files for `%s'\n" mode))
+ (yas/load-directory-2 dir mode)
+ (insert (format ";;; Do not edit! File generated at %s\n" (current-time-string)))))))
+ (yas/load-directory top-level-dir nil)))
+
+(defun yas/recompile-all ()
+ "Compile every dir in `yas/snippet-dirs'."
+ (interactive)
+ (mapc #'yas/compile-directory (yas/snippet-dirs)))
-SNIPPET-ROOTS is a list of root directories that contains the
-snippets definition.
-CODE is the code to be placed at the end of the generated file
-and that can initialize the YASnippet bundle.
+;;; JIT loading
+;;;
-Last optional argument DROPDOWN is the filename of the
-dropdown-list.el library.
+(defvar yas/scheduled-jit-loads (make-hash-table)
+ "Alist of mode-symbols to forms to be evaled when `yas/minor-mode' kicks in.")
-Here's the default value for all the parameters:
+(defun yas/schedule-jit (mode form)
+ (puthash mode
+ (cons form
+ (gethash mode yas/scheduled-jit-loads))
+ yas/scheduled-jit-loads))
- (yas/compile-bundle \"yasnippet.el\"
- \"yasnippet-bundle.el\"
- \"snippets\")
- \"(yas/initialize-bundle)
- ### autoload
- (require 'yasnippet-bundle)`\"
- \"dropdown-list.el\")
-"
- (interactive (concat "ffind the yasnippet.el file: \nFTarget bundle file: "
- "\nDSnippet directory to bundle: \nMExtra code? \nfdropdown-library: "))
-
- (let* ((yasnippet (or yasnippet
- "yasnippet.el"))
- (yasnippet-bundle (or yasnippet-bundle
- "./yasnippet-bundle.el"))
- (snippet-roots (or snippet-roots
- "snippets"))
- (dropdown (or dropdown
- "dropdown-list.el"))
- (code (or (and code
- (condition-case err (read code) (error nil))
- code)
- (concat "(yas/initialize-bundle)"
- "\n;;;###autoload" ; break through so that won't
- "(require 'yasnippet-bundle)")))
- (dirs (or (and (listp snippet-roots) snippet-roots)
- (list snippet-roots)))
- (bundle-buffer nil))
- (with-temp-file yasnippet-bundle
- (insert ";;; yasnippet-bundle.el --- "
- "Yet another snippet extension (Auto compiled bundle)\n")
- (insert-file-contents yasnippet)
- (goto-char (point-max))
- (insert "\n")
- (when dropdown
- (insert-file-contents dropdown))
- (goto-char (point-max))
- (insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n")
- (insert ";;;; Auto-generated code ;;;;\n")
- (insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n")
- (insert "(defun yas/initialize-bundle ()\n"
- " \"Initialize YASnippet and load snippets in the bundle.\"")
- (flet ((yas/define-snippets
- (mode snippets &optional parent-or-parents)
- (insert ";;; snippets for " (symbol-name mode) ", subdir " (file-name-nondirectory (replace-regexp-in-string "/$" "" default-directory)) "\n")
- (let ((literal-snippets (list)))
- (dolist (snippet snippets)
- (let ((key (first snippet))
- (template-content (second snippet))
- (name (third snippet))
- (condition (fourth snippet))
- (group (fifth snippet))
- (expand-env (sixth snippet))
- (file nil) ;; (seventh snippet)) ;; omit on purpose
- (binding (eighth snippet))
- (uuid (ninth snippet)))
- (push `(,key
- ,template-content
- ,name
- ,condition
- ,group
- ,expand-env
- ,file
- ,binding
- ,uuid)
- literal-snippets)))
- (insert (pp-to-string `(yas/define-snippets ',mode ',literal-snippets ',parent-or-parents)))
- (insert "\n\n"))))
- (dolist (dir dirs)
- (dolist (subdir (yas/subdirs dir))
- (let ((file (concat subdir "/.yas-setup.el")))
- (when (file-readable-p file)
- (insert "\n;; Supporting elisp for subdir " (file-name-nondirectory subdir) "\n\n")
- (with-temp-buffer
- (insert-file-contents file)
- (replace-regexp "^;;.*$" "" nil (point-min) (point-max))
- (replace-regexp "^[\s\t]*\n\\([\s\t]*\n\\)+" "\n" nil (point-min) (point-max))
- (kill-region (point-min) (point-max)))
- (yank)))
- (yas/load-directory-1 subdir nil))))
-
- (insert (pp-to-string `(yas/global-mode 1)))
- (insert ")\n\n" code "\n")
-
- ;; bundle-specific provide and value for yas/dont-activate
- (let ((bundle-feature-name (file-name-nondirectory
- (file-name-sans-extension
- yasnippet-bundle))))
- (insert (pp-to-string `(set-default 'yas/dont-activate
- #'(lambda ()
- (and (or yas/snippet-dirs
- (featurep ',(make-symbol bundle-feature-name)))
- (null (yas/get-snippet-tables)))))))
- (insert (pp-to-string `(provide ',(make-symbol bundle-feature-name)))))
-
- (insert ";;; "
- (file-name-nondirectory yasnippet-bundle)
- " ends here\n"))))
-
-(defun yas/compile-textmate-bundle ()
- (interactive)
- (yas/compile-bundle "yasnippet.el"
- "./yasnippet-textmate-bundle.el"
- "extras/imported/"
- (concat "(yas/initialize-bundle)"
- "\n;;;###autoload" ; break through so that won't
- "(require 'yasnippet-textmate-bundle)")
- "dropdown-list.el"))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Some user level functions
yas/version
") -- pluskid <pluskid@gmail.com>/joaotavora <joaotavora@gmail.com>")))
-(defun yas/define-snippets (mode snippets &optional parent-mode)
+(defun yas/define-parents (mode parents)
+ "Add PARENTS to the list of MODE's parents"
+ (puthash mode-sym (remove-duplicates
+ (append parents
+ (gethash mode-sym yas/parents)))
+ yas/parents))
+
+(defun yas/define-snippets (mode snippets)
"Define SNIPPETS for MODE.
SNIPPETS is a list of snippet definitions, each taking the
with the same uuid replaced the previous snippet.
You can use `yas/parse-template' to return such lists based on
-the current buffers contents.
-
-Optional PARENT-MODE can be used to specify the parent tables of
-MODE. It can be a mode symbol of a list of mode symbols. It does
-not need to be a real mode."
- ;; X) `snippet-table' is created or retrieved for MODE, same goes
- ;; for the list of snippet tables `parent-tables'.
- ;;
+the current buffers contents."
(let ((snippet-table (yas/table-get-create mode))
- (parent-tables (mapcar #'yas/table-get-create
- (if (listp parent-mode)
- parent-mode
- (list parent-mode))))
(template nil))
- ;; X) Connect `snippet-table' with `parent-tables'.
- ;;
- ;; TODO: this should be a remove-duplicates of the concatenation
- ;; of `snippet-table's existings parents with the new parents...
- ;;
- (dolist (parent parent-tables)
- (unless (find parent (yas/table-parents snippet-table))
- (push parent
- (yas/table-parents snippet-table))))
-
- ;; X) Now, iterate for evey snippet def list
- ;;
(dolist (snippet snippets)
(setq template (yas/define-snippets-1 snippet
snippet-table)))
template))
(defun yas/snippet-menu-binding-pair-get-create (template &optional type)
- "Get TEMPLATE's menu binding or assign it a new one."
+ "Get TEMPLATE's menu binding or assign it a new one.
+
+TYPE may be `:stay', signalling this menu binding should be
+static in the menu."
(or (yas/template-menu-binding-pair template)
(let ((key (yas/template-key template))
(keybinding (yas/template-keybinding template)))
"Recursively delete items with UUID from KEYMAP and its submenus."
;; XXX: This used to skip any submenus named \"parent mode\"
- ;;
+ ;;
;; First of all, recursively enter submenus, i.e. the tree is
;; searched depth first so that stale submenus can be found in the
;; higher passes.
(yas/delete-from-keymap (third (cdr item)) uuid)))
(rest keymap))
;; Set the uuid entry to nil
- ;;
+ ;;
(define-key keymap (vector (make-symbol uuid)) nil)
;; Destructively modify keymap
- ;;
+ ;;
(setcdr keymap (delete-if #'(lambda (item)
(or (null (cdr item))
(and (keymapp (third (cdr item)))
- (yas/item UUID) : Creates an entry the snippet identified with
UUID. The menu entry for a snippet thus identified is
- permanent, i.e. it will never move in the menu.
+ permanent, i.e. it will never move (be reordered) in the menu.
- (yas/separator) : Creates a separator
(define-key keymap (vector (gensym))
'(menu-item "----")))
(t
- (message "[yas] don't know anything about menu entry %s" (first e))))))
+ (yas/message 3 "Don't know anything about menu entry %s" (first e))))))
(defun yas/define (mode key template &optional name condition group)
"Define a snippet. Expanding KEY into TEMPLATE.
If expansion fails, execute the previous binding for this key"
(interactive)
(setq yas/condition-cache-timestamp (current-time))
- (let* ((vec (this-command-keys-vector))
+ (let* ((yas/prefix current-prefix-arg)
+ (vec (subseq (this-command-keys-vector) (if current-prefix-arg
+ universal-argument-num-events
+ 0)))
(templates (mapcan #'(lambda (table)
(yas/fetch table vec))
(yas/get-snippet-tables))))
(car where)
(cdr where)
(yas/template-expand-env yas/current-template))
- (message "[yas] No snippets can be inserted here!"))))
+ (yas/message 3 "No snippets can be inserted here!"))))
(defun yas/visit-snippet-file ()
"Choose a snippet to edit, selection like `yas/insert-snippet'.
(or (some #'(lambda (dir) (when (file-directory-p dir) dir)) (cdr table-and-dirs))
(let ((candidate (first (cdr table-and-dirs))))
(unless (file-writable-p (file-name-directory candidate))
- (error "[yas] %s is not writable." candidate))
+ (error (yas/format "%s is not writable." candidate)))
(if (y-or-n-p (format "Guessed directory (%s) for%s%s table \"%s\" does not exist! Create? "
candidate
(if (gethash (intern (yas/table-name (car table-and-dirs)))
;; create the .yas-parents file here...
candidate)))))
-(defun yas/new-snippet (&optional choose-instead-of-guess)
- ""
+(defun yas/new-snippet (&optional no-template)
+ "Pops a new buffer for writing a snippet.
+
+Expands a snippet-writing snippet, unless the optional prefix arg
+NO-TEMPLATE is non-nil."
(interactive "P")
(let ((guessed-directories (yas/guess-snippet-directories)))
(erase-buffer)
(kill-all-local-variables)
(snippet-mode)
+ (yas/minor-mode 1)
(set (make-local-variable 'yas/guessed-modes) (mapcar #'(lambda (d)
(intern (yas/table-name (car d))))
guessed-directories))
- (unless (and choose-instead-of-guess
- (not (y-or-n-p "Insert a snippet with useful headers? ")))
- (yas/expand-snippet "\
+ (unless no-template (yas/expand-snippet "\
# -*- mode: snippet -*-
# name: $1
# key: $2${3:
(snippet-mode)))))
(message "Could not guess snippet dir!"))))
-(defun yas/compute-major-mode-and-parents (file &optional prompt-if-failed)
+(defun yas/compute-major-mode-and-parents (file)
+ "Given FILE, find the nearest snippet directory for a given
+mode, then return a list (MODE-SYM PARENTS), the mode's symbol and a list
+representing one or more of the mode's parents.
+
+Note that MODE-SYM need not be the symbol of a real major mode,
+neither do the elements of PARENTS."
(let* ((file-dir (and file
(directory-file-name (or (some #'(lambda (special)
(locate-dominating-file file special))
(major-mode-name (and file-dir
(file-name-nondirectory file-dir)))
(major-mode-sym (or (and major-mode-name
- (intern major-mode-name))
- (when prompt-if-failed
- (read-from-minibuffer
- "[yas] Cannot auto-detect major mode! Enter a major mode: "))))
+ (intern major-mode-name))))
(parents (when (file-readable-p parents-file-name)
(mapcar #'intern
(split-string
;; neatly positioned,...
;;
(yas/editing-template
- (yas/define-snippets-1 (yas/parse-template (yas/template-file yas/editing-template))
+ (yas/define-snippets-1 (yas/parse-template (yas/template-file yas/editing-template))
(yas/template-table yas/editing-template)))
;; Try to use `yas/guessed-modes'. If we don't have that use the
;; value from `yas/compute-major-mode-and-parents'
nil
(if (first yas/guessed-modes)
(symbol-name (first yas/guessed-modes))))))))
- (set (make-local-variable 'yas/editing-template)
+ (set (make-local-variable 'yas/editing-template)
(yas/define-snippets-1 (yas/parse-template buffer-file-name)
table)))))
;; Now, offer to save this shit iff:
(second yas/snippet-dirs)
(not (string-match (expand-file-name (first yas/snippet-dirs))
(yas/template-file yas/editing-template)))))
-
- (when (y-or-n-p "[yas] Looks like a library or new snippet. Save to new file? ")
+
+ (when (y-or-n-p (yas/format "Looks like a library or new snippet. Save to new file? "))
(let* ((option (first (yas/guess-snippet-directories (yas/template-table yas/editing-template))))
(chosen (and option
(yas/make-directory-maybe option))))
(setf (yas/template-file yas/editing-template) buffer-file-name))))))
(when kill
(quit-window kill))
- (message "[yas] Snippet \"%s\" loaded for %s."
+ (yas/message 3 "Snippet \"%s\" loaded for %s."
(yas/template-name yas/editing-template)
(yas/table-name (yas/template-table yas/editing-template))))
(fboundp (car major-mode-and-parent))
(car major-mode-and-parent))
(first yas/guessed-modes)
- (intern (read-from-minibuffer "[yas] please input a mode: "))))
+ (intern (read-from-minibuffer (yas/format "Please input a mode: ")))))
(yas/current-template
(and parsed
(fboundp test-mode)
(switch-to-buffer (get-buffer-create buffer-name))
(setq buffer-undo-list nil)
(condition-case nil (funcall test-mode) (error nil))
+ (setq buffer-read-only nil)
(yas/expand-snippet (yas/template-content yas/current-template)
(point-min)
(point-max)
(require 'yasnippet-debug nil t))
(add-hook 'post-command-hook 'yas/debug-snippet-vars nil t))))
(t
- (message "[yas] Cannot test snippet for unknown major mode")))))
+ (yas/message 3 "Cannot test snippet for unknown major mode")))))
(defun yas/template-fine-group (template)
(car (last (or (yas/template-group template)
(insert "\n"))
(insert (make-string 100 ?-) "\n")
(insert "group state name key binding\n")
- (let ((groups-alist (list))
- group)
+ (let ((groups-hash (make-hash-table :test #'equal)))
(maphash #'(lambda (k v)
- (setq group (or (yas/template-fine-group v)
- "(top level)"))
- (when (yas/template-name v)
-
- (aput 'groups-alist group (cons v (aget groups-alist group)))))
+ (let ((group (or (yas/template-fine-group v)
+ "(top level)")))
+ (when (yas/template-name v)
+ (puthash group
+ (cons v (gethash group groups-hash))
+ groups-hash))))
(yas/table-uuidhash table))
- (dolist (group-and-templates groups-alist)
- (when (rest group-and-templates)
- (setq group (truncate-string-to-width (car group-and-templates) 25 0 ? "..."))
- (insert (make-string 100 ?-) "\n")
- (dolist (p (cdr group-and-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")))))))
-
-
+ (maphash
+ #'(lambda (group templates)
+ (setq group (truncate-string-to-width group 25 0 ? "..."))
+ (insert (make-string 100 ?-) "\n")
+ (dolist (p templates)
+ (let ((name (truncate-string-to-width (propertize (format "\\\\snippet `%s'" (yas/template-name p))
+ 'yasnippet p)
+ 50 0 ? "..."))
+ (group (prog1 group
+ (setq group (make-string (length group) ? ))))
+ (condition-string (let ((condition (yas/template-condition p)))
+ (if (and condition
+ original-buffer)
+ (with-current-buffer original-buffer
+ (if (yas/eval-condition condition)
+ "(y)"
+ "(s)"))
+ "(a)"))))
+ (insert group " ")
+ (insert condition-string " ")
+ (insert name
+ (if (string-match "\\.\\.\\.$" name)
+ "'"
+ " ")
+ " ")
+ (insert (truncate-string-to-width (or (yas/template-key p) "")
+ 15 0 ? "...") " ")
+ (insert (truncate-string-to-width (key-description (yas/template-keybinding p))
+ 15 0 ? "...") " ")
+ (insert "\n"))))
+ groups-hash)))
\f
Otherwise throw exception."
(when (and yas/moving-away-p (notany #'(lambda (pos) (string= pos yas/text)) possibilities))
- (yas/throw (format "[yas] field only allows %s" possibilities))))
+ (yas/throw (yas/format "Field only allows %s" possibilities))))
(defun yas/field-value (number)
"Get the string for field with NUMBER.
(defun yas/field-probably-deleted-p (snippet field)
"Guess if SNIPPET's FIELD should be skipped."
- (and (zerop (- (yas/field-start field) (yas/field-end field)))
- (or (yas/field-parent-field field)
- (and (eq field (car (last (yas/snippet-fields snippet))))
- (= (yas/field-start field) (overlay-end (yas/snippet-control-overlay snippet)))))
- ;; the field numbered 0, just before the exit marker, should
- ;; never be skipped
- (not (zerop (yas/field-number field)))))
+ (and
+ ;; field must be zero lentgh
+ ;;
+ (zerop (- (yas/field-start field) (yas/field-end field)))
+ ;; skip if:
+ (or
+ ;; 1) is a nested field and it's been modified
+ ;;
+ (and (yas/field-parent-field field)
+ (yas/field-modified-p field))
+ ;; 2) ends just before the snippet end
+ ;;
+ (and (eq field (car (last (yas/snippet-fields snippet))))
+ (= (yas/field-start field) (overlay-end (yas/snippet-control-overlay snippet)))))
+ ;; the field numbered 0, just before the exit marker, should
+ ;; never be skipped
+ ;;
+ (not (zerop (yas/field-number field)))))
(defun yas/snippets-at-point (&optional all-snippets)
"Return a sorted list of snippets at point, most recently
(yas/place-overlays snippet field)
(overlay-put yas/active-field-overlay 'yas/field field)
(let ((number (yas/field-number field)))
- ;; check for the special ${0: ...} field
+ ;; check for the special ${0: ...} field
(if (and number (zerop number))
(progn
(set-mark (yas/field-end field))
(mapc #'(lambda (snippet)
(yas/exit-snippet snippet)
(yas/check-commit-snippet))
- (yas/snippets-at-point)))
+ (yas/snippets-at-point 'all-snippets)))
\f
;;; Some low level snippet-routines
`(let ((yas/inhibit-overlay-hooks t))
(progn ,@body)))
+(defvar yas/snippet-beg nil "Beginning position of the last snippet commited.")
+(defvar yas/snippet-end nil "End position of the last snippet commited.")
+
(defun yas/commit-snippet (snippet)
"Commit SNIPPET, but leave point as it is. This renders the
-snippet as ordinary text.
-
-Return a buffer position where the point should be placed if
-exiting the snippet."
+snippet as ordinary text."
- (let ((control-overlay (yas/snippet-control-overlay snippet))
- yas/snippet-beg
- yas/snippet-end)
+ (let ((control-overlay (yas/snippet-control-overlay snippet)))
;;
;; Save the end of the moribund snippet in case we need to revive it
;; its original expansion.
;; again from `yas/take-care-of-redo'....
(setf (yas/snippet-fields snippet) nil)))
- (message "[yas] snippet %s exited." (yas/snippet-id snippet)))
+ (yas/message 3 "Snippet %s exited." (yas/snippet-id snippet)))
(defun yas/safely-run-hooks (hook-var)
(condition-case error
(run-hooks hook-var)
(error
- (message "[yas] %s error: %s" hook-var (error-message-string error)))))
+ (yas/message 3 "%s error: %s" hook-var (error-message-string error)))))
(defun yas/check-commit-snippet ()
(snippet-exit-transform))
(dolist (snippet snippets)
(let ((active-field (yas/snippet-active-field snippet)))
- (setq snippet-exit-transform (yas/snippet-force-exit snippet))
+ (setq snippet-exit-transform (yas/snippet-force-exit snippet))
(cond ((or snippet-exit-transform
(not (and active-field (yas/field-contains-point-p active-field))))
(setq snippets-left (delete snippet snippets-left))
(yas/inhibit-overlay-hooks
(setq snippet
(if expand-env
- (eval `(let ,expand-env
+ (eval `(let* ,expand-env
(insert content)
(yas/snippet-create (point-min) (point-max))))
(insert content)
(when first-field
(sit-for 0) ;; fix issue 125
(yas/move-to-field snippet first-field)))
- (message "[yas] snippet expanded.")
+ (yas/message 3 "snippet expanded.")
t))))
(defun yas/take-care-of-redo (beg end snippet)
(setq yas/dollar-regions nil)
;; protect escaped quote, backquotes and backslashes
;;
- (yas/protect-escapes nil '(?\\ ?` ?'))
+ (yas/protect-escapes nil `(?\\ ?` ?'))
;; replace all backquoted expressions
;;
(goto-char parse-start)
(widen)
(condition-case err
(indent-according-to-mode)
- (error (message "[yas] warning: yas/indent-according-to-mode habing problems running %s" indent-line-function)
+ (error (yas/message 3 "Warning: `yas/indent-according-to-mode' having problems running %s" indent-line-function)
nil)))
(mapc #'(lambda (marker)
(set-marker marker (point)))
(apply (car fn-and-args)
(cdr fn-and-args)))
yas/post-command-runonce-actions)
- (error (message "[yas] problem running `yas/post-command-runonce-actions'!")))
+ (error (yas/message 3 "Problem running `yas/post-command-runonce-actions'!")))
(setq yas/post-command-runonce-actions nil))
(cond (yas/protection-violation
(goto-char yas/protection-violation)
(gethash uuid (yas/table-uuidhash table)))))
(when yas/current-template
(yas/expand-snippet (yas/template-content yas/current-template)))))
+\f
+;;; Utils
+;;;
+
+(defvar yas/verbosity 4
+ "Log level for `yas/message' 4 means trace most anything, 0 means nothing.")
+(defun yas/message (level message &rest args)
+ (when (> yas/verbosity level)
+ (message (apply #'yas/format message args))))
+
+(defun yas/format (format-control &rest format-args)
+ (apply #'format (concat "[yas] " format-control) format-args))
\f
;;; Some hacks:
-;;;
-;; `locate-dominating-file'
+;;;
+;; `locate-dominating-file'
;; `region-active-p'
-;;
+;;
;; added for compatibility in emacs < 23
(unless (>= emacs-major-version 23)
(unless (fboundp 'region-active-p)