summaryrefslogtreecommitdiffstats
path: root/emacs.d/yasnippet/yasnippet.el
diff options
context:
space:
mode:
authorAlexander Sulfrian <alexander@sulfrian.net>2009-10-22 05:22:19 +0200
committerAlexander Sulfrian <alexander@sulfrian.net>2009-10-22 05:22:19 +0200
commitf9bf8ac91b206ad109d11018dfe9006baf559d6e (patch)
tree6d72548e5e202ca99090f4bcc28d9f6f6ab99758 /emacs.d/yasnippet/yasnippet.el
parent72db7165051ddcf8f17c8397743ae7ba06cc4411 (diff)
downloaddotfiles-f9bf8ac91b206ad109d11018dfe9006baf559d6e.tar.gz
dotfiles-f9bf8ac91b206ad109d11018dfe9006baf559d6e.tar.xz
dotfiles-f9bf8ac91b206ad109d11018dfe9006baf559d6e.zip
moved to correct place
Diffstat (limited to 'emacs.d/yasnippet/yasnippet.el')
-rw-r--r--emacs.d/yasnippet/yasnippet.el3676
1 files changed, 0 insertions, 3676 deletions
diff --git a/emacs.d/yasnippet/yasnippet.el b/emacs.d/yasnippet/yasnippet.el
deleted file mode 100644
index fcbce9e..0000000
--- a/emacs.d/yasnippet/yasnippet.el
+++ /dev/null
@@ -1,3676 +0,0 @@
-;;; Yasnippet.el --- Yet another snippet extension for Emacs.
-
-;; Copyright 2008 pluskid
-;; 2009 pluskid, joaotavora
-
-;; Authors: pluskid <pluskid@gmail.com>, joaotavora <joaotavora@gmail.com>
-;; Version: 0.6.1
-;; Package-version: 0.6.1c
-;; X-URL: http://code.google.com/p/yasnippet/
-;; Keywords: convenience, emulation
-;; URL: http://code.google.com/p/yasnippet/
-;; EmacsWiki: YaSnippetMode
-
-;; This file is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
-
-;; This file is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING. If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
-;;; Commentary:
-
-;; 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/root-directory "~/.emacs/snippets")
-;; (yas/load-directory yas/root-directory)
-;; 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
-;;
-;; Steps 4. and 5. are optional, you don't have to use the minor
-;; mode to use YASnippet.
-;;
-;; Interesting variables are:
-;;
-;; `yas/root-directory'
-;;
-;; The directory where user-created snippets are to be
-;; stored. Can also be a list of directories that
-;; `yas/reload-all' will use for bulk-reloading snippets. In
-;; that case the first directory the default for storing new
-;; snippets.
-;;
-;; `yas/mode-symbol'
-;;
-;; A local variable that you can set in a hook to override
-;; snippet-lookup based on major mode. It is a a symbol (or
-;; list of symbols) that correspond to subdirectories of
-;; `yas/root-directory' and is used for deciding which
-;; snippets to consider for the active buffer.
-;;
-;; Major commands are:
-;;
-;; M-x yas/expand
-;;
-;; Try to expand snippets before point. In `yas/minor-mode',
-;; this is bound to `yas/trigger-key' which you can customize.
-;;
-;; M-x yas/load-directory
-;;
-;; Prompts you for a directory hierarchy of snippets to load.
-;;
-;; M-x yas/insert-snippet
-;;
-;; Prompts you for possible snippet expansion if that is
-;; possible according to buffer-local and snippet-local
-;; expansion conditions. With prefix argument, ignore these
-;; conditions.
-;;
-;; M-x yas/find-snippets
-;;
-;; Lets you find the snippet files in the correct
-;; subdirectory of `yas/root-directory', according to the
-;; active major mode (if it exists) like
-;; `find-file-other-window'.
-;;
-;; M-x yas/visit-snippet-file
-;;
-;; Prompts you for possible snippet expansions like
-;; `yas/insert-snippet', but instead of expanding it, takes
-;; you directly to the snippet definition's file, if it
-;; exists.
-;;
-;; M-x yas/new-snippet
-;;
-;; Lets you create a new snippet file in the correct
-;; subdirectory of `yas/root-directory', according to the
-;; active major mode.
-;;
-;; M-x yas/load-snippet-buffer
-;;
-;; When editing a snippet, this loads the snippet. This is
-;; bound to "C-c C-c" while in the `snippet-mode' editing
-;; mode.
-;;
-;; M-x yas/tryout-snippet
-;;
-;; When editing a snippet, this opens a new empty buffer,
-;; sets it to the appropriate major mode and inserts the
-;; snippet there, so you can see what it looks like. This is
-;; bound to "C-c C-t" while in `snippet-mode'.
-;;
-;; The `dropdown-list.el' extension is bundled with YASnippet, you
-;; can optionally use it the preferred "prompting method", puting in
-;; your .emacs file, for example:
-;;
-;; (require 'dropdown-list)
-;; (setq yas/prompt-functions '(yas/dropdown-prompt
-;; yas/ido-prompt
-;; yas/completing-prompt))
-;;
-;; Also check out the customization group
-;;
-;; M-x customize-group RET yasnippet RET
-;;
-;; If you use the customization group to set variables
-;; `yas/root-directory' or `yas/global-mode', make sure the path to
-;; "yasnippet.el" is present in the `load-path' *before* the
-;; `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/
-
-;;; Code:
-
-(require 'cl)
-(require 'assoc)
-(require 'easymenu)
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; User customizable variables
-
-
-(defgroup yasnippet nil
- "Yet Another Snippet extension"
- :group 'editing)
-
-;;;###autoload
-(defcustom yas/root-directory nil
- "Root directory that stores the snippets for each major mode.
-
-If you set this from your .emacs, can also be a list of strings,
-for multiple root directories. If you make this a list, the first
-element is always the user-created snippets directory. Other
-directories are used for bulk reloading of all snippets using
-`yas/reload-all'"
- :type '(choice (string :tag "Single directory (string)")
- (repeat :args (string) :tag "List of directories (strings)"))
- :group 'yasnippet
- :require 'yasnippet
- :set #'(lambda (symbol new)
- (let ((old (and (boundp symbol)
- (symbol-value symbol))))
- (set-default symbol new)
- (unless (or (not (fboundp 'yas/reload-all))
- (equal old new))
- (yas/reload-all)))))
-
-(defcustom yas/prompt-functions '(yas/x-prompt
- yas/dropdown-prompt
- yas/completing-prompt
- yas/ido-prompt
- yas/no-prompt)
- "Functions to prompt for keys, templates, etc interactively.
-
-These functions are called with the following arguments:
-
-- PROMPT: A string to prompt the user
-
-- CHOICES: a list of strings or objects.
-
-- optional DISPLAY-FN : A function that, when applied to each of
-the objects in CHOICES will return a string.
-
-The return value of any function you put here should be one of
-the objects in CHOICES, properly formatted with DISPLAY-FN (if
-that is passed).
-
-- To signal that your particular style of prompting is
-unavailable at the moment, you can also have the function return
-nil.
-
-- To signal that the user quit the prompting process, you can
-signal `quit' with
-
- (signal 'quit \"user quit!\")."
- :type '(repeat function)
- :group 'yasnippet)
-
-(defcustom yas/indent-line 'auto
- "Controls indenting applied to a recent snippet expansion.
-
-The following values are possible:
-
-- `fixed' Indent the snippet to the current column;
-
-- `auto' Indent each line of the snippet with `indent-according-to-mode'
-
-Every other value means don't apply any snippet-side indendation
-after expansion (the manual per-line \"$>\" indentation still
-applies)."
- :type '(choice (const :tag "Nothing" nothing)
- (const :tag "Fixed" fixed)
- (const :tag "Auto" auto))
- :group 'yasnippet)
-
-(defcustom yas/also-auto-indent-first-line nil
- "Non-nil means also auto indent first line according to mode.
-
-Naturally this is only valid when `yas/indent-line' is `auto'"
- :type 'boolean
- :group 'yasnippet)
-
-(defcustom yas/snippet-revival t
- "Non-nil means re-activate snippet fields after undo/redo."
- :type 'boolean
- :group 'yasnippet)
-
-(defcustom yas/trigger-key "TAB"
- "The key bound to `yas/expand' when function `yas/minor-mode' is active.
-
-Value is a string that is converted to the internal Emacs key
-representation using `read-kbd-macro'."
- :type 'string
- :group 'yasnippet
- :set #'(lambda (symbol key)
- (let ((old (and (boundp symbol)
- (symbol-value symbol))))
- (set-default symbol key)
- ;; On very first loading of this defcustom,
- ;; `yas/trigger-key' is *not* loaded.
- (if (fboundp 'yas/trigger-key-reload)
- (yas/trigger-key-reload old)))))
-
-(defcustom yas/next-field-key '("TAB" "<tab>")
- "The key to navigate to next field when a snippet is active.
-
-Value is a string that is converted to the internal Emacs key
-representation using `read-kbd-macro'.
-
-Can also be a list of strings."
- :type '(choice (string :tag "String")
- (repeat :args (string) :tag "List of strings"))
- :group 'yasnippet
- :set #'(lambda (symbol val)
- (set-default symbol val)
- (if (fboundp 'yas/init-yas-in-snippet-keymap)
- (yas/init-yas-in-snippet-keymap))))
-
-
-(defcustom yas/prev-field-key '("<backtab>" "<S-tab>")
- "The key to navigate to previous field when a snippet is active.
-
-Value is a string that is converted to the internal Emacs key
-representation using `read-kbd-macro'.
-
-Can also be a list of strings."
- :type '(choice (string :tag "String")
- (repeat :args (string) :tag "List of strings"))
- :group 'yasnippet
- :set #'(lambda (symbol val)
- (set-default symbol val)
- (if (fboundp 'yas/init-yas-in-snippet-keymap)
- (yas/init-yas-in-snippet-keymap))))
-
-(defcustom yas/skip-and-clear-key "C-d"
- "The key to clear the currently active field.
-
-Value is a string that is converted to the internal Emacs key
-representation using `read-kbd-macro'.
-
-Can also be a list of strings."
- :type '(choice (string :tag "String")
- (repeat :args (string) :tag "List of strings"))
- :group 'yasnippet
- :set #'(lambda (symbol val)
- (set-default symbol val)
- (if (fboundp 'yas/init-yas-in-snippet-keymap)
- (yas/init-yas-in-snippet-keymap))))
-
-(defcustom yas/triggers-in-field nil
- "If non-nil, `yas/next-field-key' can trigger stacked expansions.
-
-Otherwise, `yas/next-field-key' just tries to move on to the next
-field"
- :type 'boolean
- :group 'yasnippet)
-
-(defcustom yas/fallback-behavior 'call-other-command
- "How to act when `yas/trigger-key' does *not* expand a snippet.
-
-- `call-other-command' means try to temporarily disable YASnippet
- and call the next command bound to `yas/trigger-key'.
-
-- nil or the symbol `return-nil' mean do nothing. (and
- `yas/expand-returns' nil)
-
-- A lisp form (apply COMMAND . ARGS) means interactively call
- COMMAND, if ARGS is non-nil, call COMMAND non-interactively
- with ARGS as arguments."
- :type '(choice (const :tag "Call previous command" call-other-command)
- (const :tag "Do nothing" return-nil))
- :group 'yasnippet)
-(make-variable-buffer-local 'yas/fallback-behavior)
-
-(defcustom yas/choose-keys-first nil
- "If non-nil, prompt for snippet key first, then for template.
-
-Otherwise prompts for all possible snippet names.
-
-This affects `yas/insert-snippet' and `yas/visit-snippet-file'."
- :type 'boolean
- :group 'yasnippet)
-
-(defcustom yas/choose-tables-first nil
- "If non-nil, and multiple eligible snippet tables, prompts user for tables first.
-
-Otherwise, user chooses between the merging together of all
-eligible tables.
-
-This affects `yas/insert-snippet', `yas/visit-snippet-file'"
- :type 'boolean
- :group 'yasnippet)
-
-(defcustom yas/use-menu 'real-modes
- "Display a YASnippet menu in the menu bar.
-
-When non-nil, submenus for each snippet table will be listed
-under the menu \"Yasnippet\".
-
-- If set to `real-modes' only submenus whose name more or less
-corresponds to a major mode are listed.
-
-- If set to `abbreviate', only the current major-mode
-menu and the modes set in `yas/mode-symbol' are listed.
-
-Any other non-nil value, every submenu is listed."
- :type '(choice (const :tag "Full" t)
- (const :tag "Real modes only" real-modes)
- (const :tag "Abbreviate" abbreviate))
- :group 'yasnippet)
-
-(defcustom yas/trigger-symbol " =>"
- "The text that will be used in menu to represent the trigger."
- :type 'string
- :group 'yasnippet)
-
-(defcustom yas/wrap-around-region nil
- "If non-nil, snippet expansion wraps around selected region.
-
-The wrapping occurs just before the snippet's exit marker. This
-can be overriden on a per-snippet basis."
- :type 'boolean
- :group 'yasnippet)
-
-(defcustom yas/good-grace t
- "If non-nil, don't raise errors in inline elisp evaluation.
-
-An error string \"[yas] error\" is returned instead."
- :type 'boolean
- :group 'yasnippet)
-
-(defcustom yas/ignore-filenames-as-triggers nil
- "If non-nil, don't derive tab triggers from filenames.
-
-This means a snippet without a \"# key:'\ directive wont have a
-tab trigger."
- :type 'boolean
- :group 'yasnippet)
-
-(defcustom yas/visit-from-menu nil
- "If non-nil visit snippets's files from menu, instead of expanding them.
-
-This cafn only work when snippets are loaded from files."
- :type 'boolean
- :group 'yasnippet)
-
-(defface yas/field-highlight-face
- '((((class color) (background light)) (:background "DarkSeaGreen1"))
- (t (:background "DimGrey")))
- "The face used to highlight the currently active field of a snippet"
- :group 'yasnippet)
-
-(defface yas/field-debug-face
- '()
- "The face used for debugging some overlays normally hidden"
- :group 'yasnippet)
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; User can also customize the next defvars
-(defun yas/define-some-keys (keys keymap definition)
- "Bind KEYS to DEFINITION in KEYMAP, read with `read-kbd-macro'."
- (let ((keys (or (and (listp keys) keys)
- (list keys))))
- (dolist (key keys)
- (define-key keymap (read-kbd-macro key) definition))))
-
-(defvar yas/keymap
- (let ((map (make-sparse-keymap)))
- (mapc #'(lambda (binding)
- (yas/define-some-keys (car binding) map (cdr binding)))
- `((,yas/next-field-key . yas/next-field-or-maybe-expand)
- (,yas/prev-field-key . yas/prev-field)
- ("C-g" . yas/abort-snippet)
- (,yas/skip-and-clear-key . yas/skip-and-clear-or-delete-char)))
- map)
- "The keymap active while a snippet expansion is in progress.")
-
-(defvar yas/key-syntaxes (list "w" "w_" "w_." "^ ")
- "A list of syntax of a key. This list is tried in the order
-to try to find a key. For example, if the list is '(\"w\" \"w_\").
-And in emacs-lisp-mode, where \"-\" has the syntax of \"_\":
-
-foo-bar
-
-will first try \"bar\", if not found, then \"foo-bar\" is tried.")
-
-(defvar yas/after-exit-snippet-hook
- '()
- "Hooks to run after a snippet exited.
-
-The hooks will be run in an environment where some variables bound to
-proper values:
-
-`yas/snippet-beg' : The beginning of the region of the snippet.
-
-`yas/snippet-end' : Similar to beg.
-
-Attention: These hooks are not run when exiting nested/stackd snippet expansion!")
-
-(defvar yas/before-expand-snippet-hook
- '()
- "Hooks to run just before expanding a snippet.")
-
-(defvar yas/buffer-local-condition
- '(if (and (not (bobp))
- (or (equal 'font-lock-comment-face
- (get-char-property (1- (point))
- 'face))
- (equal 'font-lock-string-face
- (get-char-property (1- (point))
- 'face))))
- '(require-snippet-condition . force-in-comment)
- t)
- "Snippet expanding condition.
-
-This variable is a lisp form:
-
- * If it evaluates to nil, no snippets can be expanded.
-
- * If it evaluates to the a cons (require-snippet-condition
- . REQUIREMENT)
-
- * Snippets bearing no \"# condition:\" directive are not
- considered
-
- * Snippets bearing conditions that evaluate to nil (or
- produce an error) won't be onsidered.
-
- * If the snippet has a condition that evaluates to non-nil
- RESULT:
-
- * If REQUIREMENT is t, the snippet is considered
-
- * If REQUIREMENT is `eq' RESULT, the snippet is
- considered
-
- * Otherwise, the snippet is not considered.
-
- * If it evaluates to the symbol 'always, all snippets are
- considered for expansion, regardless of any conditions.
-
- * If it evaluates to t or some other non-nil value
-
- * Snippet bearing no conditions, or conditions that
- evaluate to non-nil, are considered for expansion.
-
- * Otherwise, the snippet is not considered.
-
-Here's an example preventing snippets from being expanded from
-inside comments, in `python-mode' only, with the exception of
-snippets returning the symbol 'force-in-comment in their
-conditions.
-
- (add-hook 'python-mode-hook
- '(lambda ()
- (setq yas/buffer-local-condition
- '(if (python-in-string/comment)
- '(require-snippet-condition . force-in-comment)
- t))))
-
-The default value is similar, it filters out potential snippet
-expansions inside comments and string literals, unless the
-snippet itself contains a condition that returns the symbol
-`force-in-comment'.")
-(make-variable-buffer-local 'yas/buffer-local-condition)
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Internal variables
-
-(defvar yas/version "0.6.1b")
-
-(defvar yas/menu-table (make-hash-table)
- "A hash table of MAJOR-MODE symbols to menu keymaps.")
-
-(defvar yas/active-keybindings nil
- "A list of cons (KEYMAP . KEY) setup from defining snippets.")
-
-(defvar yas/known-modes
- '(ruby-mode rst-mode markdown-mode)
- "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
- "${\\([0-9]+:\\)?\\([^}]*\\)}"
- "A regexp to *almost* recognize a field.")
-
-(defconst yas/multi-dollar-lisp-expression-regexp
- "$+[ \t\n]*\\(([^)]*)\\)"
- "A regexp to *almost* recognize a \"$(...)\" expression.")
-
-(defconst yas/backquote-lisp-expression-regexp
- "`\\([^`]*\\)`"
- "A regexp to recognize a \"`lisp-expression`\" expression." )
-
-(defconst yas/transform-mirror-regexp
- "${\\(?:\\([0-9]+\\):\\)?$\\([ \t\n]*([^}]*\\)"
- "A regexp to *almost* recognize a mirror with a transform.")
-
-(defconst yas/simple-mirror-regexp
- "$\\([0-9]+\\)"
- "A regexp to recognize a simple mirror.")
-
-(defvar yas/snippet-id-seed 0
- "Contains the next id for a snippet.")
-
-(defun yas/snippet-next-id ()
- (let ((id yas/snippet-id-seed))
- (incf yas/snippet-id-seed)
- id))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Minor mode stuff
-
-;; XXX: `last-buffer-undo-list' is somehow needed in Carbon Emacs for MacOSX
-(defvar last-buffer-undo-list nil)
-
-(defvar yas/minor-mode-menu nil
- "Holds the YASnippet menu")
-
-(defun yas/init-minor-keymap ()
- (let ((map (make-sparse-keymap)))
- (easy-menu-define yas/minor-mode-menu
- map
- "Menu used when YAS/minor-mode is active."
- '("YASnippet"
- "----"
- ["Expand trigger" yas/expand
- :help "Possibly expand tab trigger before point"]
- ["Insert at point..." yas/insert-snippet
- :help "Prompt for an expandable snippet and expand it at point"]
- ["New snippet..." yas/new-snippet
- :help "Create a new snippet in an appropriate directory"]
- ["Visit snippet file..." yas/visit-snippet-file
- :help "Prompt for an expandable snippet and find its file"]
- ["Find snippets..." yas/find-snippets
- :help "Invoke `find-file' in the appropriate snippet directory"]
- "----"
- ("Snippet menu behaviour"
- ["Visit snippets" (setq yas/visit-from-menu t)
- :help "Visit snippets from the menu"
- :active t :style radio :selected yas/visit-from-menu]
- ["Expand snippets" (setq yas/visit-from-menu nil)
- :help "Expand snippets from the menu"
- :active t :style radio :selected (not yas/visit-from-menu)]
- "----"
- ["Show \"Real\" modes only" (setq yas/use-menu 'real-modes)
- :help "Show snippet submenus for modes that appear to be real major modes"
- :active t :style radio :selected (eq yas/use-menu 'real-modes)]
- ["Show all modes" (setq yas/use-menu 't)
- :help "Show one snippet submenu for each loaded table"
- :active t :style radio :selected (eq yas/use-menu 't)]
- ["Abbreviate according to current mode" (setq yas/use-menu 'abbreviate)
- :help "Show only snippet submenus for the current active modes"
- :active t :style radio :selected (eq yas/use-menu 'abbreviate)])
- ("Indenting"
- ["Auto" (setq yas/indent-line 'auto)
- :help "Indent each line of the snippet with `indent-according-to-mode'"
- :active t :style radio :selected (eq yas/indent-line 'auto)]
- ["Fixed" (setq yas/indent-line 'fixed)
- :help "Indent the snippet to the current column"
- :active t :style radio :selected (eq yas/indent-line 'fixed)]
- ["None" (setq yas/indent-line 'none)
- :help "Don't apply any particular snippet indentation after expansion"
- :active t :style radio :selected (not (member yas/indent-line '(fixed auto)))]
- "----"
- ["Also auto indent first line" (setq yas/also-auto-indent-first-line
- (not yas/also-auto-indent-first-line))
- :help "When auto-indenting also, auto indent the first line menu"
- :active (eq yas/indent-line 'auto)
- :style toggle :selected yas/also-auto-indent-first-line]
- )
- ("Prompting method"
- ["System X-widget" (setq yas/prompt-functions
- (cons 'yas/x-prompt
- (remove 'yas/x-prompt
- yas/prompt-functions)))
- :help "Use your windowing system's (gtk, mac, windows, etc...) default menu"
- :active t :style radio :selected (eq (car yas/prompt-functions)
- 'yas/x-prompt)]
- ["Dropdown-list" (setq yas/prompt-functions
- (cons 'yas/dropdown-prompt
- (remove 'yas/dropdown-prompt
- yas/prompt-functions)))
- :help "Use a special dropdown list"
- :active t :style radio :selected (eq (car yas/prompt-functions)
- 'yas/dropdown-prompt)]
- ["Ido" (setq yas/prompt-functions
- (cons 'yas/ido-prompt
- (remove 'yas/ido-prompt
- yas/prompt-functions)))
- :help "Use an ido-style minibuffer prompt"
- :active t :style radio :selected (eq (car yas/prompt-functions)
- 'yas/ido-prompt)]
- ["Completing read" (setq yas/prompt-functions
- (cons 'yas/completing-prompt
- (remove 'yas/completing-prompt-prompt
- yas/prompt-functions)))
- :help "Use a normal minibuffer prompt"
- :active t :style radio :selected (eq (car yas/prompt-functions)
- 'yas/completing-prompt-prompt)]
- )
- ("Misc"
- ["Wrap region in exit marker"
- (setq yas/wrap-around-region
- (not yas/wrap-around-region))
- :help "If non-nil automatically wrap the selected text in the $0 snippet exit"
- :style toggle :selected yas/wrap-around-region]
- ["Allow stacked expansions "
- (setq yas/triggers-in-field
- (not yas/triggers-in-field))
- :help "If non-nil allow snippets to be triggered inside other snippet fields"
- :style toggle :selected yas/triggers-in-field]
- ["Revive snippets on undo "
- (setq yas/snippet-revival
- (not yas/snippet-revival))
- :help "If non-nil allow snippets to become active again after undo"
- :style toggle :selected yas/snippet-revival]
- ["Good grace "
- (setq yas/good-grace
- (not yas/good-grace))
- :help "If non-nil don't raise errors in bad embedded eslip in snippets"
- :style toggle :selected yas/good-grace]
- ["Ignore filenames as triggers"
- (setq yas/ignore-filenames-as-triggers
- (not yas/ignore-filenames-as-triggers))
- :help "If non-nil don't derive tab triggers from filenames"
- :style toggle :selected yas/ignore-filenames-as-triggers]
- )
- "----"
- ["Load snippets..." yas/load-directory
- :help "Load snippets from a specific directory"]
- ["Reload everything" yas/reload-all
- :help "Cleanup stuff, reload snippets, rebuild menus"]
- ["About" yas/about
- :help "Display some information about YASsnippet"]))
- ;; Now for the stuff that has direct keybindings
- ;;
- (define-key map "\C-c&\C-s" 'yas/insert-snippet)
- (define-key map "\C-c&\C-n" 'yas/new-snippet)
- (define-key map "\C-c&\C-v" 'yas/visit-snippet-file)
- (define-key map "\C-c&\C-f" 'yas/find-snippets)
- map))
-
-(defvar yas/minor-mode-map (yas/init-minor-keymap)
- "The keymap used when `yas/minor-mode' is active.")
-
-(defun yas/trigger-key-reload (&optional unbind-key)
- "Rebind `yas/expand' to the new value of `yas/trigger-key'.
-
-With optional UNBIND-KEY, try to unbind that key from
-`yas/minor-mode-map'."
- (when (and unbind-key
- (stringp unbind-key)
- (not (string= unbind-key "")))
- (define-key yas/minor-mode-map (read-kbd-macro unbind-key) nil))
- (when (and yas/trigger-key
- (stringp yas/trigger-key)
- (not (string= yas/trigger-key "")))
- (define-key yas/minor-mode-map (read-kbd-macro yas/trigger-key) 'yas/expand)))
-
-;;;###autoload
-(define-minor-mode yas/minor-mode
- "Toggle YASnippet mode.
-
-When YASnippet mode is enabled, the `tas/trigger-key' key expands
-snippets of code depending on the mode.
-
-With no argument, this command toggles the mode.
-positive prefix argument turns on the mode.
-Negative prefix argument turns off the mode.
-
-You can customize the key through `yas/trigger-key'.
-
-Key bindings:
-\\{yas/minor-mode-map}"
- nil
- ;; The indicator for the mode line.
- " yas"
- :group 'yasnippet
- (when yas/minor-mode
- (yas/trigger-key-reload)
- ;; load all snippets definitions unless we still don't have a
- ;; root-directory or some snippets have already been loaded.
- (unless (or (null yas/root-directory)
- (> (hash-table-count yas/snippet-tables) 0))
- (yas/reload-all))))
-
-(defvar yas/dont-activate #'(lambda ()
- (and yas/root-directory
- (null (yas/get-snippet-tables))))
- "If non-nil don't let `yas/minor-mode-on' active yas for this buffer.
-
-`yas/minor-mode-on' is usually called by `yas/global-mode' so
-this effectively lets you define exceptions to the \"global\"
-behaviour.")
-(make-variable-buffer-local 'yas/dont-activate)
-
-
-(defun yas/minor-mode-on ()
- "Turn on YASnippet minor mode.
-
-Do this unless `yas/dont-activate' is t or the function
-`yas/get-snippet-tables' (which see), returns an empty list."
- (interactive)
- (unless (or (and (functionp yas/dont-activate)
- (funcall yas/dont-activate))
- (and (not (functionp yas/dont-activate))
- yas/dont-activate))
- (yas/minor-mode 1)))
-
-(defun yas/minor-mode-off ()
- "Turn off YASnippet minor mode."
- (interactive)
- (yas/minor-mode -1))
-
-(define-globalized-minor-mode yas/global-mode yas/minor-mode yas/minor-mode-on
- :group 'yasnippet
- :require 'yasnippet)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Major mode stuff
-;;
-(defvar yas/font-lock-keywords
- (append '(("^#.*$" . font-lock-comment-face))
- lisp-font-lock-keywords
- lisp-font-lock-keywords-1
- lisp-font-lock-keywords-2
- '(("$\\([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)))))
-
-(defun yas/init-major-keymap ()
- (let ((map (make-sparse-keymap)))
- (easy-menu-define nil
- map
- "Menu used when snippet-mode is active."
- (cons "Snippet"
- (mapcar #'(lambda (ent)
- (when (third ent)
- (define-key map (third ent) (second ent)))
- (vector (first ent) (second ent) t))
- (list
- (list "Load this snippet" 'yas/load-snippet-buffer "\C-c\C-c")
- (list "Try out this snippet" 'yas/tryout-snippet "\C-c\C-t")))))
- map))
-
-(defvar snippet-mode-map
- (yas/init-major-keymap)
- "The keymap used when `snippet-mode' is active")
-
-
-(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))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Internal structs for template management
-
-(defstruct (yas/template (:constructor yas/make-template
- (content name condition expand-env file keybinding)))
- "A template for a snippet."
- content
- name
- condition
- expand-env
- file
- keybinding)
-
-(defvar yas/snippet-tables (make-hash-table)
- "A hash table of MAJOR-MODE symbols to `yas/snippet-table' objects.")
-
-(defstruct (yas/snippet-table (:constructor yas/make-snippet-table (name)))
- "A table to store snippets for a particular mode.
-
-Has the following fields:
-
-`yas/snippet-table-name'
-
- A symbol normally corresponding to a major mode, but can also be
- a pseudo major-mode to be referenced in `yas/mode-symbol', for
- example.
-
-`yas/snippet-table-hash'
-
- A hash table the key is a string (the snippet key) and the
- value is yet another hash of (NAME TEMPLATE), where NAME is the
- snippet name and TEMPLATE is a `yas/template' object name.
-
-`yas/snippet-table-parents'
-
- A list of tables considered parents of this table: i.e. when
- searching for expansions they are searched as well."
- name
- (hash (make-hash-table :test 'equal))
- (parents nil))
-
-(defvar yas/better-guess-for-replacements nil
- "If non-nil `yas/store' better guess snippet replacements.")
-
-(defun yas/store (table name key template)
- "Store a snippet template in the TABLE."
-
- ;; This is dones by searching twice:
- ;;
- ;; * Try to get the existing namehash from TABLE using key.
- ;;
- ;; * Try to get the existing namehash from by searching the *whole*
- ;; snippet table for NAME. This is becuase they user might have
- ;; changed the key and that can no longer be used to locate the
- ;; previous `yas/template-structure'.
- ;;
- ;; * If that returns nothing, oh well...
- ;;
- (dolist (existing-namehash (remove nil (list (gethash key (yas/snippet-table-hash table))
- (when yas/better-guess-for-replacements
- (let (a)
- (maphash #'(lambda (key namehash)
- (when (gethash name namehash)
- (setq a namehash)))
- (yas/snippet-table-hash table))
- a)))))
- (let ((existing-template (gethash name existing-namehash)))
- (when existing-template
- ;; Remove the existing keybinding
- (when (yas/template-keybinding existing-template)
- (define-key
- (symbol-value (first (yas/template-keybinding existing-template)))
- (second (yas/template-keybinding existing-template))
- nil)
- (setq yas/active-keybindings
- (delete (yas/template-keybinding existing-template)
- yas/active-keybindings)))
- ;; Remove the (name . template) mapping from existing-namehash.
- (remhash name existing-namehash))))
- ;; Now store the new template independent of the previous steps.
- ;;
- (puthash name
- template
- (or (gethash key
- (yas/snippet-table-hash table))
- (puthash key
- (make-hash-table :test 'equal)
- (yas/snippet-table-hash table)))))
-
-(defun yas/fetch (table key)
- "Fetch a snippet binding to KEY from TABLE."
- (let* ((keyhash (yas/snippet-table-hash table))
- (namehash (and keyhash (gethash key keyhash))))
- (when namehash
- (yas/filter-templates-by-condition
- (let (alist)
- (maphash #'(lambda (k v)
- (push (cons k v) alist))
- namehash)
- alist)))))
-
-
-;; Filtering/condition logic
-
-(defun yas/eval-condition (condition)
- (condition-case err
- (save-excursion
- (save-restriction
- (save-match-data
- (eval condition))))
- (error (progn
- (message (format "[yas] error in condition evaluation: %s"
- (error-message-string err)))
- nil))))
-
-
-(defun yas/filter-templates-by-condition (templates)
- "Filter the templates using the applicable condition.
-
-TEMPLATES is a list of cons (NAME . TEMPLATE) where NAME is a
-string and TEMPLATE is a `yas/template' structure.
-
-This function implements the rules described in
-`yas/buffer-local-condition'. See that variables documentation."
- (let ((requirement (yas/require-template-specific-condition-p)))
- (if (eq requirement 'always)
- templates
- (remove-if-not #'(lambda (pair)
- (yas/template-can-expand-p (yas/template-condition (cdr pair)) requirement))
- templates))))
-
-(defun yas/require-template-specific-condition-p ()
- "Decides if this buffer requests/requires snippet-specific
-conditions to filter out potential expansions."
- (if (eq 'always yas/buffer-local-condition)
- 'always
- (let ((local-condition (or (and (consp yas/buffer-local-condition)
- (yas/eval-condition yas/buffer-local-condition))
- yas/buffer-local-condition)))
- (when local-condition
- (if (eq local-condition t)
- t
- (and (consp local-condition)
- (eq 'require-snippet-condition (car local-condition))
- (symbolp (cdr local-condition))
- (cdr local-condition)))))))
-
-(defun yas/template-can-expand-p (condition &optional requirement)
- "Evaluates CONDITION and REQUIREMENT and returns a boolean"
- (let* ((requirement (or requirement
- (yas/require-template-specific-condition-p)))
- (result (or (null condition)
- (yas/eval-condition
- (condition-case err
- (read condition)
- (error (progn
- (message (format "[yas] error reading condition: %s"
- (error-message-string err))))
- nil))))))
- (cond ((eq requirement t)
- result)
- (t
- (eq requirement result)))))
-
-(defun yas/snippet-table-get-all-parents (table)
- (let ((parents (yas/snippet-table-parents table)))
- (when parents
- (append (copy-list parents)
- (mapcan #'yas/snippet-table-get-all-parents parents)))))
-
-(defun yas/snippet-table-templates (table)
- (when table
- (let ((acc (list)))
- (maphash #'(lambda (key namehash)
- (maphash #'(lambda (name template)
- (push (cons name template) acc))
- namehash))
- (yas/snippet-table-hash table))
- (yas/filter-templates-by-condition acc))))
-
-(defun yas/current-key ()
- "Get the key under current position. A key is used to find
-the template of a snippet in the current snippet-table."
- (let ((start (point))
- (end (point))
- (syntaxes yas/key-syntaxes)
- syntax
- done
- templates)
- (while (and (not done) syntaxes)
- (setq syntax (car syntaxes))
- (setq syntaxes (cdr syntaxes))
- (save-excursion
- (skip-syntax-backward syntax)
- (setq start (point)))
- (setq templates
- (mapcan #'(lambda (table)
- (yas/fetch table (buffer-substring-no-properties start end)))
- (yas/get-snippet-tables)))
- (if templates
- (setq done t)
- (setq start end)))
- (list templates
- start
- end)))
-
-
-(defun yas/snippet-table-all-keys (table)
- (when table
- (let ((acc))
- (maphash #'(lambda (key templates)
- (when (yas/filter-templates-by-condition templates)
- (push key acc)))
- (yas/snippet-table-hash table))
- acc)))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Internal functions
-
-(defun yas/real-mode? (mode)
- "Try to find out if MODE is a real mode. The MODE bound to
-a function (like `c-mode') is considered real mode. Other well
-known mode like `ruby-mode' which is not part of Emacs might
-not bound to a function until it is loaded. So yasnippet keeps
-a list of modes like this to help the judgement."
- (or (fboundp mode)
- (find mode yas/known-modes)))
-
-(defun yas/read-and-eval-string (string)
- ;; TODO: This is a possible optimization point, the expression could
- ;; be stored in cons format instead of string,
- "Evaluate STRING and convert the result to string."
- (let ((retval (catch 'yas/exception
- (condition-case err
- (save-excursion
- (save-restriction
- (save-match-data
- (widen)
- (let ((result (eval (read string))))
- (when result
- (format "%s" result))))))
- (error (if yas/good-grace
- "[yas] elisp error!"
- (error (format "[yas] elisp error: %s"
- (error-message-string err)))))))))
- (when (and (consp retval)
- (eq 'yas/exception (car retval)))
- (error (cdr retval)))
- retval))
-
-(defvar yas/mode-symbol nil
- "If non-nil, lookup snippets using this instead of `major-mode'.")
-(make-variable-buffer-local 'yas/mode-symbol)
-
-(defun yas/snippet-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."
- (let ((table (gethash mode
- yas/snippet-tables)))
- (unless table
- (setq table (yas/make-snippet-table (symbol-name mode)))
- (puthash mode table yas/snippet-tables))
- table))
-
-(defun yas/get-snippet-tables (&optional mode-symbol dont-search-parents)
- "Get snippet tables for current buffer.
-
-Return a list of 'yas/snippet-table' objects indexed by mode.
-
-The modes are tried in this order: optional MODE-SYMBOL, then
-`yas/mode-symbol', 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
- (mapcar #'(lambda (mode)
- (gethash mode yas/snippet-tables))
- (append (list mode-symbol)
- (if (listp yas/mode-symbol)
- yas/mode-symbol
- (list yas/mode-symbol))
- (list major-mode
- (and (not dont-search-parents)
- (get (or mode-symbol major-mode)
- 'derived-mode-parent))))))
- (all-tables))
- (dolist (table (remove nil mode-tables))
- (push table all-tables)
- (nconc all-tables (yas/snippet-table-get-all-parents table)))
- (remove-duplicates all-tables)))
-
-(defun yas/menu-keymap-get-create (mode)
- "Get the menu keymap correspondong to MODE."
- (or (gethash mode yas/menu-table)
- (puthash mode (make-sparse-keymap) yas/menu-table)))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Template-related and snippet loading functions
-
-(defun yas/parse-template (&optional file)
- "Parse the template in the current buffer.
-
-Optional FILE is the absolute file name of the file being
-parsed.
-
-Return a snippet-definition, i.e. a list
-
- (KEY TEMPLATE NAME CONDITION GROUP VARS FILE KEYBINDING)
-
-If the buffer contains a line of \"# --\" then the contents
-above this line are ignored. Variables can be set above this
-line through the syntax:
-
-#name : value
-
-Here's a list of currently recognized variables:
-
- * name
- * contributor
- * condition
- * key
- * group
- * expand-env
-
-#name: #include \"...\"
-# --
-#include \"$1\""
- ;;
- ;;
- (goto-char (point-min))
- (let* ((name (and file
- (file-name-nondirectory file)))
- (key (unless yas/ignore-filenames-as-triggers
- (and name
- (file-name-sans-extension name))))
- template
- bound
- condition
- (group (and file
- (yas/calculate-group file)))
- expand-env
- binding)
- (if (re-search-forward "^# --\n" nil t)
- (progn (setq template
- (buffer-substring-no-properties (point)
- (point-max)))
- (setq bound (point))
- (goto-char (point-min))
- (while (re-search-forward "^# *\\([^ ]+?\\) *: *\\(.*\\)$" bound t)
- (when (string= "name" (match-string-no-properties 1))
- (setq name (match-string-no-properties 2)))
- (when (string= "condition" (match-string-no-properties 1))
- (setq condition (match-string-no-properties 2)))
- (when (string= "group" (match-string-no-properties 1))
- (setq group (match-string-no-properties 2)))
- (when (string= "expand-env" (match-string-no-properties 1))
- (setq expand-env (match-string-no-properties 2)))
- (when (string= "key" (match-string-no-properties 1))
- (setq key (match-string-no-properties 2)))
- (when (string= "binding" (match-string-no-properties 1))
- (setq binding (match-string-no-properties 2)))))
- (setq template
- (buffer-substring-no-properties (point-min) (point-max))))
- (list key template name condition group expand-env file binding)))
-
-(defun yas/calculate-group (file)
- "Calculate the group for snippet file path FILE."
- (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))))
- (extra-dir (and extra-path
- (file-name-directory extra-path)))
- (group (and extra-dir
- (replace-regexp-in-string "/"
- "."
- (directory-file-name extra-dir)))))
- group))
-
-;; (defun yas/glob-files (directory &optional recurse-p append)
-;; "Returns files under DIRECTORY ignoring dirs and hidden files.
-
-;; If RECURSE in non-nil, do that recursively."
-;; (let (ret
-;; (default-directory directory))
-;; (dolist (entry (directory-files "."))
-;; (cond ((or (string-match "^\\."
-;; (file-name-nondirectory entry))
-;; (string-match "~$"
-;; (file-name-nondirectory entry)))
-;; nil)
-;; ((and recurse-p
-;; (file-directory-p entry))
-;; (setq ret (nconc ret
-;; (yas/glob-files (expand-file-name entry)
-;; recurse-p
-;; (if append
-;; (concat append "/" entry)
-;; entry)))))
-;; ((file-directory-p entry)
-;; nil)
-;; (t
-;; (push (if append
-;; (concat append "/" entry)
-;; entry) ret))))
-;; ret))
-
-(defun yas/subdirs (directory &optional file?)
- "Return subdirs or files of DIRECTORY according to FILE?."
- (remove-if (lambda (file)
- (or (string-match "^\\."
- (file-name-nondirectory file))
- (string-match "~$"
- (file-name-nondirectory file))
- (if file?
- (file-directory-p file)
- (not (file-directory-p file)))))
- (directory-files directory t)))
-
-(defun yas/make-menu-binding (template)
- `(lambda () (interactive) (yas/expand-or-visit-from-menu ,template)))
-
-(defun yas/expand-or-visit-from-menu (template)
- (if yas/visit-from-menu
- (yas/visit-snippet-file-1 template)
- (let ((where (if mark-active
- (cons (region-beginning) (region-end))
- (cons (point) (point)))))
- (yas/expand-snippet (yas/template-content template)
- (car where)
- (cdr where)))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Popping up for keys and templates
-;;
-(defun yas/prompt-for-template (templates &optional prompt)
- "Interactively choose a template from the list TEMPLATES.
-
-TEMPLATES is a list of `yas/template'."
- (when templates
- (some #'(lambda (fn)
- (funcall fn (or prompt "Choose a snippet: ")
- templates
- #'yas/template-name))
- yas/prompt-functions)))
-
-(defun yas/prompt-for-keys (keys &optional prompt)
- "Interactively choose a template key from the list KEYS."
- (when keys
- (some #'(lambda (fn)
- (funcall fn (or prompt "Choose a snippet key: ") keys))
- yas/prompt-functions)))
-
-(defun yas/prompt-for-table (tables &optional prompt)
- (when tables
- (some #'(lambda (fn)
- (funcall fn (or prompt "Choose a snippet table: ")
- tables
- #'yas/snippet-table-name))
- yas/prompt-functions)))
-
-(defun yas/x-prompt (prompt choices &optional display-fn)
- (when (and window-system choices)
- (let ((keymap (cons 'keymap
- (cons
- prompt
- (mapcar (lambda (choice)
- (list choice
- 'menu-item
- (if display-fn
- (funcall display-fn choice)
- choice)
- t))
- choices)))))
- (when (cdr keymap)
- (car (x-popup-menu (if (fboundp 'posn-at-point)
- (let ((x-y (posn-x-y (posn-at-point (point)))))
- (list (list (+ (car x-y) 10)
- (+ (cdr x-y) 20))
- (selected-window)))
- t)
- keymap))))))
-
-(defun yas/ido-prompt (prompt choices &optional display-fn)
- (when (and (featurep 'ido)
- ido-mode)
- (let* ((formatted-choices (or (and display-fn
- (mapcar display-fn choices))
- choices))
- (chosen (and formatted-choices
- (ido-completing-read prompt
- formatted-choices
- nil
- 'require-match
- nil
- nil))))
- (when chosen
- (nth (position chosen formatted-choices :test #'string=) choices)))))
-
-(eval-when-compile (require 'dropdown-list nil t))
-(defun yas/dropdown-prompt (prompt choices &optional display-fn)
- (when (featurep 'dropdown-list)
- (let* ((formatted-choices (or (and display-fn
- (mapcar display-fn choices))
- choices))
- (chosen (and formatted-choices
- (nth (dropdown-list formatted-choices)
- choices))))
- chosen)))
-
-(defun yas/completing-prompt (prompt choices &optional display-fn)
- (let* ((formatted-choices (or (and display-fn
- (mapcar display-fn choices))
- choices))
- (chosen (and formatted-choices
- (completing-read prompt
- formatted-choices
- nil
- 'require-match
- nil
- nil))))
- (when chosen
- (nth (position chosen formatted-choices :test #'string=) choices))))
-
-(defun yas/no-prompt (prompt choices &optional display-fn)
- (first choices))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Loading snippets from files
-;;
-(defun yas/load-directory-1 (directory &optional parents no-hierarchy-parents making-groups-sym)
- "Recursively load snippet templates from DIRECTORY."
- ;; TODO: Rewrite this horrible, horrible monster I created
- (unless (file-exists-p (concat directory "/" ".yas-skip"))
- (let* ((major-mode-and-parents (unless making-groups-sym
- (yas/compute-major-mode-and-parents (concat directory "/dummy")
- nil
- no-hierarchy-parents)))
- (yas/ignore-filenames-as-triggers (or yas/ignore-filenames-as-triggers
- (file-exists-p (concat directory "/" ".yas-ignore-filenames-as-triggers"))))
- (mode-sym (and major-mode-and-parents
- (car major-mode-and-parents)))
- (parents (if making-groups-sym
- parents
- (rest major-mode-and-parents)))
- (snippet-defs nil)
- (make-groups-p (or making-groups-sym
- (file-exists-p (concat directory "/" ".yas-make-groups")))))
- (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))))
- (yas/define-snippets (or mode-sym
- making-groups-sym)
- snippet-defs
- parents)
- (dolist (subdir (yas/subdirs directory))
- (if make-groups-p
- (yas/load-directory-1 subdir parents 't (or mode-sym
- making-groups-sym))
- (yas/load-directory-1 subdir (list mode-sym)))))))
-
-(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."
- (interactive "DSelect the root directory: ")
- (unless (file-directory-p directory)
- (error "Error %s not a directory" directory))
- (unless yas/root-directory
- (setq yas/root-directory directory))
- (dolist (dir (yas/subdirs directory))
- (yas/load-directory-1 dir nil 'no-hierarchy-parents))
- (when (interactive-p)
- (message "done.")))
-
-(defun yas/kill-snippet-keybindings ()
- "Remove the all active snippet keybindings."
- (interactive)
- (dolist (keybinding yas/active-keybindings)
- (define-key (symbol-value (first keybinding)) (second keybinding) nil))
- (setq yas/active-keybindings nil))
-
-(defun yas/reload-all (&optional reset-root-directory)
- "Reload all snippets and rebuild the YASnippet menu. "
- (interactive "P")
- ;; Turn off global modes and minor modes, save their state though
- ;;
- (let ((restore-global-mode (prog1 yas/global-mode
- (yas/global-mode -1)))
- (restore-minor-mode (prog1 yas/minor-mode
- (yas/minor-mode -1))))
- ;; Empty all snippet tables and all menu tables
- ;;
- (setq yas/snippet-tables (make-hash-table))
- (setq yas/menu-table (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)))
-
- ;; Now, clean up the other keymaps we might have cluttered up.
- (yas/kill-snippet-keybindings)
-
- (when reset-root-directory
- (setq yas/root-directory nil))
-
- ;; Reload the directories listed in `yas/root-directory' or prompt
- ;; the user to select one.
- ;;
- (if yas/root-directory
- (if (listp yas/root-directory)
- (dolist (directory yas/root-directory)
- (yas/load-directory directory))
- (yas/load-directory yas/root-directory))
- (call-interactively 'yas/load-directory))
-
- ;; Restore the mode configuration
- ;;
- (when restore-minor-mode
- (yas/minor-mode 1))
- (when restore-global-mode
- (yas/global-mode 1))
-
- (message "[yas] Reloading everything... Done.")))
-
-(defun yas/quote-string (string)
- "Escape and quote STRING.
-foo\"bar\\! -> \"foo\\\"bar\\\\!\""
- (concat "\""
- (replace-regexp-in-string "[\\\"]"
- "\\\\\\&"
- string
- t)
- "\""))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Yasnippet Bundle
-
-(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.
-
-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.
-
-Last optional argument DROPDOWN is the filename of the
-dropdown-list.el library.
-
-Here's the default value for all the parameters:
-
- (yas/compile-bundle \"yasnippet.el\"
- \"yasnippet-bundle.el\"
- \"snippets\")
- \"(yas/initialize-bundle)
- ### autoload
- (require 'yasnippet-bundle)`\"
- \"dropdown-list.el\")
-"
- (interactive "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) "\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))
- ;; Omit the file on purpose
- (file nil) ;; (seventh snippet))
- (binding (eighth snippet)))
- (push `(,key
- ,template-content
- ,name
- ,condition
- ,group
- ,expand-env
- ,file
- ,binding)
- 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))
- (yas/load-directory-1 subdir nil 'no-hierarchy-parents))))
-
- (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/root-directory
- (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
-;;;
-
-(defun yas/about ()
- (interactive)
- (message (concat "yasnippet (version "
- yas/version
- ") -- pluskid <pluskid@gmail.com>/joaotavora <joaotavora@gmail.com>")))
-
-(defun yas/define-snippets (mode snippets &optional parent-mode)
- "Define SNIPPETS for MODE.
-
-SNIPPETS is a list of snippet definitions, each taking the
-following form:
-
- (KEY TEMPLATE NAME CONDITION GROUP EXPAND-ENV FILE KEYBINDING)
-
-Within these, only TEMPLATE is actually mandatory.
-
-All the elelements are strings, including CONDITION, EXPAND-ENV
-and KEYBINDING which will be `read' and eventually `eval'-ed.
-
-FILE is probably of very little use if you're programatically
-defining snippets.
-
-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."
- (let ((snippet-table (yas/snippet-table-get-create mode))
- (parent-tables (mapcar #'yas/snippet-table-get-create
- (if (listp parent-mode)
- parent-mode
- (list parent-mode))))
- (keymap (if yas/use-menu
- (yas/menu-keymap-get-create mode)
- nil)))
- ;; Setup the menu
- ;;
- (when parent-tables
- (setf (yas/snippet-table-parents snippet-table)
- parent-tables)
- (when yas/use-menu
- (let ((parent-menu-syms-and-names
- (if (listp parent-mode)
- (mapcar #'(lambda (sym)
- (cons sym (concat "parent mode - " (symbol-name sym))))
- parent-mode)
- '((parent-mode . "parent mode")))))
- (mapc #'(lambda (sym-and-name)
- (define-key keymap
- (vector (intern (replace-regexp-in-string " " "_" (cdr sym-and-name))))
- (list 'menu-item (cdr sym-and-name)
- (yas/menu-keymap-get-create (car sym-and-name)))))
- (reverse parent-menu-syms-and-names)))))
- (when yas/use-menu
- (define-key yas/minor-mode-menu (vector mode)
- `(menu-item ,(symbol-name mode) ,keymap
- :visible (yas/show-menu-p ',mode))))
- ;; Iterate the recently parsed snippets definition
- ;;
- (dolist (snippet snippets)
- (let* ((file (seventh snippet))
- (key (or (car snippet)
- (unless yas/ignore-filenames-as-triggers
- (and file
- (file-name-sans-extension (file-name-nondirectory file))))))
- (name (or (third snippet)
- (and file
- (file-name-directory file))))
- (condition (fourth snippet))
- (group (fifth snippet))
- (keybinding (eighth snippet))
- (template nil))
- ;; Read the snippet's "binding :" expression
- ;;
- (condition-case err
- (when keybinding
- (setq keybinding (read (eighth snippet)))
- (let* ((this-mode-map-symbol (intern (concat (symbol-name mode) "-map")))
- (keys (or (and (consp keybinding)
- (read-kbd-macro (cdr keybinding)))
- (read-kbd-macro keybinding)))
- (keymap-symbol (or (and (consp keybinding)
- (car keybinding))
- this-mode-map-symbol)))
- (if (and (boundp keymap-symbol)
- (keymapp (symbol-value keymap-symbol)))
- (setq keybinding (list keymap-symbol
- keys
- name))
- (error (format "keymap \"%s\" does not (yet?) exist" keymap-symbol)))))
- (error
- (message "[yas] warning: keybinding \"%s\" invalid for snippet \"%s\" since %s."
- keybinding name (error-message-string err))
- (setf keybinding nil)))
-
- ;; Create the `yas/template' object and store in the
- ;; appropriate snippet table. This only done if we have found
- ;; a key and a name for the snippet, because that is what
- ;; indexes the snippet tables
- ;;
- (setq template (yas/make-template (second snippet)
- (or name key)
- condition
- (sixth snippet)
- (seventh snippet)
- keybinding))
- (when (and key
- name)
- (yas/store snippet-table
- name
- key
- template))
- ;; If we have a keybinding, register it if it does not
- ;; conflict!
- ;;
- (when keybinding
- (let ((lookup (lookup-key (symbol-value (first keybinding)) (second keybinding))))
- (if (and lookup
- (not (numberp lookup)))
- (message "[yas] warning: won't overwrite keybinding \"%s\" for snippet \"%s\" in `%s'"
- (key-description (second keybinding)) name (first keybinding))
- (define-key
- (symbol-value (first keybinding))
- (second keybinding)
- `(lambda (&optional yas/prefix)
- (interactive "P")
- (when (yas/template-can-expand-p ,(yas/template-condition template))
- (yas/expand-snippet ,(yas/template-content template)
- nil
- nil
- ,(yas/template-expand-env template)))))
- (add-to-list 'yas/active-keybindings keybinding))))
-
- ;; Setup the menu groups, reorganizing from group to group if
- ;; necessary
- ;;
- (when yas/use-menu
- (let ((group-keymap keymap))
- ;; Delete this entry from another group if already exists
- ;; in some other group. An entry is considered as existing
- ;; in another group if its name string-matches.
- ;;
- (yas/delete-from-keymap group-keymap name)
-
- ;; ... then add this entry to the correct group
- (when (and (not (null group))
- (not (string= "" group)))
- (dolist (subgroup (mapcar #'make-symbol
- (split-string group "\\.")))
- (let ((subgroup-keymap (lookup-key group-keymap
- (vector subgroup))))
- (when (null subgroup-keymap)
- (setq subgroup-keymap (make-sparse-keymap))
- (define-key group-keymap (vector subgroup)
- `(menu-item ,(symbol-name subgroup)
- ,subgroup-keymap)))
- (setq group-keymap subgroup-keymap))))
- (define-key group-keymap (vector (gensym))
- `(menu-item ,(yas/template-name template)
- ,(yas/make-menu-binding template)
- :help ,name
- :keys ,(when (and key name)
- (concat key yas/trigger-symbol))))))))))
-
-(defun yas/show-menu-p (mode)
- (cond ((eq yas/use-menu 'abbreviate)
- (find mode
- (mapcar #'(lambda (table)
- (intern (yas/snippet-table-name table)))
- (yas/get-snippet-tables))))
- ((eq yas/use-menu 'real-modes)
- (yas/real-mode? mode))
- (t
- t)))
-
-(defun yas/delete-from-keymap (keymap name)
- "Recursively delete items name NAME from KEYMAP and its submenus.
-
-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.
- ;;
- (mapc #'(lambda (item)
- (when (and (keymapp (fourth item))
- (stringp (third item))
- (not (string-match "parent mode" (third item))))
- (yas/delete-from-keymap (fourth item) name)))
- (rest keymap))
- ;;
- (when (keymapp keymap)
- (let ((pos-in-keymap))
- (while (setq pos-in-keymap
- (position-if #'(lambda (item)
- (and (listp item)
- (or
- ;; the menu item we want to delete
- (and (eq 'menu-item (second item))
- (third item)
- (and (string= (third item) name)))
- ;; a stale subgroup
- (and (keymapp (fourth item))
- (not (and (stringp (third item))
- (string-match "parent mode"
- (third item))))
- (null (rest (fourth item)))))))
- keymap))
- (setf (nthcdr pos-in-keymap keymap)
- (nthcdr (+ 1 pos-in-keymap) keymap))))))
-
-(defun yas/define (mode key template &optional name condition group)
- "Define a snippet. Expanding KEY into TEMPLATE.
-
-NAME is a description to this template. Also update the menu if
-`yas/use-menu' is `t'. CONDITION is the condition attached to
-this snippet. If you attach a condition to a snippet, then it
-will only be expanded when the condition evaluated to non-nil."
- (yas/define-snippets mode
- (list (list key template name condition group))))
-
-(defun yas/hippie-try-expand (first-time?)
- "Integrate with hippie expand. Just put this function in
-`hippie-expand-try-functions-list'."
- (if (not first-time?)
- (let ((yas/fallback-behavior 'return-nil))
- (yas/expand))
- (undo 1)
- nil))
-
-(defun yas/expand ()
- "Expand a snippet before point.
-
-If no snippet expansion is possible, fall back to the behaviour
-defined in `yas/fallback-behavior'"
- (interactive)
- (yas/expand-1))
-
-(defun yas/expand-1 (&optional field)
- "Actually fo the work for `yas/expand'"
- (multiple-value-bind (templates start end) (if field
- (save-restriction
- (narrow-to-region (yas/field-start field) (yas/field-end field))
- (yas/current-key))
- (yas/current-key))
- (if templates
- (let ((template (or (and (rest templates) ;; more than one
- (yas/prompt-for-template (mapcar #'cdr templates)))
- (cdar templates))))
- (when template
- (yas/expand-snippet (yas/template-content template)
- start
- end
- (yas/template-expand-env template))))
- (cond ((eq yas/fallback-behavior 'return-nil)
- ;; return nil
- nil)
- ((eq yas/fallback-behavior 'call-other-command)
- (let* ((yas/minor-mode nil)
- (keys-1 (this-command-keys-vector))
- (keys-2 (and yas/trigger-key
- (stringp yas/trigger-key)
- (read-kbd-macro yas/trigger-key)))
- (command-1 (and keys-1 (key-binding keys-1)))
- (command-2 (and keys-2 (key-binding keys-2)))
- (command (or (and (not (eq command-1 'yas/expand))
- command-1)
- command-2)))
- (when (and (commandp command)
- (not (eq 'yas/expand command)))
- (setq this-command command)
- (call-interactively command))))
- ((and (listp yas/fallback-behavior)
- (cdr yas/fallback-behavior)
- (eq 'apply (car yas/fallback-behavior)))
- (if (cddr yas/fallback-behavior)
- (apply (cadr yas/fallback-behavior)
- (cddr yas/fallback-behavior))
- (when (commandp (cadr yas/fallback-behavior))
- (setq this-command (cadr yas/fallback-behavior))
- (call-interactively (cadr yas/fallback-behavior)))))
- (t
- ;; also return nil if all the other fallbacks have failed
- nil)))))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Snippet development
-
-(defun yas/all-templates (tables)
- "Return all snippet tables applicable for the current buffer.
-
-Honours `yas/choose-tables-first', `yas/choose-keys-first' and
-`yas/buffer-local-condition'"
- (when yas/choose-tables-first
- (setq tables (list (yas/prompt-for-table tables))))
- (mapcar #'cdr
- (if yas/choose-keys-first
- (let ((key (yas/prompt-for-keys
- (mapcan #'yas/snippet-table-all-keys tables))))
- (when key
- (mapcan #'(lambda (table)
- (yas/fetch table key))
- tables)))
- (mapcan #'yas/snippet-table-templates tables))))
-
-(defun yas/insert-snippet (&optional no-condition)
- "Choose a snippet to expand, pop-up a list of choices according
-to `yas/prompt-function'.
-
-With prefix argument NO-CONDITION, bypass filtering of snippets
-by condition."
- (interactive "P")
- (let* ((yas/buffer-local-condition (or (and no-condition
- 'always)
- yas/buffer-local-condition))
- (templates (yas/all-templates (yas/get-snippet-tables)))
- (template (and templates
- (or (and (rest templates) ;; more than one template for same key
- (yas/prompt-for-template templates))
- (car templates))))
- (where (if mark-active
- (cons (region-beginning) (region-end))
- (cons (point) (point)))))
- (if template
- (yas/expand-snippet (yas/template-content template)
- (car where)
- (cdr where)
- (yas/template-expand-env template))
- (message "[yas] No snippets can be inserted here!"))))
-
-(defun yas/visit-snippet-file ()
- "Choose a snippet to edit, selection like `yas/insert-snippet'.
-
-Only success if selected snippet was loaded from a file. Put the
-visited file in `snippet-mode'."
- (interactive)
- (let* ((yas/buffer-local-condition 'always)
- (templates (yas/all-templates (yas/get-snippet-tables)))
- (template (and templates
- (or (and (rest templates) ;; more than one template for same key
- (yas/prompt-for-template templates
- "Choose a snippet template to edit: "))
- (car templates)))))
-
- (when template
- (yas/visit-snippet-file-1 template))))
-
-(defun yas/visit-snippet-file-1 (template)
- (let ((file (yas/template-file template)))
- (cond ((and file (file-exists-p file))
- (find-file-other-window file)
- (snippet-mode))
- (file
- (message "Original file %s no longer exists!" file))
- (t
- (message "This snippet was not loaded from a file!")))))
-
-(defun yas/guess-snippet-directories-1 (table &optional suffix)
- "Guesses possible snippet subdirsdirectories for TABLE."
- (unless suffix
- (setq suffix (yas/snippet-table-name table)))
- (cons suffix
- (mapcan #'(lambda (parent)
- (yas/guess-snippet-directories-1
- parent
- (concat (yas/snippet-table-name parent) "/" suffix)))
- (yas/snippet-table-parents table))))
-
-(defun yas/guess-snippet-directories ()
- "Try to guess suitable directories based on the current active
-tables.
-
-Returns a a list of options alist TABLE -> DIRS where DIRS are
-all the possibly directories where snippets of table might be
-lurking."
- (let ((main-dir (or (and (listp yas/root-directory)
- (first yas/root-directory))
- yas/root-directory
- (setq yas/root-directory "~/.emacs.d/snippets")))
- (tables (yas/get-snippet-tables)))
- ;; HACK! the snippet table created here is a dummy table that
- ;; holds the correct name so that `yas/make-directory-maybe' can
- ;; work. The real table, if it does not exist in
- ;; yas/snippet-tables will be created when the first snippet for
- ;; that mode is loaded.
- ;;
- (unless (gethash major-mode yas/snippet-tables)
- (setq tables (cons (yas/make-snippet-table (symbol-name major-mode))
- tables)))
-
- (mapcar #'(lambda (table)
- (cons table
- (mapcar #'(lambda (subdir)
- (concat main-dir "/" subdir))
- (yas/guess-snippet-directories-1 table))))
- tables)))
-
-(defun yas/make-directory-maybe (table-and-dirs &optional main-table-string)
- "Returns a dir inside TABLE-AND-DIRS, prompts for creation if none exists."
- (or (some #'(lambda (dir) (when (file-directory-p dir) dir)) (cdr table-and-dirs))
- (let ((candidate (first (cdr table-and-dirs))))
- (if (y-or-n-p (format "Guessed directory (%s) for%s%s table \"%s\" does not exist! Create? "
- candidate
- (if (gethash (intern (yas/snippet-table-name (car table-and-dirs)))
- yas/snippet-tables)
- ""
- " brand new")
- (or main-table-string
- "")
- (yas/snippet-table-name (car table-and-dirs))))
- (progn
- (make-directory candidate 'also-make-parents)
- ;; create the .yas-parents file here...
- candidate)))))
-
-(defun yas/new-snippet (&optional choose-instead-of-guess)
- ""
- (interactive "P")
- (let* ((guessed-directories (yas/guess-snippet-directories))
- (option (or (and choose-instead-of-guess
- (some #'(lambda (fn)
- (funcall fn "Choose a snippet table: "
- guessed-directories
- #'(lambda (option)
- (yas/snippet-table-name (car option)))))
- yas/prompt-functions))
- (first guessed-directories)))
- (chosen))
- (setq chosen (yas/make-directory-maybe option (unless choose-instead-of-guess
- " main")))
- (unless (or chosen
- choose-instead-of-guess)
- (if (y-or-n-p (format "Continue guessing for other active tables %s? "
- (mapcar #'(lambda (table-and-dirs)
- (yas/snippet-table-name (car table-and-dirs)))
- (rest guessed-directories))))
- (setq chosen (some #'yas/make-directory-maybe
- (rest guessed-directories)))))
- (unless (or chosen
- choose-instead-of-guess)
- (when (y-or-n-p "Having trouble... use snippet root dir? ")
- (setq chosen (if (listp yas/root-directory)
- (first yas/root-directory)
- yas/root-directory))))
- (if chosen
- (let ((default-directory chosen)
- (name (read-from-minibuffer "Enter a snippet name: ")))
- (find-file-other-window (concat name
- ".yasnippet"))
- (snippet-mode)
- (unless (and choose-instead-of-guess
- (not (y-or-n-p "Insert a snippet with useful headers? ")))
- (yas/expand-snippet (format
- "\
-# -*- mode: snippet -*-
-# name: %s
-# key: $1${2:
-# binding: \"${3:keybinding}\"}${4:
-# expand-env: ((${5:some-var} ${6:some-value}))}
-# --
-$0" name))))
- (message "[yas] aborted snippet creation."))))
-
-(defun yas/find-snippets (&optional same-window )
- "Look for user snippets in guessed current mode's directory.
-
-Calls `find-file' interactively in the guessed directory.
-
-With prefix arg SAME-WINDOW opens the buffer in the same window.
-
-Because snippets can be loaded from many different locations,
-this has to guess the correct directory using
-`yas/guess-snippet-directories', which returns a list of
-options.
-
-If any one of these exists, it is taken and `find-file' is called
-there, otherwise, proposes to create the first option returned by
-`yas/guess-snippet-directories'."
- (interactive "P")
- (let* ((guessed-directories (yas/guess-snippet-directories))
- (chosen)
- (buffer))
- (setq chosen (yas/make-directory-maybe (first guessed-directories) " main"))
- (unless chosen
- (if (y-or-n-p (format "Continue guessing for other active tables %s? "
- (mapcar #'(lambda (table-and-dirs)
- (yas/snippet-table-name (car table-and-dirs)))
- (rest guessed-directories))))
- (setq chosen (some #'yas/make-directory-maybe
- (rest guessed-directories)))))
- (unless chosen
- (when (y-or-n-p "Having trouble... go to snippet root dir? ")
- (setq chosen (if (listp yas/root-directory)
- (first yas/root-directory)
- yas/root-directory))))
- (if chosen
- (let ((default-directory chosen))
- (setq buffer (call-interactively (if same-window
- 'find-file
- 'find-file-other-window)))
- (when buffer
- (save-excursion
- (set-buffer buffer)
- (when (eq major-mode 'fundamental-mode)
- (snippet-mode)))))
- (message "Could not guess snippet dir!"))))
-
-(defun yas/compute-major-mode-and-parents (file &optional prompt-if-failed no-hierarchy-parents)
- (let* ((file-dir (and file
- (directory-file-name (or (locate-dominating-file file ".yas-make-groups")
- (directory-file-name (file-name-directory file))))))
- (major-mode-name (and file-dir
- (file-name-nondirectory file-dir)))
- (parent-file-dir (and file-dir
- (directory-file-name (file-name-directory file-dir))))
- (parent-mode-name (and parent-file-dir
- (not no-hierarchy-parents)
- (file-name-nondirectory parent-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: "))))
- (parent-mode-sym (and parent-mode-name
- (intern parent-mode-name)))
- (extra-parents-file-name (concat file-dir "/.yas-parents"))
- (more-parents (when (file-readable-p extra-parents-file-name)
- (mapcar #'intern
- (split-string
- (with-temp-buffer
- (insert-file-contents extra-parents-file-name)
- (buffer-substring-no-properties (point-min)
- (point-max))))))))
- (when major-mode-sym
- (remove nil (append (list major-mode-sym parent-mode-sym)
- more-parents)))))
-
-(defun yas/load-snippet-buffer (&optional kill)
- "Parse and load current buffer's snippet definition.
-
-With optional prefix argument KILL quit the window and buffer."
- (interactive "P")
- (if buffer-file-name
- (let ((major-mode-and-parent (yas/compute-major-mode-and-parents buffer-file-name)))
- (if major-mode-and-parent
- (let* ((parsed (yas/parse-template buffer-file-name))
- (name (and parsed
- (third parsed))))
- (when name
- (let ((yas/better-guess-for-replacements t))
- (yas/define-snippets (car major-mode-and-parent)
- (list parsed)
- (cdr major-mode-and-parent)))
- (when (and (buffer-modified-p)
- (y-or-n-p "Save snippet? "))
- (save-buffer))
- (if kill
- (quit-window kill)
- (message "[yas] Snippet \"%s\" loaded for %s."
- name
- (car major-mode-and-parent)))))
- (message "[yas] Cannot load snippet for unknown major mode")))
- (message "Save the buffer as a file first!")))
-
-(defun yas/tryout-snippet (&optional debug)
- "Test current buffers's snippet template in other buffer."
- (interactive "P")
- (let* ((major-mode-and-parent (yas/compute-major-mode-and-parents buffer-file-name))
- (parsed (yas/parse-template))
- (test-mode (or (and (car major-mode-and-parent)
- (fboundp (car major-mode-and-parent))
- (car major-mode-and-parent))
- (intern (read-from-minibuffer "[yas] please input a mode: "))))
- (template (and parsed
- (fboundp test-mode)
- (yas/make-template (second parsed)
- (third parsed)
- nil
- (sixth parsed)
- nil
- nil))))
- (cond (template
- (let ((buffer-name (format "*YAS TEST: %s*" (yas/template-name template))))
- (set-buffer (switch-to-buffer buffer-name))
- (erase-buffer)
- (setq buffer-undo-list nil)
- (funcall test-mode)
- (yas/expand-snippet (yas/template-content template)
- (point-min)
- (point-max)
- (yas/template-expand-env template))
- (when debug
- (add-hook 'post-command-hook 'yas/debug-snippet-vars 't 'local))))
- (t
- (message "[yas] Cannot test snippet for unknown major mode")))))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; User convenience functions, for using in snippet definitions
-
-(defvar yas/modified-p nil
- "Non-nil if field has been modified by user or transformation.")
-
-(defvar yas/moving-away-p nil
- "Non-nil if user is about to exit field.")
-
-(defvar yas/text nil
- "Contains current field text.")
-
-(defun yas/substr (str pattern &optional subexp)
- "Search PATTERN in STR and return SUBEXPth match.
-
-If found, the content of subexp group SUBEXP (default 0) is
- returned, or else the original STR will be returned."
- (let ((grp (or subexp 0)))
- (save-match-data
- (if (string-match pattern str)
- (match-string-no-properties grp str)
- str))))
-
-(defun yas/choose-value (possibilities)
- "Prompt for a string in the list POSSIBILITIES and return it."
- (unless (or yas/moving-away-p
- yas/modified-p)
- (some #'(lambda (fn)
- (funcall fn "Choose: " possibilities))
- yas/prompt-functions)))
-
-(defun yas/key-to-value (alist)
- "Prompt for a string in the list POSSIBILITIES and return it."
- (unless (or yas/moving-away-p
- yas/modified-p)
- (let ((key (read-key-sequence "")))
- (when (stringp key)
- (or (cdr (find key alist :key #'car :test #'string=))
- key)))))
-
-(defun yas/throw (text)
- "Throw a yas/exception with TEXT as the reason."
- (throw 'yas/exception (cons 'yas/exception text)))
-
-(defun yas/verify-value (possibilities)
- "Verify that the current field value is in POSSIBILITIES
-
-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))))
-
-(defun yas/field-value (number)
- (let* ((snippet (car (yas/snippets-at-point)))
- (field (and snippet
- (yas/snippet-find-field snippet number))))
- (when field
- (yas/field-text-for-display field))))
-
-(defun yas/default-from-field (number)
- (unless yas/modified-p
- (yas/field-value number)))
-
-(defun yas/inside-string ()
- (equal 'font-lock-string-face (get-char-property (1- (point)) 'face)))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; Snippet expansion and field management
-
-(defvar yas/active-field-overlay nil
- "Overlays the currently active field.")
-
-(defvar yas/field-protection-overlays nil
- "Two overlays protect the current active field ")
-
-(defconst yas/prefix nil
- "A prefix argument for expansion direct from keybindings")
-
-(defvar yas/deleted-text nil
- "The text deleted in the last snippet expansion.")
-
-(defvar yas/selected-text nil
- "The selected region deleted on the last snippet expansion.")
-
-(defvar yas/start-column nil
- "The column where the snippet expansion started.")
-
-(make-variable-buffer-local 'yas/active-field-overlay)
-(make-variable-buffer-local 'yas/field-protection-overlays)
-(make-variable-buffer-local 'yas/deleted-text)
-
-(defstruct (yas/snippet (:constructor yas/make-snippet ()))
- "A snippet.
-
-..."
- (fields '())
- (exit nil)
- (id (yas/snippet-next-id) :read-only t)
- (control-overlay nil)
- active-field
- ;; stacked expansion: the `previous-active-field' slot saves the
- ;; active field where the child expansion took place
- previous-active-field
- force-exit)
-
-(defstruct (yas/field (:constructor yas/make-field (number start end parent-field)))
- "A field."
- number
- start end
- parent-field
- (mirrors '())
- (transform nil)
- (modified-p nil)
- next)
-
-(defstruct (yas/mirror (:constructor yas/make-mirror (start end transform)))
- "A mirror."
- start end
- (transform nil)
- next)
-
-(defstruct (yas/exit (:constructor yas/make-exit (marker)))
- marker
- next)
-
-(defun yas/apply-transform (field-or-mirror field)
- "Calculate the value of the field/mirror. If there's a transform
-for this field, apply it. Otherwise, returned nil."
- (let* ((yas/text (yas/field-text-for-display field))
- (text yas/text)
- (yas/modified-p (yas/field-modified-p field))
- (yas/moving-away-p nil)
- (transform (if (yas/mirror-p field-or-mirror)
- (yas/mirror-transform field-or-mirror)
- (yas/field-transform field-or-mirror)))
- (start-point (if (yas/mirror-p field-or-mirror)
- (yas/mirror-start field-or-mirror)
- (yas/field-start field-or-mirror)))
- (transformed (and transform
- (save-excursion
- (goto-char start-point)
- (yas/read-and-eval-string transform)))))
- transformed))
-
-(defsubst yas/replace-all (from to &optional text)
- "Replace all occurance from FROM to TO.
-
-With optional string TEXT do it in that string."
- (if text
- (replace-regexp-in-string (regexp-quote from) to text t t)
- (goto-char (point-min))
- (while (search-forward from nil t)
- (replace-match to t t text))))
-
-(defun yas/snippet-find-field (snippet number)
- (find-if #'(lambda (field)
- (eq number (yas/field-number field)))
- (yas/snippet-fields snippet)))
-
-(defun yas/snippet-sort-fields (snippet)
- "Sort the fields of SNIPPET in navigation order."
- (setf (yas/snippet-fields snippet)
- (sort (yas/snippet-fields snippet)
- '(lambda (field1 field2)
- (yas/snippet-field-compare field1 field2)))))
-
-(defun yas/snippet-field-compare (field1 field2)
- "Compare two fields. The field with a number is sorted first.
-If they both have a number, compare through the number. If neither
-have, compare through the field's start point"
- (let ((n1 (yas/field-number field1))
- (n2 (yas/field-number field2)))
- (if n1
- (if n2
- (< n1 n2)
- t)
- (if n2
- nil
- (< (yas/field-start field1)
- (yas/field-start field2))))))
-
-(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)))))))
-
-(defun yas/snippets-at-point (&optional all-snippets)
- "Return a sorted list of snippets at point, most recently
-inserted first."
- (sort
- (remove nil (remove-duplicates (mapcar #'(lambda (ov)
- (overlay-get ov 'yas/snippet))
- (if all-snippets
- (overlays-in (point-min) (point-max))
- (overlays-at (point))))))
- #'(lambda (s1 s2)
- (<= (yas/snippet-id s2) (yas/snippet-id s1)))))
-
-(defun yas/next-field-or-maybe-expand ()
- "Try to expand a snippet at a key before point, otherwise
-delegate to `yas/next-field'."
- (interactive)
- (if yas/triggers-in-field
- (let ((yas/fallback-behavior 'return-nil)
- (active-field (overlay-get yas/active-field-overlay 'yas/field)))
- (when active-field
- (unless (yas/expand-1 active-field)
- (yas/next-field))))
- (yas/next-field)))
-
-(defun yas/next-field (&optional arg)
- "Navigate to next field. If there's none, exit the snippet."
- (interactive)
- (let* ((arg (or arg
- 1))
- (snippet (first (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 (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))
- (let* ((yas/moving-away-p t)
- (yas/text (yas/field-text-for-display active-field))
- (text yas/text)
- (yas/modified-p (yas/field-modified-p active-field)))
- ;; primary field transform: exit call to field-transform
- (yas/read-and-eval-string (yas/field-transform active-field))))
- ;; Now actually move...
- (cond ((>= target-pos (length live-fields))
- (yas/exit-snippet snippet))
- (target-field
- (yas/move-to-field snippet target-field))
- (t
- nil))))
-
-(defun yas/place-overlays (snippet field)
- "Correctly place overlays for SNIPPET's FIELD"
- (yas/make-move-field-protection-overlays snippet field)
- (yas/make-move-active-field-overlay snippet field))
-
-(defun yas/move-to-field (snippet field)
- "Update SNIPPET to move to field FIELD.
-
-Also create some protection overlays"
- (goto-char (yas/field-start field))
- (setf (yas/snippet-active-field snippet) field)
- (yas/place-overlays snippet field)
- (overlay-put yas/active-field-overlay 'yas/field field)
- ;; primary field transform: first call to snippet transform
- (unless (yas/field-modified-p field)
- (if (yas/field-update-display field snippet)
- (let ((inhibit-modification-hooks t))
- (yas/update-mirrors snippet))
- (setf (yas/field-modified-p field) nil))))
-
-(defun yas/prev-field ()
- "Navigate to prev field. If there's none, exit the snippet."
- (interactive)
- (yas/next-field -1))
-
-(defun yas/abort-snippet (&optional snippet)
- (interactive)
- (let ((snippet (or snippet
- (car (yas/snippets-at-point)))))
- (when snippet
- (setf (yas/snippet-force-exit snippet) t))))
-
-(defun yas/exit-snippet (snippet)
- "Goto exit-marker of SNIPPET."
- (interactive)
- (setf (yas/snippet-force-exit snippet) t)
- (goto-char (if (yas/snippet-exit snippet)
- (yas/exit-marker (yas/snippet-exit snippet))
- (overlay-end (yas/snippet-control-overlay snippet)))))
-
-(defun yas/exit-all-snippets ()
- "Exit all snippets."
- (interactive)
- (mapc #'(lambda (snippet)
- (yas/exit-snippet snippet)
- (yas/check-commit-snippet))
- (yas/snippets-at-point)))
-
-
-;;; Apropos markers-to-points:
-;;;
-;;; This was found useful for performance reasons, so that an
-;;; excessive number of live markers aren't kept around in the
-;;; `buffer-undo-list'. However, in `markers-to-points', the
-;;; set-to-nil markers can't simply be discarded and replaced with
-;;; fresh ones in `points-to-markers'. The original marker that was
-;;; just set to nil has to be reused.
-;;;
-;;; This shouldn't bring horrible problems with undo/redo, but it
-;;; you never know
-;;;
-
-(defun yas/markers-to-points (snippet)
- "Convert all markers in SNIPPET to a cons (POINT . MARKER)
-where POINT is the original position of the marker and MARKER is
-the original marker object with the position set to nil."
- (dolist (field (yas/snippet-fields snippet))
- (let ((start (marker-position (yas/field-start field)))
- (end (marker-position (yas/field-end field))))
- (set-marker (yas/field-start field) nil)
- (set-marker (yas/field-end field) nil)
- (setf (yas/field-start field) (cons start (yas/field-start field)))
- (setf (yas/field-end field) (cons end (yas/field-end field))))
- (dolist (mirror (yas/field-mirrors field))
- (let ((start (marker-position (yas/mirror-start mirror)))
- (end (marker-position (yas/mirror-end mirror))))
- (set-marker (yas/mirror-start mirror) nil)
- (set-marker (yas/mirror-end mirror) nil)
- (setf (yas/mirror-start mirror) (cons start (yas/mirror-start mirror)))
- (setf (yas/mirror-end mirror) (cons end (yas/mirror-end mirror))))))
- (let ((snippet-exit (yas/snippet-exit snippet)))
- (when snippet-exit
- (let ((exit (marker-position (yas/exit-marker snippet-exit))))
- (set-marker (yas/exit-marker snippet-exit) nil)
- (setf (yas/exit-marker snippet-exit) (cons exit (yas/exit-marker snippet-exit)))))))
-
-(defun yas/points-to-markers (snippet)
- "Convert all cons (POINT . MARKER) in SNIPPET to markers. This
-is done by setting MARKER to POINT with `set-marker'."
- (dolist (field (yas/snippet-fields snippet))
- (setf (yas/field-start field) (set-marker (cdr (yas/field-start field))
- (car (yas/field-start field))))
- (setf (yas/field-end field) (set-marker (cdr (yas/field-end field))
- (car (yas/field-end field))))
- (dolist (mirror (yas/field-mirrors field))
- (setf (yas/mirror-start mirror) (set-marker (cdr (yas/mirror-start mirror))
- (car (yas/mirror-start mirror))))
- (setf (yas/mirror-end mirror) (set-marker (cdr (yas/mirror-end mirror))
- (car (yas/mirror-end mirror))))))
- (let ((snippet-exit (yas/snippet-exit snippet)))
- (when snippet-exit
- (setf (yas/exit-marker snippet-exit) (set-marker (cdr (yas/exit-marker snippet-exit))
- (car (yas/exit-marker snippet-exit)))))))
-
-(defun yas/commit-snippet (snippet &optional no-hooks)
- "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.
-
-NO-HOOKS means don't run the `yas/after-exit-snippet-hook' hooks."
-
- (let ((control-overlay (yas/snippet-control-overlay snippet))
- yas/snippet-beg
- yas/snippet-end)
- ;;
- ;; Save the end of the moribund snippet in case we need to revive it
- ;; its original expansion.
- ;;
- (when (and control-overlay
- (overlay-buffer control-overlay))
- (setq yas/snippet-beg (overlay-start control-overlay))
- (setq yas/snippet-end (overlay-end control-overlay))
- (delete-overlay control-overlay))
-
- (let ((inhibit-modification-hooks t))
- (when yas/active-field-overlay
- (delete-overlay yas/active-field-overlay))
- (when yas/field-protection-overlays
- (mapc #'delete-overlay yas/field-protection-overlays)))
-
- ;; stacked expansion: if the original expansion took place from a
- ;; field, make sure we advance it here at least to
- ;; `yas/snippet-end'...
- ;;
- (let ((previous-field (yas/snippet-previous-active-field snippet)))
- (when (and yas/snippet-end previous-field)
- (yas/advance-end-maybe previous-field yas/snippet-end)))
-
- ;; Convert all markers to points,
- ;;
- (yas/markers-to-points snippet)
-
- ;; Take care of snippet revival
- ;;
- (if yas/snippet-revival
- (push `(apply yas/snippet-revive ,yas/snippet-beg ,yas/snippet-end ,snippet)
- buffer-undo-list)
- ;; Dismember the snippet... this is useful if we get called
- ;; again from `yas/take-care-of-redo'....
- (setf (yas/snippet-fields snippet) nil))
-
- ;; XXX: `yas/after-exit-snippet-hook' should be run with
- ;; `yas/snippet-beg' and `yas/snippet-end' bound. That might not
- ;; be the case if the main overlay had somehow already
- ;; disappeared, which sometimes happens when the snippet's messed
- ;; up...
- ;;
- (unless no-hooks (run-hooks 'yas/after-exit-snippet-hook)))
-
- (message "[yas] snippet exited."))
-
-(defun yas/check-commit-snippet ()
- "Checks if point exited the currently active field of the
-snippet, if so cleans up the whole snippet up."
- (let* ((snippets (yas/snippets-at-point 'all-snippets))
- (snippets-left snippets))
- (dolist (snippet snippets)
- (let ((active-field (yas/snippet-active-field snippet)))
- (cond ((or (prog1 (yas/snippet-force-exit snippet)
- (setf (yas/snippet-force-exit snippet) nil))
- (not (and active-field (yas/field-contains-point-p active-field))))
- (setq snippets-left (delete snippet snippets-left))
- (yas/commit-snippet snippet snippets-left))
- ((and active-field
- (or (not yas/active-field-overlay)
- (not (overlay-buffer yas/active-field-overlay))))
- ;;
- ;; stacked expansion: this case is mainly for recent
- ;; snippet exits that place us back int the field of
- ;; another snippet
- ;;
- (save-excursion
- (yas/move-to-field snippet active-field)
- (yas/update-mirrors snippet)))
- (t
- nil))))
- (unless snippets-left
- (remove-hook 'post-command-hook 'yas/post-command-handler 'local)
- (remove-hook 'pre-command-hook 'yas/pre-command-handler 'local))))
-
-(defun yas/field-contains-point-p (field &optional point)
- (let ((point (or point
- (point))))
- (and (>= point (yas/field-start field))
- (<= point (yas/field-end field)))))
-
-(defun yas/field-text-for-display (field)
- "Return the propertized display text for field FIELD. "
- (buffer-substring (yas/field-start field) (yas/field-end field)))
-
-(defun yas/undo-in-progress ()
- "True if some kind of undo is in progress"
- (or undo-in-progress
- (eq this-command 'undo)
- (eq this-command 'redo)))
-
-(defun yas/make-control-overlay (snippet start end)
- "Creates the control overlay that surrounds the snippet and
-holds the keymap."
- (let ((overlay (make-overlay start
- end
- nil
- nil
- t)))
- (overlay-put overlay 'keymap yas/keymap)
- (overlay-put overlay 'yas/snippet snippet)
- overlay))
-
-(defun yas/skip-and-clear-or-delete-char (&optional field)
- "Clears unmodified field if at field start, skips to next tab.
-
-Otherwise deletes a character normally by calling `delete-char'."
- (interactive)
- (let ((field (or field
- (and yas/active-field-overlay
- (overlay-buffer yas/active-field-overlay)
- (overlay-get yas/active-field-overlay 'yas/field)))))
- (cond ((and field
- (not (yas/field-modified-p field))
- (eq (point) (marker-position (yas/field-start field))))
- (yas/skip-and-clear field)
- (yas/next-field 1))
- (t
- (call-interactively 'delete-char)))))
-
-(defun yas/skip-and-clear (field)
- "Deletes the region of FIELD and sets it modified state to t"
- (setf (yas/field-modified-p field) t)
- (delete-region (yas/field-start field) (yas/field-end field)))
-
-(defun yas/make-move-active-field-overlay (snippet field)
- "Place the active field overlay in SNIPPET's FIELD.
-
-Move the overlay, or create it if it does not exit."
- (if (and yas/active-field-overlay
- (overlay-buffer yas/active-field-overlay))
- (move-overlay yas/active-field-overlay
- (yas/field-start field)
- (yas/field-end field))
- (setq yas/active-field-overlay
- (make-overlay (yas/field-start field)
- (yas/field-end field)
- nil nil t))
- (overlay-put yas/active-field-overlay 'priority 100)
- (overlay-put yas/active-field-overlay 'face 'yas/field-highlight-face)
- (overlay-put yas/active-field-overlay 'yas/snippet snippet)
- (overlay-put yas/active-field-overlay 'modification-hooks '(yas/on-field-overlay-modification))
- (overlay-put yas/active-field-overlay 'insert-in-front-hooks
- '(yas/on-field-overlay-modification))
- (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)
- "Clears the field and updates mirrors, conditionally.
-
-Only clears the field if it hasn't been modified and it point it
-at field start. This hook doesn't do anything if an undo is in
-progress."
- (unless (yas/undo-in-progress)
- (let ((field (overlay-get yas/active-field-overlay 'yas/field)))
- (cond (after?
- (yas/advance-end-maybe field (overlay-end overlay))
-;;; primary field transform: normal calls to expression
- (let ((saved-point (point)))
- (yas/field-update-display field (car (yas/snippets-at-point)))
- (goto-char saved-point))
- (yas/update-mirrors (car (yas/snippets-at-point))))
- (field
- (when (and (not after?)
- (not (yas/field-modified-p field))
- (eq (point) (if (markerp (yas/field-start field))
- (marker-position (yas/field-start field))
- (yas/field-start field))))
- (yas/skip-and-clear field))
- (setf (yas/field-modified-p field) t))))))
-
-;;; Apropos protection overlays:
-;;;
-;;; These exist for nasty users who will try to delete parts of the
-;;; snippet outside the active field. Actual protection happens in
-;;; `yas/on-protection-overlay-modification'.
-;;;
-;;; Currently this signals an error which inhibits the command. For
-;;; commands that move point (like `kill-line'), point is restored in
-;;; the `yas/post-command-handler' using a global
-;;; `yas/protection-violation' variable.
-;;;
-;;; Alternatively, I've experimented with an implementation that
-;;; commits the snippet before actually calling `this-command'
-;;; interactively, and then signals an eror, which is ignored. but
-;;; blocks all other million modification hooks. This presented some
-;;; problems with stacked expansion.
-;;;
-
-(defun yas/make-move-field-protection-overlays (snippet field)
- "Place protection overlays surrounding SNIPPET's FIELD.
-
-Move the overlays, or create them if they do not exit."
- (let ((start (yas/field-start field))
- (end (yas/field-end field)))
- ;; First check if the (1+ end) is contained in the buffer,
- ;; otherwise we'll have to do a bit of cheating and silently
- ;; insert a newline. the `(1+ (buffer-size))' should prevent this
- ;; when using stacked expansion
- ;;
- (when (< (buffer-size) end)
- (save-excursion
- (let ((inhibit-modification-hooks t))
- (goto-char (point-max))
- (newline))))
- ;; go on to normal overlay creation/moving
- ;;
- (cond ((and yas/field-protection-overlays
- (every #'overlay-buffer yas/field-protection-overlays))
- (move-overlay (first yas/field-protection-overlays) (1- start) start)
- (move-overlay (second yas/field-protection-overlays) end (1+ end)))
- (t
- (setq yas/field-protection-overlays
- (list (make-overlay (1- start) start nil t nil)
- (make-overlay end (1+ end) nil t nil)))
- (dolist (ov yas/field-protection-overlays)
- (overlay-put ov 'face 'yas/field-debug-face)
- (overlay-put ov 'yas/snippet snippet)
- ;; (overlay-put ov 'evaporate t)
- (overlay-put ov 'modification-hooks '(yas/on-protection-overlay-modification)))))))
-
-(defvar yas/protection-violation nil
- "When non-nil, signals attempts to erronesly exit or modify the snippet.
-
-Functions in the `post-command-hook', for example
-`yas/post-command-handler' can check it and reset its value to
-nil. The variables value is the point where the violation
-originated")
-
-(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'"
- (cond ((not (or after?
- (yas/undo-in-progress)))
- (setq yas/protection-violation (point))
- (error "Exit the snippet first!"))))
-
-(add-to-list 'debug-ignored-errors "^Exit the snippet first!$")
-
-
-;;; Apropos stacked expansion:
-;;;
-;;; the parent snippet does not run its fields modification hooks
-;;; (`yas/on-field-overlay-modification' and
-;;; `yas/on-protection-overlay-modification') while the child snippet
-;;; is active. This means, among other things, that the mirrors of the
-;;; parent snippet are not updated, this only happening when one exits
-;;; the child snippet.
-;;;
-;;; Unfortunately, this also puts some ugly (and not fully-tested)
-;;; bits of code in `yas/expand-snippet' and
-;;; `yas/commit-snippet'. I've tried to mark them with "stacked
-;;; expansion:".
-;;;
-;;; This was thought to be safer in in an undo/redo perpective, but
-;;; maybe the correct implementation is to make the globals
-;;; `yas/active-field-overlay' and `yas/field-protection-overlays' be
-;;; snippet-local and be active even while the child snippet is
-;;; running. This would mean a lot of overlay modification hooks
-;;; running, but if managed correctly (including overlay priorities)
-;;; they should account for all situations...
-;;;
-
-(defun yas/expand-snippet (template &optional start end expand-env)
- "Expand snippet at current point. Text between START and END
-will be deleted before inserting template."
- (run-hooks 'yas/before-expand-snippet-hook)
-
- ;; If a region is active, set `yas/selected-text'
- (setq yas/selected-text
- (when mark-active
- (prog1 (buffer-substring-no-properties (region-beginning)
- (region-end))
- (unless start (setq start (region-beginning))
- (unless end (setq end (region-end)))))))
-
- (when start
- (goto-char start))
-
- ;; stacked expansion: shoosh the overlay modification hooks
- ;;
- (let ((to-delete (and start end (buffer-substring-no-properties start end)))
- (start (or start (point)))
- (end (or end (point)))
- (inhibit-modification-hooks t)
- (column (current-column))
- snippet)
-
- ;; Delete the region to delete, this *does* get undo-recorded.
- ;;
- (when (and to-delete
- (> end start))
- (delete-region start end)
- (setq yas/deleted-text to-delete))
-
- ;; Narrow the region down to the template, shoosh the
- ;; `buffer-undo-list', and create the snippet, the new snippet
- ;; updates its mirrors once, so we are left with some plain text.
- ;; The undo action for deleting this plain text will get recorded
- ;; at the end of this function.
- (save-restriction
- (narrow-to-region start start)
- (let ((buffer-undo-list t))
- ;; snippet creation might evaluate users elisp, which
- ;; might generate errors, so we have to be ready to catch
- ;; them mostly to make the undo information
- ;;
- (setq yas/start-column (save-restriction (widen) (current-column)))
- (insert template)
-
- (setq snippet
- (if expand-env
- (let ((read-vars (condition-case err
- (read expand-env)
- (error nil))))
- (eval `(let ,read-vars
- (yas/snippet-create (point-min) (point-max)))))
- (yas/snippet-create (point-min) (point-max))))))
-
- ;; stacked-expansion: This checks for stacked expansion, save the
- ;; `yas/previous-active-field' and advance its boudary.
- ;;
- (let ((existing-field (and yas/active-field-overlay
- (overlay-buffer yas/active-field-overlay)
- (overlay-get yas/active-field-overlay 'yas/field))))
- (when existing-field
- (setf (yas/snippet-previous-active-field snippet) existing-field)
- (yas/advance-end-maybe existing-field (overlay-end yas/active-field-overlay))))
-
- ;; Exit the snippet immediately if no fields
- ;;
- (unless (yas/snippet-fields snippet)
- (yas/exit-snippet snippet))
-
- ;; Push two undo actions: the deletion of the inserted contents of
- ;; the new snippet (without the "key") followed by an apply of
- ;; `yas/take-care-of-redo' on the newly inserted snippet boundaries
- ;;
- (let ((start (overlay-start (yas/snippet-control-overlay snippet)))
- (end (overlay-end (yas/snippet-control-overlay snippet))))
- (push (cons start end) buffer-undo-list)
- (push `(apply yas/take-care-of-redo ,start ,end ,snippet)
- buffer-undo-list))
- ;; Now, move to the first field
- ;;
- (let ((first-field (car (yas/snippet-fields snippet))))
- (when first-field
- (yas/move-to-field snippet first-field))))
- (message "[yas] snippet expanded."))
-
-(defun yas/take-care-of-redo (beg end snippet)
- "Commits SNIPPET, which in turn pushes an undo action for
-reviving it.
-
-Meant to exit in the `buffer-undo-list'."
- ;; slightly optimize: this action is only needed for snippets with
- ;; at least one field
- (when (yas/snippet-fields snippet)
- (yas/commit-snippet snippet 'no-hooks)))
-
-(defun yas/snippet-revive (beg end snippet)
- "Revives the SNIPPET and creates a control overlay from BEG to
-END.
-
-BEG and END are, we hope, the original snippets boudaries. All
-the markers/points exiting existing inside SNIPPET should point
-to their correct locations *at the time the snippet is revived*.
-
-After revival, push the `yas/take-care-of-redo' in the
-`buffer-undo-list'"
- ;; Reconvert all the points to markers
- ;;
- (yas/points-to-markers snippet)
- ;; When at least one editable field existed in the zombie snippet,
- ;; try to revive the whole thing...
- ;;
- (let ((target-field (or (yas/snippet-active-field snippet)
- (car (yas/snippet-fields snippet)))))
- (when target-field
- (setf (yas/snippet-control-overlay snippet) (yas/make-control-overlay snippet beg end))
- (overlay-put (yas/snippet-control-overlay snippet) 'yas/snippet snippet)
-
- (yas/move-to-field snippet target-field)
-
- (add-hook 'post-command-hook 'yas/post-command-handler nil t)
- (add-hook 'pre-command-hook 'yas/pre-command-handler t t)
-
- (push `(apply yas/take-care-of-redo ,beg ,end ,snippet)
- buffer-undo-list))))
-
-(defun yas/snippet-create (begin end)
- "Creates a snippet from an template inserted between BEGIN and END.
-
-Returns the newly created snippet."
- (let ((snippet (yas/make-snippet)))
- (goto-char begin)
- (yas/snippet-parse-create snippet)
-
- ;; Sort and link each field
- (yas/snippet-sort-fields snippet)
-
- ;; Create keymap overlay for snippet
- (setf (yas/snippet-control-overlay snippet)
- (yas/make-control-overlay snippet (point-min) (point-max)))
-
- ;; Move to end
- (goto-char (point-max))
-
- ;; Setup hooks
- (add-hook 'post-command-hook 'yas/post-command-handler nil t)
- (add-hook 'pre-command-hook 'yas/pre-command-handler t t)
-
- snippet))
-
-
-;;; Apropos adjacencies: Once the $-constructs bits like "$n" and
-;;; "${:n" are deleted in the recently expanded snippet, we might
-;;; actually have many fields, mirrors (and the snippet exit) in the
-;;; very same position in the buffer. Therefore we need to single-link
-;;; the fields-or-mirrors-or-exit, which I have called "fom",
-;;; according to their original positions in the buffer.
-;;;
-;;; Then we have operation `yas/advance-end-maybe' and
-;;; `yas/advance-start-maybe', which conditionally push the starts and
-;;; ends of these foms down the chain.
-;;;
-;;; This allows for like the printf with the magic ",":
-;;;
-;;; printf ("${1:%s}\\n"${1:$(if (string-match "%" text) "," "\);")} \
-;;; $2${1:$(if (string-match "%" text) "\);" "")}$0
-;;;
-
-(defun yas/fom-start (fom)
- (cond ((yas/field-p fom)
- (yas/field-start fom))
- ((yas/mirror-p fom)
- (yas/mirror-start fom))
- (t
- (yas/exit-marker fom))))
-
-(defun yas/fom-end (fom)
- (cond ((yas/field-p fom)
- (yas/field-end fom))
- ((yas/mirror-p fom)
- (yas/mirror-end fom))
- (t
- (yas/exit-marker fom))))
-
-(defun yas/fom-next (fom)
- (cond ((yas/field-p fom)
- (yas/field-next fom))
- ((yas/mirror-p fom)
- (yas/mirror-next fom))
- (t
- (yas/exit-next fom))))
-
-(defun yas/calculate-adjacencies (snippet)
- "Calculate adjacencies for fields or mirrors of SNIPPET.
-
-This is according to their relative positions in the buffer, and
-has to be called before the $-constructs are deleted."
- (flet ((yas/fom-set-next-fom (fom nextfom)
- (cond ((yas/field-p fom)
- (setf (yas/field-next fom) nextfom))
- ((yas/mirror-p fom)
- (setf (yas/mirror-next fom) nextfom))
- (t
- (setf (yas/exit-next fom) nextfom))))
- (yas/compare-fom-begs (fom1 fom2)
- (> (yas/fom-start fom2) (yas/fom-start fom1)))
- (yas/link-foms (fom1 fom2)
- (yas/fom-set-next-fom fom1 fom2)))
- ;; make some yas/field, yas/mirror and yas/exit soup
- (let ((soup))
- (when (yas/snippet-exit snippet)
- (push (yas/snippet-exit snippet) soup))
- (dolist (field (yas/snippet-fields snippet))
- (push field soup)
- (dolist (mirror (yas/field-mirrors field))
- (push mirror soup)))
- (setq soup
- (sort soup
- #'yas/compare-fom-begs))
- (when soup
- (reduce #'yas/link-foms soup)))))
-
-(defun yas/advance-end-maybe (fom newend)
- "Maybe advance FOM's end to NEWEND if it needs it.
-
-If it does, also:
-
-* call `yas/advance-start-maybe' on FOM's next fom.
-
-* in case FOM is field call `yas/advance-end-maybe' on its parent
- field"
- (when (and fom (< (yas/fom-end fom) newend))
- (set-marker (yas/fom-end fom) newend)
- (yas/advance-start-maybe (yas/fom-next fom) newend)
- (if (and (yas/field-p fom)
- (yas/field-parent-field fom))
- (yas/advance-end-maybe (yas/field-parent-field fom) newend))))
-
-(defun yas/advance-start-maybe (fom newstart)
- "Maybe advance FOM's start to NEWSTART if it needs it.
-
-If it does, also call `yas/advance-end-maybe' on FOM."
- (when (and fom (< (yas/fom-start fom) newstart))
- (set-marker (yas/fom-start fom) newstart)
- (yas/advance-end-maybe fom newstart)))
-
-(defvar yas/dollar-regions nil
- "When expanding the snippet the \"parse-create\" functions add
- cons cells to this var")
-
-(defun yas/snippet-parse-create (snippet)
- "Parse a recently inserted snippet template, creating all
-necessary fields, mirrors and exit points.
-
-Meant to be called in a narrowed buffer, does various passes"
- (let ((parse-start (point)))
- ;; Reset the yas/dollar-regions
- ;;
- (setq yas/dollar-regions nil)
- ;; protect escaped quote, backquotes and backslashes
- ;;
- (yas/protect-escapes nil '(?\\ ?` ?'))
- ;; replace all backquoted expressions
- ;;
- (goto-char parse-start)
- (yas/replace-backquotes)
- ;; protect escapes again since previous steps might have generated
- ;; more characters needing escaping
- ;;
- (goto-char parse-start)
- (yas/protect-escapes)
- ;; parse fields with {}
- ;;
- (goto-char parse-start)
- (yas/field-parse-create snippet)
- ;; parse simple mirrors and fields
- ;;
- (goto-char parse-start)
- (yas/simple-mirror-parse-create snippet)
- ;; parse mirror transforms
- ;;
- (goto-char parse-start)
- (yas/transform-mirror-parse-create snippet)
- ;; calculate adjacencies of fields and mirrors
- ;;
- (yas/calculate-adjacencies snippet)
- ;; Delete $-constructs
- ;;
- (yas/delete-regions yas/dollar-regions)
- ;; restore escapes
- ;;
- (goto-char parse-start)
- (yas/restore-escapes)
- ;; update mirrors for the first time
- ;;
- (yas/update-mirrors snippet)
- ;; indent the best we can
- ;;
- (goto-char parse-start)
- (yas/indent snippet)))
-
-(defun yas/indent-according-to-mode (snippet-markers)
- "Indent current line according to mode, preserving
-SNIPPET-MARKERS."
- ;; XXX: Here seems to be the indent problem:
- ;;
- ;; `indent-according-to-mode' uses whatever
- ;; `indent-line-function' is available. Some
- ;; implementations of these functions delete text
- ;; before they insert. If there happens to be a marker
- ;; just after the text being deleted, the insertion
- ;; actually happens after the marker, which misplaces
- ;; it.
- ;;
- ;; This would also happen if we had used overlays with
- ;; the `front-advance' property set to nil.
- ;;
- ;; This is why I have these `trouble-markers', they are the ones at
- ;; they are the ones at the first non-whitespace char at the line
- ;; (i.e. at `yas/real-line-beginning'. After indentation takes place
- ;; we should be at the correct to restore them to. All other
- ;; non-trouble-markers have been *pushed* and don't need special
- ;; attention.
- ;;
- (goto-char (yas/real-line-beginning))
- (let ((trouble-markers (remove-if-not #'(lambda (marker)
- (= marker (point)))
- snippet-markers)))
- (save-restriction
- (widen)
- (condition-case err
- (indent-according-to-mode)
- (error (message "[yas] warning: yas/indent-according-to-mode habing problems running %s" indent-line-function)
- nil)))
- (mapc #'(lambda (marker)
- (set-marker marker (point)))
- trouble-markers)))
-
-(defun yas/indent (snippet)
- (let ((snippet-markers (yas/collect-snippet-markers snippet)))
- ;; Look for those $>
- (save-excursion
- (while (re-search-forward "$>" nil t)
- (delete-region (match-beginning 0) (match-end 0))
- (when (not (eq yas/indent-line 'auto))
- (yas/indent-according-to-mode snippet-markers))))
- ;; Now do stuff for 'fixed and 'auto
- (save-excursion
- (cond ((eq yas/indent-line 'fixed)
- (while (and (zerop (forward-line))
- (zerop (current-column)))
- (indent-to-column column)))
- ((eq yas/indent-line 'auto)
- (let ((end (set-marker (make-marker) (point-max)))
- (indent-first-line-p yas/also-auto-indent-first-line))
- (while (and (zerop (if indent-first-line-p
- (prog1
- (forward-line 0)
- (setq indent-first-line-p nil))
- (forward-line 1)))
- (not (eobp))
- (<= (point) end))
- (yas/indent-according-to-mode snippet-markers))))
- (t
- nil)))))
-
-(defun yas/collect-snippet-markers (snippet)
- "Make a list of all the markers used by SNIPPET."
- (let (markers)
- (dolist (field (yas/snippet-fields snippet))
- (push (yas/field-start field) markers)
- (push (yas/field-end field) markers)
- (dolist (mirror (yas/field-mirrors field))
- (push (yas/mirror-start mirror) markers)
- (push (yas/mirror-end mirror) markers)))
- (let ((snippet-exit (yas/snippet-exit snippet)))
- (when (and snippet-exit
- (marker-buffer (yas/exit-marker snippet-exit)))
- (push (yas/exit-marker snippet-exit) markers)))
- markers))
-
-(defun yas/real-line-beginning ()
- (let ((c (char-after (line-beginning-position)))
- (n (line-beginning-position)))
- (while (or (eql c ?\ )
- (eql c ?\t))
- (incf n)
- (setq c (char-after n)))
- n))
-
-(defun yas/escape-string (escaped)
- (concat "YASESCAPE" (format "%d" escaped) "PROTECTGUARD"))
-
-(defun yas/protect-escapes (&optional text escaped)
- "Protect all escaped characters with their numeric ASCII value.
-
-With optional string TEXT do it in string instead of buffer."
- (let ((changed-text text)
- (text-provided-p text))
- (mapc #'(lambda (escaped)
- (setq changed-text
- (yas/replace-all (concat "\\" (char-to-string escaped))
- (yas/escape-string escaped)
- (when text-provided-p changed-text))))
- (or escaped yas/escaped-characters))
- changed-text))
-
-(defun yas/restore-escapes (&optional text escaped)
- "Restore all escaped characters from their numeric ASCII value.
-
-With optional string TEXT do it in string instead of the buffer."
- (let ((changed-text text)
- (text-provided-p text))
- (mapc #'(lambda (escaped)
- (setq changed-text
- (yas/replace-all (yas/escape-string escaped)
- (char-to-string escaped)
- (when text-provided-p changed-text))))
- (or escaped yas/escaped-characters))
- changed-text))
-
-(defun yas/replace-backquotes ()
- "Replace all the \"`(lisp-expression)`\"-style expression
- with their evaluated value"
- (while (re-search-forward yas/backquote-lisp-expression-regexp nil t)
- (let ((transformed (yas/read-and-eval-string (yas/restore-escapes (match-string 1)))))
- (goto-char (match-end 0))
- (when transformed (insert transformed))
- (delete-region (match-beginning 0) (match-end 0)))))
-
-(defun yas/scan-sexps (from count)
- (condition-case err
- (with-syntax-table (standard-syntax-table)
- (scan-sexps from count))
- (error
- nil)))
-
-(defun yas/make-marker (pos)
- "Create a marker at POS with `nil' `marker-insertion-type'"
- (let ((marker (set-marker (make-marker) pos)))
- (set-marker-insertion-type marker nil)
- marker))
-
-(defun yas/field-parse-create (snippet &optional parent-field)
- "Parse most field expressions, except for the simple one \"$n\".
-
-The following count as a field:
-
-* \"${n: text}\", for a numbered field with default text, as long as N is not 0;
-
-* \"${n: text$(expression)}, the same with a lisp expression;
- this is caught with the curiously named `yas/multi-dollar-lisp-expression-regexp'
-
-* the same as above but unnumbered, (no N:) and number is calculated automatically.
-
-When multiple expressions are found, only the last one counts."
- ;;
- (save-excursion
- (while (re-search-forward yas/field-regexp nil t)
- (let* ((real-match-end-0 (yas/scan-sexps (1+ (match-beginning 0)) 1))
- (number (and (match-string-no-properties 1)
- (string-to-number (match-string-no-properties 1))))
- (brand-new-field (and real-match-end-0
- ;; break if on "$(" immediately
- ;; after the ":", this will be
- ;; caught as a mirror with
- ;; transform later.
- (not (save-match-data
- (eq (string-match "$[ \t\n]*("
- (match-string-no-properties 2)) 0)))
- (not (and number (zerop number)))
- (yas/make-field number
- (yas/make-marker (match-beginning 2))
- (yas/make-marker (1- real-match-end-0))
- parent-field))))
- (when brand-new-field
- (goto-char real-match-end-0)
- (push (cons (1- real-match-end-0) real-match-end-0)
- yas/dollar-regions)
- (push (cons (match-beginning 0) (match-beginning 2))
- yas/dollar-regions)
- (push brand-new-field (yas/snippet-fields snippet))
- (save-excursion
- (save-restriction
- (narrow-to-region (yas/field-start brand-new-field) (yas/field-end brand-new-field))
- (goto-char (point-min))
- (yas/field-parse-create snippet brand-new-field)))))))
- ;; if we entered from a parent field, now search for the
- ;; `yas/multi-dollar-lisp-expression-regexp'. THis is used for
- ;; primary field transformations
- ;;
- (when parent-field
- (save-excursion
- (while (re-search-forward yas/multi-dollar-lisp-expression-regexp nil t)
- (let* ((real-match-end-1 (yas/scan-sexps (match-beginning 1) 1)))
- ;; commit the primary field transformation if we don't find
- ;; it in yas/dollar-regions (a subnested field) might have
- ;; already caught it.
- (when (and real-match-end-1
- (not (member (cons (match-beginning 0)
- real-match-end-1)
- yas/dollar-regions)))
- (let ((lisp-expression-string (buffer-substring-no-properties (match-beginning 1)
- real-match-end-1)))
- (setf (yas/field-transform parent-field) (yas/restore-escapes lisp-expression-string)))
- (push (cons (match-beginning 0) real-match-end-1)
- yas/dollar-regions)))))))
-
-(defun yas/transform-mirror-parse-create (snippet)
- "Parse the \"${n:$(lisp-expression)}\" mirror transformations."
- (while (re-search-forward yas/transform-mirror-regexp nil t)
- (let* ((real-match-end-0 (yas/scan-sexps (1+ (match-beginning 0)) 1))
- (number (string-to-number (match-string-no-properties 1)))
- (field (and number
- (not (zerop number))
- (yas/snippet-find-field snippet number))))
- (when (and real-match-end-0
- field)
- (push (yas/make-mirror (yas/make-marker (match-beginning 0))
- (yas/make-marker (match-beginning 0))
- (yas/restore-escapes
- (buffer-substring-no-properties (match-beginning 2)
- (1- real-match-end-0))))
- (yas/field-mirrors field))
- (push (cons (match-beginning 0) real-match-end-0) yas/dollar-regions)))))
-
-(defun yas/simple-mirror-parse-create (snippet)
- "Parse the simple \"$n\" mirrors and the exit-marker."
- (while (re-search-forward yas/simple-mirror-regexp nil t)
- (let ((number (string-to-number (match-string-no-properties 1))))
- (cond ((zerop number)
-
- (setf (yas/snippet-exit snippet)
- (yas/make-exit (yas/make-marker (match-end 0))))
- (save-excursion
- (goto-char (match-beginning 0))
- (when yas/wrap-around-region
- (cond (yas/selected-text
- (insert yas/selected-text))
- ((and (eq yas/wrap-around-region 'cua)
- cua-mode
- (get-register ?0))
- (insert (prog1 (get-register ?0)
- (set-register ?0 nil))))))
- (push (cons (point) (yas/exit-marker (yas/snippet-exit snippet)))
- yas/dollar-regions)))
- (t
- (let ((field (yas/snippet-find-field snippet number)))
- (if field
- (push (yas/make-mirror (yas/make-marker (match-beginning 0))
- (yas/make-marker (match-beginning 0))
- nil)
- (yas/field-mirrors field))
- (push (yas/make-field number
- (yas/make-marker (match-beginning 0))
- (yas/make-marker (match-beginning 0))
- nil)
- (yas/snippet-fields snippet))))
- (push (cons (match-beginning 0) (match-end 0))
- yas/dollar-regions))))))
-
-(defun yas/delete-regions (regions)
- "Sort disjuct REGIONS by start point, then delete from the back."
- (mapc #'(lambda (reg)
- (delete-region (car reg) (cdr reg)))
- (sort regions
- #'(lambda (r1 r2)
- (>= (car r1) (car r2))))))
-
-(defun yas/update-mirrors (snippet)
- "Updates all the mirrors of SNIPPET."
- (save-excursion
- (dolist (field (yas/snippet-fields snippet))
- (dolist (mirror (yas/field-mirrors field))
- ;; stacked expansion: I added an `inhibit-modification-hooks'
- ;; here, for safety, may need to remove if we the mechanism is
- ;; altered.
- ;;
- (let ((inhibit-modification-hooks t))
- (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)."
- (let ((reflection (or (yas/apply-transform mirror field)
- (yas/field-text-for-display field))))
- (when (and reflection
- (not (string= reflection (buffer-substring-no-properties (yas/mirror-start mirror)
- (yas/mirror-end mirror)))))
- (goto-char (yas/mirror-start mirror))
- (insert reflection)
- (if (> (yas/mirror-end mirror) (point))
- (delete-region (point) (yas/mirror-end mirror))
- (set-marker (yas/mirror-end mirror) (point))
- (yas/advance-start-maybe (yas/mirror-next mirror) (point))))))
-
-(defun yas/field-update-display (field snippet)
- "Much like `yas/mirror-update-display', but for fields"
- (when (yas/field-transform field)
- (let ((inhibit-modification-hooks t)
- (transformed (yas/apply-transform field field))
- (point (point)))
- (when (and transformed
- (not (string= transformed (buffer-substring-no-properties (yas/field-start field)
- (yas/field-end field)))))
- (setf (yas/field-modified-p field) t)
- (goto-char (yas/field-start field))
- (insert transformed)
- (if (> (yas/field-end field) (point))
- (delete-region (point) (yas/field-end field))
- (set-marker (yas/field-end field) (point))
- (yas/advance-start-maybe (yas/field-next field) (point)))
- t))))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Pre- and post-command hooks
-;;
-(defun yas/pre-command-handler () )
-
-(defun yas/post-command-handler ()
- "Handles various yasnippet conditions after each command."
- (cond (yas/protection-violation
- (goto-char yas/protection-violation)
- (setq yas/protection-violation nil))
- ((eq 'undo this-command)
- ;;
- ;; After undo revival the correct field is sometimes not
- ;; restored correctly, this condition handles that
- ;;
- (let* ((snippet (car (yas/snippets-at-point)))
- (target-field (and snippet
- (find-if-not #'(lambda (field)
- (yas/field-probably-deleted-p snippet field))
- (remove nil
- (cons (yas/snippet-active-field snippet)
- (yas/snippet-fields snippet)))))))
- (when target-field
- (yas/move-to-field snippet target-field))))
- ((not (yas/undo-in-progress))
- ;; When not in an undo, check if we must commit the snippet (use exited it).
- (yas/check-commit-snippet))))
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Debug functions. Use (or change) at will whenever needed.
-;;
-;; some useful debug code for looking up snippet tables
-;;
-;; (insert (pp
-;; (let ((shit))
-;; (maphash #'(lambda (k v)
-;; (push k shit))
-;; (yas/snippet-table-hash (gethash 'ruby-mode yas/snippet-tables)))
-;; shit)))
-;;
-
-(defun yas/debug-tables ()
- (interactive)
- (with-output-to-temp-buffer "*YASnippet tables*"
- (dolist (symbol (remove nil (append (list major-mode)
- (if (listp yas/mode-symbol)
- yas/mode-symbol
- (list yas/mode-symbol)))))
- (princ (format "Snippet table hash keys for %s:\n\n" symbol))
- (let ((keys))
- (maphash #'(lambda (k v)
- (push k keys))
- (yas/snippet-table-hash (gethash symbol yas/snippet-tables)))
- (princ keys))
-
- (princ (format "Keymap for %s:\n\n" symbol))
- (princ (gethash symbol yas/menu-table)))))
-
-(defun yas/debug-snippet-vars ()
- "Debug snippets, fields, mirrors and the `buffer-undo-list'."
- (interactive)
- (with-output-to-temp-buffer "*YASnippet trace*"
- (princ "Interesting YASnippet vars: \n\n")
-
- (princ (format "\nPost command hook: %s\n" post-command-hook))
- (princ (format "\nPre command hook: %s\n" pre-command-hook))
-
- (princ (format "%s live snippets in total\n" (length (yas/snippets-at-point (quote all-snippets)))))
- (princ (format "%s overlays in buffer:\n\n" (length (overlays-in (point-min) (point-max)))))
- (princ (format "%s live snippets at point:\n\n" (length (yas/snippets-at-point))))
-
-
- (dolist (snippet (yas/snippets-at-point))
- (princ (format "\tsid: %d control overlay from %d to %d\n"
- (yas/snippet-id snippet)
- (overlay-start (yas/snippet-control-overlay snippet))
- (overlay-end (yas/snippet-control-overlay snippet))))
- (princ (format "\tactive field: %d from %s to %s covering \"%s\"\n"
- (yas/field-number (yas/snippet-active-field snippet))
- (marker-position (yas/field-start (yas/snippet-active-field snippet)))
- (marker-position (yas/field-end (yas/snippet-active-field snippet)))
- (buffer-substring-no-properties (yas/field-start (yas/snippet-active-field snippet)) (yas/field-end (yas/snippet-active-field snippet)))))
- (when (yas/snippet-exit snippet)
- (princ (format "\tsnippet-exit: at %s next: %s\n"
- (yas/exit-marker (yas/snippet-exit snippet))
- (yas/exit-next (yas/snippet-exit snippet)))))
- (dolist (field (yas/snippet-fields snippet))
- (princ (format "\tfield: %d from %s to %s covering \"%s\" next: %s\n"
- (yas/field-number field)
- (marker-position (yas/field-start field))
- (marker-position (yas/field-end field))
- (buffer-substring-no-properties (yas/field-start field) (yas/field-end field))
- (yas/debug-format-fom-concise (yas/field-next field))))
- (dolist (mirror (yas/field-mirrors field))
- (princ (format "\t\tmirror: from %s to %s covering \"%s\" next: %s\n"
- (marker-position (yas/mirror-start mirror))
- (marker-position (yas/mirror-end mirror))
- (buffer-substring-no-properties (yas/mirror-start mirror) (yas/mirror-end mirror))
- (yas/debug-format-fom-concise (yas/mirror-next mirror)))))))
-
- (princ (format "\nUndo is %s and point-max is %s.\n"
- (if (eq buffer-undo-list t)
- "DISABLED"
- "ENABLED")
- (point-max)))
- (unless (eq buffer-undo-list t)
- (princ (format "Undpolist has %s elements. First 10 elements follow:\n" (length buffer-undo-list)))
- (let ((first-ten (subseq buffer-undo-list 0 19)))
- (dolist (undo-elem first-ten)
- (princ (format "%2s: %s\n" (position undo-elem first-ten) (truncate-string-to-width (format "%s" undo-elem) 70))))))))
-
-(defun yas/debug-format-fom-concise (fom)
- (when fom
- (cond ((yas/field-p fom)
- (format "field %d from %d to %d"
- (yas/field-number fom)
- (marker-position (yas/field-start fom))
- (marker-position (yas/field-end fom))))
- ((yas/mirror-p fom)
- (format "mirror from %d to %d"
- (marker-position (yas/mirror-start fom))
- (marker-position (yas/mirror-end fom))))
- (t
- (format "snippet exit at %d"
- (marker-position (yas/fom-start fom)))))))
-
-
-(defun yas/exterminate-package ()
- (interactive)
- (yas/global-mode -1)
- (yas/minor-mode -1)
- (yas/kill-snippet-keybindings)
- (mapatoms #'(lambda (atom)
- (when (string-match "yas/" (symbol-name atom))
- (unintern atom)))))
-
-(defun yas/debug-test (&optional quiet)
- (interactive "P")
- (yas/load-directory (or (and (listp yas/root-directory)
- (first yas/root-directory))
- yas/root-directory
- "~/Source/yasnippet/snippets/"))
- (set-buffer (switch-to-buffer "*YAS TEST*"))
- (mapc #'yas/commit-snippet (yas/snippets-at-point 'all-snippets))
- (erase-buffer)
- (setq buffer-undo-list nil)
- (setq undo-in-progress nil)
- (snippet-mode)
- (yas/minor-mode 1)
- (let ((abbrev))
- (setq abbrev "$f")
- (insert abbrev))
- (unless quiet
- (add-hook 'post-command-hook 'yas/debug-snippet-vars 't 'local)))
-
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; `locate-dominating-file' is added for compatibility in emacs < 23
-(unless (or (eq emacs-major-version 23)
- (fboundp 'locate-dominating-file))
- (defvar locate-dominating-stop-dir-regexp
- "\\`\\(?:[\\/][\\/][^\\/]+[\\/]\\|/\\(?:net\\|afs\\|\\.\\.\\.\\)/\\)\\'"
- "Regexp of directory names which stop the search in `locate-dominating-file'.
-Any directory whose name matches this regexp will be treated like
-a kind of root directory by `locate-dominating-file' which will stop its search
-when it bumps into it.
-The default regexp prevents fruitless and time-consuming attempts to find
-special files in directories in which filenames are interpreted as hostnames,
-or mount points potentially requiring authentication as a different user.")
-
- (defun locate-dominating-file (file name)
- "Look up the directory hierarchy from FILE for a file named NAME.
-Stop at the first parent directory containing a file NAME,
-and return the directory. Return nil if not found."
- ;; We used to use the above locate-dominating-files code, but the
- ;; directory-files call is very costly, so we're much better off doing
- ;; multiple calls using the code in here.
- ;;
- ;; Represent /home/luser/foo as ~/foo so that we don't try to look for
- ;; `name' in /home or in /.
- (setq file (abbreviate-file-name file))
- (let ((root nil)
- (prev-file file)
- ;; `user' is not initialized outside the loop because
- ;; `file' may not exist, so we may have to walk up part of the
- ;; hierarchy before we find the "initial UID".
- (user nil)
- try)
- (while (not (or root
- (null file)
- ;; FIXME: Disabled this heuristic because it is sometimes
- ;; inappropriate.
- ;; As a heuristic, we stop looking up the hierarchy of
- ;; directories as soon as we find a directory belonging
- ;; to another user. This should save us from looking in
- ;; things like /net and /afs. This assumes that all the
- ;; files inside a project belong to the same user.
- ;; (let ((prev-user user))
- ;; (setq user (nth 2 (file-attributes file)))
- ;; (and prev-user (not (equal user prev-user))))
- (string-match locate-dominating-stop-dir-regexp file)))
- (setq try (file-exists-p (expand-file-name name file)))
- (cond (try (setq root file))
- ((equal file (setq prev-file file
- file (file-name-directory
- (directory-file-name file))))
- (setq file nil))))
- root)))
-
-(provide 'yasnippet)
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;; Monkey patching for other functions that's causing
-;; problems to yasnippet. For details on why I patch
-;; those functions, refer to
-;; http://code.google.com/p/yasnippet/wiki/MonkeyPatching
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defadvice c-neutralize-syntax-in-CPP
- (around yas-mp/c-neutralize-syntax-in-CPP activate)
- "Adviced `c-neutralize-syntax-in-CPP' to properly
-handle the end-of-buffer error fired in it by calling
-`forward-char' at the end of buffer."
- (condition-case err
- ad-do-it
- (error (message (error-message-string err)))))
-
-;; disable c-electric-* serial command in YAS fields
-(add-hook 'c-mode-common-hook
- '(lambda ()
- (dolist (k '(":" ">" ";" "<" "{" "}"))
- (define-key (symbol-value (make-local-variable 'yas/keymap))
- k 'self-insert-command))))
-
-
-;;; yasnippet.el ends here