forked from colonelpanic/dotfiles
		
	
		
			
				
	
	
		
			4460 lines
		
	
	
		
			208 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
			
		
		
	
	
			4460 lines
		
	
	
		
			208 KiB
		
	
	
	
		
			EmacsLisp
		
	
	
	
	
	
| ;;; yasnippet-bundle.el --- Yet another snippet extension (Auto compiled bundle)
 | ||
| ;;; 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.1
 | ||
| ;; 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
 | ||
| 
 | ||
| ;;; dropdown-list.el --- Drop-down menu interface
 | ||
| ;;
 | ||
| ;; Filename: dropdown-list.el
 | ||
| ;; Description: Drop-down menu interface
 | ||
| ;; Author: Jaeyoun Chung [jay.chung@gmail.com]
 | ||
| ;; Maintainer:
 | ||
| ;; Copyright (C) 2008 Jaeyoun Chung
 | ||
| ;; Created: Sun Mar 16 11:20:45 2008 (Pacific Daylight Time)
 | ||
| ;; Version:
 | ||
| ;; Last-Updated: Sun Mar 16 12:19:49 2008 (Pacific Daylight Time)
 | ||
| ;;           By: dradams
 | ||
| ;;     Update #: 43
 | ||
| ;; URL: http://www.emacswiki.org/cgi-bin/wiki/dropdown-list.el
 | ||
| ;; Keywords: convenience menu
 | ||
| ;; Compatibility: GNU Emacs 21.x, GNU Emacs 22.x
 | ||
| ;;
 | ||
| ;; Features that might be required by this library:
 | ||
| ;;
 | ||
| ;;   `cl'.
 | ||
| ;;
 | ||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | ||
| ;;
 | ||
| ;;; Commentary:
 | ||
| ;;
 | ||
| ;;  According to Jaeyoun Chung, "overlay code stolen from company-mode.el."
 | ||
| ;;
 | ||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | ||
| ;;
 | ||
| ;;; Change log:
 | ||
| ;;
 | ||
| ;; 2008/03/16 dadams
 | ||
| ;;     Clean-up - e.g. use char-to-string for control chars removed by email posting.
 | ||
| ;;     Moved example usage code (define-key*, command-selector) inside the library.
 | ||
| ;;     Require cl.el at byte-compile time.
 | ||
| ;;     Added GPL statement.
 | ||
| ;; 2008/01/06 Jaeyoun Chung
 | ||
| ;;     Posted to gnu-emacs-sources@gnu.org at 9:10 p.m.
 | ||
| ;;
 | ||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | ||
| ;;
 | ||
| ;; This program 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 3, or
 | ||
| ;; (at your option) any later version.
 | ||
| ;;
 | ||
| ;; This program 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 this program; see the file COPYING.  If not, write to
 | ||
| ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
 | ||
| ;; Floor, Boston, MA 02110-1301, USA.
 | ||
| ;;
 | ||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | ||
| ;;
 | ||
| ;;; Code:
 | ||
| 
 | ||
| (eval-when-compile (require 'cl)) ;; decf, fourth, incf, loop, mapcar*
 | ||
| 
 | ||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | ||
| 
 | ||
| (defface dropdown-list-face
 | ||
|   '((t :inherit default :background "lightyellow" :foreground "black"))
 | ||
|   "*Bla." :group 'dropdown-list)
 | ||
| 
 | ||
| (defface dropdown-list-selection-face
 | ||
|   '((t :inherit dropdown-list-face :background "purple"))
 | ||
|   "*Bla." :group 'dropdown-list)
 | ||
| 
 | ||
| (defvar dropdown-list-overlays nil)
 | ||
| 
 | ||
| (defun dropdown-list-hide ()
 | ||
|   (while dropdown-list-overlays
 | ||
|     (delete-overlay (pop dropdown-list-overlays))))
 | ||
| 
 | ||
| (defun dropdown-list-put-overlay (beg end &optional prop value prop2 value2)
 | ||
|   (let ((ov (make-overlay beg end)))
 | ||
|     (overlay-put ov 'window t)
 | ||
|     (when prop
 | ||
|       (overlay-put ov prop value)
 | ||
|       (when prop2 (overlay-put ov prop2 value2)))
 | ||
|     ov))
 | ||
| 
 | ||
| (defun dropdown-list-line (start replacement &optional no-insert)
 | ||
|   ;; start might be in the middle of a tab, which means we need to hide the
 | ||
|   ;; tab and add spaces
 | ||
|   (let ((end (+ start (length replacement)))
 | ||
|         beg-point end-point
 | ||
|         before-string after-string)
 | ||
|     (goto-char (point-at-eol))
 | ||
|     (if (< (current-column) start)
 | ||
|         (progn (setq before-string (make-string (- start (current-column)) ? ))
 | ||
|                (setq beg-point (point)))
 | ||
|       (goto-char (point-at-bol)) ;; Emacs bug, move-to-column is wrong otherwise
 | ||
|       (move-to-column start)
 | ||
|       (setq beg-point (point))
 | ||
|       (when (> (current-column) start)
 | ||
|         (goto-char (1- (point)))
 | ||
|         (setq beg-point (point))
 | ||
|         (setq before-string (make-string (- start (current-column)) ? ))))
 | ||
|     (move-to-column end)
 | ||
|     (setq end-point (point))
 | ||
|     (let ((end-offset (- (current-column) end)))
 | ||
|       (when (> end-offset 0) (setq after-string (make-string end-offset ?b))))
 | ||
|     (when no-insert
 | ||
|       ;; prevent inheriting of faces
 | ||
|       (setq before-string (when before-string (propertize before-string 'face 'default)))
 | ||
|       (setq after-string (when after-string (propertize after-string 'face 'default))))
 | ||
|     (let ((string (concat before-string replacement after-string)))
 | ||
|       (if no-insert
 | ||
|           string
 | ||
|         (push (dropdown-list-put-overlay beg-point end-point 'invisible t
 | ||
|                                          'after-string string)
 | ||
|               dropdown-list-overlays)))))
 | ||
| 
 | ||
| (defun dropdown-list-start-column (display-width)
 | ||
|   (let ((column (mod (current-column) (window-width)))
 | ||
|         (width (window-width)))
 | ||
|     (cond ((<= (+ column display-width) width) column)
 | ||
|           ((> column display-width) (- column display-width))
 | ||
|           ((>= width display-width) (- width display-width))
 | ||
|           (t nil))))
 | ||
| 
 | ||
| (defun dropdown-list-move-to-start-line (candidate-count)
 | ||
|   (decf candidate-count)
 | ||
|   (let ((above-line-count (save-excursion (- (vertical-motion (- candidate-count)))))
 | ||
|         (below-line-count (save-excursion (vertical-motion candidate-count))))
 | ||
|     (cond ((= below-line-count candidate-count)
 | ||
|            t)
 | ||
|           ((= above-line-count candidate-count)
 | ||
|            (vertical-motion (- candidate-count))
 | ||
|            t)
 | ||
|           ((>= (+ below-line-count above-line-count) candidate-count)
 | ||
|            (vertical-motion (- (- candidate-count below-line-count)))
 | ||
|            t)
 | ||
|           (t nil))))
 | ||
| 
 | ||
| (defun dropdown-list-at-point (candidates &optional selidx)
 | ||
|   (dropdown-list-hide)
 | ||
|   (let* ((lengths (mapcar #'length candidates))
 | ||
|          (max-length (apply #'max lengths))
 | ||
|          (start (dropdown-list-start-column (+ max-length 3)))
 | ||
|          (i -1)
 | ||
|          (candidates (mapcar* (lambda (candidate length)
 | ||
|                                 (let ((diff (- max-length length)))
 | ||
|                                   (propertize
 | ||
|                                    (concat (if (> diff 0)
 | ||
|                                                (concat candidate (make-string diff ? ))
 | ||
|                                              (substring candidate 0 max-length))
 | ||
|                                            (format "%3d" (+ 2 i)))
 | ||
|                                    'face (if (eql (incf i) selidx)
 | ||
|                                              'dropdown-list-selection-face
 | ||
|                                            'dropdown-list-face))))
 | ||
|                               candidates
 | ||
|                               lengths)))
 | ||
|     (save-excursion
 | ||
|       (and start
 | ||
|            (dropdown-list-move-to-start-line (length candidates))
 | ||
|            (loop initially (vertical-motion 0)
 | ||
|                  for candidate in candidates
 | ||
|                  do (dropdown-list-line (+ (current-column) start) candidate)
 | ||
|                  while (/= (vertical-motion 1) 0)
 | ||
|                  finally return t)))))
 | ||
| 
 | ||
| (defun dropdown-list (candidates)
 | ||
|   (let ((selection)
 | ||
|         (temp-buffer))
 | ||
|     (save-window-excursion
 | ||
|       (unwind-protect
 | ||
|           (let ((candidate-count (length candidates))
 | ||
|                 done key (selidx 0))
 | ||
|             (while (not done)
 | ||
|               (unless (dropdown-list-at-point candidates selidx)
 | ||
|                 (switch-to-buffer (setq temp-buffer (get-buffer-create "*selection*"))
 | ||
|                                   'norecord)
 | ||
|                 (delete-other-windows)
 | ||
|                 (delete-region (point-min) (point-max))
 | ||
|                 (insert (make-string (length candidates) ?\n))
 | ||
|                 (goto-char (point-min))
 | ||
|                 (dropdown-list-at-point candidates selidx))
 | ||
|               (setq key (read-key-sequence ""))
 | ||
|               (cond ((and (stringp key)
 | ||
|                           (>= (aref key 0) ?1)
 | ||
|                           (<= (aref key 0) (+ ?0 (min 9 candidate-count))))
 | ||
|                      (setq selection (- (aref key 0) ?1)
 | ||
|                            done      t))
 | ||
|                     ((member key `(,(char-to-string ?\C-p) [up] "p"))
 | ||
|                      (setq selidx (mod (+ candidate-count (1- (or selidx 0)))
 | ||
|                                        candidate-count)))
 | ||
|                     ((member key `(,(char-to-string ?\C-n) [down] "n"))
 | ||
|                      (setq selidx (mod (1+ (or selidx -1)) candidate-count)))
 | ||
|                     ((member key `(,(char-to-string ?\f))))
 | ||
|                     ((member key `(,(char-to-string ?\r) [return]))
 | ||
|                      (setq selection selidx
 | ||
|                            done      t))
 | ||
|                     (t (setq done t)))))
 | ||
|         (dropdown-list-hide)
 | ||
|         (and temp-buffer (kill-buffer temp-buffer)))
 | ||
|       ;;     (when selection
 | ||
|       ;;       (message "your selection => %d: %s" selection (nth selection candidates))
 | ||
|       ;;       (sit-for 1))
 | ||
|       selection)))
 | ||
| 
 | ||
| (defun define-key* (keymap key command)
 | ||
|   "Add COMMAND to the multiple-command binding of KEY in KEYMAP.
 | ||
| Use multiple times to bind different COMMANDs to the same KEY."
 | ||
|   (define-key keymap key (combine-command command (lookup-key keymap key))))
 | ||
| 
 | ||
| (defun combine-command (command defs)
 | ||
|   "$$$$$ FIXME - no doc string"
 | ||
|   (cond ((null defs) command)
 | ||
|         ((and (listp defs)
 | ||
|               (eq 'lambda (car defs))
 | ||
|               (= (length defs) 4)
 | ||
|               (listp (fourth defs))
 | ||
|               (eq 'command-selector (car (fourth defs))))
 | ||
|          (unless (member `',command (cdr (fourth defs)))
 | ||
|            (setcdr (fourth defs) (nconc (cdr (fourth defs)) `(',command))))
 | ||
|          defs)
 | ||
|         (t
 | ||
|          `(lambda () (interactive) (command-selector ',defs ',command)))))
 | ||
| 
 | ||
| (defvar command-selector-last-command nil "$$$$$ FIXME - no doc string")
 | ||
| 
 | ||
| (defun command-selector (&rest candidates)
 | ||
|   "$$$$$ FIXME - no doc string"
 | ||
|   (if (and (eq last-command this-command) command-selector-last-command)
 | ||
|       (call-interactively command-selector-last-command)
 | ||
|     (let* ((candidate-strings
 | ||
|             (mapcar (lambda (candidate)
 | ||
|                       (format "%s" (if (symbolp candidate)
 | ||
|                                        candidate
 | ||
|                                      (let ((s (format "%s" candidate)))
 | ||
|                                        (if (>= (length s) 7)
 | ||
|                                            (concat (substring s 0 7) "...")
 | ||
|                                          s)))))
 | ||
|                     candidates))
 | ||
|            (selection (dropdown-list candidate-strings)))
 | ||
|       (when selection
 | ||
|         (let ((cmd (nth selection candidates)))
 | ||
|           (call-interactively cmd)
 | ||
|           (setq command-selector-last-command cmd))))))
 | ||
| 
 | ||
| ;;;;;;;;;;;;;;;;;;;;
 | ||
| 
 | ||
| (provide 'dropdown-list)
 | ||
| 
 | ||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | ||
| ;;; dropdown-list.el ends here;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | ||
| ;;;;      Auto-generated code         ;;;;
 | ||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 | ||
| (defun yas/initialize-bundle ()
 | ||
|   "Initialize YASnippet and load snippets in the bundle.";;; snippets for text-mode
 | ||
| (yas/define-snippets 'text-mode
 | ||
| 		     '(("email" "`(replace-regexp-in-string \"@\" \"@NOSPAM.\" user-mail-address)`" "(user's email)" nil nil nil nil nil)
 | ||
| 		       ("time" "`(current-time-string)`" "(current time)" nil nil nil nil nil))
 | ||
| 		     'nil)
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for cc-mode
 | ||
| (yas/define-snippets 'cc-mode
 | ||
| 		     '(("do" "do\n{\n    $0\n} while (${1:condition});" "do { ... } while (...)" nil nil nil nil nil)
 | ||
| 		       ("for" "for (${1:int i = 0}; ${2:i < N}; ${3:++i})\n{\n    $0\n}" "for (...; ...; ...) { ... }" nil nil nil nil nil)
 | ||
| 		       ("if" "if (${1:condition})\n{\n    $0\n}" "if (...) { ... }" nil nil nil nil nil)
 | ||
| 		       ("inc" "#include \"$1\"\n" "#include \"...\"" nil nil nil nil nil)
 | ||
| 		       ("inc" "#include <$1>\n" "#include <...>" nil nil nil nil nil)
 | ||
| 		       ("main" "int main(int argc, char *argv[])\n{\n    $0\n    return 0;\n}\n" "int main(argc, argv) { ... }" nil nil nil nil nil)
 | ||
| 		       ("once" "#ifndef ${1:_`(upcase (file-name-nondirectory (file-name-sans-extension (buffer-file-name))))`_H_}\n#define $1\n\n$0\n\n#endif /* $1 */" "#ifndef XXX; #define XXX; #endif" nil nil nil nil nil)
 | ||
| 		       ("struct" "struct ${1:name}\n{\n    $0\n};" "struct ... { ... }" nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for c++-mode
 | ||
| (yas/define-snippets 'c++-mode
 | ||
| 		     '(("beginend" "${1:v}.begin(), $1.end" "v.begin(), v.end()" nil nil nil nil nil)
 | ||
| 		       ("class" "class ${1:Name}\n{\npublic:\n    ${1:$(yas/substr text \"[^: ]*\")}($2);\n    virtual ~${1:$(yas/substr text \"[^: ]*\")}();\n};" "class ... { ... }" nil nil nil nil nil)
 | ||
| 		       ("ns" "namespace " "namespace ..." nil nil nil nil nil)
 | ||
| 		       ("template" "template <typename ${T}>" "template <typename ...>" nil nil nil nil nil)
 | ||
| 		       ("using" "using namespace ${std};\n$0" "using namespace ... " nil nil nil nil nil))
 | ||
| 		     '(cc-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for c-mode
 | ||
| (yas/define-snippets 'c-mode
 | ||
| 		     '(("fopen" "FILE *${fp} = fopen(${\"file\"}, \"${r}\");\n" "FILE *fp = fopen(..., ...);" nil nil nil nil nil)
 | ||
| 		       ("printf" "printf (\"${1:%s}\\\\n\"${1:$(if (string-match \"%\" text) \",\" \"\\);\")\n}$2${1:$(if (string-match \"%\" text) \"\\);\" \"\")}" "printf " nil nil nil nil nil))
 | ||
| 		     '(cc-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for csharp-mode
 | ||
| (yas/define-snippets 'csharp-mode
 | ||
| 		     '(("attrib" "/// <summary>\n/// $3\n/// </summary>\nprivate $1 $2;\n" "private attribute ....;" nil nil nil nil nil)
 | ||
| 		       ("attrib" "/// <summary>\n/// $3\n/// </summary>\nprivate $1 $2;\n\n/// <summary>\n/// $4\n/// </summary>\n/// <value>$5</value>\npublic $1 $2\n{\n    get {\n        return this.$2;\n    }\n    set {\n        this.$2 = value;\n    }\n}\n" "private attribute ....; public property ... ... { ... }" nil nil nil nil nil)
 | ||
| 		       ("attrib" "/// <summary>\n/// $3\n/// </summary>\nprivate $1 ${2:$(if (> (length text) 0) (format \"_%s%s\" (downcase (substring text 0 1)) (substring text 1 (length text))) \"\")};\n\n/// <summary>\n/// ${3:Description}\n/// </summary>\n/// <value><c>$1</c></value>\npublic ${1:Type} ${2:Name}\n{\n    get {\n        return this.${2:$(if (> (length text) 0) (format \"_%s%s\" (downcase (substring text 0 1)) (substring text 1 (length text))) \"\")};\n    }\n    set {\n        this.${2:$(if (> (length text) 0) (format \"_%s%s\" (downcase (substring text 0 1)) (substring text 1 (length text))) \"\")} = value;\n    }\n}\n" "private _attribute ....; public Property ... ... { ... }" nil nil nil nil nil)
 | ||
| 		       ("class" "${5:public} class ${1:Name}\n{\n    #region Ctor & Destructor\n    /// <summary>\n    /// ${3:Standard Constructor}\n    /// </summary>\n    public $1($2)\n    {\n    }\n\n    /// <summary>\n    /// ${4:Default Destructor}\n    /// </summary>    \n    public ~$1()\n    {\n    }\n    #endregion\n}\n" "class ... { ... }" nil nil nil nil nil)
 | ||
| 		       ("comment" "/// <summary>\n/// $1\n/// </summary>\n" "/// <summary> ... </summary>" nil nil nil nil nil)
 | ||
| 		       ("comment" "/// <param name=\"$1\">$2</param>\n" "/// <param name=\"...\"> ... </param>" nil nil nil nil nil)
 | ||
| 		       ("comment" "/// <returns>$1</returns>\n" "/// <param name=\"...\"> ... </param>" nil nil nil nil nil)
 | ||
| 		       ("comment" "/// <exception cref=\"$1\">$2</exception>\n" "/// <exception cref=\"...\"> ... </exception>" nil nil nil nil nil)
 | ||
| 		       ("method" "/// <summary>\n/// ${5:Description}\n/// </summary>${2:$(if (string= (upcase text) \"VOID\") \"\" (format \"%s%s%s\" \"\\n/// <returns><c>\" text \"</c></returns>\"))}\n${1:public} ${2:void} ${3:MethodName}($4)\n{\n$0\n}\n" "public void Method { ... }" nil nil nil nil nil)
 | ||
| 		       ("namespace" "namespace $1\n{\n$0\n}\n" "namespace .. { ... }" nil nil nil nil nil)
 | ||
| 		       ("prop" "/// <summary>\n/// $5\n/// </summary>\n/// <value>$6</value>\n$1 $2 $3\n{\n    get {\n        return this.$4;\n    }\n    set {\n        this.$4 = value;\n    }\n}\n" "property ... ... { ... }" nil nil nil nil nil)
 | ||
| 		       ("region" "#region $1\n$0\n#endregion\n" "#region ... #endregion" nil nil nil nil nil)
 | ||
| 		       ("using" "using $1;\n" "using ...;" nil nil nil nil nil)
 | ||
| 		       ("using" "using System;\n" "using System;" nil nil nil nil nil)
 | ||
| 		       ("using" "using System.$1;\n" "using System....;" nil nil nil nil nil))
 | ||
| 		     '(cc-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for objc-mode
 | ||
| (yas/define-snippets 'objc-mode
 | ||
| 		     '(("prop" "- (${1:id})${2:foo}\n{\n    return $2;\n}\n\n- (void)set${2:$(capitalize text)}:($1)aValue\n{\n    [$2 autorelease];\n    $2 = [aValue retain];\n}\n$0" "foo { ... } ; setFoo { ... }" nil nil nil nil nil))
 | ||
| 		     '(cc-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for css-mode
 | ||
| (yas/define-snippets 'css-mode
 | ||
| 		     '(("bg" "background-color: #${1:DDD};" "background-color: ..." nil nil nil nil nil)
 | ||
| 		       ("bg" "background-image: url($1);" "background-image: ..." nil nil nil nil nil)
 | ||
| 		       ("bor" "border: ${1:1px} ${2:solid} #${3:999};" "border size style color" nil nil nil nil nil)
 | ||
| 		       ("cl" "clear: $1;\n" "clear: ..." nil nil nil nil nil)
 | ||
| 		       ("disp" "display: block;\n" "display: block" nil nil nil nil nil)
 | ||
| 		       ("disp" "display: inline;\n" "display: inline" nil nil nil nil nil)
 | ||
| 		       ("disp" "display: none;\n" "display: none" nil nil nil nil nil)
 | ||
| 		       ("ff" "font-family: $1;\n" "font-family: ..." nil nil nil nil nil)
 | ||
| 		       ("fs" "font-size: ${12px};\n" "font-size: ..." nil nil nil nil nil)
 | ||
| 		       ("mar" "margin-bottom: $1;\n" "margin-bottom: ..." nil nil nil nil nil)
 | ||
| 		       ("mar" "margin-left: $1;\n" "margin-left: ..." nil nil nil nil nil)
 | ||
| 		       ("mar" "margin: $1;\n" "margin: ..." nil nil nil nil nil)
 | ||
| 		       ("mar" "margin: ${top} ${right} ${bottom} ${left};\n" "margin top right bottom left" nil nil nil nil nil)
 | ||
| 		       ("mar" "margin-right: $1;\n" "margin-right: ..." nil nil nil nil nil)
 | ||
| 		       ("mar" "margin-top: $1;\n" "margin-top: ..." nil nil nil nil nil)
 | ||
| 		       ("pad" "padding-bottom: $1;\n" "padding-bottom: ..." nil nil nil nil nil)
 | ||
| 		       ("pad" "padding-left: $1;\n" "padding-left: ..." nil nil nil nil nil)
 | ||
| 		       ("pad" "padding: $1;\n" "padding: ..." nil nil nil nil nil)
 | ||
| 		       ("pad" "padding: ${top} ${right} ${bottom} ${left};\n" "padding: top right bottom left" nil nil nil nil nil)
 | ||
| 		       ("pad" "padding-right: $1;\n" "padding-right: ..." nil nil nil nil nil)
 | ||
| 		       ("pad" "padding-top: $1;\n" "padding-top: ..." nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for emacs-lisp-mode
 | ||
| (yas/define-snippets 'emacs-lisp-mode
 | ||
| 		     '(("defun" "(defun $1 ()\n  \"thisandthat.\"\n  (interactive)\n  (let (var1)\n    (setq var1 some)\n    $0\n  )\n)" "function template" nil nil nil nil nil)
 | ||
| 		       ("dired" ";; idiom for processing a list of files in dired's marked files\n \n;; suppose myProcessFile is your function that takes a file path\n;; and do some processing on the file\n\n(defun dired-myProcessFile ()\n  \"apply myProcessFile function to marked files in dired.\"\n  (interactive)\n  (require 'dired)\n  (mapc 'myProcessFile (dired-get-marked-files))\n)\n\n;; to use it, type M-x dired-myProcessFile\n" "process marked files in dired" nil nil nil nil nil)
 | ||
| 		       ("file" "(defun doThisFile (fpath)\n  \"Process the file at path FPATH ...\"\n  (let ()\n    ;; create temp buffer without undo record or font lock. (more efficient)\n    ;; first space in temp buff name is necessary\n    (set-buffer (get-buffer-create \" myTemp\"))\n    (insert-file-contents fpath nil nil nil t)\n\n    ;; process it ...\n    ;; (goto-char 0) ; move to begining of file's content (in case it was open)\n    ;; ... do something here\n    ;; (write-file fpath) ;; write back to the file\n\n    (kill-buffer \" myTemp\")))\n" "a function that process a file" nil nil nil nil nil)
 | ||
| 		       ("file" "(defun read-lines (filePath)\n  \"Return a list of lines in FILEPATH.\"\n  (with-temp-buffer\n    (insert-file-contents filePath)\n    (split-string\n     (buffer-string) \"\\n\" t)) )\n\n;; process all lines\n(mapc \n (lambda (aLine) \n   (message aLine) ; do your stuff here\n   )\n (read-lines \"inputFilePath\")\n)" "read lines of a file" nil nil nil nil nil)
 | ||
| 		       ("find-replace" "(defun replace-html-chars-region (start end)\n  \"Replace < to < and other chars in HTML.\nThis works on the current region.\"\n  (interactive \"r\")\n  (save-restriction \n    (narrow-to-region start end)\n    (goto-char (point-min))\n    (while (search-forward \"&\" nil t) (replace-match \"&\" nil t))\n    (goto-char (point-min))\n    (while (search-forward \"<\" nil t) (replace-match \"<\" nil t))\n    (goto-char (point-min))\n    (while (search-forward \">\" nil t) (replace-match \">\" nil t))\n    )\n  )\n" "find and replace on region" nil nil nil nil nil)
 | ||
| 		       ("grabstring" "(setq $0 (buffer-substring-no-properties myStartPos myEndPos))\n" "grab buffer substring" nil nil nil nil nil)
 | ||
| 		       ("grabthing" "(setq $0 (thing-at-point 'symbol))\n" "grab word under cursor" nil nil nil nil nil)
 | ||
| 		       ("traverse_dir" ";; apply a function to all files in a dir\n(require 'find-lisp)\n(mapc 'my-process-file (find-lisp-find-files \"~/myweb/\" \"\\\\.html$\"))\n" "traversing a directory" nil nil nil nil nil)
 | ||
| 		       ("word-or-region" ";; example of a command that works on current word or text selection\n(defun down-case-word-or-region ()\n  \"Lower case the current word or text selection.\"\n(interactive)\n(let (pos1 pos2 meat)\n  (if (and transient-mark-mode mark-active)\n      (setq pos1 (region-beginning)\n            pos2 (region-end))\n    (setq pos1 (car (bounds-of-thing-at-point 'symbol))\n          pos2 (cdr (bounds-of-thing-at-point 'symbol))))\n\n  ; now, pos1 and pos2 are the starting and ending positions\n  ; of the current word, or current text selection if exists\n\n  ;; put your code here.\n  $0\n  ;; Some example of things you might want to do\n  (downcase-region pos1 pos2) ; example of a func that takes region as args\n  (setq meat (buffer-substring-no-properties pos1 pos2)) ; grab the text.\n  (delete-region pos1 pos2) ; get rid of it\n  (insert \"newText\") ; insert your new text\n\n  )\n)\n" "Command that works on region or word" nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for erlang-mode
 | ||
| (yas/define-snippets 'erlang-mode
 | ||
| 		     '(("after" "after\n    $1 -> $0\n" "after ... ->" nil nil nil nil nil)
 | ||
| 		       ("begin" "begin\n    $0\nend\n" "begin ... end" nil nil nil nil nil)
 | ||
| 		       ("beh" "-behaviour(${1:gen_server}).\n$0\n" "-behaviour(...)." nil nil nil nil nil)
 | ||
| 		       ("case" "case $1 of\n    $0\nend\n" "case ... of ... end" nil nil nil nil nil)
 | ||
| 		       ("compile" "-compile([${1:export_all}]).\n$0\n" "-compile(...)." nil nil nil nil nil)
 | ||
| 		       ("def" "-define($1,$2).\n$0\n" "-define(...,...)." nil nil nil nil nil)
 | ||
| 		       ("exp" "-export([${1:start/0}]).\n$0\n" "-export([])." nil nil nil nil nil)
 | ||
| 		       ("fun" "fun ($1) -> $0 end\n" "fun (...) -> ... end" nil nil nil nil nil)
 | ||
| 		       ("if" "if\n    $1 -> $2;\n    true -> $0\nend\n" "if ... -> ... ; true -> ... end" nil nil nil nil nil)
 | ||
| 		       ("ifdef" "-ifdef($1).\n$0\n-endif.\n" "-ifdef(...). ... -endif." nil nil nil nil nil)
 | ||
| 		       ("ifndef" "-ifndef($1).\n$0\n-endif.\n" "-ifndef(...). ... -endif." nil nil nil nil nil)
 | ||
| 		       ("imp" "-import(${1:lists}, [${2:map/2, sum/1}]).\n$0\n" "-import([])." nil nil nil nil nil)
 | ||
| 		       ("inc" "-include(\"$1\").\n$0\n" "-include(\"...\")." nil nil nil nil nil)
 | ||
| 		       ("inc" "-include_lib(\"$1\").\n$0\n" "-include_lib(\"...\")." nil nil nil nil nil)
 | ||
| 		       ("loop" "${1:loop}($2) ->\n    receive\n	${3:_} ->\n	    $1($2)\n    end.\n$0\n" "loop(...) -> receive _ -> loop(...) end." nil nil nil nil nil)
 | ||
| 		       ("mod" "-module(${1:`(file-name-nondirectory\n              (file-name-sans-extension (or (buffer-file-name) (buffer-name))))`}).\n$0\n" "-module()." nil nil nil nil nil)
 | ||
| 		       ("rcv" "receive\n    $1 -> $0\nend\n" "receive ... -> ... end" nil nil nil nil nil)
 | ||
| 		       ("rcv" "receive\nafter\n    $1 -> $0\nend\n" "receive after ... -> ... end" nil nil nil nil nil)
 | ||
| 		       ("rec" "-record($1,{$2}).\n$0\n" "-record(...,{...})." nil nil nil nil nil)
 | ||
| 		       ("try" "try $1 of\n    $0\ncatch\nafter\nend\n" "try ... of ... catch after end" nil nil nil nil nil)
 | ||
| 		       ("undef" "-undef($1).\n$0\n" "-undef(...)." nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for f90-mode
 | ||
| (yas/define-snippets 'f90-mode
 | ||
| 		     '(("au" "automatic $0 \n" "automatic" nil nil nil nil nil)
 | ||
| 		       ("bd" "block data $0\n" "block data" nil nil nil nil nil)
 | ||
| 		       ("c" "continue $0\n" "continue" nil nil nil nil nil)
 | ||
| 		       ("ch" "character $0\n" "character" nil nil nil nil nil)
 | ||
| 		       ("cx" "complex $0\n" "complex" nil nil nil nil nil)
 | ||
| 		       ("dc" "double complex $0\n" "double complex" nil nil nil nil nil)
 | ||
| 		       ("do" "do while (${1:condition})\n   $0\nend do\n" "do while (...) end do" nil nil nil nil nil)
 | ||
| 		       ("dp" "double precision $0\n" "double precision" nil nil nil nil nil)
 | ||
| 		       ("eq" "equivalence $0\n" "equivalence" nil nil nil nil nil)
 | ||
| 		       ("ib" "implicit byte $0\n" "implicit byte" nil nil nil nil nil)
 | ||
| 		       ("ic" "implicit complex $0\n" "implicit complex" nil nil nil nil nil)
 | ||
| 		       ("ich" "implicit character $0\n" "implicit character" nil nil nil nil nil)
 | ||
| 		       ("if" "if ( ${1:condition} ) then\n   $0\nend if\n" "if then end if" nil nil nil nil nil)
 | ||
| 		       ("ii" "implicit integer $0\n" "implicit integer " nil nil nil nil nil)
 | ||
| 		       ("il" "implicit logical $0\n" "implicit logical" nil nil nil nil nil)
 | ||
| 		       ("in" "implicit none\n" "implicit none" nil nil nil nil nil)
 | ||
| 		       ("inc" "include $0\n" "include" nil nil nil nil nil)
 | ||
| 		       ("intr" "intrinsic $0\n" "intrinsic" nil nil nil nil nil)
 | ||
| 		       ("ir" "implicit real $0\n" "implicit real" nil nil nil nil nil)
 | ||
| 		       ("l" "logical $0\n" "logical" nil nil nil nil nil)
 | ||
| 		       ("pa" "parameter $0\n" "parameter" nil nil nil nil nil)
 | ||
| 		       ("pr" "program ${1:name}\n  $0\nend program ${1:name}\n" "program ... end program ..." nil nil nil nil nil)
 | ||
| 		       ("re" "read (${1:*},${2:*}) $0\n" "read (*,*)" nil nil nil nil nil)
 | ||
| 		       ("st" "structure $0\n" "structure" nil nil nil nil nil)
 | ||
| 		       ("su" "subroutine $0\n" "subroutine" nil nil nil nil nil)
 | ||
| 		       ("wr" "write (${1:*},${2:*}) $0\n" "write (*,*)" nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for html-mode
 | ||
| (yas/define-snippets 'html-mode
 | ||
| 		     '(("body" "<body$1>\n  $0\n</body>" "<body>...</body>" nil nil nil nil nil)
 | ||
| 		       ("br" "<br />" "<br />" nil nil nil nil nil)
 | ||
| 		       ("code" "<code>\n  $0\n</code>" "<code>...</code>" nil nil nil nil nil)
 | ||
| 		       ("code" "<code class=\"$1\">\n  $0\n</code>" "<code class=\"...\">...</code>" nil nil nil nil nil)
 | ||
| 		       ("dd" "<dd>$1</dd>" "<dd> ... </dd>" nil "list" nil nil nil)
 | ||
| 		       ("div" "<div${1: id=\"${2:some_id}\"}${3: class=\"${4:some_class}\"}>$0</div> " "<div...>...</div>" nil nil nil nil nil)
 | ||
| 		       ("div" "<div class=\"$1\">\n  $0\n</div>" "<div class=\"...\">...</div>" nil nil nil nil nil)
 | ||
| 		       ("div" "<div id=\"$1\">\n  $0\n</div>" "<div id=\"...\">...</div>" nil nil nil nil nil)
 | ||
| 		       ("div" "<div id=\"$1\" class=\"$2\">\n  $0\n</div>" "<div id=\"...\" class=\"...\">...</div>" nil nil nil nil nil)
 | ||
| 		       ("dl" "<dl>\n    $0\n</dl>\n" "<dl> ... </dl>" nil "list" nil nil nil)
 | ||
| 		       ("dl" "<dl id=\"$1\">\n    $0\n</dl>" "<dl> ... </dl>" nil "list" nil nil nil)
 | ||
| 		       ("doctype" "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" "Doctype HTML 4.01 Strict" nil "meta" nil nil nil)
 | ||
| 		       ("doctype" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">" "DocType XHTML 1.0 frameset" nil "meta" nil nil nil)
 | ||
| 		       ("doctype" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">" "DocType XHTML 1.1" nil "meta" nil nil nil)
 | ||
| 		       ("doctype" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" "DocType XHTML 1.0 Strict" nil "meta" nil nil nil)
 | ||
| 		       ("doctype" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" "DocType XHTML 1.0 Transitional" nil "meta" nil nil nil)
 | ||
| 		       ("dov" "a mirror up here $3\n\n\n<dov ${1:id=\"${2:some_id and here comes another nested field: ${3:nested_shit}}\"}>\n    $0\n</dov>\n<dov $1>\n    actually some other shit and $3\n</dov>\n" "<dov...>...</dov>" nil nil nil nil nil)
 | ||
| 		       ("dt" "<dt>$1</dt>" "<dt> ... </dt>" nil "list" nil nil nil)
 | ||
| 		       ("form" "<form method=\"$1\" id=\"$2\" action=\"$3\">\n  $0\n</form>" "<form method=\"...\" id=\"...\" action=\"...\"></form>" nil nil nil nil nil)
 | ||
| 		       ("h1" "<h1>$1</h1>" "<h1>...</h1>" nil "header" nil nil nil)
 | ||
| 		       ("h2" "<h2>$1</h2>" "<h2>...</h2>" nil "header" nil nil nil)
 | ||
| 		       ("h3" "<h3>$1</h3>" "<h3>...</h3>" nil "header" nil nil nil)
 | ||
| 		       ("h4" "<h4>$1</h4>" "<h4>...</h4>" nil "header" nil nil nil)
 | ||
| 		       ("h5" "<h5>$1</h5>" "<h5>...</h5>" nil "header" nil nil nil)
 | ||
| 		       ("h6" "<h6>$1</h6>" "<h6>...</h6>" nil "header" nil nil nil)
 | ||
| 		       ("head" "<head>\n  $0\n</head>" "<head>...</head>" nil nil nil nil nil)
 | ||
| 		       ("hr" "<hr />\n" "<hr />" nil nil nil nil nil)
 | ||
| 		       ("href" "<a href=\"$1\">$2</a>" "<a href=\"...\">...</a>" nil nil nil nil nil)
 | ||
| 		       ("html" "<html>\n  $0\n</html>\n" "<html>...</html>" nil nil nil nil nil)
 | ||
| 		       ("html" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"${1:en}\" lang=\"${2:en}\">\n  $0\n</html>\n" "<html xmlns=\"...\">...</html>" nil nil nil nil nil)
 | ||
| 		       ("img" "<img src=\"$1\" class=\"$2\" alt=\"$3\" />" "<img src=\"...\" class=\"...\" alt=\"...\" />" nil nil nil nil nil)
 | ||
| 		       ("input" "<input type=\"$1\" name=\"$2\" value=\"$3\" />" "<input ... />" nil nil nil nil nil)
 | ||
| 		       ("li" "<li>$1</li>" "<li>...</li>" nil "list" nil nil nil)
 | ||
| 		       ("li" "<li class=\"$1\">$2</li>" "<li class=\"...\">...</li>" nil "list" nil nil nil)
 | ||
| 		       ("link" "<link rel=\"${1:stylesheet}\" href=\"${2:url}\" type=\"${3:text/css}\" media=\"${4:screen}\" />" "<link stylesheet=\"...\" />" nil nil nil nil nil)
 | ||
| 		       ("link" "<!--[if IE]>\n<link rel=\"${1:stylesheet}\" href=\"${2:url}\" type=\"${3:text/css}\" media=\"${4:screen}\" />\n<![endif]-->" "<!--[if IE]><link stylesheet=\"...\" /><![endif]-->" nil nil nil nil nil)
 | ||
| 		       ("mailto" "<a href=\"mailto:$1@$2\">$0</a>" "<a href=\"mailto:...@...\">...</a>" nil nil nil nil nil)
 | ||
| 		       ("meta" "<meta name=\"${1:generator}\" content=\"${2:content}\" />" "<meta name=\"...\" content=\"...\" />" nil "meta" nil nil nil)
 | ||
| 		       ("meta" "<meta name=\"${1:Content-Type}\" content=\"${2:text/html; charset=UTF-8}\" />" "<meta http-equiv=\"...\" content=\"...\" />" nil "meta" nil nil nil)
 | ||
| 		       ("ol" "<ol>\n  $0\n</ol>" "<ol>...</ol>" nil "list" nil nil nil)
 | ||
| 		       ("ol" "<ol class=\"$1\">\n  $0\n</ol>" "<ol class=\"...\">...</ol>" nil "list" nil nil nil)
 | ||
| 		       ("ol" "<ol id=\"$1\">\n  $0\n</ol>" "<ol id=\"...\">...</ol>" nil "list" nil nil nil)
 | ||
| 		       ("p" "<p>$1</p>" "<p>...</p>" nil nil nil nil nil)
 | ||
| 		       ("pre" "<pre>\n  $0\n</pre>" "<pre>...</pre>" nil nil nil nil nil)
 | ||
| 		       ("quote" "<blockquote>\n  $1\n</blockquote>" "<blockquote>...</blockquote>" nil nil nil nil nil)
 | ||
| 		       ("script" "<script type=\"text/javascript\">\n  $0\n</script>" "<script type=\"text/javascript\">...</script> " nil nil nil nil nil)
 | ||
| 		       ("script" "<script type=\"text/javascript\" src=\"$1\"></script>" "<script type=\"text/javascript\" src=\"...\"></script> " nil nil nil nil nil)
 | ||
| 		       ("span" "<span>$1</span>" "<span>...</span>" nil nil nil nil nil)
 | ||
| 		       ("span" "<span class=\"$1\">$2</span>" "<span class=\"...\">...</span>" nil nil nil nil nil)
 | ||
| 		       ("span" "<span id=\"$1\">$2</span>" "<span id=\"...\">...</span>" nil nil nil nil nil)
 | ||
| 		       ("style" "<style type=\"text/css\" media=\"${1:screen}\">\n  $0\n</style>" "<style type=\"text/css\" media=\"...\">...</style>" nil nil nil nil nil)
 | ||
| 		       ("table" "<table width=\"$1\" cellspacing=\"$2\" cellpadding=\"$3\" border=\"$4\">\n  $0\n</table>" "<table ...>...</table>" nil "table" nil nil nil)
 | ||
| 		       ("td" "<td$1>$2</td>" "<td>...</td>" nil "table" nil nil nil)
 | ||
| 		       ("textarea" "<textarea name=\"$1\" id=\"$2\" rows=\"$3\" cols=\"$4\" tabindex=\"$5\"></textarea>" "<textarea ...></textarea>" nil nil nil nil nil)
 | ||
| 		       ("th" "<th$1>$2</th>" "<th>...</th>" nil "table" nil nil nil)
 | ||
| 		       ("title" "<title>$1</title>" "<title>...</title>" nil nil nil nil nil)
 | ||
| 		       ("tr" "<tr>\n  $0\n</tr>" "<tr>...</tr>" nil "table" nil nil nil)
 | ||
| 		       ("ul" "<ul>\n  $0\n</ul>" "<ul>...</ul>" nil "list" nil nil nil)
 | ||
| 		       ("ul" "<ul class=\"$1\">\n  $0\n</ul>" "<ul class=\"...\">...</ul>" nil "list" nil nil nil)
 | ||
| 		       ("ul" "<ul id=\"$1\">\n  $0\n</ul>" "<ul id=\"...\">...</ul>" nil "list" nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for latex-mode
 | ||
| (yas/define-snippets 'latex-mode
 | ||
| 		     '(("begin" "\n\\begin{${1:environment}}\n$0\n\\end{$1}\n" "\\begin{environment} ... \\end{environment}" nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for markdown-mode
 | ||
| (yas/define-snippets 'markdown-mode
 | ||
| 		     '(("+" "+ ${1:Text}\n+$0\n" "Unordered List" nil nil nil nil nil)
 | ||
| 		       ("-" "- ${1:Text}\n-$0\n" "Unordered List" nil nil nil nil nil)
 | ||
| 		       ("_" "_${1:Text}_ $0\n" "Emphasis" nil nil nil nil nil)
 | ||
| 		       ("__" "**${1:Text}** $0\n" "Strong" nil nil nil nil nil)
 | ||
| 		       ("`" "\\`${1:Code}\\` $0\n" "Inline Code" nil nil nil nil nil)
 | ||
| 		       ("h1" "# ${1:Header 1} #\n\n$0\n" "Header 1 (#)" nil nil nil nil nil)
 | ||
| 		       ("h1" "${1:Header 1}\n${1:$(make-string (string-width text) ?\\=)}\n\n$0\n" "Header 1 (=)" nil nil nil nil nil)
 | ||
| 		       ("h2" "## ${1:Header 1} ##\n\n$0\n" "Header 2 (##)" nil nil nil nil nil)
 | ||
| 		       ("h2" "${1:Header 2}\n${1:$(make-string (string-width text) ?\\-)}\n\n$0\n" "Header 2 (-)" nil nil nil nil nil)
 | ||
| 		       ("h3" "### ${1:Header 3} ###\n\n$0\n" "Header 3" nil nil nil nil nil)
 | ||
| 		       ("h4" "#### ${1:Header 4} ####\n\n$0\n" "Header 4" nil nil nil nil nil)
 | ||
| 		       ("h5" "##### ${1:Header 5} #####\n\n$0\n" "Header 5" nil nil nil nil nil)
 | ||
| 		       ("h6" "###### ${1:Header 6} ######\n\n$0\n" "Header 6" nil nil nil nil nil)
 | ||
| 		       ("hr" "\n----------\n\n$0\n" "Horizontal Rule (-)" nil nil nil nil nil)
 | ||
| 		       ("hr" "\n*******\n\n$0\n" "Horizontal Rule (*)" nil nil nil nil nil)
 | ||
| 		       ("img" " $0\n" "Image" nil nil nil nil nil)
 | ||
| 		       ("link" "[${1:Link Text}](${2:URL} $3) $0\n" "Link" nil nil nil nil nil)
 | ||
| 		       ("ol" "${1:1}. ${2:Text}\n${1:$(number-to-string (1+ (string-to-number text)))}. $0\n" "Ordered List" nil nil nil nil nil)
 | ||
| 		       ("rimg" "![${1:Alt Text}][$2] $0\n" "Referenced Image" nil nil nil nil nil)
 | ||
| 		       ("rlb" "[${1:Reference}]: ${2:URL} $3\n$0\n" "Reference Label" nil nil nil nil nil)
 | ||
| 		       ("rlink" "[${1:Link Text}][$2] $0\n" "Reference Link" nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for nxml-mode
 | ||
| (yas/define-snippets 'nxml-mode
 | ||
| 		     '(("body" "<body$1>\n  $0\n</body>" "<body>...</body>" nil nil nil nil nil)
 | ||
| 		       ("br" "<br />" "<br />" nil nil nil nil nil)
 | ||
| 		       ("code" "<code>\n  $0\n</code>" "<code>...</code>" nil nil nil nil nil)
 | ||
| 		       ("div" "<div$1>$0</div>" "<div...>...</div>" nil nil nil nil nil)
 | ||
| 		       ("doctype" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">" "DocType XHTML 1.1" nil "meta" nil nil nil)
 | ||
| 		       ("doctype" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">" "DocType XHTML 1.0 Strict" nil "meta" nil nil nil)
 | ||
| 		       ("doctype" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" "DocType XHTML 1.0 Transitional" nil "meta" nil nil nil)
 | ||
| 		       ("form" "<form method=\"$1\" action=\"$2\">\n  $0\n</form>" "<form method=\"...\" action=\"...\"></form>" nil nil nil nil nil)
 | ||
| 		       ("h1" "<h1>$1</h1>" "<h1>...</h1>" nil "header" nil nil nil)
 | ||
| 		       ("h2" "<h2>$1</h2>" "<h2>...</h2>" nil "header" nil nil nil)
 | ||
| 		       ("h3" "<h3>$1</h3>" "<h3>...</h3>" nil "header" nil nil nil)
 | ||
| 		       ("h4" "<h4>$1</h4>" "<h4>...</h4>" nil "header" nil nil nil)
 | ||
| 		       ("h5" "<h5>$1</h5>" "<h5>...</h5>" nil "header" nil nil nil)
 | ||
| 		       ("h6" "<h6>$1</h6>" "<h6>...</h6>" nil "header" nil nil nil)
 | ||
| 		       ("head" "<head>\n  $0\n</head>" "<head>...</head>" nil nil nil nil nil)
 | ||
| 		       ("hr" "<hr />\n" "<hr />" nil nil nil nil nil)
 | ||
| 		       ("href" "<a href=\"$1\">$2</a>" "<a href=\"...\">...</a>" nil nil nil nil nil)
 | ||
| 		       ("html" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"${1:en}\" lang=\"${2:en}\">\n  $0\n</html>\n" "<html xmlns=\"...\">...</html>" nil nil nil nil nil)
 | ||
| 		       ("img" "<img src=\"$1\" alt=\"$2\" />" "<img src=\"...\" alt=\"...\" />" nil nil nil nil nil)
 | ||
| 		       ("input" "<input type=\"$1\" name=\"$2\" value=\"$3\" />" "<input ... />" nil nil nil nil nil)
 | ||
| 		       ("li" "<li>$1</li>" "<li>...</li>" nil nil nil nil nil)
 | ||
| 		       ("link" "<link rel=\"${1:stylesheet}\" href=\"${2:url}\" type=\"${3:text/css}\" media=\"${4:screen}\" />" "<link stylesheet=\"...\" />" nil nil nil nil nil)
 | ||
| 		       ("meta" "<meta name=\"${1:generator}\" content=\"${2:content}\" />" "<meta name=\"...\" content=\"...\" />" nil "meta" nil nil nil)
 | ||
| 		       ("name" "<a name=\"$1\"></a>" "<a name=\"...\"></a>" nil nil nil nil nil)
 | ||
| 		       ("ol" "<ol>\n  $0\n</ol>" "<ol>...</ol>" nil nil nil nil nil)
 | ||
| 		       ("p" "<p>$1</p>" "<p>...</p>" nil nil nil nil nil)
 | ||
| 		       ("pre" "<pre>\n  $0\n</pre>" "<pre>...</pre>" nil nil nil nil nil)
 | ||
| 		       ("quote" "<blockquote>\n  $1\n</blockquote>" "<blockquote>...</blockquote>" nil nil nil nil nil)
 | ||
| 		       ("span" "<span>$1</span>" "<span>...</span>" nil nil nil nil nil)
 | ||
| 		       ("style" "<style type=\"text/css\" media=\"${1:screen}\">\n  $0\n</style>" "<style type=\"text/css\" media=\"...\">...</style>" nil nil nil nil nil)
 | ||
| 		       ("table" "<table>\n  $0\n</table>" "<table>...</table>" nil nil nil nil nil)
 | ||
| 		       ("tag" "<${1:tag}>$2</$1>$0" "<tag>...</tag>" nil nil nil nil nil)
 | ||
| 		       ("tag" "<${1:tag}>\n  $2\n</$1>$0" "<tag> \\n...\\n</tag>" nil nil nil nil nil)
 | ||
| 		       ("td" "<td$1>$2</td>" "<td>...</td>" nil nil nil nil nil)
 | ||
| 		       ("th" "<th$1>$2</th>" "<th>...</th>" nil nil nil nil nil)
 | ||
| 		       ("title" "<title>$1</title>" "<title>...</title>" nil nil nil nil nil)
 | ||
| 		       ("tr" "<tr>\n  $0\n</tr>" "<tr>...</tr>" nil nil nil nil nil)
 | ||
| 		       ("ul" "<ul>\n  $0\n</ul>" "<ul>...</ul>" nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for perl-mode
 | ||
| (yas/define-snippets 'perl-mode
 | ||
| 		     '(("eval" "eval {\n    ${1:# do something risky...}\n};\nif (\\$@) {\n    ${2:# handle failure...}\n}" "eval { ... } if ($@) { ... }" nil nil nil nil nil)
 | ||
| 		       ("for" "for (my \\$${1:var} = 0; \\$$1 < ${2:expression}; \\$$1++) {\n    ${3:# body...}\n}" "for (...) { ... }" nil nil nil nil nil)
 | ||
| 		       ("fore" "foreach my \\$${1:x} (@${2:array}) {\n    ${3:# body...}\n}" "foreach ... { ... }" nil nil nil nil nil)
 | ||
| 		       ("if" "if ($1) {\n    $0\n}" "if (...) { ... }" nil nil nil nil nil)
 | ||
| 		       ("ife" "if ($1) {\n    $2\n} else {\n    $3\n}" "if (...) { ... } else { ... }" nil nil nil nil nil)
 | ||
| 		       ("ifee" "if ($1) {\n	${2:# body...}\n} elsif ($3) {\n	${4:# elsif...}\n} else {\n	${5:# else...}\n}" "if, elsif, else ..." nil nil nil nil nil)
 | ||
| 		       ("sub" "sub ${1:function_name} {\n    $0\n}" "sub ... { ... }" nil nil nil nil nil)
 | ||
| 		       ("unless" "unless ($1) {\n    $0\n}" "unless (...) { ... }" nil nil nil nil nil)
 | ||
| 		       ("while" "while ($1) {\n    $0\n}" "while (...) { ... }" nil nil nil nil nil)
 | ||
| 		       ("xfore" "${1:expression} foreach @${2:array};" "... foreach ..." nil nil nil nil nil)
 | ||
| 		       ("xif" "${1:expression} if ${2:condition}" "... if ..." nil nil nil nil nil)
 | ||
| 		       ("xunless" "${1:expression} unless ${2:condition}" "... unless ..." nil nil nil nil nil)
 | ||
| 		       ("xwhile" "${1:expression} while ${2:condition};" "... while ..." nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for cperl-mode
 | ||
| (yas/define-snippets 'cperl-mode 'nil
 | ||
| 		     '(perl-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for python-mode
 | ||
| (yas/define-snippets 'python-mode
 | ||
| 		     '(("__" "__${init}__" "__...__" nil nil nil nil nil)
 | ||
| 		       ("class" "class ${1:ClassName}(${2:object}):\n    \"\"\"$3\n    \"\"\"\n\n    def __init__(self, $4):\n        \"\"\"$5\n        ${4:$\n        (let* ((indent\n                (concat \"\\n\" (make-string (current-column) 32)))\n               (args\n                (mapconcat\n                 '(lambda (x)\n                    (if (not (string= (nth 0 x) \"\"))\n                        (concat \"- \" (char-to-string 96) (nth 0 x)\n                                (char-to-string 96) \":\")))\n                 (mapcar\n                  '(lambda (x)\n                     (mapcar\n                      (lambda (x)\n                        (replace-regexp-in-string \"[[:blank:]]*$\" \"\"\n                         (replace-regexp-in-string \"^[[:blank:]]*\" \"\" x))) x))\n                  (mapcar '(lambda (x) (split-string x \"=\"))\n                          (split-string text \",\")))\n                 indent)))\n          (if (string= args \"\")\n              (make-string 3 34)\n            (mapconcat\n             'identity\n             (list \"\" \"Arguments:\" args (make-string 3 34))\n             indent)))\n        }\n        ${4:$\n        (mapconcat\n         '(lambda (x)\n            (if (not (string= (nth 0 x) \"\"))\n                (concat \"self._\" (nth 0 x) \" = \" (nth 0 x))))\n         (mapcar\n          '(lambda (x)\n             (mapcar\n              '(lambda (x)\n                 (replace-regexp-in-string \"[[:blank:]]*$\" \"\"\n                  (replace-regexp-in-string \"^[[:blank:]]*\" \"\" x)))\n              x))\n          (mapcar '(lambda (x) (split-string x \"=\"))\n                  (split-string text \",\")))\n         (concat \"\\n\" (make-string (current-column) 32)))\n        }\n        $0\n" "class" nil nil nil nil nil)
 | ||
| 		       ("def" "def ${1:name}($2):\n    \"\"\"$3\n    ${2:$\n      (let* \n        ((indent\n            (concat \"\\n\" (make-string (current-column) 32)))\n           (args\n            (mapconcat\n             '(lambda (x)\n                (if (not (string= (nth 0 x) \"\"))\n                    (concat \"- \" (char-to-string 96) (nth 0 x)\n                            (char-to-string 96) \":\")))\n             (mapcar\n              '(lambda (x)\n                 (mapcar\n                  '(lambda (x)\n                     (replace-regexp-in-string \"[[:blank:]]*$\" \"\"\n                      (replace-regexp-in-string \"^[[:blank:]]*\" \"\" x)))\n                  x))\n              (mapcar '(lambda (x) (split-string x \"=\"))\n                      (split-string text \",\")))\n             indent)))\n      (if (string= args \"\")\n          (make-string 3 34)\n        (mapconcat\n         'identity\n         (list \"\" \"Arguments:\" args (make-string 3 34))\n         indent)))\n    }\n    $0\n" "def" nil nil nil nil nil)
 | ||
| 		       ("defm" "def ${1:name}(self, $2):\n    \"\"\"$3\n    ${2:$\n    (let* ((indent\n            (concat \"\\n\" (make-string (current-column) 32)))\n           (args\n            (mapconcat\n             '(lambda (x)\n                (if (not (string= (nth 0 x) \"\"))\n                    (concat \"- \" (char-to-string 96) (nth 0 x)\n                            (char-to-string 96) \":\")))\n             (mapcar\n              '(lambda (x)\n                 (mapcar\n                  '(lambda (x)\n                     (replace-regexp-in-string \"[[:blank:]]*$\" \"\"\n                      (replace-regexp-in-string \"^[[:blank:]]*\" \"\" x)))\n                  x))\n              (mapcar '(lambda (x) (split-string x \"=\"))\n                      (split-string text \",\")))\n             indent)))\n      (if (string= args \"\")\n          (make-string 3 34)\n        (mapconcat\n         'identity\n         (list \"\" \"Arguments:\" args (make-string 3 34))\n         indent)))\n    }\n    $0\n" "defm" nil nil nil nil nil)
 | ||
| 		       ("for" "for ${var} in ${collection}:\n    $0" "for ... in ... : ..." nil nil nil nil nil)
 | ||
| 		       ("ifmain" "if __name__ == '__main__':\n    $0" "if __name__ == '__main__': ..." nil nil nil nil nil)
 | ||
| 		       ("prop" "def ${1:foo}():\n   doc = \"\"\"${2:Doc string}\"\"\"\n   def fget(self):\n       return self._$1\n   def fset(self, value):\n       self._$1 = value\n   def fdel(self):\n       del self._$1\n   return locals()\n$1 = property(**$1())\n\n$0\n" "prop" nil nil nil nil nil)
 | ||
| 		       ("propg" "def _get_${1:foo}(self):\n    return self._$1\n\n$1 = property(_get_$1)\n\n$0\n" "_get_foo ... foo=property(...)" nil nil nil nil nil)
 | ||
| 		       ("propsg" "def _set_${1:foo}(self, value):\n    self._$1 = value\n\ndef _get_$1(self):\n    return self._$1\n\n$1 = property(_get_$1, _set_$1)\n\n$0\n" "_get_foo ... _set_foo ... foo=property(...)" nil nil nil nil nil)
 | ||
| 		       ("while" "while ${condition}:\n    $0" "while ... : ..." nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for rst-mode
 | ||
| (yas/define-snippets 'rst-mode
 | ||
| 		     '(("chap" "${1:Chapter}\n${1:$(make-string (string-width text) ?\\=)}\n\n$0" "Chapter title" nil nil nil nil nil)
 | ||
| 		       ("sec" "${1:Section}\n${1:$(make-string (string-width text) ?\\-)}\n\n$0" "Section title" nil nil nil nil nil)
 | ||
| 		       ("tit" "${1:$(make-string (string-width text) ?\\=)}\n${1:Title}\n${1:$(make-string (string-width text) ?\\=)}\n\n$0" "Document title" nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for ruby-mode
 | ||
| (yas/define-snippets 'ruby-mode
 | ||
| 		     '(("#" "# => " "# =>" nil "general" nil nil nil)
 | ||
| 		       ("=b" "=begin rdoc\n  $0\n=end" "=begin rdoc ... =end" nil "general" nil nil nil)
 | ||
| 		       ("Comp" "include Comparable\n\ndef <=> other\n  $0\nend" "include Comparable; def <=> ... end" nil "definitions" nil nil nil)
 | ||
| 		       ("all" "all? { |${e}| $0 }" "all? { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("am" "alias_method :${new_name}, :${old_name}" "alias_method new, old" nil "definitions" nil nil nil)
 | ||
| 		       ("any" "any? { |${e}| $0 }" "any? { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("app" "if __FILE__ == $PROGRAM_NAME\n  $0\nend" "if __FILE__ == $PROGRAM_NAME ... end" nil "general" nil nil nil)
 | ||
| 		       ("bm" "Benchmark.bmbm(${1:10}) do |x|\n  $0\nend" "Benchmark.bmbm(...) do ... end" nil "general" nil nil nil)
 | ||
| 		       ("case" "case ${1:object}\nwhen ${2:condition}\n  $0\nend" "case ... end" nil "general" nil nil nil)
 | ||
| 		       ("cla" "class << ${self}\n  $0\nend" "class << self ... end" nil "definitions" nil nil nil)
 | ||
| 		       ("classify" "classify { |${e}| $0 }" "classify { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("cls" "class ${1:`(let ((fn (capitalize (file-name-nondirectory\n                                 (file-name-sans-extension\n				 (or (buffer-file-name)\n				     (buffer-name (current-buffer))))))))\n           (cond\n             ((string-match \"_\" fn) (replace-match \"\" nil nil fn))\n              (t fn)))`}\n  $0\nend\n" "class ... end" nil "definitions" nil nil nil)
 | ||
| 		       ("collect" "collect { |${e}| $0 }" "collect { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("dee" "Marshal.load(Marshal.dump($0))" "deep_copy(...)" nil "general" nil nil nil)
 | ||
| 		       ("deli" "delete_if { |${e} $0 }" "delete_if { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("det" "detect { |${e}| $0 }" "detect { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("dow" "downto(${0}) { |${n}|\n  $0\n}" "downto(...) { |n| ... }" nil "control structure" nil nil nil)
 | ||
| 		       ("ea" "each { |${e}| $0 }" "each { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("eac" "each_cons(${1:2}) { |${group}| $0 }" "each_cons(...) { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("eai" "each_index { |${i}| $0 }" "each_index { |i| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("eav" "each_value { |${val}| $0 }" "each_value { |val| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("eawi" "each_with_index { |${e}, ${i}| $0 }" "each_with_index { |e, i| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("forin" "for ${1:element} in ${2:collection}\n  $0\nend" "for ... in ...; ... end" nil "control structure" nil nil nil)
 | ||
| 		       ("if" "if ${1:condition}\n  $0\nend" "if ... end" nil "control structure" nil nil nil)
 | ||
| 		       ("ife" "if ${1:condition}\n  $2\nelse\n  $3\nend" "if ... else ... end" nil "control structure" nil nil nil)
 | ||
| 		       ("inject" "inject(${1:0}) { |${2:injection}, ${3:element}| $0 }" "inject(...) { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("mm" "def method_missing(method, *args)\n  $0\nend" "def method_missing ... end" nil "definitions" nil nil nil)
 | ||
| 		       ("r" "attr_reader :" "attr_reader ..." nil "definitions" nil nil nil)
 | ||
| 		       ("rb" "#!/usr/bin/ruby -wKU\n" "/usr/bin/ruby -wKU" nil "general" nil nil nil)
 | ||
| 		       ("reject" "reject { |${1:element}| $0 }" "reject { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("req" "require \"$0\"" "require \"...\"" nil "general" nil nil nil)
 | ||
| 		       ("rreq" "require File.join(File.dirname(__FILE__), $0)" "require File.join(File.dirname(__FILE__), ...)" nil "general" nil nil nil)
 | ||
| 		       ("rw" "attr_accessor :" "attr_accessor ..." nil "definitions" nil nil nil)
 | ||
| 		       ("select" "select { |${1:element}| $0 }" "select { |...| ... }" nil "collections" nil nil nil)
 | ||
| 		       ("tim" "times { |${n}| $0 }" "times { |n| ... }" nil "control structure" nil nil nil)
 | ||
| 		       ("until" "until ${condition}\n  $0\nend" "until ... end" nil "control structure" nil nil nil)
 | ||
| 		       ("upt" "upto(${n}) { |${i}|\n  $0\n}" "upto(...) { |n| ... }" nil "control structure" nil nil nil)
 | ||
| 		       ("w" "attr_writer :" "attr_writer ..." nil "definitions" nil nil nil)
 | ||
| 		       ("when" "when ${condition}\n  $0\nend" "when ... end" nil "control structure" nil nil nil)
 | ||
| 		       ("while" "while ${condition}\n  $0\nend" "while ... end" nil "control structure" nil nil nil)
 | ||
| 		       ("y" ":yields: $0" ":yields: arguments (rdoc)" nil "general" nil nil nil)
 | ||
| 		       ("zip" "zip(${enums}) { |${row}| $0 }" "zip(...) { |...| ... }" nil "collections" nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for scala-mode
 | ||
| (yas/define-snippets 'scala-mode
 | ||
| 		     '(("act" "def act = {\n  loop {\n    react {\n      $0\n    }\n  }\n}" "def act = { ..}" nil nil nil nil nil)
 | ||
| 		       ("act" "def act(${1:arg}: ${2:type}) = {\n  loop {\n    react {\n      $0\n    }\n  }\n}" "def act(arg: T) = { ..}" nil nil nil nil nil)
 | ||
| 		       ("actor" "val a = actor {\n  loop {\n    react {\n      $0\n    }\n  }\n}" "val a = actor { ..}" nil nil nil nil nil)
 | ||
| 		       ("ano" "($1) => ${2:body} $0" "(args) => ..." nil nil nil nil nil)
 | ||
| 		       ("app" "object ${1:name} extends Application {\n  $0\n}" "object name extends Application" nil nil nil nil nil)
 | ||
| 		       ("arr" "Array[${1:value}](${2:args}) $0" "Array[T](..)" nil nil nil nil nil)
 | ||
| 		       ("arr" "val ${1:arr} = Array[${2:value}](${3:args}) $0" "val a = Array[T](..)" nil nil nil nil nil)
 | ||
| 		       ("asof" "asInstanceOf[${1:type}] $0" "asInstanceOf[T] " nil nil nil nil nil)
 | ||
| 		       ("ass" "assert(${1:x} === ${2:y}) $0" "assert(x === y)" nil nil nil nil nil)
 | ||
| 		       ("ass" "assert(true) $0" "assert(true)" nil nil nil nil nil)
 | ||
| 		       ("at" "@author ${1:name} $0" "@author name" nil nil nil nil nil)
 | ||
| 		       ("at" "@param ${1:name} ${2:description} $0" "@param name description" nil nil nil nil nil)
 | ||
| 		       ("at" "@return ${1:description} $0" "@return description" nil nil nil nil nil)
 | ||
| 		       ("at" "@version ${1:0.1} $0" "@version number" nil nil nil nil nil)
 | ||
| 		       ("bang" "${1:actor} ! ${2:message} $0" "actor ! message" nil nil nil nil nil)
 | ||
| 		       ("case" "case ${1:pattern} => $0" "case pattern => " nil nil nil nil nil)
 | ||
| 		       ("case" "case _ => $0" "case _ => " nil nil nil nil nil)
 | ||
| 		       ("cast" "asInstanceOf[${1:type}] $0" "asInstanceOf[T] " nil nil nil nil nil)
 | ||
| 		       ("cc" "case class ${1:name}(${2:arg}: ${3:type}) $0" "case class T(arg: A)" nil nil nil nil nil)
 | ||
| 		       ("cl" "class ${1:name} {\n  $0\n}" "class T { .. }" nil nil nil nil nil)
 | ||
| 		       ("cl" "abstract class ${1:name} {\n  $0\n}" "abstract class T { .. }" nil nil nil nil nil)
 | ||
| 		       ("cl" "abstract class ${1:name}(${2:args}) {\n  $0\n}" "abstract class T(args) { .. }" nil nil nil nil nil)
 | ||
| 		       ("cl" "class ${1:name}(${2:args}) {\n  $0\n}" "class T(args) { .. }" nil nil nil nil nil)
 | ||
| 		       ("clof" "classOf[${1:type}] $0" "classOf[T] " nil nil nil nil nil)
 | ||
| 		       ("co" "case object ${1:name} $0" "case object T" nil nil nil nil nil)
 | ||
| 		       ("cons" "${1:element1} :: ${2:element2} $0" "element1 :: element2" nil nil nil nil nil)
 | ||
| 		       ("cons" "${1:element1} :: Nil $0\n" "element1 :: Nil" nil nil nil nil nil)
 | ||
| 		       ("def" "def ${1:name}(${2:args}) = $0" "def f(arg: T) = ..." nil nil nil nil nil)
 | ||
| 		       ("def" "def ${1:name}(${2:args}) = {\n  $0\n}" "def f(arg: T) = {...}" nil nil nil nil nil)
 | ||
| 		       ("def" "def ${1:name}(${2:args}): ${3:Unit} = $0" "def f(arg: T): R = ..." nil nil nil nil nil)
 | ||
| 		       ("def" "def ${1:name}(${2:args}): ${3:Unit} = {\n  $0\n}" "def f(arg: T): R = {...}" nil nil nil nil nil)
 | ||
| 		       ("def" "def ${1:name} = {\n  $0\n}" "def f = {...}" nil nil nil nil nil)
 | ||
| 		       ("def" "def ${1:name}: ${2:Unit} = $0" "def f: R = ..." nil nil nil nil nil)
 | ||
| 		       ("def" "def ${1:name}: ${3:Unit} = {\n  $0\n}" "def f: R = {...}" nil nil nil nil nil)
 | ||
| 		       ("def" "def ${1:name} = $0" "def f = ..." nil nil nil nil nil)
 | ||
| 		       ("doc" "/** \n * `(scala-mode-find-clstrtobj-name-doc)`\n * ${1:description}\n * $0  \n */" "/** cls/trt/obj name */" nil nil nil nil nil)
 | ||
| 		       ("doc" "/** \n * `(scala-mode-def-and-args-doc)`\n */ " "/** method name */" nil nil nil nil nil)
 | ||
| 		       ("doc" "/**\n * `(scala-mode-file-doc)`\n * $0\n * @author ${1:name}\n * @version ${2:0.1} \n */" "/** file name */" nil nil nil nil nil)
 | ||
| 		       ("doc" "/*                     __                                               *\\\n**     ________ ___   / /  ___     Scala $3                               **\n**    / __/ __// _ | / /  / _ |    (c) 2005-`(format-time-string \"%Y\")` , LAMP/EPFL             **\n**  __\\ \\/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **\n** /____/\\___/_/ |_/____/_/ | |                                         **\n**                          |/                                          **\n\\*                                                                      */\n/** \n * $0\n * @author ${1:name} \n * @version ${2:0.1}\n * $Id$\n */" "/** scala file */" nil nil nil nil nil)
 | ||
| 		       ("doc" "/*                     __                                               *\\\n**     ________ ___   / /  ___     Scala API                            **\n**    / __/ __// _ | / /  / _ |    (c) 2005-`(format-time-string \"%Y\")`, LAMP/EPFL             **\n**  __\\ \\/ /__/ __ |/ /__/ __ |    http://scala-lang.org/               **\n** /____/\\___/_/ |_/____/_/ | |                                         **\n**                          |/                                          **\n\\*                                                                      */\n/** \n * $0\n * @author ${1:name} \n * @version ${2:0.1}\n * $Id$\n */" "/** scala api file */" nil nil nil nil nil)
 | ||
| 		       ("doc" "/**\n * ${1:description}\n * $0\n */" "/** ... */" nil nil nil nil nil)
 | ||
| 		       ("expect" "expect(${1:reply}) {\n  $0\n}" "expect(value) { ..}" nil nil nil nil nil)
 | ||
| 		       ("ext" "extends $0" "extends T" nil nil nil nil nil)
 | ||
| 		       ("for" "${1:x} <- ${2:xs}" "x <- xs" nil nil nil nil nil)
 | ||
| 		       ("for" "for (${1:x} <- ${2:xs} if ${3:guard}) {\n  $0\n}" "for (x <- xs if guard) { ... }" nil nil nil nil nil)
 | ||
| 		       ("for" "for (${1:x} <- ${2:xs}) {\n  $0\n}" "for (x <- xs) { ... }" nil nil nil nil nil)
 | ||
| 		       ("for" "for {\n  ${1:x} <- ${2:xs}\n  ${3:x} <- ${4:xs}\n} {\n  yield $0\n}" "for {x <- xs \\ y <- ys} { yield }" nil nil nil nil nil)
 | ||
| 		       ("foreach" "foreach(${1:x} => ${2:body}) $0" "foreach(x => ..)" nil nil nil nil nil)
 | ||
| 		       ("hmap" "new HashMap[${1:key}, ${2:value}] $0" "new HashMap[K, V]" nil nil nil nil nil)
 | ||
| 		       ("hmap" "val ${1:m} = new HashMap[${2:key}, ${3:value}] $0" "val m = new HashMap[K, V]" nil nil nil nil nil)
 | ||
| 		       ("hset" "new HashSet[${1:key}] $0\n" "new HashSet[K]" nil nil nil nil nil)
 | ||
| 		       ("hset" "val ${1:m} = new HashSet[${2:key}] $0" "val m = new HashSet[K]" nil nil nil nil nil)
 | ||
| 		       ("if" "if (${1:condition}) {\n  $0\n}" "if (cond) { .. }" nil nil nil nil nil)
 | ||
| 		       ("if" "if (${1:condition}) {\n  $2\n} else {\n  $0\n}" "if (cond) { .. } else { .. }" nil nil nil nil nil)
 | ||
| 		       ("imp" "import $0" "import .." nil nil nil nil nil)
 | ||
| 		       ("intercept" "intercept(classOf[${1:Exception]}) {\n  $0\n}" "intercept(classOf[T]) { ..}" nil nil nil nil nil)
 | ||
| 		       ("isof" "isInstanceOf[${1:type}] $0" "isInstanceOf[T] " nil nil nil nil nil)
 | ||
| 		       ("ls" "List(${1:args}, ${2:args}) $0" "List(..)" nil nil nil nil nil)
 | ||
| 		       ("ls" "val ${1:l} = List(${2:args}, ${3:args}) $0" "val l = List(..)" nil nil nil nil nil)
 | ||
| 		       ("main" "def main(args: Array[String]) = {\n  $0\n}" "def main(args: Array[String]) = { ... }" nil nil nil nil nil)
 | ||
| 		       ("map" "map(${1:x} => ${2:body}) $0" "map(x => ..)" nil nil nil nil nil)
 | ||
| 		       ("map" "Map(${1:key} -> ${2:value}) $0" "Map(key -> value)" nil nil nil nil nil)
 | ||
| 		       ("match" "${1:cc} match {\n  case ${2:pattern} => $0\n}" "cc match { .. }" nil nil nil nil nil)
 | ||
| 		       ("match" "${1:option} match {\n  case Full(res) => $0\n\n  case Empty => \n\n  case Failure(msg, _, _) => \n\n}" "can match { case Full(res) => .. }" nil nil nil nil nil)
 | ||
| 		       ("match" "${1:option} match {\n  case None => $0\n  case Some(res) => \n\n}" "option match { case None => .. }" nil nil nil nil nil)
 | ||
| 		       ("mix" "trait ${1:name} {\n  $0\n}" "trait T { .. }" nil nil nil nil nil)
 | ||
| 		       ("ob" "object ${1:name} extends ${2:type} $0" "object name extends T" nil nil nil nil nil)
 | ||
| 		       ("pac" "package $0" "package .." nil nil nil nil nil)
 | ||
| 		       ("pr" "println(${1:obj}) $0" "println(..)" nil nil nil nil nil)
 | ||
| 		       ("pr" "print(${1:obj}) $0" "print(..)" nil nil nil nil nil)
 | ||
| 		       ("pr" "println(\"${1:msg}\") $0" "println(\"..\")" nil nil nil nil nil)
 | ||
| 		       ("pr" "println(\"${1:obj}: \" + ${1:obj}) $0" "println(\"obj: \" + obj)" nil nil nil nil nil)
 | ||
| 		       ("pri" "private $0" "private" nil nil nil nil nil)
 | ||
| 		       ("pri" "private[${1:this}] $0" "private[this]" nil nil nil nil nil)
 | ||
| 		       ("pro" "protected $0" "protected" nil nil nil nil nil)
 | ||
| 		       ("pro" "protected[${1:this}] $0" "protected[this]" nil nil nil nil nil)
 | ||
| 		       ("suite" "import org.scalatest._\n\nclass ${1:name} extends Suite {\n  $0\n}" "class T extends Suite { .. }" nil nil nil nil nil)
 | ||
| 		       ("test" "//@Test\ndef test${1:name} = {\n  $0\n}" "@Test def testX = ..." nil nil nil nil nil)
 | ||
| 		       ("throw" "throw new ${1:Exception}(${2:msg}) $0" "throw new Exception" nil nil nil nil nil)
 | ||
| 		       ("tr" "trait ${1:name} {\n  $0\n}" "trait T { .. }" nil nil nil nil nil)
 | ||
| 		       ("tr" "trait ${1:name} extends ${2:class} {\n  $0\n}" "trait T extends C { .. }" nil nil nil nil nil)
 | ||
| 		       ("tr" "trait ${1:name} extends ${2:class} with ${3:trait} {\n  $0\n}" "trait T1 extends C with T2 { .. }" nil nil nil nil nil)
 | ||
| 		       ("tr" "trait ${1:name} with ${2:trait} {\n  $0\n}" "trait T1 with T2 { .. }" nil nil nil nil nil)
 | ||
| 		       ("try" "try {\n  $0\n} catch {\n  case ${1:e}: ${2:Exception} => \n    ${1:println(\\\"ERROR: \\\" + e) // TODO: handle exception}\\n}\n}" "try { .. } catch { case e => ..}" nil nil nil nil nil)
 | ||
| 		       ("try" "try {\n  $0\n} catch {\n  case ${1:e}: ${2:Exception} => \n    ${1:println(\\\"ERROR: \\\" + e) // TODO: handle exception}\\n}\n} finally {\n\n}" "try { .. } catch { case e => ..} finally { ..}" nil nil nil nil nil)
 | ||
| 		       ("try" "try {\n\n} finally {\n  $0\n}" "try { .. } finally { .. }" nil nil nil nil nil)
 | ||
| 		       ("tup" "${1:element1} -> ${2:element2} $0" "element1 -> element2" nil nil nil nil nil)
 | ||
| 		       ("tup" "(${1:element1}, ${2:element2}) $0" "(element1, element2)" nil nil nil nil nil)
 | ||
| 		       ("val" "val ${1:name} = ${2:obj} $0" "val name = .." nil nil nil nil nil)
 | ||
| 		       ("val" "val ${1:name} = new ${2:obj} $0" "val name = new .." nil nil nil nil nil)
 | ||
| 		       ("val" "val ${1:name}: ${2:T} = ${3:obj} $0\n" "val name: T = .." nil nil nil nil nil)
 | ||
| 		       ("var" "var ${1:name} = ${2:obj} $0\n" "var name = .." nil nil nil nil nil)
 | ||
| 		       ("var" "var ${1:name} = new ${2:obj} $0\n" "var name = new .." nil nil nil nil nil)
 | ||
| 		       ("var" "var ${1:name}: ${2:T} = ${3:obj} $0\n" "var name: T = .." nil nil nil nil nil)
 | ||
| 		       ("whi" "while (${1:condition}) {\n  $0\n}" "while(cond) { .. }" nil nil nil nil nil)
 | ||
| 		       ("with" "with $0" "with T" nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for snippet-mode
 | ||
| (yas/define-snippets 'snippet-mode
 | ||
| 		     '(("$f" "\\${${1:${2:n}:}$3${4:\\$(${5:lisp-fn})}\\}$0" "${ ...  } field" nil nil nil nil nil)
 | ||
| 		       ("$m" "\\${${2:n}:${4:\\$(${5:reflection-fn})}\\}$0" "${n:$(...)} mirror" nil nil nil nil nil)
 | ||
| 		       ("vars" "# name : $1${2:\n# key : ${3:expand-key}}${4:\n# group : ${5:group}} \n# contributor : $6\n# --\n$0" "Snippet header" nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| ;;; snippets for sql-mode
 | ||
| (yas/define-snippets 'sql-mode
 | ||
| 		     '(("column" "	,	${1:Name}		${2:Type}			${3:NOT NULL}\n" ", ColumnName ColumnType NOT NULL..." nil nil nil nil nil)
 | ||
| 		       ("constraint" "CONSTRAINT [${1:PK_Name}] PRIMARY KEY ${2:CLUSTERED} ([${3:ColumnName}]) \n" "CONSTRAINT [..] PRIMARY KEY ..." nil nil nil nil nil)
 | ||
| 		       ("constraint" "CONSTRAINT [${1:FK_Name}] FOREIGN KEY ${2:CLUSTERED} ([${3:ColumnName}]) \n" "CONSTRAINT [..] FOREIGN KEY ..." nil nil nil nil nil)
 | ||
| 		       ("create" "CREATE TABLE [${1:dbo}].[${2:TableName}] \n(\n		${3:Id}		${4:INT IDENTITY(1,1)}		${5:NOT NULL}\n$0\n	CONSTRAINT [${6:PK_}] PRIMARY KEY ${7:CLUSTERED} ([$3]) \n)\nGO\n" "create table ..." nil nil nil nil nil)
 | ||
| 		       ("create" "CREATE PROCEDURE [${1:dbo}].[${2:Name}] \n(\n		$3		$4		= ${5:NULL}		${6:OUTPUT}\n)\nAS\nBEGIN\n$0\nEND\nGO\n" "create procedure ..." nil nil nil nil nil)
 | ||
| 		       ("references" "REFERENCES ${1:TableName}([${2:ColumnName}])\n" "REFERENCES ..." nil nil nil nil nil))
 | ||
| 		     '(text-mode))
 | ||
| 
 | ||
| 
 | ||
| (yas/global-mode 1)
 | ||
| )
 | ||
| 
 | ||
| (yas/initialize-bundle)
 | ||
| ;;;###autoload(require 'yasnippet-bundle)
 | ||
| (set-default 'yas/dont-activate
 | ||
| 	     #'(lambda nil
 | ||
| 		 (and
 | ||
| 		  (or yas/root-directory
 | ||
| 		      (featurep 'yasnippet-bundle))
 | ||
| 		  (null
 | ||
| 		   (yas/get-snippet-tables)))))
 | ||
| (provide 'yasnippet-bundle)
 | ||
| ;;; yasnippet-bundle.el ends here
 |