PageRenderTime 57ms CodeModel.GetById 29ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/yasnippet/yasnippet.el

http://github.com/rejeep/emacs
Emacs Lisp | 3676 lines | 2704 code | 437 blank | 535 comment | 79 complexity | b772cd5ccc2eb9cb7294e279dfa92b89 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

   1;;; Yasnippet.el --- Yet another snippet extension for Emacs.
   2
   3;; Copyright 2008 pluskid
   4;;           2009 pluskid, joaotavora
   5
   6;; Authors: pluskid <pluskid@gmail.com>, joaotavora <joaotavora@gmail.com>
   7;; Version: 0.6.1
   8;; Package-version: 0.6.1c
   9;; X-URL: http://code.google.com/p/yasnippet/
  10;; Keywords: convenience, emulation
  11;; URL: http://code.google.com/p/yasnippet/
  12;; EmacsWiki: YaSnippetMode
  13
  14;; This file is free software; you can redistribute it and/or modify
  15;; it under the terms of the GNU General Public License as published by
  16;; the Free Software Foundation; either version 2, or (at your option)
  17;; any later version.
  18
  19;; This file is distributed in the hope that it will be useful,
  20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22;; GNU General Public License for more details.
  23
  24;; You should have received a copy of the GNU General Public License
  25;; along with GNU Emacs; see the file COPYING.  If not, write to
  26;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  27;; Boston, MA 02111-1307, USA.
  28
  29;;; Commentary:
  30
  31;; Basic steps to setup:
  32;;
  33;;   1. In your .emacs file:
  34;;        (add-to-list 'load-path "/dir/to/yasnippet.el")
  35;;        (require 'yasnippet)
  36;;   2. Place the `snippets' directory somewhere.  E.g: ~/.emacs.d/snippets
  37;;   3. In your .emacs file
  38;;        (setq yas/root-directory "~/.emacs/snippets")
  39;;        (yas/load-directory yas/root-directory)
  40;;   4. To enable the YASnippet menu and tab-trigger expansion
  41;;        M-x yas/minor-mode
  42;;   5. To globally enable the minor mode in *all* buffers
  43;;        M-x yas/global-mode
  44;;
  45;;   Steps 4. and 5. are optional, you don't have to use the minor
  46;;   mode to use YASnippet.
  47;;
  48;;   Interesting variables are:
  49;;
  50;;       `yas/root-directory'
  51;;
  52;;           The directory where user-created snippets are to be
  53;;           stored. Can also be a list of directories that
  54;;           `yas/reload-all' will use for bulk-reloading snippets. In
  55;;           that case the first directory the default for storing new
  56;;           snippets.
  57;;
  58;;       `yas/mode-symbol'
  59;;
  60;;           A local variable that you can set in a hook to override
  61;;           snippet-lookup based on major mode. It is a a symbol (or
  62;;           list of symbols) that correspond to subdirectories of
  63;;           `yas/root-directory' and is used for deciding which
  64;;           snippets to consider for the active buffer.
  65;;
  66;;   Major commands are:
  67;;
  68;;       M-x yas/expand
  69;;
  70;;           Try to expand snippets before point.  In `yas/minor-mode',
  71;;           this is bound to `yas/trigger-key' which you can customize.
  72;;
  73;;       M-x yas/load-directory
  74;;
  75;;           Prompts you for a directory hierarchy of snippets to load.
  76;;
  77;;       M-x yas/insert-snippet
  78;;
  79;;           Prompts you for possible snippet expansion if that is
  80;;           possible according to buffer-local and snippet-local
  81;;           expansion conditions.  With prefix argument, ignore these
  82;;           conditions.
  83;;
  84;;       M-x yas/find-snippets
  85;;
  86;;           Lets you find the snippet files in the correct
  87;;           subdirectory of `yas/root-directory', according to the
  88;;           active major mode (if it exists) like
  89;;           `find-file-other-window'.
  90;;
  91;;       M-x yas/visit-snippet-file
  92;;
  93;;           Prompts you for possible snippet expansions like
  94;;           `yas/insert-snippet', but instead of expanding it, takes
  95;;           you directly to the snippet definition's file, if it
  96;;           exists.
  97;;
  98;;       M-x yas/new-snippet
  99;;
 100;;           Lets you create a new snippet file in the correct
 101;;           subdirectory of `yas/root-directory', according to the
 102;;           active major mode.
 103;;
 104;;       M-x yas/load-snippet-buffer
 105;;
 106;;           When editing a snippet, this loads the snippet.  This is
 107;;           bound to "C-c C-c" while in the `snippet-mode' editing
 108;;           mode.
 109;;
 110;;       M-x yas/tryout-snippet
 111;;
 112;;           When editing a snippet, this opens a new empty buffer,
 113;;           sets it to the appropriate major mode and inserts the
 114;;           snippet there, so you can see what it looks like.  This is
 115;;           bound to "C-c C-t" while in `snippet-mode'.
 116;;
 117;;   The `dropdown-list.el' extension is bundled with YASnippet, you
 118;;   can optionally use it the preferred "prompting method", puting in
 119;;   your .emacs file, for example:
 120;;
 121;;       (require 'dropdown-list)
 122;;       (setq yas/prompt-functions '(yas/dropdown-prompt
 123;;                                    yas/ido-prompt
 124;;                                    yas/completing-prompt))
 125;;
 126;;   Also check out the customization group
 127;;
 128;;        M-x customize-group RET yasnippet RET
 129;;
 130;;   If you use the customization group to set variables
 131;;   `yas/root-directory' or `yas/global-mode', make sure the path to
 132;;   "yasnippet.el" is present in the `load-path' *before* the
 133;;   `custom-set-variables' is executed in your .emacs file.
 134;;
 135;;   For more information and detailed usage, refer to the project page:
 136;;      http://code.google.com/p/yasnippet/
 137
 138;;; Code:
 139
 140(require 'cl)
 141(require 'assoc)
 142(require 'easymenu)
 143
 144
 145;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 146;; User customizable variables
 147
 148
 149(defgroup yasnippet nil
 150  "Yet Another Snippet extension"
 151  :group 'editing)
 152
 153;;;###autoload
 154(defcustom yas/root-directory nil
 155  "Root directory that stores the snippets for each major mode.
 156
 157If you set this from your .emacs, can also be a list of strings,
 158for multiple root directories. If you make this a list, the first
 159element is always the user-created snippets directory. Other
 160directories are used for bulk reloading of all snippets using
 161`yas/reload-all'"
 162  :type '(choice (string :tag "Single directory (string)")
 163                 (repeat :args (string) :tag "List of directories (strings)"))
 164  :group 'yasnippet
 165  :require 'yasnippet
 166  :set #'(lambda (symbol new)
 167           (let ((old (and (boundp symbol)
 168                           (symbol-value symbol))))
 169             (set-default symbol new)
 170             (unless (or (not (fboundp 'yas/reload-all))
 171                         (equal old new))
 172               (yas/reload-all)))))
 173
 174(defcustom yas/prompt-functions '(yas/x-prompt
 175                                  yas/dropdown-prompt
 176                                  yas/completing-prompt
 177                                  yas/ido-prompt
 178                                  yas/no-prompt)
 179  "Functions to prompt for keys, templates, etc interactively.
 180
 181These functions are called with the following arguments:
 182
 183- PROMPT: A string to prompt the user
 184
 185- CHOICES: a list of strings or objects.
 186
 187- optional DISPLAY-FN : A function that, when applied to each of
 188the objects in CHOICES will return a string.
 189
 190The return value of any function you put here should be one of
 191the objects in CHOICES, properly formatted with DISPLAY-FN (if
 192that is passed).
 193
 194- To signal that your particular style of prompting is
 195unavailable at the moment, you can also have the function return
 196nil.
 197
 198- To signal that the user quit the prompting process, you can
 199signal `quit' with
 200
 201  (signal 'quit \"user quit!\")."
 202  :type '(repeat function)
 203  :group 'yasnippet)
 204
 205(defcustom yas/indent-line 'auto
 206  "Controls indenting applied to a recent snippet expansion.
 207
 208The following values are possible:
 209
 210- `fixed' Indent the snippet to the current column;
 211
 212- `auto' Indent each line of the snippet with `indent-according-to-mode'
 213
 214Every other value means don't apply any snippet-side indendation
 215after expansion (the manual per-line \"$>\" indentation still
 216applies)."
 217  :type '(choice (const :tag "Nothing"  nothing)
 218                 (const :tag "Fixed"    fixed)
 219                 (const :tag "Auto"     auto))
 220  :group 'yasnippet)
 221
 222(defcustom yas/also-auto-indent-first-line nil
 223  "Non-nil means also auto indent first line according to mode.
 224
 225Naturally this is only valid when `yas/indent-line' is `auto'"
 226  :type 'boolean
 227  :group 'yasnippet)
 228
 229(defcustom yas/snippet-revival t
 230  "Non-nil means re-activate snippet fields after undo/redo."
 231  :type 'boolean
 232  :group 'yasnippet)
 233
 234(defcustom yas/trigger-key "TAB"
 235  "The key bound to `yas/expand' when function `yas/minor-mode' is active.
 236
 237Value is a string that is converted to the internal Emacs key
 238representation using `read-kbd-macro'."
 239  :type 'string
 240  :group 'yasnippet
 241  :set #'(lambda (symbol key)
 242           (let ((old (and (boundp symbol)
 243                           (symbol-value symbol))))
 244             (set-default symbol key)
 245             ;; On very first loading of this defcustom,
 246             ;; `yas/trigger-key' is *not* loaded.
 247             (if (fboundp 'yas/trigger-key-reload)
 248                 (yas/trigger-key-reload old)))))
 249  
 250(defcustom yas/next-field-key '("TAB" "<tab>")
 251  "The key to navigate to next field when a snippet is active.
 252
 253Value is a string that is converted to the internal Emacs key
 254representation using `read-kbd-macro'.
 255
 256Can also be a list of strings."
 257  :type '(choice (string :tag "String")
 258                 (repeat :args (string) :tag "List of strings"))
 259  :group 'yasnippet
 260  :set #'(lambda (symbol val)
 261           (set-default symbol val)
 262           (if (fboundp 'yas/init-yas-in-snippet-keymap)
 263               (yas/init-yas-in-snippet-keymap))))
 264           
 265
 266(defcustom yas/prev-field-key '("<backtab>" "<S-tab>")
 267  "The key to navigate to previous field when a snippet is active.
 268
 269Value is a string that is converted to the internal Emacs key
 270representation using `read-kbd-macro'.
 271
 272Can also be a list of strings."
 273  :type '(choice (string :tag "String")
 274                 (repeat :args (string) :tag "List of strings"))
 275  :group 'yasnippet
 276  :set #'(lambda (symbol val)
 277           (set-default symbol val)
 278           (if (fboundp 'yas/init-yas-in-snippet-keymap)
 279               (yas/init-yas-in-snippet-keymap))))
 280
 281(defcustom yas/skip-and-clear-key "C-d"
 282  "The key to clear the currently active field.
 283
 284Value is a string that is converted to the internal Emacs key
 285representation using `read-kbd-macro'.
 286
 287Can also be a list of strings."
 288  :type '(choice (string :tag "String")
 289                 (repeat :args (string) :tag "List of strings"))
 290  :group 'yasnippet
 291  :set #'(lambda (symbol val)
 292           (set-default symbol val)
 293           (if (fboundp 'yas/init-yas-in-snippet-keymap)
 294               (yas/init-yas-in-snippet-keymap))))
 295
 296(defcustom yas/triggers-in-field nil
 297  "If non-nil, `yas/next-field-key' can trigger stacked expansions.
 298
 299Otherwise, `yas/next-field-key' just tries to move on to the next
 300field"
 301  :type 'boolean
 302  :group 'yasnippet)
 303
 304(defcustom yas/fallback-behavior 'call-other-command
 305  "How to act when `yas/trigger-key' does *not* expand a snippet.
 306
 307- `call-other-command' means try to temporarily disable YASnippet
 308    and call the next command bound to `yas/trigger-key'.
 309
 310- nil or the symbol `return-nil' mean do nothing. (and
 311  `yas/expand-returns' nil)
 312
 313- A lisp form (apply COMMAND . ARGS) means interactively call
 314  COMMAND, if ARGS is non-nil, call COMMAND non-interactively
 315  with ARGS as arguments."
 316  :type '(choice (const :tag "Call previous command"  call-other-command)
 317                 (const :tag "Do nothing"             return-nil))
 318  :group 'yasnippet)
 319(make-variable-buffer-local 'yas/fallback-behavior)
 320
 321(defcustom yas/choose-keys-first nil
 322  "If non-nil, prompt for snippet key first, then for template.
 323
 324Otherwise prompts for all possible snippet names.
 325
 326This affects `yas/insert-snippet' and `yas/visit-snippet-file'."
 327  :type 'boolean
 328  :group 'yasnippet)
 329
 330(defcustom yas/choose-tables-first nil
 331  "If non-nil, and multiple eligible snippet tables, prompts user for tables first.
 332
 333Otherwise, user chooses between the merging together of all
 334eligible tables.
 335
 336This affects `yas/insert-snippet', `yas/visit-snippet-file'"
 337  :type 'boolean
 338  :group 'yasnippet)
 339
 340(defcustom yas/use-menu 'real-modes
 341  "Display a YASnippet menu in the menu bar.
 342
 343When non-nil, submenus for each snippet table will be listed
 344under the menu \"Yasnippet\".
 345
 346- If set to `real-modes' only submenus whose name more or less
 347corresponds to a major mode are listed.
 348
 349- If set to `abbreviate', only the current major-mode
 350menu and the modes set in `yas/mode-symbol' are listed.
 351
 352Any other non-nil value, every submenu is listed."
 353  :type '(choice (const :tag "Full"  t)
 354                 (const :tag "Real modes only" real-modes)
 355                 (const :tag "Abbreviate" abbreviate))
 356  :group 'yasnippet)
 357
 358(defcustom yas/trigger-symbol " =>"
 359  "The text that will be used in menu to represent the trigger."
 360  :type 'string
 361  :group 'yasnippet)
 362
 363(defcustom yas/wrap-around-region nil
 364  "If non-nil, snippet expansion wraps around selected region.
 365
 366The wrapping occurs just before the snippet's exit marker.  This
 367can be overriden on a per-snippet basis."
 368  :type 'boolean
 369  :group 'yasnippet)
 370
 371(defcustom yas/good-grace t
 372  "If non-nil, don't raise errors in inline elisp evaluation.
 373
 374An error string \"[yas] error\" is returned instead."
 375  :type 'boolean
 376  :group 'yasnippet)
 377
 378(defcustom yas/ignore-filenames-as-triggers nil
 379  "If non-nil, don't derive tab triggers from filenames.
 380
 381This means a snippet without a \"# key:'\ directive wont have a
 382tab trigger."
 383  :type 'boolean
 384  :group 'yasnippet)
 385
 386(defcustom yas/visit-from-menu nil
 387  "If non-nil visit snippets's files from menu, instead of expanding them.
 388
 389This cafn only work when snippets are loaded from files."
 390  :type 'boolean
 391  :group 'yasnippet)
 392
 393(defface yas/field-highlight-face
 394  '((((class color) (background light)) (:background "DarkSeaGreen1"))
 395    (t (:background "DimGrey")))
 396  "The face used to highlight the currently active field of a snippet"
 397  :group 'yasnippet)
 398
 399(defface yas/field-debug-face
 400  '()
 401  "The face used for debugging some overlays normally hidden"
 402  :group 'yasnippet)
 403
 404
 405;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 406;; User can also customize the next defvars
 407(defun yas/define-some-keys (keys keymap definition)
 408  "Bind KEYS to DEFINITION in KEYMAP, read with `read-kbd-macro'."
 409  (let ((keys (or (and (listp keys) keys)
 410                  (list keys))))
 411    (dolist (key keys)
 412      (define-key keymap (read-kbd-macro key) definition))))
 413
 414(defvar yas/keymap
 415  (let ((map (make-sparse-keymap)))
 416    (mapc #'(lambda (binding)
 417              (yas/define-some-keys (car binding) map (cdr binding)))
 418          `((,yas/next-field-key     . yas/next-field-or-maybe-expand)
 419            (,yas/prev-field-key     . yas/prev-field)
 420            ("C-g"                   . yas/abort-snippet)
 421            (,yas/skip-and-clear-key . yas/skip-and-clear-or-delete-char)))
 422    map)
 423  "The keymap active while a snippet expansion is in progress.")
 424
 425(defvar yas/key-syntaxes (list "w" "w_" "w_." "^ ")
 426  "A list of syntax of a key. This list is tried in the order
 427to try to find a key. For example, if the list is '(\"w\" \"w_\").
 428And in emacs-lisp-mode, where \"-\" has the syntax of \"_\":
 429
 430foo-bar
 431
 432will first try \"bar\", if not found, then \"foo-bar\" is tried.")
 433
 434(defvar yas/after-exit-snippet-hook
 435  '()
 436  "Hooks to run after a snippet exited.
 437
 438The hooks will be run in an environment where some variables bound to
 439proper values:
 440
 441`yas/snippet-beg' : The beginning of the region of the snippet.
 442
 443`yas/snippet-end' : Similar to beg.
 444
 445Attention: These hooks are not run when exiting nested/stackd snippet expansion!")
 446
 447(defvar yas/before-expand-snippet-hook
 448  '()
 449  "Hooks to run just before expanding a snippet.")
 450
 451(defvar yas/buffer-local-condition
 452  '(if (and (not (bobp))
 453            (or (equal 'font-lock-comment-face
 454                       (get-char-property (1- (point))
 455                                          'face))
 456                (equal 'font-lock-string-face
 457                       (get-char-property (1- (point))
 458                                          'face))))
 459       '(require-snippet-condition . force-in-comment)
 460     t)
 461  "Snippet expanding condition.
 462
 463This variable is a lisp form:
 464
 465    * If it evaluates to nil, no snippets can be expanded.
 466
 467    * If it evaluates to the a cons (require-snippet-condition
 468      . REQUIREMENT)
 469
 470       * Snippets bearing no \"# condition:\" directive are not
 471         considered
 472
 473       * Snippets bearing conditions that evaluate to nil (or
 474         produce an error) won't be onsidered.
 475
 476       * If the snippet has a condition that evaluates to non-nil
 477         RESULT:
 478
 479          * If REQUIREMENT is t, the snippet is considered
 480
 481          * If REQUIREMENT is `eq' RESULT, the snippet is
 482            considered
 483
 484          * Otherwise, the snippet is not considered.
 485
 486    * If it evaluates to the symbol 'always, all snippets are
 487      considered for expansion, regardless of any conditions.
 488
 489    * If it evaluates to t or some other non-nil value
 490
 491       * Snippet bearing no conditions, or conditions that
 492         evaluate to non-nil, are considered for expansion. 
 493
 494       * Otherwise, the snippet is not considered.
 495
 496Here's an example preventing snippets from being expanded from
 497inside comments, in `python-mode' only, with the exception of
 498snippets returning the symbol 'force-in-comment in their
 499conditions.
 500
 501 (add-hook 'python-mode-hook
 502           '(lambda ()
 503              (setq yas/buffer-local-condition
 504                    '(if (python-in-string/comment)
 505                         '(require-snippet-condition . force-in-comment)
 506                       t))))
 507
 508The default value is similar, it filters out potential snippet
 509expansions inside comments and string literals, unless the
 510snippet itself contains a condition that returns the symbol
 511`force-in-comment'.")
 512(make-variable-buffer-local 'yas/buffer-local-condition)
 513
 514
 515;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 516;; Internal variables
 517
 518(defvar yas/version "0.6.1b")
 519
 520(defvar yas/menu-table (make-hash-table)
 521  "A hash table of MAJOR-MODE symbols to menu keymaps.")
 522
 523(defvar yas/active-keybindings nil
 524  "A list of cons (KEYMAP . KEY) setup from defining snippets.")
 525
 526(defvar yas/known-modes
 527  '(ruby-mode rst-mode markdown-mode)
 528  "A list of mode which is well known but not part of emacs.")
 529
 530(defvar yas/escaped-characters
 531  '(?\\ ?` ?' ?$ ?} )
 532  "List of characters which *might* need to be escaped.")
 533
 534(defconst yas/field-regexp
 535  "${\\([0-9]+:\\)?\\([^}]*\\)}"
 536  "A regexp to *almost* recognize a field.")
 537
 538(defconst yas/multi-dollar-lisp-expression-regexp
 539  "$+[ \t\n]*\\(([^)]*)\\)"
 540  "A regexp to *almost* recognize a \"$(...)\" expression.")
 541
 542(defconst yas/backquote-lisp-expression-regexp
 543  "`\\([^`]*\\)`"
 544  "A regexp to recognize a \"`lisp-expression`\" expression." )
 545
 546(defconst yas/transform-mirror-regexp
 547  "${\\(?:\\([0-9]+\\):\\)?$\\([ \t\n]*([^}]*\\)"
 548  "A regexp to *almost* recognize a mirror with a transform.")
 549
 550(defconst yas/simple-mirror-regexp
 551  "$\\([0-9]+\\)"
 552  "A regexp to recognize a simple mirror.")
 553
 554(defvar yas/snippet-id-seed 0
 555  "Contains the next id for a snippet.")
 556
 557(defun yas/snippet-next-id ()
 558  (let ((id yas/snippet-id-seed))
 559    (incf yas/snippet-id-seed)
 560    id))
 561
 562
 563;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 564;; Minor mode stuff
 565
 566;; XXX: `last-buffer-undo-list' is somehow needed in Carbon Emacs for MacOSX
 567(defvar last-buffer-undo-list nil)
 568
 569(defvar yas/minor-mode-menu nil
 570  "Holds the YASnippet menu")
 571
 572(defun yas/init-minor-keymap ()
 573  (let ((map (make-sparse-keymap)))
 574    (easy-menu-define yas/minor-mode-menu
 575      map
 576      "Menu used when YAS/minor-mode is active."
 577      '("YASnippet"
 578        "----"
 579        ["Expand trigger" yas/expand
 580         :help "Possibly expand tab trigger before point"]
 581        ["Insert at point..." yas/insert-snippet
 582         :help "Prompt for an expandable snippet and expand it at point"]
 583        ["New snippet..." yas/new-snippet
 584         :help "Create a new snippet in an appropriate directory"]
 585        ["Visit snippet file..." yas/visit-snippet-file
 586         :help "Prompt for an expandable snippet and find its file"]
 587        ["Find snippets..." yas/find-snippets
 588         :help "Invoke `find-file' in the appropriate snippet directory"] 
 589        "----"
 590        ("Snippet menu behaviour"
 591         ["Visit snippets" (setq yas/visit-from-menu t)
 592          :help "Visit snippets from the menu"
 593          :active t :style radio   :selected yas/visit-from-menu]
 594         ["Expand snippets" (setq yas/visit-from-menu nil)
 595          :help "Expand snippets from the menu"
 596          :active t :style radio :selected (not yas/visit-from-menu)]
 597         "----"
 598         ["Show \"Real\" modes only" (setq yas/use-menu 'real-modes)
 599          :help "Show snippet submenus for modes that appear to be real major modes"
 600          :active t :style radio   :selected (eq yas/use-menu 'real-modes)]
 601         ["Show all modes" (setq yas/use-menu 't)
 602          :help "Show one snippet submenu for each loaded table"
 603          :active t :style radio   :selected (eq yas/use-menu 't)]
 604         ["Abbreviate according to current mode" (setq yas/use-menu 'abbreviate)
 605          :help "Show only snippet submenus for the current active modes"
 606          :active t :style radio   :selected (eq yas/use-menu 'abbreviate)])
 607        ("Indenting"
 608         ["Auto" (setq yas/indent-line 'auto)
 609          :help "Indent each line of the snippet with `indent-according-to-mode'"
 610          :active t :style radio   :selected (eq yas/indent-line 'auto)]
 611         ["Fixed" (setq yas/indent-line 'fixed)
 612          :help "Indent the snippet to the current column"
 613          :active t :style radio   :selected (eq yas/indent-line 'fixed)]
 614         ["None" (setq yas/indent-line 'none)
 615          :help "Don't apply any particular snippet indentation after expansion"
 616          :active t :style radio   :selected (not (member yas/indent-line '(fixed auto)))]
 617         "----"
 618         ["Also auto indent first line" (setq yas/also-auto-indent-first-line
 619                                              (not yas/also-auto-indent-first-line))
 620          :help "When auto-indenting also, auto indent the first line menu"
 621          :active (eq yas/indent-line 'auto)
 622          :style toggle :selected yas/also-auto-indent-first-line]
 623         )
 624        ("Prompting method"
 625         ["System X-widget" (setq yas/prompt-functions
 626                                  (cons 'yas/x-prompt
 627                                        (remove 'yas/x-prompt
 628                                                yas/prompt-functions)))
 629          :help "Use your windowing system's (gtk, mac, windows, etc...) default menu"
 630          :active t :style radio   :selected (eq (car yas/prompt-functions)
 631                                                 'yas/x-prompt)]
 632         ["Dropdown-list" (setq yas/prompt-functions
 633                                (cons 'yas/dropdown-prompt
 634                                      (remove 'yas/dropdown-prompt
 635                                              yas/prompt-functions)))
 636          :help "Use a special dropdown list"
 637          :active t :style radio   :selected (eq (car yas/prompt-functions)
 638                                                 'yas/dropdown-prompt)]
 639         ["Ido" (setq yas/prompt-functions
 640                      (cons 'yas/ido-prompt
 641                            (remove 'yas/ido-prompt
 642                                    yas/prompt-functions)))
 643          :help "Use an ido-style minibuffer prompt"
 644          :active t :style radio   :selected (eq (car yas/prompt-functions)
 645                                                 'yas/ido-prompt)]
 646         ["Completing read" (setq yas/prompt-functions
 647                                  (cons 'yas/completing-prompt
 648                                        (remove 'yas/completing-prompt-prompt
 649                                                yas/prompt-functions)))
 650          :help "Use a normal minibuffer prompt"
 651          :active t :style radio   :selected (eq (car yas/prompt-functions)
 652                                                 'yas/completing-prompt-prompt)]
 653         )
 654        ("Misc"
 655         ["Wrap region in exit marker" 
 656          (setq yas/wrap-around-region
 657                (not yas/wrap-around-region))
 658          :help "If non-nil automatically wrap the selected text in the $0 snippet exit"
 659          :style toggle :selected yas/wrap-around-region]
 660         ["Allow stacked expansions " 
 661          (setq yas/triggers-in-field
 662                (not yas/triggers-in-field))
 663          :help "If non-nil allow snippets to be triggered inside other snippet fields"
 664          :style toggle :selected yas/triggers-in-field]
 665         ["Revive snippets on undo " 
 666          (setq yas/snippet-revival
 667                (not yas/snippet-revival))
 668          :help "If non-nil allow snippets to become active again after undo"
 669          :style toggle :selected yas/snippet-revival]
 670         ["Good grace " 
 671          (setq yas/good-grace
 672                (not yas/good-grace))
 673          :help "If non-nil don't raise errors in bad embedded eslip in snippets"
 674          :style toggle :selected yas/good-grace]
 675         ["Ignore filenames as triggers" 
 676          (setq yas/ignore-filenames-as-triggers
 677                (not yas/ignore-filenames-as-triggers))
 678          :help "If non-nil don't derive tab triggers from filenames"
 679          :style toggle :selected yas/ignore-filenames-as-triggers]
 680         )
 681        "----"
 682        ["Load snippets..."  yas/load-directory
 683         :help "Load snippets from a specific directory"]
 684        ["Reload everything" yas/reload-all
 685         :help "Cleanup stuff, reload snippets, rebuild menus"]
 686        ["About"            yas/about
 687         :help "Display some information about YASsnippet"]))
 688    ;; Now for the stuff that has direct keybindings
 689    ;;
 690    (define-key map "\C-c&\C-s" 'yas/insert-snippet)
 691    (define-key map "\C-c&\C-n" 'yas/new-snippet)
 692    (define-key map "\C-c&\C-v" 'yas/visit-snippet-file)
 693    (define-key map "\C-c&\C-f" 'yas/find-snippets)
 694    map))
 695
 696(defvar yas/minor-mode-map (yas/init-minor-keymap)
 697  "The keymap used when `yas/minor-mode' is active.")
 698
 699(defun yas/trigger-key-reload (&optional unbind-key)
 700  "Rebind `yas/expand' to the new value of `yas/trigger-key'.
 701
 702With optional UNBIND-KEY, try to unbind that key from
 703`yas/minor-mode-map'."
 704  (when (and unbind-key
 705             (stringp unbind-key)
 706             (not (string= unbind-key "")))
 707    (define-key yas/minor-mode-map (read-kbd-macro unbind-key) nil)) 
 708  (when  (and yas/trigger-key
 709              (stringp yas/trigger-key)
 710              (not (string= yas/trigger-key "")))
 711    (define-key yas/minor-mode-map (read-kbd-macro yas/trigger-key) 'yas/expand)))
 712
 713;;;###autoload
 714(define-minor-mode yas/minor-mode
 715  "Toggle YASnippet mode.
 716
 717When YASnippet mode is enabled, the `tas/trigger-key' key expands
 718snippets of code depending on the mode.
 719
 720With no argument, this command toggles the mode.
 721positive prefix argument turns on the mode.
 722Negative prefix argument turns off the mode.
 723
 724You can customize the key through `yas/trigger-key'.
 725
 726Key bindings:
 727\\{yas/minor-mode-map}"
 728  nil
 729  ;; The indicator for the mode line.
 730  " yas"
 731  :group 'yasnippet
 732  (when yas/minor-mode
 733    (yas/trigger-key-reload)
 734    ;; load all snippets definitions unless we still don't have a
 735    ;; root-directory or some snippets have already been loaded.
 736    (unless (or (null yas/root-directory)
 737                (> (hash-table-count yas/snippet-tables) 0))
 738      (yas/reload-all))))
 739
 740(defvar yas/dont-activate #'(lambda ()
 741                              (and yas/root-directory
 742                                   (null (yas/get-snippet-tables))))
 743  "If non-nil don't let `yas/minor-mode-on' active yas for this buffer.
 744
 745`yas/minor-mode-on' is usually called by `yas/global-mode' so
 746this effectively lets you define exceptions to the \"global\"
 747behaviour.")
 748(make-variable-buffer-local 'yas/dont-activate)
 749
 750
 751(defun yas/minor-mode-on ()
 752  "Turn on YASnippet minor mode.
 753
 754Do this unless `yas/dont-activate' is t or the function
 755`yas/get-snippet-tables' (which see), returns an empty list."
 756  (interactive)
 757  (unless (or (and (functionp yas/dont-activate)
 758                   (funcall yas/dont-activate))
 759              (and (not (functionp yas/dont-activate))
 760                   yas/dont-activate))
 761    (yas/minor-mode 1)))
 762
 763(defun yas/minor-mode-off ()
 764  "Turn off YASnippet minor mode."
 765  (interactive)
 766  (yas/minor-mode -1))
 767
 768(define-globalized-minor-mode yas/global-mode yas/minor-mode yas/minor-mode-on
 769  :group 'yasnippet
 770  :require 'yasnippet)
 771
 772;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 773;; Major mode stuff
 774;;
 775(defvar yas/font-lock-keywords
 776  (append '(("^#.*$" . font-lock-comment-face))
 777          lisp-font-lock-keywords
 778          lisp-font-lock-keywords-1
 779          lisp-font-lock-keywords-2
 780          '(("$\\([0-9]+\\)"
 781             (0 font-lock-keyword-face)
 782             (1 font-lock-string-face t))
 783            ("${\\([0-9]+\\):?"
 784             (0 font-lock-keyword-face)
 785             (1 font-lock-warning-face t))
 786            ("${" font-lock-keyword-face)
 787            ("$[0-9]+?" font-lock-preprocessor-face)
 788            ("\\(\\$(\\)" 1 font-lock-preprocessor-face)
 789            ("}"
 790             (0 font-lock-keyword-face)))))
 791
 792(defun yas/init-major-keymap ()
 793  (let ((map (make-sparse-keymap)))
 794    (easy-menu-define nil
 795      map
 796      "Menu used when snippet-mode is active."
 797      (cons "Snippet"
 798            (mapcar #'(lambda (ent)
 799                        (when (third ent)
 800                          (define-key map (third ent) (second ent)))
 801                        (vector (first ent) (second ent) t))
 802                    (list
 803                     (list "Load this snippet" 'yas/load-snippet-buffer "\C-c\C-c")
 804                     (list "Try out this snippet" 'yas/tryout-snippet "\C-c\C-t")))))
 805    map))
 806
 807(defvar snippet-mode-map
 808  (yas/init-major-keymap)
 809  "The keymap used when `snippet-mode' is active")
 810
 811
 812(define-derived-mode snippet-mode text-mode "Snippet"
 813  "A mode for editing yasnippets"
 814  (set-syntax-table (standard-syntax-table))
 815  (setq font-lock-defaults '(yas/font-lock-keywords))
 816  (set (make-local-variable 'require-final-newline) nil)
 817  (use-local-map snippet-mode-map))
 818
 819;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 820;; Internal structs for template management
 821
 822(defstruct (yas/template (:constructor yas/make-template
 823                                       (content name condition expand-env file keybinding)))
 824  "A template for a snippet."
 825  content
 826  name
 827  condition
 828  expand-env
 829  file
 830  keybinding)
 831
 832(defvar yas/snippet-tables (make-hash-table)
 833  "A hash table of MAJOR-MODE symbols to `yas/snippet-table' objects.")
 834
 835(defstruct (yas/snippet-table (:constructor yas/make-snippet-table (name)))
 836  "A table to store snippets for a particular mode.
 837
 838Has the following fields:
 839
 840`yas/snippet-table-name'
 841
 842  A symbol normally corresponding to a major mode, but can also be
 843  a pseudo major-mode to be referenced in `yas/mode-symbol', for
 844  example.
 845
 846`yas/snippet-table-hash'
 847
 848  A hash table the key is a string (the snippet key) and the
 849  value is yet another hash of (NAME TEMPLATE), where NAME is the
 850  snippet name and TEMPLATE is a `yas/template' object name.
 851
 852`yas/snippet-table-parents'
 853
 854  A list of tables considered parents of this table: i.e. when
 855  searching for expansions they are searched as well."
 856  name
 857  (hash (make-hash-table :test 'equal))
 858  (parents nil))
 859
 860(defvar yas/better-guess-for-replacements nil
 861  "If non-nil `yas/store' better guess snippet replacements.")
 862
 863(defun yas/store (table name key template)
 864  "Store a snippet template in the TABLE."
 865
 866  ;; This is dones by searching twice:
 867  ;;
 868  ;; * Try to get the existing namehash from TABLE using key.
 869  ;;
 870  ;; * Try to get the existing namehash from by searching the *whole*
 871  ;; snippet table for NAME. This is becuase they user might have
 872  ;; changed the key and that can no longer be used to locate the
 873  ;; previous `yas/template-structure'.
 874  ;;
 875  ;; * If that returns nothing, oh well...
 876  ;;
 877  (dolist (existing-namehash (remove nil (list (gethash key (yas/snippet-table-hash table))
 878                                               (when yas/better-guess-for-replacements
 879                                                 (let (a)
 880                                                   (maphash #'(lambda (key namehash)
 881                                                                (when (gethash name namehash)
 882                                                                  (setq a namehash)))
 883                                                            (yas/snippet-table-hash table))
 884                                                   a)))))
 885    (let ((existing-template (gethash name existing-namehash)))
 886      (when existing-template
 887        ;; Remove the existing keybinding
 888        (when (yas/template-keybinding existing-template)
 889          (define-key
 890            (symbol-value (first (yas/template-keybinding existing-template)))
 891            (second (yas/template-keybinding existing-template))
 892            nil)
 893          (setq yas/active-keybindings
 894                (delete (yas/template-keybinding existing-template)
 895                        yas/active-keybindings)))
 896        ;; Remove the (name . template) mapping from existing-namehash.
 897        (remhash name existing-namehash))))
 898  ;; Now store the new template independent of the previous steps.
 899  ;;
 900  (puthash name
 901           template
 902           (or (gethash key
 903                        (yas/snippet-table-hash table))
 904               (puthash key
 905                        (make-hash-table :test 'equal)
 906                        (yas/snippet-table-hash table)))))
 907
 908(defun yas/fetch (table key)
 909  "Fetch a snippet binding to KEY from TABLE."
 910  (let* ((keyhash (yas/snippet-table-hash table))
 911         (namehash (and keyhash (gethash key keyhash))))
 912    (when namehash
 913      (yas/filter-templates-by-condition
 914       (let (alist)
 915         (maphash #'(lambda (k v)
 916                      (push (cons k v) alist))
 917                  namehash)
 918         alist)))))
 919
 920
 921;; Filtering/condition logic
 922
 923(defun yas/eval-condition (condition)
 924  (condition-case err
 925      (save-excursion
 926        (save-restriction
 927          (save-match-data
 928            (eval condition))))
 929    (error (progn
 930             (message (format "[yas] error in condition evaluation: %s"
 931                              (error-message-string err)))
 932             nil))))
 933
 934
 935(defun yas/filter-templates-by-condition (templates)
 936  "Filter the templates using the applicable condition.
 937
 938TEMPLATES is a list of cons (NAME . TEMPLATE) where NAME is a
 939string and TEMPLATE is a `yas/template' structure.
 940
 941This function implements the rules described in
 942`yas/buffer-local-condition'.  See that variables documentation."
 943  (let ((requirement (yas/require-template-specific-condition-p)))
 944    (if (eq requirement 'always)
 945        templates
 946      (remove-if-not #'(lambda (pair)
 947                         (yas/template-can-expand-p (yas/template-condition (cdr pair)) requirement))
 948                     templates))))
 949
 950(defun yas/require-template-specific-condition-p ()
 951  "Decides if this buffer requests/requires snippet-specific
 952conditions to filter out potential expansions."
 953  (if (eq 'always yas/buffer-local-condition)
 954      'always
 955    (let ((local-condition (or (and (consp yas/buffer-local-condition)
 956                                    (yas/eval-condition yas/buffer-local-condition))
 957                               yas/buffer-local-condition)))
 958      (when local-condition
 959        (if (eq local-condition t)
 960            t
 961          (and (consp local-condition)
 962               (eq 'require-snippet-condition (car local-condition))
 963               (symbolp (cdr local-condition))
 964               (cdr local-condition)))))))
 965
 966(defun yas/template-can-expand-p (condition &optional requirement)
 967  "Evaluates CONDITION and REQUIREMENT and returns a boolean"
 968  (let* ((requirement (or requirement
 969                          (yas/require-template-specific-condition-p)))
 970         (result (or (null condition)
 971                     (yas/eval-condition
 972                      (condition-case err
 973                          (read condition)
 974                        (error (progn
 975                                 (message (format "[yas] error reading condition: %s"
 976                                                  (error-message-string err))))
 977                               nil))))))
 978    (cond ((eq requirement t)
 979           result)
 980          (t
 981           (eq requirement result)))))
 982
 983(defun yas/snippet-table-get-all-parents (table)
 984  (let ((parents (yas/snippet-table-parents table)))
 985    (when parents
 986      (append (copy-list parents)
 987              (mapcan #'yas/snippet-table-get-all-parents parents)))))
 988
 989(defun yas/snippet-table-templates (table)
 990  (when table
 991    (let ((acc (list)))
 992      (maphash #'(lambda (key namehash)
 993                   (maphash #'(lambda (name template)
 994                                (push (cons name template) acc))
 995                            namehash))
 996               (yas/snippet-table-hash table))
 997      (yas/filter-templates-by-condition acc))))
 998
 999(defun yas/current-key ()
1000  "Get the key under current position. A key is used to find
1001the template of a snippet in the current snippet-table."
1002  (let ((start (point))
1003        (end (point))
1004        (syntaxes yas/key-syntaxes)
1005        syntax
1006        done
1007        templates)
1008    (while (and (not done) syntaxes)
1009      (setq syntax (car syntaxes))
1010      (setq syntaxes (cdr syntaxes))
1011      (save-excursion
1012        (skip-syntax-backward syntax)
1013        (setq start (point)))
1014      (setq templates
1015            (mapcan #'(lambda (table)
1016                        (yas/fetch table (buffer-substring-no-properties start end)))
1017                    (yas/get-snippet-tables)))
1018      (if templates
1019          (setq done t)
1020        (setq start end)))
1021    (list templates
1022          start
1023          end)))
1024
1025
1026(defun yas/snippet-table-all-keys (table)
1027  (when table
1028    (let ((acc))
1029      (maphash #'(lambda (key templates)
1030                   (when (yas/filter-templates-by-condition templates)
1031                     (push key acc)))
1032               (yas/snippet-table-hash table))
1033      acc)))
1034
1035
1036;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1037;; Internal functions
1038
1039(defun yas/real-mode? (mode)
1040  "Try to find out if MODE is a real mode. The MODE bound to
1041a function (like `c-mode') is considered real mode. Other well
1042known mode like `ruby-mode' which is not part of Emacs might
1043not bound to a function until it is loaded. So yasnippet keeps
1044a list of modes like this to help the judgement."
1045  (or (fboundp mode)
1046      (find mode yas/known-modes)))
1047
1048(defun yas/read-and-eval-string (string)
1049  ;; TODO: This is a possible optimization point, the expression could
1050  ;; be stored in cons format instead of string,
1051  "Evaluate STRING and convert the result to string."
1052  (let ((retval (catch 'yas/exception
1053                  (condition-case err
1054                      (save-excursion
1055                        (save-restriction
1056                          (save-match-data
1057                            (widen)
1058                            (let ((result (eval (read string))))
1059                              (when result
1060                                (format "%s" result))))))
1061                    (error (if yas/good-grace
1062                               "[yas] elisp error!"
1063                             (error (format "[yas] elisp error: %s"
1064                                            (error-message-string err)))))))))
1065    (when (and (consp retval)
1066               (eq 'yas/exception (car retval)))
1067      (error (cdr retval)))
1068    retval))
1069
1070(defvar yas/mode-symbol nil
1071  "If non-nil, lookup snippets using this instead of `major-mode'.")
1072(make-variable-buffer-local 'yas/mode-symbol)
1073
1074(defun yas/snippet-table-get-create (mode)
1075  "Get the snippet table corresponding to MODE.
1076
1077Optional DIRECTORY gets recorded as the default directory to
1078search for snippet files if the retrieved/created table didn't
1079already have such a property."
1080  (let ((table (gethash mode
1081                        yas/snippet-tables)))
1082    (unless table
1083      (setq table (yas/make-snippet-table (symbol-name mode)))
1084      (puthash mode table yas/snippet-tables))
1085    table))
1086
1087(defun yas/get-snippet-tables (&optional mode-symbol dont-search-parents)
1088  "Get snippet tables for current buffer.
1089
1090Return a list of 'yas/snippet-table' objects indexed by mode.
1091
1092The modes are tried in this order: optional MODE-SYMBOL, then
1093`yas/mode-symbol', then `major-mode' then, unless
1094DONT-SEARCH-PARENTS is non-nil, the guessed parent mode of either
1095MODE-SYMBOL or `major-mode'.
1096
1097Guessing is done by looking up the MODE-SYMBOL's
1098`derived-mode-parent' property, see also `derived-mode-p'."
1099  (let ((mode-tables
1100         (mapcar #'(lambda (mode)
1101                     (gethash mode yas/snippet-tables))
1102                 (append (list mode-symbol)
1103                         (if (listp yas/mode-symbol)
1104                             yas/mode-symbol
1105                           (list yas/mode-symbol))
1106                         (list major-mode
1107                               (and (not dont-search-parents)
1108                                    (get (or mode-symbol major-mode)
1109                                         'derived-mode-parent))))))
1110        (all-tables))
1111    (dolist (table (remove nil mode-tables))
1112      (push table all-tables)
1113      (nconc all-tables (yas/snippet-table-get-all-parents table)))
1114    (remove-duplicates all-tables)))
1115
1116(defun yas/menu-keymap-get-create (mode)
1117  "Get the menu keymap correspondong to MODE."
1118  (or (gethash mode yas/menu-table)
1119      (puthash mode (make-sparse-keymap) yas/menu-table)))
1120
1121;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1122;;; Template-related and snippet loading functions
1123
1124(defun yas/parse-template (&optional file)
1125  "Parse the template in the current buffer.
1126
1127Optional FILE is the absolute file name of the file being
1128parsed.
1129
1130Return a snippet-definition, i.e. a list
1131
1132 (KEY TEMPLATE NAME CONDITION GROUP VARS FILE KEYBINDING)
1133
1134If the buffer contains a line of \"# --\" then the contents
1135above this line are ignored. Variables can be set above this
1136line through the syntax:
1137
1138#name : value
1139
1140Here's a list of currently recognized variables:
1141
1142 * name
1143 * contributor
1144 * condition
1145 * key
1146 * group
1147 * expand-env
1148
1149#name: #include \"...\"
1150# --
1151#include \"$1\""
1152  ;;
1153  ;;
1154  (goto-char (point-min))
1155  (let* ((name (and file
1156                    (file-name-nondirectory file)))
1157         (key (unless yas/ignore-filenames-as-triggers
1158                (and name
1159                     (file-name-sans-extension name))))
1160         template
1161         bound
1162         condition
1163         (group (and file
1164                     (yas/calculate-group file)))
1165         expand-env
1166         binding)
1167    (if (re-search-forward "^# --\n" nil t)
1168        (progn (setq template
1169                     (buffer-substring-no-properties (point)
1170                                                     (point-max)))
1171               (setq bound (point))
1172               (goto-char (point-min))
1173               (while (re-search-forward "^# *\\([^ ]+?\\) *: *\\(.*\\)$" bound t)
1174                 (when (string= "name" (match-string-no-properties 1))
1175                   (setq name (match-string-no-properties 2)))
1176                 (when (string= "condition" (match-string-no-properties 1))
1177                   (setq condition (match-string-no-properties 2)))
1178                 (when (string= "group" (match-string-no-properties 1))
1179                   (setq group (match-string-no-properties 2)))
1180                 (when (string= "expand-env" (match-string-no-properties 1))
1181                   (setq expand-env (match-string-no-properties 2)))
1182                 (when (string= "key" (match-string-no-properties 1))
1183                   (setq key (match-string-no-properties 2)))
1184                 (when (string= "binding" (match-string-no-properties 1))
1185                   (setq binding (match-string-no-properties 2)))))
1186      (setq template
1187            (buffer-substring-no-properties (point-min) (point-max))))
1188    (list key template name condition group expand-env file binding)))
1189
1190(defun yas/calculate-group (file)
1191  "Calculate the group for snippet file path FILE."
1192  (let* ((dominating-dir (locate-dominating-file file
1193                                                 ".yas-make-groups"))
1194         (extra-path (and dominating-dir
1195                          (replace-regexp-in-string (concat "^"
1196                                                            (expand-file-name dominating-dir))
1197                                                    ""
1198                                                    (expand-file-name file))))
1199         (extra-dir (and extra-path
1200                         (file-name-directory extra-path)))
1201         (group (and extra-dir
1202                     (replace-regexp-in-string "/"
1203                                               "."
1204                                               (directory-file-name extra-dir)))))
1205    group))
1206
1207;; (defun yas/glob-files (directory &optional recurse-p append)
1208;;   "Returns files under DIRECTORY ignoring dirs and hidden files.
1209
1210;; If RECURSE in non-nil, do that recursively."
1211;;   (let (ret
1212;;         (default-directory directory))
1213;;     (dolist (entry (directory-files "."))
1214;;       (cond ((or (string-match "^\\."
1215;;                                (file-name-nondirectory entry))
1216;;                  (string-match "~$"
1217;;                                (file-name-nondirectory entry)))
1218;;              nil)
1219;;             ((and recurse-p
1220;;                   (file-directory-p entry))
1221;;              (setq ret (nconc ret
1222;;                               (yas/glob-files (expand-file-name entry)
1223;;                                               recurse-p
1224;;                                               (if append
1225;;                                                   (concat append "/" entry)
1226;;                                                 entry)))))
1227;;             ((file-directory-p entry)
1228;;              nil)
1229;;             (t
1230;;              (push (if append
1231;;                        (concat append "/" entry)
1232;;                      entry) ret))))
1233;;     ret))
1234
1235(defun yas/subdirs (directory &optional file?)
1236  "Return subdirs or files of DIRECTORY according to FILE?."
1237  (remove-if (lambda (file)
1238               (or (string-match "^\\."
1239                                 (file-name-nondirectory file))
1240                   (string-match "~$"
1241                                 (file-name-nondirectory file))
1242                   (if file?
1243                       (file-directory-p file)
1244                     (not (file-directory-p file)))))
1245             (directory-files directory t)))
1246
1247(defun yas/make-menu-binding (template)
1248  `(lambda () (interactive) (yas/expand-or-visit-from-menu ,template)))
1249
1250(defun yas/expand-or-visit-from-menu (template)
1251  (if yas/visit-from-menu
1252      (yas/visit-snippet-file-1 template)
1253    (let ((where (if mark-active
1254                     (cons (region-beginning) (region-end))
1255                   (cons (point) (point)))))
1256      (yas/expand-snippet (yas/template-content template)
1257                          (car where)
1258                          (cdr where)))))
1259
1260;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1261;; Popping up for keys and templates
1262;;
1263(defun yas/prompt-for-template (templates &optional prompt)
1264  "Interactively choose a template from the list TEMPLATES.
1265
1266TEMPLATES is a list of `yas/template'."
1267  (when templates
1268    (some #'(lambda (fn)
1269              (funcall fn (or prompt "Choose a snippet: ")
1270                       templates
1271                       #'yas/template-name))
1272          yas/prompt-functions)))
1273
1274(defun yas/prompt-for-keys (keys &optional prompt)
1275  "Interactively choose a template key from the list KEYS."
1276  (when keys
1277    (some #'(lambda (fn)
1278              (funcall fn (or prompt "Choose a snippet key: ") keys))
1279          yas/prompt-functions)))
1280
1281(defun yas/prompt-for-table (tables &optional prompt)
1282  (when tables
1283    (some #'(lambda (fn)
1284              (funcall fn (or prompt "Choose a snippet table: ")
1285                       tables
1286                       #'yas/snippet-table-name))
1287          yas/prompt-functions)))
1288
1289(defun yas/x-prompt (prompt choices &optional display-fn)
1290  (when (and window-system choices)
1291    (let ((keymap (cons 'keymap
1292                        (cons
1293                         prompt
1294                         (mapcar (lambda (choice)
1295                                   (list choice
1296                                         'menu-item
1297                                         (if display-fn
1298                                             (funcall display-fn choice)
1299                                           choice)
1300                                         t))
1301                                 choices)))))
1302      (when (cdr keymap)
1303        (car (x-popup-menu (if (fboundp 'posn-at-point)
1304                               (let ((x-y (posn-x-y (posn-at-point (point)))))
1305                                 (list (list (+ (car x-y) 10)
1306                                             (+ (cdr x-y) 20))
1307                                       (selected-window)))
1308                             t)
1309                           keymap))))))
1310
1311(defun yas/ido-prompt (prompt choices &optional display-fn)
1312  (when (and (featurep 'ido)
1313             ido-mode)
1314    (let* ((formatted-choices (or (and display-fn
1315                                       (mapcar display-fn choices))
1316                                  choices))
1317           (chosen (and formatted-choices
1318                        (ido-completing-read prompt
1319                                             formatted-choices
1320                                             nil
1321                                             'require-match
1322                                             nil
1323                                             nil))))
1324      (when chosen
1325        (nth (position chosen formatted-choices :test #'string=) choices)))))
1326
1327(eval-when-compile (require 'dropdown-list nil t))
1328(defun yas/dropdown-promp

Large files files are truncated, but you can click here to view the full file