.emacs.d/yasnippet.el
author Adam Gomaa <adam@gomaa.us>
Sun Dec 18 13:13:02 2011 -0500
changeset 521 67f37d330ad0
permissions -rw-r--r--
Remove project & _list_projects, I don't use them anymore.
     1 ;;; yasnippet.el --- Yet another snippet extension for Emacs.
     2 
     3 ;; Copyright 2008 pluskid
     4 ;; 
     5 ;; Author: pluskid <pluskid@gmail.com>
     6 ;; Version: 0.5.2
     7 ;; X-URL: http://code.google.com/p/yasnippet/
     8 
     9 ;; This file is free software; you can redistribute it and/or modify
    10 ;; it under the terms of the GNU General Public License as published by
    11 ;; the Free Software Foundation; either version 2, or (at your option)
    12 ;; any later version.
    13 
    14 ;; This file is distributed in the hope that it will be useful,
    15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
    16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17 ;; GNU General Public License for more details.
    18 
    19 ;; You should have received a copy of the GNU General Public License
    20 ;; along with GNU Emacs; see the file COPYING.  If not, write to
    21 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    22 ;; Boston, MA 02111-1307, USA.
    23 
    24 ;;; Commentary:
    25 
    26 ;; Basic steps to setup:
    27 ;;   1. Place `yasnippet.el' in your `load-path'.
    28 ;;   2. In your .emacs file:
    29 ;;        (require 'yasnippet)
    30 ;;   3. Place the `snippets' directory somewhere. E.g: ~/.emacs.d/snippets
    31 ;;   4. In your .emacs file
    32 ;;        (yas/initialize)
    33 ;;        (yas/load-directory "~/.emacs.d/snippets")
    34 ;;
    35 ;; For more information and detailed usage, refer to the project page:
    36 ;;      http://code.google.com/p/yasnippet/
    37 
    38 (require 'cl)
    39 
    40 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    41 ;; User customizable variables
    42 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    43 (defvar yas/key-syntaxes (list "w" "w_" "w_." "^ ")
    44   "A list of syntax of a key. This list is tried in the order
    45 to try to find a key. For example, if the list is '(\"w\" \"w_\").
    46 And in emacs-lisp-mode, where \"-\" has the syntax of \"_\":
    47 
    48 foo-bar
    49 
    50 will first try \"bar\", if not found, then \"foo-bar\" is tried.")
    51 
    52 (defvar yas/root-directory nil
    53   "The (list of) root directory that stores the snippets for each 
    54 major modes.")
    55 
    56 (defvar yas/indent-line t
    57   "Each (except the 1st) line of the snippet template is indented to
    58 current column if this variable is non-`nil'.")
    59 (make-variable-buffer-local 'yas/indent-line)
    60 
    61 (defvar yas/trigger-key (kbd "TAB")
    62   "The key to bind as a trigger of snippet.")
    63 (defvar yas/next-field-key (kbd "TAB")
    64   "The key to navigate to next field.")
    65 
    66 (defvar yas/keymap (make-sparse-keymap)
    67   "The keymap of snippet.")
    68 (define-key yas/keymap yas/next-field-key 'yas/next-field-group)
    69 (define-key yas/keymap (kbd "S-TAB") 'yas/prev-field-group)
    70 (define-key yas/keymap (kbd "<S-iso-lefttab>") 'yas/prev-field-group)
    71 (define-key yas/keymap (kbd "<S-tab>") 'yas/prev-field-group)
    72 (define-key yas/keymap (kbd "<backtab>") 'yas/prev-field-group)
    73 
    74 (defvar yas/show-all-modes-in-menu nil
    75   "Currently yasnippet only all \"real modes\" to menubar. For
    76 example, you define snippets for \"cc-mode\" and make it the
    77 parent of `c-mode', `c++-mode' and `java-mode'. There's really
    78 no such mode like \"cc-mode\". So we don't show it in the yasnippet
    79 menu to avoid the menu becoming too big with strange modes. The
    80 snippets defined for \"cc-mode\" can still be accessed from
    81 menu-bar->c-mode->parent (or c++-mode, java-mode, all are ok).
    82 However, if you really like to show all modes in the menu, set
    83 this variable to t.")
    84 (defvar yas/use-menu t
    85   "If this is set to `t', all snippet template of the current
    86 mode will be listed under the menu \"yasnippet\".")
    87 (defvar yas/trigger-symbol " =>"
    88   "The text that will be used in menu to represent the trigger.")
    89 
    90 (defface yas/field-highlight-face
    91   '((((class color) (background light)) (:background "DarkSeaGreen2"))
    92     (t (:background "DimGrey")))
    93   "The face used to highlight a field of snippet.")
    94 (defface yas/mirror-highlight-face
    95   '((((class color) (background light)) (:background "LightYellow2"))
    96     (t (:background "gray22")))
    97   "The face used to highlight mirror fields of a snippet.")
    98 
    99 (defvar yas/window-system-popup-function #'yas/dropdown-list-popup-for-template
   100   "When there's multiple candidate for a snippet key. This function
   101 is called to let user select one of them. `yas/text-popup-function'
   102 is used instead when not in a window system.")
   103 (defvar yas/text-popup-function #'yas/dropdown-list-popup-for-template
   104   "When there's multiple candidate for a snippet key. If not in a
   105 window system, this function is called to let user select one of
   106 them. `yas/window-system-popup-function' is used instead when in
   107 a window system.")
   108 
   109 (defvar yas/extra-mode-hooks
   110   '(ruby-mode-hook actionscript-mode-hook)
   111   "A list of mode-hook that should be hooked to enable yas/minor-mode.
   112 Most modes need no special consideration. Some mode (like ruby-mode)
   113 doesn't call `after-change-major-mode-hook' need to be hooked explicitly.")
   114 
   115 (defvar yas/after-exit-snippet-hook
   116   '()
   117   "Hooks to run after a snippet exited.
   118 The hooks will be run in an environment where some variables bound to 
   119 proper values:
   120  * yas/snippet-beg : The beginning of the region of the snippet.
   121  * yas/snippet-end : Similar to beg.")
   122 
   123 (defvar yas/before-expand-snippet-hook
   124   '()
   125   "Hooks to run after a before expanding a snippet.")
   126 
   127 (defvar yas/buffer-local-condition 
   128   '(if (and (not (bobp))
   129 	    (or (equal "font-lock-comment-face"
   130 		       (get-char-property (1- (point))
   131 					  'face))
   132 		(equal "font-lock-string-face"
   133 		       (get-char-property (1- (point))
   134 					  'face))))
   135        '(require-snippet-condition . force-in-comment)
   136      t)
   137   "Condition to yasnippet local to each buffer.
   138 
   139     * If yas/buffer-local-condition evaluate to nil, snippet
   140       won't be expanded.
   141 
   142     * If it evaluate to the a cons cell where the car is the
   143       symbol require-snippet-condition and the cdr is a
   144       symbol (let's call it requirement):
   145        * If the snippet has no condition, then it won't be
   146          expanded.
   147        * If the snippet has a condition but evaluate to nil or
   148          error occured during evaluation, it won't be expanded.
   149        * If the snippet has a condition that evaluate to
   150          non-nil (let's call it result):
   151           * If requirement is t, the snippet is ready to be
   152             expanded.
   153           * If requirement is eq to result, the snippet is ready
   154             to be expanded.
   155           * Otherwise the snippet won't be expanded.
   156     * If it evaluate to other non-nil value:
   157        * If the snippet has no condition, or has a condition that
   158          evaluate to non-nil, it is ready to be expanded.
   159        * Otherwise, it won't be expanded.
   160 
   161 Here's an example:
   162 
   163  (add-hook 'python-mode-hook
   164            '(lambda ()
   165               (setq yas/buffer-local-condition
   166                     '(if (python-in-string/comment)
   167                          '(require-snippet-condition . force-in-comment)
   168                        t))))")
   169 
   170 (defvar yas/fallback-behavior 'call-other-command
   171   "The fall back behavior of YASnippet when it can't find a snippet
   172 to expand. 
   173 
   174  * 'call-other-command means try to temporarily disable
   175     YASnippet and call other command bound to `yas/trigger-key'.
   176  * 'return-nil means return nil.")
   177 
   178 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   179 ;; Internal variables
   180 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   181 (defvar yas/version "0.5.2")
   182 
   183 (defvar yas/snippet-tables (make-hash-table)
   184   "A hash table of snippet tables corresponding to each major-mode.")
   185 (defvar yas/menu-table (make-hash-table)
   186   "A hash table of menus of corresponding major-mode.")
   187 (defvar yas/menu-keymap (make-sparse-keymap "YASnippet"))
   188 ;; empty menu will cause problems, so we insert some items
   189 (define-key yas/menu-keymap [yas/about]
   190   '(menu-item "About" yas/about))
   191 (define-key yas/menu-keymap [yas/reload]
   192   '(menu-item "Reload all snippets" yas/reload-all))
   193 (define-key yas/menu-keymap [yas/load]
   194   '(menu-item "Load snippets..." yas/load-directory))
   195 (define-key yas/menu-keymap [yas/separator]
   196   '(menu-item "--"))
   197 
   198 (defvar yas/known-modes
   199   '(ruby-mode rst-mode)
   200   "A list of mode which is well known but not part of emacs.")
   201 (defconst yas/escape-backslash
   202   (concat "YASESCAPE" "BACKSLASH" "PROTECTGUARD"))
   203 (defconst yas/escape-dollar
   204   (concat "YASESCAPE" "DOLLAR" "PROTECTGUARD"))
   205 (defconst yas/escape-backquote
   206   (concat "YASESCAPE" "BACKQUOTE" "PROTECTGUARD"))
   207 
   208 (defconst yas/field-regexp
   209   (concat "$\\([0-9]+\\)" "\\|"
   210 	  "${\\(?:\\([0-9]+\\):\\)?\\([^}]*\\)}"))
   211 
   212 (defvar yas/snippet-id-seed 0
   213   "Contains the next id for a snippet")
   214 (defun yas/snippet-next-id ()
   215   (let ((id yas/snippet-id-seed))
   216     (incf yas/snippet-id-seed)
   217     id))
   218 
   219 (defvar yas/overlay-modification-hooks
   220   (list 'yas/overlay-modification-hook)
   221   "The list of hooks to the overlay modification event.")
   222 (defvar yas/overlay-insert-in-front-hooks
   223   (list 'yas/overlay-insert-in-front-hook)
   224   "The list of hooks of the overlay inserted in front event.")
   225 (defvar yas/keymap-overlay-modification-hooks
   226   (list 'yas/overlay-maybe-insert-behind-hook)
   227   "The list of hooks of the big keymap overlay modification event.")
   228 
   229 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   230 ;; YASnippet minor mode
   231 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   232 (defvar yas/minor-mode-map (make-sparse-keymap)
   233   "The keymap of yas/minor-mode")
   234 (defvar yas/minor-mode-on-hook nil
   235   "Hook to call when yas/minor-mode is on.")
   236 (defvar yas/minor-mode-off-hook nil
   237   "Hook to call when yas/minor-mode is off.")
   238 (define-minor-mode yas/minor-mode
   239   "Toggle YASnippet mode.
   240 With no argument, this command toggles the mode.
   241 positive prefix argument turns on the mode.
   242 Negative prefix argument turns off the mode.
   243 
   244 When YASnippet mode is enabled, the TAB key
   245 expands snippets of code depending on the mode.
   246 
   247 You can customize the key through `yas/trigger-key'."
   248   ;; The initial value.
   249   nil
   250   ;; The indicator for the mode line.
   251   " yas"
   252   :group 'editing
   253   (define-key yas/minor-mode-map yas/trigger-key 'yas/expand))
   254 
   255 (defun yas/minor-mode-on ()
   256   "Turn on YASnippet minor mode."
   257   (interactive)
   258   (yas/minor-mode 1))
   259 (defun yas/minor-mode-off ()
   260   "Turn off YASnippet minor mode."
   261   (interactive)
   262   (yas/minor-mode -1))
   263 
   264 
   265 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   266 ;; Internal Structs
   267 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   268 (defstruct (yas/template (:constructor yas/make-template
   269 				       (content name condition)))
   270   "A template for a snippet."
   271   content
   272   name
   273   condition)
   274 (defstruct (yas/snippet (:constructor yas/make-snippet ()))
   275   "A snippet."
   276   (groups nil)
   277   (exit-marker nil)
   278   (id (yas/snippet-next-id) :read-only t)
   279   (overlay nil))
   280 (defstruct (yas/group (:constructor yas/make-group (primary-field snippet)))
   281   "A group contains a list of field with the same number."
   282   primary-field
   283   (fields (list primary-field))
   284   (next nil)
   285   (prev nil)
   286   snippet)
   287 (defstruct (yas/field 
   288 	    (:constructor yas/make-field (overlay number value transform)))
   289   "A field in a snippet."
   290   overlay
   291   number
   292   transform
   293   value)
   294 (defstruct (yas/snippet-table (:constructor yas/make-snippet-table ()))
   295   "A table to store snippets for a perticular mode."
   296   (hash (make-hash-table :test 'equal))
   297   (parent nil))
   298 
   299 (defun yas/snippet-valid? (snippet)
   300   "See if snippet is valid (ie. still alive)."
   301   (and (not (null snippet))
   302        (not (null (yas/snippet-overlay snippet)))
   303        (not (null (overlay-start (yas/snippet-overlay snippet))))))
   304 
   305 (defun yas/snippet-add-field (snippet field)
   306   "Add FIELD to SNIPPET."
   307   (let ((group (find field
   308 		     (yas/snippet-groups snippet)
   309 		     :test
   310 		     '(lambda (field group)
   311 			(and (not (null (yas/field-number field)))
   312 			     (not (null (yas/group-number group)))
   313 			     (= (yas/field-number field)
   314 				(yas/group-number group)))))))
   315     (if group
   316 	(yas/group-add-field group field)
   317       (push (yas/make-group field snippet)
   318 	    (yas/snippet-groups snippet)))))
   319 
   320 (defun yas/group-value (group)
   321   "Get the default value of the field group."
   322   (or (yas/field-value
   323        (yas/group-primary-field group))
   324       ""))
   325 (defun yas/group-number (group)
   326   "Get the number of the field group."
   327   (yas/field-number
   328    (yas/group-primary-field group)))
   329 (defun yas/group-add-field (group field)
   330   "Add a field to the field group. If the value of the primary 
   331 field is nil and that of the field is not nil, the field is set
   332 as the primary field of the group."
   333   (push field (yas/group-fields group))
   334   (when (and (null (yas/field-value (yas/group-primary-field group)))
   335 	     (yas/field-value field))
   336     (setf (yas/group-primary-field group) field)))
   337 
   338 (defun yas/snippet-field-compare (field1 field2)
   339   "Compare two fields. The field with a number is sorted first.
   340 If they both have a number, compare through the number. If neither
   341 have, compare through the start point of the overlay."
   342   (let ((n1 (yas/field-number field1))
   343 	(n2 (yas/field-number field2)))
   344     (if n1
   345 	(if n2
   346 	    (< n1 n2)
   347 	  t)
   348       (if n2
   349 	  nil
   350 	(< (overlay-start (yas/field-overlay field1))
   351 	   (overlay-start (yas/field-overlay field2)))))))
   352 
   353 (defun yas/template-condition-predicate (condition)
   354   (condition-case err
   355       (save-excursion
   356 	(save-restriction
   357 	  (save-match-data
   358 	    (eval condition))))
   359     (error (progn
   360 	     (message (format "[yas]error in condition evaluation: %s"
   361 			      (error-message-string err)))
   362 	     nil))))
   363 
   364 (defun yas/filter-templates-by-condition (templates)
   365   "Filter the templates using the condition. The rules are:
   366 
   367  * If the template has no condition, it is kept.
   368  * If the template's condition eval to non-nil, it is kept.
   369  * Otherwise (eval error or eval to nil) it is filtered."
   370   (remove-if '(lambda (pair)
   371 		(let ((condition (yas/template-condition (cdr pair))))
   372 		  (if (null condition)
   373 		      (if yas/require-template-condition
   374 			  t
   375 			nil)
   376 		    (let ((result 
   377 			   (yas/template-condition-predicate condition)))
   378 		      (if (eq yas/require-template-condition t)
   379 			  result
   380 			(not (eq result yas/require-template-condition)))))))
   381 	     templates))
   382 
   383 (defun yas/snippet-table-fetch (table key)
   384   "Fetch a snippet binding to KEY from TABLE. If not found,
   385 fetch from parent if any."
   386   (let ((templates (yas/filter-templates-by-condition
   387 		    (gethash key (yas/snippet-table-hash table)))))
   388     (when (and (null templates)
   389 	       (not (null (yas/snippet-table-parent table))))
   390       (setq templates (yas/snippet-table-fetch
   391 		       (yas/snippet-table-parent table)
   392 		       key)))
   393     templates))
   394 (defun yas/snippet-table-store (table full-key key template)
   395   "Store a snippet template in the table."
   396   (puthash key
   397 	   (yas/modify-alist (gethash key
   398 				      (yas/snippet-table-hash table))
   399 			     full-key
   400 			     template)
   401 	   (yas/snippet-table-hash table)))
   402 
   403 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   404 ;; Internal functions
   405 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   406 (defun yas/ensure-minor-mode-priority ()
   407   "Ensure that the key binding of yas/minor-mode takes priority."
   408   (unless (eq 'yas/minor-mode
   409 	      (caar minor-mode-map-alist))
   410     (setq minor-mode-map-alist
   411 	  (cons
   412 	   (cons 'yas/minor-mode yas/minor-mode-map)
   413 	   (assq-delete-all 'yas/minor-mode
   414 			    minor-mode-map-alist)))))
   415 
   416 (defun yas/real-mode? (mode)
   417   "Try to find out if MODE is a real mode. The MODE bound to
   418 a function (like `c-mode') is considered real mode. Other well
   419 known mode like `ruby-mode' which is not part of Emacs might
   420 not bound to a function until it is loaded. So yasnippet keeps
   421 a list of modes like this to help the judgement."
   422   (or (fboundp mode)
   423       (find mode yas/known-modes)))
   424 
   425 (defun yas/eval-string (string)
   426   "Evaluate STRING and convert the result to string."
   427   (condition-case err
   428       (save-excursion
   429 	(save-restriction
   430 	  (save-match-data
   431 	    (format "%s" (eval (read string))))))
   432     (error (format "(error in elisp evaluation: %s)" 
   433 		   (error-message-string err)))))
   434 (defun yas/calculate-field-value (field value)
   435   "Calculate the value of the field. If there's a transform
   436 for this field, apply it. Otherwise, the value is returned
   437 unmodified."
   438   (let ((text value)
   439 	(transform (yas/field-transform field)))
   440     (if transform
   441 	(yas/eval-string transform)
   442       text)))
   443 (defsubst yas/replace-all (from to)
   444   "Replace all occurance from FROM to TO."
   445   (goto-char (point-min))
   446   (while (search-forward from nil t)
   447     (replace-match to t t)))
   448 
   449 (defun yas/snippet-table (mode)
   450   "Get the snippet table corresponding to MODE."
   451   (let ((table (gethash mode yas/snippet-tables)))
   452     (unless table
   453       (setq table (yas/make-snippet-table))
   454       (puthash mode table yas/snippet-tables))
   455     table))
   456 (defsubst yas/current-snippet-table ()
   457   "Get the snippet table for current major-mode."
   458   (yas/snippet-table major-mode))
   459 
   460 (defun yas/menu-keymap-for-mode (mode)
   461   "Get the menu keymap correspondong to MODE."
   462   (let ((keymap (gethash mode yas/menu-table)))
   463     (unless keymap
   464       (setq keymap (make-sparse-keymap))
   465       (puthash mode keymap yas/menu-table))
   466     keymap))
   467 
   468 (defun yas/current-key ()
   469   "Get the key under current position. A key is used to find
   470 the template of a snippet in the current snippet-table."
   471   (let ((start (point))
   472 	(end (point))
   473 	(syntaxes yas/key-syntaxes)
   474 	syntax done templates)
   475     (while (and (not done) syntaxes)
   476       (setq syntax (car syntaxes))
   477       (setq syntaxes (cdr syntaxes))
   478       (save-excursion
   479 	(skip-syntax-backward syntax)
   480 	(setq start (point)))
   481       (setq templates
   482 	    (yas/snippet-table-fetch
   483 	     (yas/current-snippet-table)
   484 	     (buffer-substring-no-properties start end)))
   485       (if templates
   486 	  (setq done t)
   487 	(setq start end)))
   488     (list templates
   489 	  start
   490 	  end)))
   491 
   492 (defun yas/synchronize-fields (field-group)
   493   "Update all fields' text according to the primary field."
   494   (when (yas/snippet-valid? (yas/group-snippet field-group))
   495     (save-excursion
   496       (let* ((inhibit-modification-hooks t)
   497 	     (primary (yas/group-primary-field field-group))
   498 	     (primary-overlay (yas/field-overlay primary))
   499 	     (text (buffer-substring-no-properties (overlay-start primary-overlay)
   500 						   (overlay-end primary-overlay))))
   501 	(dolist (field (yas/group-fields field-group))
   502 	  (let* ((field-overlay (yas/field-overlay field))
   503 		 (original-length (- (overlay-end field-overlay)
   504 				     (overlay-start field-overlay))))
   505 	    (unless (eq field-overlay primary-overlay)
   506 	      (goto-char (overlay-start field-overlay))
   507 	      (insert (yas/calculate-field-value field text))
   508 	      (if (= (overlay-start field-overlay)
   509 		     (overlay-end field-overlay))
   510 		  (move-overlay field-overlay
   511 				(overlay-start field-overlay)
   512 				(point))
   513 		(delete-char original-length)))))))))
   514   
   515 (defun yas/overlay-modification-hook (overlay after? beg end &optional length)
   516   "Modification hook for snippet field overlay."
   517   (when (and after? (not undo-in-progress))
   518     (yas/synchronize-fields (overlay-get overlay 'yas/group))))
   519 (defun yas/overlay-insert-in-front-hook (overlay after? beg end &optional length)
   520   "Hook for snippet overlay when text is inserted in front of a snippet field."
   521   (when after?
   522     (let ((field-group (overlay-get overlay 'yas/group))
   523 	  (inhibit-modification-hooks t))
   524       (when (not (overlay-get overlay 'yas/modified?))
   525 	(overlay-put overlay 'yas/modified? t)
   526 	(when (> (overlay-end overlay) end)
   527 	  (save-excursion
   528 	    (goto-char end)
   529 	    (delete-char (- (overlay-end overlay) end)))))
   530      (yas/synchronize-fields field-group))))
   531 (defun yas/overlay-maybe-insert-behind-hook (overlay after? beg end &optional length)
   532   "Insert behind hook sometimes doesn't get called. I don't know why.
   533 So I add modification hook in the big overlay and try to detect `insert-behind'
   534 event manually."
   535   (when after?
   536     (cond ((and (= beg end)
   537 		(> length 0)
   538 		(= (overlay-start overlay)
   539 		   (overlay-end overlay)))
   540 	   (yas/exit-snippet (overlay-get overlay 'yas/snippet-reference)))
   541 	  ((and (= length 0)
   542 		(> end beg)
   543 		(null (yas/current-snippet-overlay beg))
   544 		(not (bobp)))
   545 	   (let ((field-overlay (yas/current-snippet-overlay (1- beg))))
   546 	     (if field-overlay
   547 		 (when (= beg (overlay-end field-overlay))
   548 		   (move-overlay field-overlay
   549 				 (overlay-start field-overlay)
   550 				 end)
   551 		   (yas/synchronize-fields (overlay-get field-overlay 'yas/group)))
   552 	       (let ((snippet (yas/snippet-of-current-keymap))
   553 		     (done nil))
   554 		 (if snippet
   555 		     (do* ((groups (yas/snippet-groups snippet) (cdr groups))
   556 			   (group (car groups) (car groups)))
   557 			 ((or (null groups)
   558 			      done))
   559 		       (setq field-overlay (yas/field-overlay 
   560 					    (yas/group-primary-field group)))
   561 		       (when (and (= (overlay-start field-overlay)
   562 				     (overlay-end field-overlay))
   563 				  (= beg
   564 				     (overlay-start field-overlay)))
   565 			 (move-overlay field-overlay beg end)
   566 			 (yas/synchronize-fields group)
   567 			 (setq done t)))))))))))
   568 
   569 (defun yas/undo-expand-snippet (start end key snippet)
   570   "Undo a snippet expansion. Delete the overlays. This undo can't be
   571 redo-ed."
   572   (let ((undo (car buffer-undo-list)))
   573     (while (null undo)
   574       (setq buffer-undo-list (cdr buffer-undo-list))
   575       (setq undo (car buffer-undo-list)))
   576     ;; Remove this undo operation record
   577     (setq buffer-undo-list (cdr buffer-undo-list))
   578   (let ((inhibit-modification-hooks t)
   579 	(buffer-undo-list t))
   580     (yas/exit-snippet snippet)
   581     (goto-char start)
   582     (delete-char (- end start))
   583     (insert key))))
   584 
   585 (defun yas/expand-snippet (start end template)
   586   "Expand snippet at current point. Text between START and END
   587 will be deleted before inserting template."
   588   (run-hooks 'yas/before-expand-snippet-hook)
   589 
   590   (goto-char start)
   591 
   592   (let ((key (buffer-substring-no-properties start end))
   593 	(original-undo-list buffer-undo-list)
   594 	(inhibit-modification-hooks t)
   595 	(length (- end start))
   596 	(column (current-column)))
   597     (save-restriction
   598       (narrow-to-region start start)
   599 
   600       (setq buffer-undo-list t)
   601       (insert template)
   602 
   603       ;; Step 1: do necessary indent
   604       (when yas/indent-line
   605 	(let* ((indent (if indent-tabs-mode
   606 			   (concat (make-string (/ column tab-width) ?\t)
   607 				   (make-string (% column tab-width) ?\ ))
   608 			 (make-string column ?\ ))))
   609 	  (goto-char (point-min))
   610 	  (while (and (zerop (forward-line))
   611 		      (= (current-column) 0))
   612 	    (insert indent))))
   613 
   614       ;; Step 2: protect backslash and backquote
   615       (yas/replace-all "\\\\" yas/escape-backslash)
   616       (yas/replace-all "\\`" yas/escape-backquote)
   617 
   618       ;; Step 3: evaluate all backquotes
   619       (goto-char (point-min))
   620       (while (re-search-forward "`\\([^`]*\\)`" nil t)
   621 	(replace-match (yas/eval-string (match-string-no-properties 1))
   622 		       t t))
   623 
   624       ;; Step 4: protect all escapes, including backslash and backquot
   625       ;; which may be produced in Step 3
   626       (yas/replace-all "\\\\" yas/escape-backslash)
   627       (yas/replace-all "\\`" yas/escape-backquote)
   628       (yas/replace-all "\\$" yas/escape-dollar)
   629 
   630       (let ((snippet (yas/make-snippet)))
   631 	;; Step 5: Create fields
   632 	(goto-char (point-min))
   633 	(while (re-search-forward yas/field-regexp nil t)
   634 	  (let ((number (or (match-string-no-properties 1)
   635 			    (match-string-no-properties 2)))
   636 		(transform nil)
   637 		(value (match-string-no-properties 3)))
   638 	    (when (eq (elt value 0) ?\$)
   639 	      (setq transform (substring value 1))
   640 	      (setq value nil))
   641 	    (if (and number
   642 		     (string= "0" number))
   643 		(progn
   644 		  (replace-match "")
   645 		  (setf (yas/snippet-exit-marker snippet)
   646 			(copy-marker (point) t)))
   647 	      (yas/snippet-add-field
   648 	       snippet
   649 	       (yas/make-field
   650 		(make-overlay (match-beginning 0) (match-end 0))
   651 		(and number (string-to-number number))
   652 		value
   653 		transform)))))
   654 
   655 	;; Step 6: Sort and link each field group
   656 	(setf (yas/snippet-groups snippet)
   657 	      (sort (yas/snippet-groups snippet)
   658 		    '(lambda (group1 group2)
   659 		       (yas/snippet-field-compare
   660 			(yas/group-primary-field group1)
   661 			(yas/group-primary-field group2)))))
   662 	(let ((prev nil))
   663 	  (dolist (group (yas/snippet-groups snippet))
   664 	    (setf (yas/group-prev group) prev)
   665 	    (when prev
   666 	      (setf (yas/group-next prev) group))
   667 	    (setq prev group)))
   668 
   669 	;; Step 7: Create keymap overlay for snippet
   670 	(let ((overlay (make-overlay (point-min)
   671 				     (point-max)
   672 				     nil
   673 				     nil
   674 				     t)))
   675 	  (overlay-put overlay 
   676 		       'modification-hooks
   677 		       yas/keymap-overlay-modification-hooks)
   678 	  (overlay-put overlay 
   679 		       'insert-behind-hooks
   680 		       yas/keymap-overlay-modification-hooks)
   681 	  (overlay-put overlay 'keymap yas/keymap)
   682 	  (overlay-put overlay 'yas/snippet-reference snippet)
   683 	  (setf (yas/snippet-overlay snippet) overlay))
   684 	
   685 	;; Step 8: Replace fields with default values
   686 	(dolist (group (yas/snippet-groups snippet))
   687 	  (let ((value (yas/group-value group)))
   688 	    (dolist (field (yas/group-fields group))
   689 	      (let* ((overlay (yas/field-overlay field))
   690 		     (start (overlay-start overlay))
   691 		     (end (overlay-end overlay))
   692 		     (length (- end start)))
   693 		(goto-char start)
   694 		(insert (yas/calculate-field-value field value))
   695 		(delete-char length)))))
   696 
   697 	;; Step 9: restore all escape characters
   698 	(yas/replace-all yas/escape-dollar "$")
   699 	(yas/replace-all yas/escape-backquote "`")
   700 	(yas/replace-all yas/escape-backslash "\\")
   701 
   702 	;; Step 10: Set up properties of overlays
   703 	(dolist (group (yas/snippet-groups snippet))
   704 	  (let ((overlay (yas/field-overlay
   705 			  (yas/group-primary-field group))))
   706 	    (overlay-put overlay 'yas/snippet snippet)
   707 	    (overlay-put overlay 'yas/group group)
   708 	    (overlay-put overlay 'yas/modified? nil)
   709 	    (overlay-put overlay 'modification-hooks yas/overlay-modification-hooks)
   710 	    (overlay-put overlay 'insert-in-front-hooks yas/overlay-insert-in-front-hooks)
   711 	    (overlay-put overlay 'face 'yas/field-highlight-face)
   712 	    (dolist (field (yas/group-fields group))
   713 	      (unless (equal overlay (yas/field-overlay field))
   714 		(overlay-put (yas/field-overlay field)
   715 			     'face 
   716 			     'yas/mirror-highlight-face)))))
   717 
   718 	;; Step 11: move to end and make sure exit-marker exist
   719 	(goto-char (point-max))
   720 	(unless (yas/snippet-exit-marker snippet)
   721 	  (setf (yas/snippet-exit-marker snippet) (copy-marker (point) t)))
   722 
   723 	;; Step 12: Construct undo information
   724 	(unless (eq original-undo-list t)
   725 	  (add-to-list 'original-undo-list
   726 		       `(apply yas/undo-expand-snippet
   727 			       ,(point-min)
   728 			       ,(point-max)
   729 			       ,key
   730 			       ,snippet)))
   731 
   732 	;; Step 13: remove the trigger key
   733 	(widen)
   734 	(delete-char length)
   735 
   736 	(setq buffer-undo-list original-undo-list)
   737 
   738 	;; Step 14: place the cursor at a proper place
   739 	(let ((groups (yas/snippet-groups snippet))
   740 	      (exit-marker (yas/snippet-exit-marker snippet)))
   741 	  (if groups
   742 	      (goto-char (overlay-start 
   743 			  (yas/field-overlay
   744 			   (yas/group-primary-field
   745 			    (car groups)))))
   746 	    ;; no need to call exit-snippet, since no overlay created.
   747 	    (yas/exit-snippet snippet)))))))
   748 
   749 (defun yas/current-snippet-overlay (&optional point)
   750   "Get the most proper overlay which is belongs to a snippet."
   751   (let ((point (or point (point)))
   752 	(snippet-overlay nil))
   753     (dolist (overlay (overlays-at point))
   754       (when (overlay-get overlay 'yas/snippet)
   755 	(if (null snippet-overlay)
   756 	    (setq snippet-overlay overlay)
   757 	  (when (> (yas/snippet-id (overlay-get overlay 'yas/snippet))
   758 		   (yas/snippet-id (overlay-get snippet-overlay 'yas/snippet)))
   759 	    (setq snippet-overlay overlay)))))
   760     snippet-overlay))
   761 
   762 (defun yas/snippet-of-current-keymap (&optional point)
   763   "Get the snippet holding the snippet keymap under POINT."
   764   (let ((point (or point (point)))
   765 	(keymap-snippet nil)
   766 	(snippet nil))
   767     (dolist (overlay (overlays-at point))
   768       (setq snippet (overlay-get overlay 'yas/snippet-reference))
   769       (when snippet
   770 	(if (null keymap-snippet)
   771 	    (setq keymap-snippet snippet)
   772 	  (when (> (yas/snippet-id snippet)
   773 		   (yas/snippet-id keymap-snippet))
   774 	    (setq keymap-snippet snippet)))))
   775     keymap-snippet))
   776 
   777 (defun yas/current-overlay-for-navigation ()
   778   "Get current overlay for navigation. Might be overlay at current or previous point."
   779   (let ((overlay1 (yas/current-snippet-overlay))
   780 	(overlay2 (if (bobp)
   781 		      nil
   782 		    (yas/current-snippet-overlay (- (point) 1)))))
   783     (if (null overlay1)
   784 	overlay2
   785       (if (or (null overlay2)
   786 	      (eq (overlay-get overlay1 'yas/snippet) 
   787 		  (overlay-get overlay2 'yas/snippet)))
   788 	  overlay1
   789 	(if (> (yas/snippet-id (overlay-get overlay2 'yas/snippet))
   790 	       (yas/snippet-id (overlay-get overlay1 'yas/snippet)))
   791 	    overlay2
   792 	  overlay1)))))
   793 
   794 (defun yas/navigate-group (group next?)
   795   "Go to next of previous field group. Exit snippet if none."
   796   (let ((target (if next?
   797 		    (yas/group-next group)
   798 		  (yas/group-prev group))))
   799     (if target
   800 	(goto-char (overlay-start
   801 		    (yas/field-overlay
   802 		     (yas/group-primary-field target))))
   803       (yas/exit-snippet (yas/group-snippet group)))))
   804 
   805 (defun yas/parse-template ()
   806   "Parse the template in the current buffer.
   807 If the buffer contains a line of \"# --\" then the contents
   808 above this line are ignored. Variables can be set above this
   809 line through the syntax:
   810 
   811 #name : value
   812 
   813 Here's a list of currently recognized variables:
   814 
   815  * name
   816  * contributor
   817  * condition
   818 
   819 #name: #include \"...\"
   820 # --
   821 #include \"$1\""
   822   (goto-char (point-min))
   823   (let (template name bound condition)
   824     (if (re-search-forward "^# --\n" nil t)
   825 	(progn (setq template 
   826 		     (buffer-substring-no-properties (point) 
   827 						     (point-max)))
   828 	       (setq bound (point))
   829 	       (goto-char (point-min))
   830 	       (while (re-search-forward "^#\\([^ ]+\\) *: *\\(.*\\)$" bound t)
   831 		 (when (string= "name" (match-string-no-properties 1))
   832 		   (setq name (match-string-no-properties 2)))
   833 		 (when (string= "condition" (match-string-no-properties 1))
   834 		   (setq condition (read (match-string-no-properties 2))))))
   835       (setq template
   836 	    (buffer-substring-no-properties (point-min) (point-max))))
   837     (list template name condition)))
   838 
   839 (defun yas/directory-files (directory file?)
   840   "Return directory files or subdirectories in full path."
   841   (remove-if (lambda (file)
   842 	       (or (string-match "^\\."
   843 				 (file-name-nondirectory file))
   844 		   (if file?
   845 		       (file-directory-p file)
   846 		     (not (file-directory-p file)))))
   847 	     (directory-files directory t)))
   848 
   849 (defun yas/make-menu-binding (template)
   850   (lexical-let ((template template))
   851     (lambda ()
   852       (interactive)
   853       (yas/expand-snippet (point) 
   854 			  (point)
   855 			  template))))
   856 
   857 (defun yas/modify-alist (alist key value)
   858   "Modify ALIST to map KEY to VALUE. return the new alist."
   859   (let ((pair (assoc key alist)))
   860     (if (null pair)
   861 	(cons (cons key value)
   862 	      alist)
   863       (setcdr pair value)
   864       alist)))
   865 
   866 (defun yas/fake-keymap-for-popup (templates)
   867   "Create a fake keymap for popup menu usage."
   868   (cons 'keymap 
   869 	(mapcar (lambda (pair)
   870 		  (let* ((template (cdr pair))
   871 			 (name (yas/template-name template))
   872 			 (content (yas/template-content template)))
   873 		    (list content 'menu-item name t)))
   874 		templates)))
   875 
   876 (defun yas/point-to-coord (&optional point)
   877   "Get the xoffset/yoffset information of POINT.
   878 If POINT is not given, default is to current point.
   879 If `posn-at-point' is not available (like in Emacs 21.3),
   880 t is returned simply."
   881   (if (fboundp 'posn-at-point)
   882       (let ((x-y (posn-x-y (posn-at-point (or point (point))))))
   883 	(list (list (+ (car x-y) 10)
   884 		    (+ (cdr x-y) 20))
   885 	      (selected-window)))
   886     t))
   887  
   888 (defun yas/x-popup-menu-for-template (templates)
   889   "Show a popup menu listing templates to let the user select one."
   890   (car (x-popup-menu (yas/point-to-coord)
   891 		     (yas/fake-keymap-for-popup templates))))
   892 (defun yas/text-popup-for-template (templates)
   893   "Can't display popup menu in text mode. Just select the first one."
   894   (yas/template-content (cdar templates)))
   895 (defun yas/dropdown-list-popup-for-template (templates)
   896   "Use dropdown-list.el to popup for templates. Better than the 
   897 default \"select first\" behavior of `yas/text-popup-for-template'.
   898 You can also use this in window-system.
   899 
   900 NOTE: You need to download and install dropdown-list.el to use this."
   901   (if (fboundp 'dropdown-list)
   902       (let ((n (dropdown-list (mapcar (lambda (i)
   903 					(yas/template-name
   904 					 (cdr i)))
   905 				      templates))))
   906 	(if n
   907 	    (yas/template-content
   908 	     (cdr (nth n templates)))
   909 	  nil))
   910     (error "Please download and install dropdown-list.el to use this")))
   911 
   912 (defun yas/popup-for-template (templates)
   913   (if window-system
   914       (funcall yas/window-system-popup-function templates)
   915     (funcall yas/text-popup-function templates)))
   916 
   917 (defun yas/load-directory-1 (directory &optional parent)
   918   "Really do the job of loading snippets from a directory 
   919 hierarchy."
   920   (let ((mode-sym (intern (file-name-nondirectory directory)))
   921 	(snippets nil))
   922     (with-temp-buffer
   923       (dolist (file (yas/directory-files directory t))
   924 	(when (file-readable-p file)
   925 	  (insert-file-contents file nil nil nil t)
   926 	  (push (cons (file-name-nondirectory file)
   927 		      (yas/parse-template))
   928 		snippets))))
   929     (yas/define-snippets mode-sym
   930 			 snippets
   931 			 parent)
   932     (dolist (subdir (yas/directory-files directory nil))
   933       (yas/load-directory-1 subdir mode-sym))))
   934 
   935 (defun yas/quote-string (string)
   936   "Escape and quote STRING.
   937 foo\"bar\\! -> \"foo\\\"bar\\\\!\""
   938   (concat "\""
   939 	  (replace-regexp-in-string "[\\\"]"
   940 				    "\\\\\\&"
   941 				    string
   942 				    t)
   943 	  "\""))
   944 
   945 (defun yas/compile-bundle
   946   (&optional yasnippet yasnippet-bundle snippet-roots code)
   947   "Compile snippets in SNIPPET-ROOTS to a single bundle file.
   948 SNIPPET-ROOTS is a list of root directories that contains the snippets
   949 definition. YASNIPPET is the yasnippet.el file path. YASNIPPET-BUNDLE
   950 is the output file of the compile result. CODE is the code you would
   951 like to used to initialize yasnippet. Here's the default value for
   952 all the parameters:
   953 
   954  (yas/compile-bundle \"yasnippet.el\"
   955                      \"./yasnippet-bundle.el\"
   956                      '(\"snippets\")
   957                      \"(yas/initialize)\")"
   958   (when (null yasnippet)
   959     (setq yasnippet "yasnippet.el"))
   960   (when (null yasnippet-bundle)
   961     (setq yasnippet-bundle "./yasnippet-bundle.el"))
   962   (when (null snippet-roots)
   963     (setq snippet-roots '("snippets")))
   964   (when (null code)
   965     (setq code "(yas/initialize)"))
   966 
   967   (let ((dirs (or (and (listp snippet-roots) snippet-roots)
   968 		  (list snippet-roots)))
   969 	(bundle-buffer nil))
   970     (with-temp-buffer
   971       (setq bundle-buffer (current-buffer))
   972       (insert-file-contents yasnippet)
   973       (goto-char (point-max))
   974       (insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n")
   975       (insert ";;;;      Auto-generated code         ;;;;\n")
   976       (insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n")
   977       (insert code "\n")
   978       (flet ((yas/define-snippets 
   979 	      (mode snippets &optional parent)
   980 	      (with-current-buffer bundle-buffer
   981 		(insert ";;; snippets for " (symbol-name mode) "\n")
   982 		(insert "(yas/define-snippets '" (symbol-name mode) "\n")
   983 		(insert "'(\n")
   984 		(dolist (snippet snippets)
   985 		  (insert "  (" 
   986 			  (yas/quote-string (car snippet))
   987 			  " "
   988 			  (yas/quote-string (cadr snippet))
   989 			  " "
   990 			  (if (caddr snippet)
   991 			      (yas/quote-string (caddr snippet))
   992 			    "nil")
   993 			  " "
   994 			  (if (nth 3 snippet)
   995 			      (format "'%s" (nth 3 snippet))
   996 			    "nil")
   997 			  ")\n"))
   998 		(insert "  )\n")
   999 		(insert (if parent
  1000 			    (concat "'" (symbol-name parent))
  1001 			  "nil")
  1002 			")\n\n"))))
  1003 	    (dolist (dir dirs)
  1004 	      (dolist (subdir (yas/directory-files dir nil))
  1005 		(yas/load-directory-1 subdir nil))))
  1006       (insert "(provide '"
  1007 	      (file-name-nondirectory
  1008 	       (file-name-sans-extension
  1009 		yasnippet-bundle))
  1010 	      ")\n")
  1011       (setq buffer-file-name yasnippet-bundle)
  1012       (save-buffer))))
  1013 
  1014 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1015 ;; User level functions
  1016 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1017 (defun yas/about ()
  1018   (interactive)
  1019   (message (concat "yasnippet (version "
  1020 		   yas/version
  1021 		   ") -- pluskid <pluskid@gmail.com>")))
  1022 (defun yas/reload-all ()
  1023   "Reload all snippets."
  1024   (interactive)
  1025   (if yas/root-directory
  1026       (if (listp yas/root-directory)
  1027 	  (dolist (directory yas/root-directory)
  1028 	    (yas/load-directory directory))
  1029 	(yas/load-directory yas/root-directory))
  1030     (call-interactively 'yas/load-directory))
  1031   (message "done."))
  1032 
  1033 (defun yas/load-directory (directory)
  1034   "Load snippet definition from a directory hierarchy.
  1035 Below the top-level directory, each directory is a mode
  1036 name. And under each subdirectory, each file is a definition
  1037 of a snippet. The file name is the trigger key and the
  1038 content of the file is the template."
  1039   (interactive "DSelect the root directory: ")
  1040   (when (and (interactive-p)
  1041 	     (file-directory-p directory))
  1042     (add-to-list 'yas/root-directory directory))
  1043   (dolist (dir (yas/directory-files directory nil))
  1044     (yas/load-directory-1 dir))
  1045   (when (interactive-p)
  1046     (message "done.")))
  1047 
  1048 (defun yas/initialize ()
  1049   "Do necessary initialization."
  1050   (add-hook 'after-change-major-mode-hook
  1051 	    'yas/minor-mode-on)
  1052   (dolist (hook yas/extra-mode-hooks)
  1053     (add-hook hook
  1054 	      'yas/minor-mode-on))
  1055   (add-hook 'yas/minor-mode-on-hook
  1056 	    'yas/ensure-minor-mode-priority)
  1057   (when yas/use-menu
  1058     (define-key-after 
  1059       (lookup-key global-map [menu-bar])
  1060       [yasnippet]
  1061       (cons "YASnippet" yas/menu-keymap)
  1062       'buffer)))
  1063 
  1064 (defun yas/define-snippets (mode snippets &optional parent-mode)
  1065   "Define snippets for MODE. SNIPPETS is a list of
  1066 snippet definition, of the following form:
  1067 
  1068  (KEY TEMPLATE NAME CONDITION)
  1069 
  1070 or the NAME and CONDITION may be omitted. The optional 3rd
  1071 parameter can be used to specify the parent mode of MODE. That
  1072 is, when looking a snippet in MODE failed, it can refer to its
  1073 parent mode. The PARENT-MODE may not need to be a real mode."
  1074   (let ((snippet-table (yas/snippet-table mode))
  1075 	(parent-table (if parent-mode
  1076 			  (yas/snippet-table parent-mode)
  1077 			nil))
  1078 	(keymap (if yas/use-menu
  1079 		    (yas/menu-keymap-for-mode mode)
  1080 		  nil)))
  1081     (when parent-table
  1082       (setf (yas/snippet-table-parent snippet-table)
  1083 	    parent-table)
  1084       (when yas/use-menu
  1085 	(define-key keymap (vector 'parent-mode)
  1086 	  `(menu-item "parent mode"
  1087 		      ,(yas/menu-keymap-for-mode parent-mode)))))
  1088     (when (and yas/use-menu
  1089 	       (yas/real-mode? mode))
  1090       (define-key yas/menu-keymap (vector mode)
  1091 	`(menu-item ,(symbol-name mode) ,keymap)))
  1092     (dolist (snippet snippets)
  1093       (let* ((full-key (car snippet))
  1094 	     (key (file-name-sans-extension full-key))
  1095 	     (name (caddr snippet))
  1096 	     (condition (nth 3 snippet))
  1097 	     (template (yas/make-template (cadr snippet)
  1098 					  (or name key)
  1099 					  condition)))
  1100 	(yas/snippet-table-store snippet-table
  1101 				 full-key
  1102 				 key
  1103 				 template)
  1104 	(when yas/use-menu
  1105 	  (define-key keymap (vector (make-symbol full-key))
  1106 	    `(menu-item ,(yas/template-name template)
  1107 			,(yas/make-menu-binding (yas/template-content template))
  1108 			:keys ,(concat key yas/trigger-symbol))))))))
  1109 
  1110 (defun yas/set-mode-parent (mode parent)
  1111   "Set parent mode of MODE to PARENT."
  1112   (setf (yas/snippet-table-parent
  1113 	 (yas/snippet-table mode))
  1114 	(yas/snippet-table parent))
  1115   (when yas/use-menu
  1116     (define-key (yas/menu-keymap-for-mode mode) (vector 'parent-mode)
  1117       `(menu-item "parent mode"
  1118 		  ,(yas/menu-keymap-for-mode parent)))))
  1119 
  1120 (defun yas/define (mode key template &optional name condition)
  1121   "Define a snippet. Expanding KEY into TEMPLATE.
  1122 NAME is a description to this template. Also update
  1123 the menu if `yas/use-menu' is `t'. CONDITION is the
  1124 condition attached to this snippet. If you attach a
  1125 condition to a snippet, then it will only be expanded
  1126 when the condition evaluated to non-nil."
  1127   (yas/define-snippets mode
  1128 		       (list (list key template name condition))))
  1129     
  1130 
  1131 (defun yas/hippie-try-expand (first-time?)
  1132   "Integrate with hippie expand. Just put this function in
  1133 `hippie-expand-try-functions-list'."
  1134   (if (not first-time?)
  1135       (let ((yas/fallback-behavior 'return-nil))
  1136 	(yas/expand))
  1137     (when (and (null (car buffer-undo-list))
  1138 	       (eq 'apply
  1139 		   (car (cadr buffer-undo-list)))
  1140 	       (eq 'yas/undo-expand-snippet
  1141 		   (cadr (cadr buffer-undo-list))))
  1142       (undo 1))
  1143     nil))
  1144 
  1145 (defun yas/expand ()
  1146   "Expand a snippet."
  1147   (interactive)
  1148   (let ((local-condition (yas/template-condition-predicate
  1149 			  yas/buffer-local-condition)))
  1150     (if local-condition
  1151 	(let ((yas/require-template-condition 
  1152 	       (if (and (consp local-condition)
  1153 			(eq 'require-snippet-condition (car local-condition))
  1154 			(symbolp (cdr local-condition)))
  1155 		   (cdr local-condition)
  1156 		 nil)))
  1157 	  (multiple-value-bind (templates start end) (yas/current-key)
  1158 	    (if templates
  1159 		(let ((template (if (null (cdr templates)) ; only 1 template
  1160 				    (yas/template-content (cdar templates))
  1161 				  (yas/popup-for-template templates))))
  1162 		  (if template
  1163 		    (progn (yas/expand-snippet start end template)
  1164 			   'expanded)	; expanded successfully
  1165 		    'interruptted))	; interrupted by user
  1166 	      (if (eq yas/fallback-behavior 'return-nil)
  1167 		  nil			; return nil
  1168 		(let* ((yas/minor-mode nil)
  1169 		       (command (key-binding yas/trigger-key)))
  1170 		  (when (commandp command)
  1171 		    (call-interactively command))))))))))
  1172       
  1173 (defun yas/next-field-group ()
  1174   "Navigate to next field group. If there's none, exit the snippet."
  1175   (interactive)
  1176   (let ((overlay (yas/current-overlay-for-navigation)))
  1177     (if overlay
  1178 	(yas/navigate-group (overlay-get overlay 'yas/group) t)
  1179       (let ((snippet (yas/snippet-of-current-keymap))
  1180 	    (done nil))
  1181 	(if snippet
  1182 	    (do* ((groups (yas/snippet-groups snippet) (cdr groups))
  1183 		  (group (car groups) (car groups)))
  1184 		((or (null groups)
  1185 		     done)
  1186 		 (unless done 
  1187 		   (let* ((overlay (yas/snippet-overlay snippet))
  1188 			  (keymap (overlay-get overlay 'keymap))
  1189 			  (command nil))
  1190 		     (overlay-put overlay 'keymap nil)
  1191 		     (overlay-put overlay 'yas/snippet-reference nil)
  1192 		     (setq command (key-binding yas/next-field-key))
  1193 		     (when (commandp command)
  1194 		       (call-interactively command))
  1195 		     (overlay-put overlay 'keymap keymap)
  1196 		     (overlay-put overlay 'yas/snippet-reference snippet))))
  1197 	      (when (= (point)
  1198 		       (overlay-start
  1199 			(yas/field-overlay
  1200 			 (yas/group-primary-field group))))
  1201 		(setq done t)
  1202 		(yas/navigate-group group t))))))))
  1203 
  1204 (defun yas/prev-field-group ()
  1205   "Navigate to prev field group. If there's none, exit the snippet."
  1206   (interactive)
  1207   (let ((overlay (yas/current-overlay-for-navigation)))
  1208     (if overlay
  1209 	(yas/navigate-group (overlay-get overlay 'yas/group) nil)
  1210       (let ((snippet (yas/snippet-of-current-keymap))
  1211 	    (done nil))
  1212 	(if snippet
  1213 	  (do* ((groups (yas/snippet-groups snippet) (cdr groups))
  1214 		(group (car groups) (car groups)))
  1215 	      ((or (null groups)
  1216 		   done)
  1217 	       (unless done (message "Not in a snippet field.")))
  1218 	    (when (= (point)
  1219 		     (overlay-start
  1220 		      (yas/field-overlay
  1221 		       (yas/group-primary-field group))))
  1222 	      (setq done t)
  1223 	      (yas/navigate-group group nil)))
  1224 	  (message "Not in a snippet field."))))))
  1225 
  1226 (defun yas/exit-snippet (snippet)
  1227   "Goto exit-marker of SNIPPET and delete the snippet."
  1228   (interactive)
  1229   (let ((overlay (yas/snippet-overlay snippet)))
  1230     (let ((yas/snippet-beg (overlay-start overlay))
  1231 	  (yas/snippet-end (overlay-end overlay)))
  1232       (goto-char (yas/snippet-exit-marker snippet))
  1233       (delete-overlay overlay)
  1234       (dolist (group (yas/snippet-groups snippet))
  1235 	(dolist (field (yas/group-fields group))
  1236 	  (delete-overlay (yas/field-overlay field))))
  1237 
  1238       (run-hooks 'yas/after-exit-snippet-hook))))
  1239 
  1240 (provide 'yasnippet)
  1241 
  1242 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1243 ;; Monkey patching for other functions that's causing
  1244 ;; problems to yasnippet. For details on why I patch
  1245 ;; those functions, refer to
  1246 ;;   http://code.google.com/p/yasnippet/wiki/MonkeyPatching
  1247 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1248 (defadvice c-neutralize-syntax-in-CPP
  1249   (around yas-mp/c-neutralize-syntax-in-CPP activate)
  1250   "Adviced `c-neutralize-syntax-in-CPP' to properly 
  1251 handle the end-of-buffer error fired in it by calling
  1252 `forward-char' at the end of buffer."
  1253   (condition-case err
  1254       ad-do-it
  1255     (error (message (error-message-string err)))))
  1256 
  1257 
  1258 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1259 ;; Contents of dropdown-list.el
  1260 ;;
  1261 ;; dropdown-list.el is used by yasnippet to select multiple
  1262 ;; candidate snippets.
  1263 ;;
  1264 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1265 ;;; dropdown-list.el --- Drop-down menu interface
  1266 ;;
  1267 ;; Filename: dropdown-list.el
  1268 ;; Description: Drop-down menu interface
  1269 ;; Author: Jaeyoun Chung [jay.chung@gmail.com]
  1270 ;; Maintainer:
  1271 ;; Copyright (C) 2008 Jaeyoun Chung
  1272 ;; Created: Sun Mar 16 11:20:45 2008 (Pacific Daylight Time)
  1273 ;; Version: 
  1274 ;; Last-Updated: Sun Mar 16 12:19:49 2008 (Pacific Daylight Time)
  1275 ;;           By: dradams
  1276 ;;     Update #: 43
  1277 ;; URL: http://www.emacswiki.org/cgi-bin/wiki/dropdown-list.el
  1278 ;; Keywords: convenience menu
  1279 ;; Compatibility: GNU Emacs 21.x, GNU Emacs 22.x
  1280 ;;
  1281 ;; Features that might be required by this library:
  1282 ;;
  1283 ;;   `cl'.
  1284 ;;
  1285 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1286 ;;
  1287 ;;; Commentary:
  1288 ;;
  1289 ;;  According to Jaeyoun Chung, "overlay code stolen from company-mode.el."
  1290 ;;
  1291 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1292 ;;
  1293 ;;; Change log:
  1294 ;;
  1295 ;; 2008/03/16 dadams
  1296 ;;     Clean-up - e.g. use char-to-string for control chars removed by email posting.
  1297 ;;     Moved example usage code (define-key*, command-selector) inside the library.
  1298 ;;     Require cl.el at byte-compile time.
  1299 ;;     Added GPL statement.
  1300 ;; 2008/01/06 Jaeyoun Chung
  1301 ;;     Posted to gnu-emacs-sources@gnu.org at 9:10 p.m.
  1302 ;;
  1303 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1304 ;;
  1305 ;; This program is free software; you can redistribute it and/or
  1306 ;; modify it under the terms of the GNU General Public License as
  1307 ;; published by the Free Software Foundation; either version 3, or
  1308 ;; (at your option) any later version.
  1309 ;;
  1310 ;; This program is distributed in the hope that it will be useful,
  1311 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  1312 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  1313 ;; General Public License for more details.
  1314 ;;
  1315 ;; You should have received a copy of the GNU General Public License
  1316 ;; along with this program; see the file COPYING.  If not, write to
  1317 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  1318 ;; Floor, Boston, MA 02110-1301, USA.
  1319 ;;
  1320 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1321 ;;
  1322 ;;; Code:
  1323 
  1324 (eval-when-compile (require 'cl)) ;; decf, fourth, incf, loop, mapcar*
  1325 
  1326 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1327 
  1328 (defface dropdown-list-face
  1329     '((t :inherit default :background "lightyellow" :foreground "black"))
  1330   "*Bla." :group 'dropdown-list)
  1331 
  1332 (defface dropdown-list-selection-face
  1333     '((t :inherit dropdown-list :background "purple"))
  1334   "*Bla." :group 'dropdown-list)
  1335 
  1336 (defvar dropdown-list-overlays nil)
  1337 
  1338 (defun dropdown-list-hide ()
  1339   (while dropdown-list-overlays
  1340     (delete-overlay (pop dropdown-list-overlays))))
  1341 
  1342 (defun dropdown-list-put-overlay (beg end &optional prop value prop2 value2)
  1343   (let ((ov (make-overlay beg end)))
  1344     (overlay-put ov 'window t)
  1345     (when prop
  1346       (overlay-put ov prop value)
  1347       (when prop2 (overlay-put ov prop2 value2)))
  1348     ov))
  1349 
  1350 (defun dropdown-list-line (start replacement &optional no-insert)
  1351   ;; start might be in the middle of a tab, which means we need to hide the
  1352   ;; tab and add spaces
  1353   (let ((end (+ start (length replacement)))
  1354         beg-point end-point
  1355         before-string after-string)
  1356     (goto-char (point-at-eol))
  1357     (if (< (current-column) start)
  1358         (progn (setq before-string (make-string (- start (current-column)) ? ))
  1359                (setq beg-point (point)))
  1360       (goto-char (point-at-bol)) ;; Emacs bug, move-to-column is wrong otherwise
  1361       (move-to-column start)
  1362       (setq beg-point (point))
  1363       (when (> (current-column) start)
  1364         (goto-char (1- (point)))
  1365         (setq beg-point (point))
  1366         (setq before-string (make-string (- start (current-column)) ? ))))
  1367     (move-to-column end)
  1368     (setq end-point (point))
  1369     (let ((end-offset (- (current-column) end)))
  1370       (when (> end-offset 0) (setq after-string (make-string end-offset ?b))))
  1371     (when no-insert
  1372       ;; prevent inheriting of faces
  1373       (setq before-string (when before-string (propertize before-string 'face 'default)))
  1374       (setq after-string (when after-string (propertize after-string 'face 'default))))
  1375     (let ((string (concat before-string replacement after-string)))
  1376       (if no-insert
  1377           string
  1378         (push (dropdown-list-put-overlay beg-point end-point 'invisible t
  1379                                          'after-string string)
  1380               dropdown-list-overlays)))))
  1381 
  1382 (defun dropdown-list-start-column (display-width)
  1383   (let ((column (mod (current-column) (window-width)))
  1384         (width (window-width)))
  1385     (cond ((<= (+ column display-width) width) column)
  1386           ((> column display-width) (- column display-width))
  1387           ((>= width display-width) (- width display-width))
  1388           (t nil))))
  1389 
  1390 (defun dropdown-list-move-to-start-line (candidate-count)
  1391   (decf candidate-count)
  1392   (let ((above-line-count (save-excursion (- (vertical-motion (- candidate-count)))))
  1393         (below-line-count (save-excursion (vertical-motion candidate-count))))
  1394     (cond ((= below-line-count candidate-count)
  1395            t)
  1396           ((= above-line-count candidate-count)
  1397            (vertical-motion (- candidate-count))
  1398            t)
  1399           ((>= (+ below-line-count above-line-count) candidate-count)
  1400            (vertical-motion (- (- candidate-count below-line-count)))
  1401            t)
  1402           (t nil))))
  1403 
  1404 (defun dropdown-list-at-point (candidates &optional selidx)
  1405   (dropdown-list-hide)
  1406   (let* ((lengths (mapcar #'length candidates))
  1407          (max-length (apply #'max lengths))
  1408          (start (dropdown-list-start-column (+ max-length 3)))
  1409          (i -1)
  1410          (candidates (mapcar* (lambda (candidate length)
  1411                                 (let ((diff (- max-length length)))
  1412                                   (propertize
  1413                                    (concat (if (> diff 0)
  1414                                                (concat candidate (make-string diff ? ))
  1415                                              (substring candidate 0 max-length))
  1416                                            (format "%3d" (+ 2 i)))
  1417                                    'face (if (eql (incf i) selidx)
  1418                                              'dropdown-list-selection-face
  1419                                            'dropdown-list-face))))
  1420                               candidates
  1421                               lengths)))
  1422     (save-excursion
  1423       (and start
  1424            (dropdown-list-move-to-start-line (length candidates))
  1425            (loop initially (vertical-motion 0)
  1426               for candidate in candidates
  1427               do (dropdown-list-line (+ (current-column) start) candidate)
  1428               while (/= (vertical-motion 1) 0)
  1429               finally return t)))))
  1430 
  1431 (defun dropdown-list (candidates)
  1432   (let ((selection)
  1433         (temp-buffer))
  1434     (save-window-excursion
  1435       (unwind-protect
  1436            (let ((candidate-count (length candidates))
  1437                  done key selidx)
  1438              (while (not done)
  1439                (unless (dropdown-list-at-point candidates selidx)
  1440                  (switch-to-buffer (setq temp-buffer (get-buffer-create "*selection*"))
  1441                                    'norecord)
  1442                  (delete-other-windows)
  1443                  (delete-region (point-min) (point-max))
  1444                  (insert (make-string (length candidates) ?\n))
  1445                  (goto-char (point-min))
  1446                  (dropdown-list-at-point candidates selidx))
  1447                (setq key (read-key-sequence ""))
  1448                (cond ((and (stringp key)
  1449                            (>= (aref key 0) ?1)
  1450                            (<= (aref key 0) (+ ?0 (min 9 candidate-count))))
  1451                       (setq selection (- (aref key 0) ?1)
  1452                             done      t))
  1453                      ((member key `(,(char-to-string ?\C-p) [up]))
  1454                       (setq selidx (mod (+ candidate-count (1- (or selidx 0)))
  1455                                         candidate-count)))
  1456                      ((member key `(,(char-to-string ?\C-n) [down]))
  1457                       (setq selidx (mod (1+ (or selidx -1)) candidate-count)))
  1458                      ((member key `(,(char-to-string ?\f))))
  1459                      ((member key `(,(char-to-string ?\r) [return]))
  1460                       (setq selection selidx
  1461                             done      t))
  1462                      (t (setq done t)))))
  1463         (dropdown-list-hide)
  1464         (and temp-buffer (kill-buffer temp-buffer)))
  1465       ;;     (when selection
  1466       ;;       (message "your selection => %d: %s" selection (nth selection candidates))
  1467       ;;       (sit-for 1))
  1468       selection)))
  1469 
  1470 (defun define-key* (keymap key command)
  1471   "Add COMMAND to the multiple-command binding of KEY in KEYMAP.
  1472 Use multiple times to bind different COMMANDs to the same KEY."
  1473   (define-key keymap key (combine-command command (lookup-key keymap key))))
  1474 
  1475 (defun combine-command (command defs)
  1476   "$$$$$ FIXME - no doc string"
  1477   (cond ((null defs) command)
  1478         ((and (listp defs)
  1479               (eq 'lambda (car defs))
  1480               (= (length defs) 4)
  1481               (listp (fourth defs))
  1482               (eq 'command-selector (car (fourth defs))))
  1483          (unless (member `',command (cdr (fourth defs)))
  1484            (setcdr (fourth defs) (nconc (cdr (fourth defs)) `(',command))))
  1485          defs)
  1486         (t
  1487          `(lambda () (interactive) (command-selector ',defs ',command)))))
  1488 
  1489 (defvar command-selector-last-command nil "$$$$$ FIXME - no doc string")
  1490 
  1491 (defun command-selector (&rest candidates)
  1492   "$$$$$ FIXME - no doc string"
  1493   (if (and (eq last-command this-command) command-selector-last-command)
  1494       (call-interactively command-selector-last-command)
  1495     (let* ((candidate-strings
  1496             (mapcar (lambda (candidate)
  1497                       (format "%s" (if (symbolp candidate)
  1498                                        candidate
  1499                                      (let ((s (format "%s" candidate)))
  1500                                        (if (>= (length s) 7)
  1501                                            (concat (substring s 0 7) "...")
  1502                                          s)))))
  1503                     candidates))
  1504            (selection (dropdown-list candidate-strings)))
  1505       (when selection
  1506         (let ((cmd (nth selection candidates)))
  1507           (call-interactively cmd)
  1508           (setq command-selector-last-command cmd))))))
  1509 
  1510 ;;;;;;;;;;;;;;;;;;;;
  1511 
  1512 (provide 'dropdown-list)
  1513 
  1514 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1515 ;;; dropdown-list.el ends here
  1516