* merged from trunk finally (expect more bugs)

* fixed indentation working
* auto-indentation apparently working with dirty hack
* , but did get to see the famous python bug twice,
* contrived existing python snippets are working, even with `yas/indent-line' set to 'auto
* fixed more bugs...
This commit is contained in:
capitaomorte 2009-07-16 16:00:02 +00:00
parent c15f037874
commit c454bd2451

View File

@ -1,10 +1,13 @@
;;; yasnippet.el --- Yet another snippet extension for Emacs. ;;; yasnippet.el --- Yet another snippet extension for Emacs.
;; Copyright 2008 pluskid ;; Copyright 2008 pluskid
;;
;; Authors: pluskid <pluskid@gmail.com>, joaotavora <joaotavora@gmail.com> ;; Authors: pluskid <pluskid@gmail.com>, joaotavora <joaotavora@gmail.com>
;; Version: 0.6.0 ;; Version: 0.6.0
;; X-URL: http://code.google.com/p/yasnippet/ ;; X-URL: http://code.google.com/p/yasnippet/
;; Keywords: snippet, textmate
;; URL: http://code.google.com/p/yasnippet/
;; EmacsWiki: YaSnippetMode
;; This file is free software; you can redistribute it and/or modify ;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by ;; it under the terms of the GNU General Public License as published by
@ -35,7 +38,9 @@
;; For more information and detailed usage, refer to the project page: ;; For more information and detailed usage, refer to the project page:
;; http://code.google.com/p/yasnippet/ ;; http://code.google.com/p/yasnippet/
(require 'cl) ;;; Code:
(eval-when-compile (require 'cl))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; User customizable variables ;; User customizable variables
@ -244,34 +249,43 @@ Attention: These hooks are not run when exiting nested/stackd snippet expansion!
(defvar yas/buffer-local-condition (defvar yas/buffer-local-condition
'(if (and (not (bobp)) '(if (and (not (bobp))
(or (equal "font-lock-comment-face" (or (equal 'font-lock-comment-face
(get-char-property (1- (point)) (get-char-property (1- (point))
'face)) 'face))
(equal "font-lock-string-face" (equal 'font-lock-string-face
(get-char-property (1- (point)) (get-char-property (1- (point))
'face)))) 'face))))
'(require-snippet-condition . force-in-comment) '(require-snippet-condition . force-in-comment)
t) t)
"Condition to yasnippet local to each buffer. "Condition to yasnippet local to each buffer.
The default value helps filtering out potential snippet
expansions inside comments and string literals, unless the
snippet itself contains a condition that returns the symbol
`force-in-comment'.
* If yas/buffer-local-condition evaluate to nil, snippet * If yas/buffer-local-condition evaluate to nil, snippet
won't be expanded. won't be expanded.
* If it evaluate to the a cons cell where the car is the * If it evaluate to the a cons cell where the car is the
symbol require-snippet-condition and the cdr is a symbol `require-snippet-condition' and the cdr is a
symbol (let's call it requirement): symbol (let's call it \"requirement\"):
* If the snippet has no condition, then it won't be * If the snippet has no condition, then it won't be
expanded. expanded.
* If the snippet has a condition but evaluate to nil or * If the snippet has a condition but it evaluates to nil or
error occured during evaluation, it won't be expanded. error occured during evaluation, it won't be expanded.
* If the snippet has a condition that evaluate to * If the snippet has a condition that evaluate to
non-nil (let's call it result): non-nil (let's call it \"result\"):
* If requirement is t, the snippet is ready to be * If \"requirement\" is t, the snippet is ready to be
expanded. expanded.
* If requirement is eq to result, the snippet is ready * If \"requirement\" is eq to \"result\", the snippet is ready
to be expanded. to be expanded.
* Otherwise the snippet won't be expanded. * Otherwise the snippet won't be expanded.
* If it evaluate to other non-nil value:
* If it evaluates to `always', snippet is unconditionally
expanded.
* If it evaluates to other non-nil value:
* If the snippet has no condition, or has a condition that * If the snippet has no condition, or has a condition that
evaluate to non-nil, it is ready to be expanded. evaluate to non-nil, it is ready to be expanded.
* Otherwise, it won't be expanded. * Otherwise, it won't be expanded.
@ -284,6 +298,13 @@ Here's an example:
'(if (python-in-string/comment) '(if (python-in-string/comment)
'(require-snippet-condition . force-in-comment) '(require-snippet-condition . force-in-comment)
t))))") t))))")
(make-variable-buffer-local 'yas/buffer-local-condition)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Utility functions for transformations
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Internal variables ;; Internal variables
@ -415,34 +436,33 @@ You can customize the key through `yas/trigger-key'."
(error-message-string err))) (error-message-string err)))
nil)))) nil))))
(defun yas/filter-templates-by-condition (templates) (defun yas/filter-templates-by-condition (templates)
"Filter the templates using the condition. The rules are: "Filter the templates using the applicable condition.
* If the template has no condition, it is kept. TEMPLATES is a list of cons (KEY . TEMPLATE) where KEY is a
* If the template's condition eval to non-nil, it is kept. string and TEMPLATE is a `yas/template' structure.
* Otherwise (eval error or eval to nil) it is filtered."
(remove-if-not '(lambda (pair)
(let ((condition (yas/template-condition (cdr pair))))
(if (null condition)
(if (yas/require-template-condition)
nil
t)
(let ((result
(yas/template-condition-predicate condition)))
(if (yas/require-template-condition)
(if (eq (yas/require-template-condition) t)
result
(eq result (yas/require-template-condition)))
result)))))
templates))
(defun yas/snippet-table-fetch (table key &optional no-condition) This function implements the rules described in
`yas/buffer-local-condition'. See that variables documentation."
(let ((requirement (yas/require-template-specific-condition-p)))
(if (eq requirement 'always)
templates
(remove-if-not #'(lambda (pair)
(let* ((condition (yas/template-condition (cdr pair)))
(result (and condition
(yas/template-condition-predicate condition))))
(cond ((eq requirement t)
result)
(t
(eq requirement result)))))
templates))))
(defun yas/snippet-table-fetch (table key)
"Fetch a snippet binding to KEY from TABLE. If not found, "Fetch a snippet binding to KEY from TABLE. If not found,
fetch from parent if any." fetch from parent if any."
(let* ((unfiltered (gethash key (yas/snippet-table-hash table))) (let* ((unfiltered (gethash key (yas/snippet-table-hash table)))
(templates (or (and no-condition (templates (yas/filter-templates-by-condition unfiltered)))
unfiltered)
(yas/filter-templates-by-condition unfiltered))))
(when (and (null templates) (when (and (null templates)
(not (null (yas/snippet-table-parent table)))) (not (null (yas/snippet-table-parent table))))
(setq templates (yas/snippet-table-fetch (setq templates (yas/snippet-table-fetch
@ -583,26 +603,32 @@ Here's a list of currently recognized variables:
* name * name
* contributor * contributor
* condition * condition
* key
* group
#name: #include \"...\" #name: #include \"...\"
# -- # --
#include \"$1\"" #include \"$1\""
(goto-char (point-min)) (goto-char (point-min))
(let ((name file-name) template bound condition) (let ((name file-name) template bound condition key group)
(if (re-search-forward "^# --\n" nil t) (if (re-search-forward "^# --\n" nil t)
(progn (setq template (progn (setq template
(buffer-substring-no-properties (point) (buffer-substring-no-properties (point)
(point-max))) (point-max)))
(setq bound (point)) (setq bound (point))
(goto-char (point-min)) (goto-char (point-min))
(while (re-search-forward "^#\\([^ ]+\\) *: *\\(.*\\)$" bound t) (while (re-search-forward "^#\\([^ ]+?\\) *: *\\(.*\\)$" bound t)
(when (string= "name" (match-string-no-properties 1)) (when (string= "name" (match-string-no-properties 1))
(setq name (match-string-no-properties 2))) (setq name (match-string-no-properties 2)))
(when (string= "condition" (match-string-no-properties 1)) (when (string= "condition" (match-string-no-properties 1))
(setq condition (read (match-string-no-properties 2)))))) (setq condition (read (match-string-no-properties 2))))
(when (string= "group" (match-string-no-properties 1))
(setq group (match-string-no-properties 2)))
(when (string= "key" (match-string-no-properties 1))
(setq key (match-string-no-properties 2)))))
(setq template (setq template
(buffer-substring-no-properties (point-min) (point-max)))) (buffer-substring-no-properties (point-min) (point-max))))
(list template name condition))) (list key template name condition group)))
(defun yas/directory-files (directory file?) (defun yas/directory-files (directory file?)
"Return directory files or subdirectories in full path." "Return directory files or subdirectories in full path."
@ -649,12 +675,14 @@ TEMPLATES."
(defun yas/prompt-for-keys (keys) (defun yas/prompt-for-keys (keys)
"Interactively choose a template key from the list KEYS." "Interactively choose a template key from the list KEYS."
(if keys
(some #'(lambda (fn) (some #'(lambda (fn)
(funcall fn "Choose a snippet key: " keys)) (funcall fn "Choose a snippet key: " keys))
yas/prompt-functions)) yas/prompt-functions)
(message "[yas] no expansions possible here!")))
(defun yas/x-prompt (prompt choices &optional display-fn) (defun yas/x-prompt (prompt choices &optional display-fn)
(when window-system (when (and window-system choices)
(let ((keymap (cons 'keymap (let ((keymap (cons 'keymap
(cons (cons
prompt prompt
@ -713,10 +741,11 @@ hierarchy."
(dolist (file (yas/directory-files directory t)) (dolist (file (yas/directory-files directory t))
(when (file-readable-p file) (when (file-readable-p file)
(insert-file-contents file nil nil nil t) (insert-file-contents file nil nil nil t)
(let ((snippet-file-name (file-name-nondirectory file))) (let* ((snip (yas/parse-template))
(push (cons snippet-file-name (key (or (car snip)
(yas/parse-template snippet-file-name)) (file-name-nondirectory file)))
snippets))))) (snip (cdr snip)))
(push (cons key snip) snippets)))))
(yas/define-snippets mode-sym (yas/define-snippets mode-sym
snippets snippets
parent) parent)
@ -779,19 +808,25 @@ all the parameters:
(when (null snippet-roots) (when (null snippet-roots)
(setq snippet-roots '("snippets"))) (setq snippet-roots '("snippets")))
(when (null code) (when (null code)
(setq code "(yas/initialize)")) (setq code (concat "(yas/initialize-bundle)"
"\n;;;###autoload" ; break through so that won't
"(require 'yasnippet-bundle)"))) ; be treated as magic comment
(let ((dirs (or (and (listp snippet-roots) snippet-roots) (let ((dirs (or (and (listp snippet-roots) snippet-roots)
(list snippet-roots))) (list snippet-roots)))
(bundle-buffer nil)) (bundle-buffer nil))
(with-temp-buffer (with-temp-buffer
(setq bundle-buffer (current-buffer)) (setq bundle-buffer (current-buffer))
(insert ";;; yasnippet-bundle.el --- "
"Yet another snippet extension (Auto compiled bundle)\n")
(insert-file-contents yasnippet) (insert-file-contents yasnippet)
(goto-char (point-max)) (goto-char (point-max))
(insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n") (insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n")
(insert ";;;; Auto-generated code ;;;;\n") (insert ";;;; Auto-generated code ;;;;\n")
(insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n") (insert ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n")
(insert code "\n") (insert "(defun yas/initialize-bundle ()\n"
" \"Initialize YASnippet and load snippets in the bundle.\""
" (yas/initialize)\n")
(flet ((yas/define-snippets (flet ((yas/define-snippets
(mode snippets &optional parent) (mode snippets &optional parent)
(with-current-buffer bundle-buffer (with-current-buffer bundle-buffer
@ -802,15 +837,19 @@ all the parameters:
(insert " (" (insert " ("
(yas/quote-string (car snippet)) (yas/quote-string (car snippet))
" " " "
(yas/quote-string (cadr snippet)) (yas/quote-string (nth 1 snippet))
" " " "
(if (caddr snippet) (if (nth 2 snippet)
(yas/quote-string (caddr snippet)) (yas/quote-string (nth 2 snippet))
"nil") "nil")
" " " "
(if (nth 3 snippet) (if (nth 3 snippet)
(format "'%s" (nth 3 snippet)) (format "'%s" (nth 3 snippet))
"nil") "nil")
" "
(if (nth 4 snippet)
(yas/quote-string (nth 4 snippet))
"nil")
")\n")) ")\n"))
(insert " )\n") (insert " )\n")
(insert (if parent (insert (if parent
@ -820,11 +859,16 @@ all the parameters:
(dolist (dir dirs) (dolist (dir dirs)
(dolist (subdir (yas/directory-files dir nil)) (dolist (subdir (yas/directory-files dir nil))
(yas/load-directory-1 subdir nil)))) (yas/load-directory-1 subdir nil))))
(insert ")\n\n" code "\n")
(insert "(provide '" (insert "(provide '"
(file-name-nondirectory (file-name-nondirectory
(file-name-sans-extension (file-name-sans-extension
yasnippet-bundle)) yasnippet-bundle))
")\n") ")\n")
(insert ";;; "
(file-name-nondirectory yasnippet-bundle)
" ends here\n")
(setq buffer-file-name yasnippet-bundle) (setq buffer-file-name yasnippet-bundle)
(save-buffer)))) (save-buffer))))
@ -853,9 +897,9 @@ all the parameters:
"Define snippets for MODE. SNIPPETS is a list of "Define snippets for MODE. SNIPPETS is a list of
snippet definition, of the following form: snippet definition, of the following form:
(KEY TEMPLATE NAME CONDITION) (KEY TEMPLATE NAME CONDITION GROUP)
or the NAME and CONDITION may be omitted. The optional 3rd or the NAME, CONDITION or GROUP may be omitted. The optional 3rd
parameter can be used to specify the parent mode of MODE. That parameter can be used to specify the parent mode of MODE. That
is, when looking a snippet in MODE failed, it can refer to its is, when looking a snippet in MODE failed, it can refer to its
parent mode. The PARENT-MODE may not need to be a real mode." parent mode. The PARENT-MODE may not need to be a real mode."
@ -880,9 +924,10 @@ parent mode. The PARENT-MODE may not need to be a real mode."
(dolist (snippet snippets) (dolist (snippet snippets)
(let* ((full-key (car snippet)) (let* ((full-key (car snippet))
(key (file-name-sans-extension full-key)) (key (file-name-sans-extension full-key))
(name (or (caddr snippet) (file-name-extension full-key))) (name (or (nth 2 snippet) (file-name-extension full-key)))
(condition (nth 3 snippet)) (condition (nth 3 snippet))
(template (yas/make-template (cadr snippet) (group (nth 4 snippet))
(template (yas/make-template (nth 1 snippet)
(or name key) (or name key)
condition))) condition)))
(yas/snippet-table-store snippet-table (yas/snippet-table-store snippet-table
@ -890,10 +935,24 @@ parent mode. The PARENT-MODE may not need to be a real mode."
key key
template) template)
(when yas/use-menu (when yas/use-menu
(define-key keymap (vector (make-symbol full-key)) (let ((group-keymap keymap))
(when (and (not (null group))
(not (string= "" group)))
(dolist (subgroup (mapcar #'make-symbol
(split-string group "\\.")))
(let ((subgroup-keymap (lookup-key group-keymap
(vector subgroup))))
(when (null subgroup-keymap)
(setq subgroup-keymap (make-sparse-keymap))
(define-key group-keymap (vector subgroup)
`(menu-item ,(symbol-name subgroup)
,subgroup-keymap)))
(setq group-keymap subgroup-keymap))))
(define-key group-keymap (vector (make-symbol full-key))
`(menu-item ,(yas/template-name template) `(menu-item ,(yas/template-name template)
,(yas/make-menu-binding (yas/template-content template)) ,(yas/make-menu-binding (yas/template-content
:keys ,(concat key yas/trigger-symbol)))))))) template))
:keys ,(concat key yas/trigger-symbol)))))))))
(defun yas/set-mode-parent (mode parent) (defun yas/set-mode-parent (mode parent)
"Set parent mode of MODE to PARENT." "Set parent mode of MODE to PARENT."
@ -905,7 +964,7 @@ parent mode. The PARENT-MODE may not need to be a real mode."
`(menu-item "parent mode" `(menu-item "parent mode"
,(yas/menu-keymap-for-mode parent))))) ,(yas/menu-keymap-for-mode parent)))))
(defun yas/define (mode key template &optional name condition) (defun yas/define (mode key template &optional name condition group)
"Define a snippet. Expanding KEY into TEMPLATE. "Define a snippet. Expanding KEY into TEMPLATE.
NAME is a description to this template. Also update NAME is a description to this template. Also update
the menu if `yas/use-menu' is `t'. CONDITION is the the menu if `yas/use-menu' is `t'. CONDITION is the
@ -913,7 +972,7 @@ condition attached to this snippet. If you attach a
condition to a snippet, then it will only be expanded condition to a snippet, then it will only be expanded
when the condition evaluated to non-nil." when the condition evaluated to non-nil."
(yas/define-snippets mode (yas/define-snippets mode
(list (list key template name condition)))) (list (list key template name condition group))))
(defun yas/hippie-try-expand (first-time?) (defun yas/hippie-try-expand (first-time?)
"Integrate with hippie expand. Just put this function in "Integrate with hippie expand. Just put this function in
@ -924,14 +983,18 @@ when the condition evaluated to non-nil."
(undo 1) (undo 1)
nil)) nil))
(defun yas/require-template-condition () (defun yas/require-template-specific-condition-p ()
"Decides if this buffer requests/requires snippet-specific
conditions to filter out potential expansions."
(if (eq 'always yas/buffer-local-condition)
'always
(let ((local-condition (yas/template-condition-predicate (let ((local-condition (yas/template-condition-predicate
yas/buffer-local-condition))) yas/buffer-local-condition)))
(and local-condition (and local-condition
(consp local-condition) (consp local-condition)
(eq 'require-snippet-condition (car local-condition)) (eq 'require-snippet-condition (car local-condition))
(symbolp (cdr local-condition)) (symbolp (cdr local-condition))
(cdr local-condition)))) (cdr local-condition)))))
(defun yas/expand (&optional field) (defun yas/expand (&optional field)
"Expand a snippet." "Expand a snippet."
@ -954,15 +1017,21 @@ when the condition evaluated to non-nil."
(when (commandp command) (when (commandp command)
(call-interactively command))))))) (call-interactively command)))))))
(defun yas/choose-snippet () (defun yas/choose-snippet (&optional no-condition)
"Choose a snippet to expand, pop-up a list of choices according "Choose a snippet to expand, pop-up a list of choices according
to `yas/prompt-function'." to `yas/prompt-function'.
(interactive)
(let* ((templates (mapcar #'cdr With prefix argument NO-CONDITION, bypass filtering of snippets
by condition."
(interactive "P")
(let* ((yas/buffer-local-condition (or (and no-condition
'always)
yas/buffer-local-condition))
(templates (mapcar #'cdr
(if yas/choose-keys-first (if yas/choose-keys-first
(let ((key (yas/prompt-for-keys (yas/snippet-table-all-keys (yas/current-snippet-table))))) (let ((key (yas/prompt-for-keys (yas/snippet-table-all-keys (yas/current-snippet-table)))))
(when key (when key
(yas/snippet-table-fetch (yas/current-snippet-table) key 'no-condition))) (yas/snippet-table-fetch (yas/current-snippet-table) key)))
(yas/snippet-table-all-templates (yas/current-snippet-table))))) (yas/snippet-table-all-templates (yas/current-snippet-table)))))
(template-content (and templates (template-content (and templates
(or (and (rest templates) ;; more than one template for same key (or (and (rest templates) ;; more than one template for same key
@ -978,7 +1047,19 @@ to `yas/prompt-function'."
;;; User conveniente functions, for using in snippet definitions ;;; User conveniente functions, for using in snippet definitions
;;; ;;;
(defun yas/substr (str pattern &optional subexp)
"Search PATTERN in STR and return SUBEXPth match.
If found, the content of subexp group SUBEXP (default 0) is
returned, or else the original STR will be returned."
(let ((grp (or subexp 0)))
(save-match-data
(if (string-match pattern str)
(match-string-no-properties grp str)
str))))
(defun yas/choose-value (&rest possibilities) (defun yas/choose-value (&rest possibilities)
"Prompt for a string in the list POSSIBILITIES."
(some #'(lambda (fn) (some #'(lambda (fn)
(funcall fn "Choose: " possibilities)) (funcall fn "Choose: " possibilities))
yas/prompt-functions)) yas/prompt-functions))
@ -987,11 +1068,14 @@ to `yas/prompt-function'."
(throw 'yas/exception (cons 'yas/exception text))) (throw 'yas/exception (cons 'yas/exception text)))
(defun yas/verify-value (&rest possibilities) (defun yas/verify-value (&rest possibilities)
"Verify that the current field value is in POSSIBILITIES
Otherwise throw exception."
(when (and yas/moving-away (notany #'(lambda (pos) (string= pos yas/text)) possibilities)) (when (and yas/moving-away (notany #'(lambda (pos) (string= pos yas/text)) possibilities))
(yas/throw (format "[yas] field only allows %s" possibilities)))) (yas/throw (format "[yas] field only allows %s" possibilities))))
(defun yas/field-value (number) (defun yas/field-value (number)
(let ((snippet (car (yas/snippets-at-point))) (let* ((snippet (car (yas/snippets-at-point)))
(field (and snippet (field (and snippet
(yas/snippet-find-field snippet number)))) (yas/snippet-find-field snippet number))))
(when field (when field
@ -1016,10 +1100,9 @@ to `yas/prompt-function'."
(defvar yas/start-column nil (defvar yas/start-column nil
"The column where the snippet expansion started.") "The column where the snippet expansion started.")
(eval-when-compile
(make-variable-buffer-local 'yas/active-field-overlay) (make-variable-buffer-local 'yas/active-field-overlay)
(make-variable-buffer-local 'yas/field-protection-overlays) (make-variable-buffer-local 'yas/field-protection-overlays)
(make-variable-buffer-local 'yas/deleted-text)) (make-variable-buffer-local 'yas/deleted-text)
(defstruct (yas/snippet (:constructor yas/make-snippet ())) (defstruct (yas/snippet (:constructor yas/make-snippet ()))
"A snippet. "A snippet.
@ -1061,8 +1144,13 @@ for this field, apply it. Otherwise, returned nil."
(transform (if (yas/mirror-p field-or-mirror) (transform (if (yas/mirror-p field-or-mirror)
(yas/mirror-transform field-or-mirror) (yas/mirror-transform field-or-mirror)
(yas/field-transform field-or-mirror))) (yas/field-transform field-or-mirror)))
(start-point (if (yas/mirror-p field-or-mirror)
(yas/mirror-start field-or-mirror)
(yas/field-start field-or-mirror)))
(transformed (and transform (transformed (and transform
(yas/eval-string transform)))) (save-excursion
(goto-char start-point)
(yas/eval-string transform)))))
transformed)) transformed))
(defsubst yas/replace-all (from to) (defsubst yas/replace-all (from to)
@ -1350,7 +1438,7 @@ snippet, if so cleans up the whole snippet up."
(eq this-command 'undo) (eq this-command 'undo)
(eq this-command 'redo))) (eq this-command 'redo)))
(defun yas/make-control-overlay (start end) (defun yas/make-control-overlay (snippet start end)
"Creates the control overlay that surrounds the snippet and "Creates the control overlay that surrounds the snippet and
holds the keymap." holds the keymap."
(let ((overlay (make-overlay start (let ((overlay (make-overlay start
@ -1544,27 +1632,9 @@ will be deleted before inserting template."
;; updates its mirrors once, so we are left with some plain text. ;; updates its mirrors once, so we are left with some plain text.
;; The undo action for deleting this plain text will get recorded ;; The undo action for deleting this plain text will get recorded
;; at the end of this function. ;; at the end of this function.
;;
;; (save-restriction
;; (narrow-to-region end end)
;; (condition-case err
;; (let ((buffer-undo-list t))
;; ;; snippet creation might evaluate users elisp, which
;; ;; might generate errors, so we have to be ready to catch
;; ;; them mostly to make the undo information
;; ;;
;; (insert template)
;; (setq yas/deleted-text key)
;; (setq yas/selected-text (if mark-active key ""))
;; (setq snippet (yas/snippet-create (point-min) (point-max))))
;; (error
;; (push (cons (point-min) (point-max)) buffer-undo-list)
;; (error (cadr err)))))
(save-restriction (save-restriction
(narrow-to-region start start) (narrow-to-region start start)
(condition-case err
(let ((buffer-undo-list t)) (let ((buffer-undo-list t))
;; snippet creation might evaluate users elisp, which ;; snippet creation might evaluate users elisp, which
;; might generate errors, so we have to be ready to catch ;; might generate errors, so we have to be ready to catch
@ -1574,7 +1644,10 @@ will be deleted before inserting template."
(insert template) (insert template)
(setq yas/deleted-text key) (setq yas/deleted-text key)
(setq yas/selected-text (when mark-active key)) (setq yas/selected-text (when mark-active key))
(setq snippet (yas/snippet-create (point-min) (point-max))))) (setq snippet (yas/snippet-create (point-min) (point-max))))
(error
(push (cons (point-min) (point-max)) buffer-undo-list)
(error (format "[yas] parse error: %s" (cadr err))))))
;; stacked-expansion: This checks for stacked expansion, save the ;; stacked-expansion: This checks for stacked expansion, save the
;; `yas/previous-active-field' and advance its boudary. ;; `yas/previous-active-field' and advance its boudary.
@ -1631,7 +1704,7 @@ After revival, push the `yas/take-care-of-redo' in the
(let ((target-field (or (yas/snippet-active-field snippet) (let ((target-field (or (yas/snippet-active-field snippet)
(car (yas/snippet-fields snippet))))) (car (yas/snippet-fields snippet)))))
(when target-field (when target-field
(setf (yas/snippet-control-overlay snippet) (yas/make-control-overlay beg end)) (setf (yas/snippet-control-overlay snippet) (yas/make-control-overlay snippet beg end))
(overlay-put (yas/snippet-control-overlay snippet) 'yas/snippet snippet) (overlay-put (yas/snippet-control-overlay snippet) 'yas/snippet snippet)
(yas/move-to-field snippet target-field) (yas/move-to-field snippet target-field)
@ -1657,7 +1730,7 @@ Returns the newly created snippet."
(yas/update-mirrors snippet) (yas/update-mirrors snippet)
;; Create keymap overlay for snippet ;; Create keymap overlay for snippet
(setf (yas/snippet-control-overlay snippet) (yas/make-control-overlay (point-min) (point-max))) (setf (yas/snippet-control-overlay snippet) (yas/make-control-overlay snippet (point-min) (point-max)))
;; Move to end ;; Move to end
(goto-char (point-max)) (goto-char (point-max))
@ -1702,14 +1775,14 @@ Meant to be called in a narrowed buffer, does various passes"
;; ;;
(goto-char parse-start) (goto-char parse-start)
(yas/field-parse-create snippet) (yas/field-parse-create snippet)
;; parse mirror transforms
;;
(goto-char parse-start)
(yas/transform-mirror-parse-create snippet)
;; parse simple mirrors ;; parse simple mirrors
;; ;;
(goto-char parse-start) (goto-char parse-start)
(yas/simple-mirror-parse-create snippet) (yas/simple-mirror-parse-create snippet)
;; parse mirror transforms
;;
(goto-char parse-start)
(yas/transform-mirror-parse-create snippet)
;; restore escapes ;; restore escapes
;; ;;
(goto-char parse-start) (goto-char parse-start)
@ -1720,21 +1793,21 @@ Meant to be called in a narrowed buffer, does various passes"
(yas/indent snippet))) (yas/indent snippet)))
(defun yas/indent (snippet) (defun yas/indent (snippet)
;;; XXX: fixed indentation not working
(save-excursion (save-excursion
(cond ((eq yas/indent-line 'fixed) (cond ((eq yas/indent-line 'fixed)
(let ((fill-prefix (make-string yas/start-column ? ))) (let* ((indent (if indent-tabs-mode
(indent-region (point-min) (point-max)))) (concat (make-string (/ column tab-width) ?\t)
(make-string (% column tab-width) ?\ ))
(make-string (current-colum) ?\ ))))
(goto-char (point-min))
(while (and (zerop (forward-line))
(= (current-column) 0))
(insert indent))))
((eq yas/indent-line 'auto) ((eq yas/indent-line 'auto)
(let ((begin (point-min)) (let ((end (set-marker (make-marker) (point-max))))
(end (point-max)))
(save-restriction (save-restriction
(widen) (widen)
(indent-region (line-beginning-position) (point-max)) ;; XXX: Here seems to be the indent problem:
(when (yas/snippet-exit snippet)
(goto-char (yas/snippet-exit snippet))
(indent-according-to-mode)
;; XXX: Here is the indent problem:
;; ;;
;; `indent-according-to-mode' uses whatever ;; `indent-according-to-mode' uses whatever
;; `indent-line-function' is available. Some ;; `indent-line-function' is available. Some
@ -1747,7 +1820,13 @@ Meant to be called in a narrowed buffer, does various passes"
;; This would also happen if we had used overlays with ;; This would also happen if we had used overlays with
;; the `front-advance' property set to nil. ;; the `front-advance' property set to nil.
;; ;;
(set-marker (yas/snippet-exit snippet) (point)))))) (while (and (zerop (forward-line))
(<= (point) end))
(goto-char (yas/real-line-beginning))
(insert-before-markers "Y")
(indent-according-to-mode)
(backward-delete-char 1))
(set-marker end nil))))
(t (t
nil))) nil)))
(save-excursion (save-excursion
@ -1756,6 +1835,15 @@ Meant to be called in a narrowed buffer, does various passes"
(when (not (eq yas/indent-line 'auto)) (when (not (eq yas/indent-line 'auto))
(indent-according-to-mode))))) (indent-according-to-mode)))))
(defun yas/real-line-beginning ()
(let ((c (char-after (line-beginning-position)))
(n (line-beginning-position)))
(while (or (eql c ?\ )
(eql c ?\t))
(incf n)
(setq c (char-after n)))
n))
(defun yas/escape-string (escaped) (defun yas/escape-string (escaped)
(concat "YASESCAPE" (format "%d" escaped) "PROTECTGUARD")) (concat "YASESCAPE" (format "%d" escaped) "PROTECTGUARD"))
@ -1783,6 +1871,13 @@ Meant to be called in a narrowed buffer, does various passes"
(insert transformed) (insert transformed)
(delete-region (match-beginning 0) (match-end 0))))) (delete-region (match-beginning 0) (match-end 0)))))
(defun yas/scan-sexps (from count)
(condition-case err
(with-syntax-table (standard-syntax-table)
(scan-sexps from count))
(error
nil)))
(defun yas/field-parse-create (snippet &optional parent-field) (defun yas/field-parse-create (snippet &optional parent-field)
"Parse most field expression, except for the simple one \"$n\". "Parse most field expression, except for the simple one \"$n\".
@ -1795,12 +1890,12 @@ The following count as a field:
When multiple expressions are found, only the last one counts." When multiple expressions are found, only the last one counts."
(save-excursion (save-excursion
(while (re-search-forward yas/field-regexp nil t) (while (re-search-forward yas/field-regexp nil t)
(let* ((real-match-end-0 (scan-sexps (1+ (match-beginning 0)) 1)) (let* ((real-match-end-0 (yas/scan-sexps (1+ (match-beginning 0)) 1))
(number (and (match-string-no-properties 1) (number (and (match-string-no-properties 1)
(string-to-number (match-string-no-properties 1)))) (string-to-number (match-string-no-properties 1))))
(brand-new-field (and real-match-end-0 (brand-new-field (and real-match-end-0
(not (save-match-data (not (save-match-data
(eq (string-match "$(" (match-string-no-properties 2)) 0))) (eq (string-match "$[ \t\n]+(" (match-string-no-properties 2)) 0)))
(not (and number (zerop number))) (not (and number (zerop number)))
(yas/make-field number (yas/make-field number
(set-marker (make-marker) (match-beginning 2)) (set-marker (make-marker) (match-beginning 2))
@ -1818,7 +1913,7 @@ When multiple expressions are found, only the last one counts."
(when parent-field (when parent-field
(save-excursion (save-excursion
(while (re-search-forward yas/multi-dollar-lisp-expression-regexp nil t) (while (re-search-forward yas/multi-dollar-lisp-expression-regexp nil t)
(let* ((real-match-end-0 (scan-sexps (1+ (match-beginning 0)) 1))) (let* ((real-match-end-0 (yas/scan-sexps (1+ (match-beginning 0)) 1)))
(when real-match-end-0 (when real-match-end-0
(let ((lisp-expression-string (buffer-substring-no-properties (match-beginning 1) real-match-end-0))) (let ((lisp-expression-string (buffer-substring-no-properties (match-beginning 1) real-match-end-0)))
(setf (yas/field-transform parent-field) lisp-expression-string)) (setf (yas/field-transform parent-field) lisp-expression-string))
@ -1827,7 +1922,7 @@ When multiple expressions are found, only the last one counts."
(defun yas/transform-mirror-parse-create (snippet) (defun yas/transform-mirror-parse-create (snippet)
"Parse the \"${n:$(lisp-expression)}\" mirror transformations." "Parse the \"${n:$(lisp-expression)}\" mirror transformations."
(while (re-search-forward yas/transform-mirror-regexp nil t) (while (re-search-forward yas/transform-mirror-regexp nil t)
(let* ((real-match-end-0 (scan-sexps (1+ (match-beginning 0)) 1)) (let* ((real-match-end-0 (yas/scan-sexps (1+ (match-beginning 0)) 1))
(number (string-to-number (match-string-no-properties 1))) (number (string-to-number (match-string-no-properties 1)))
(field (and number (field (and number
(not (zerop number)) (not (zerop number))
@ -2008,3 +2103,14 @@ handle the end-of-buffer error fired in it by calling
(condition-case err (condition-case err
ad-do-it ad-do-it
(error (message (error-message-string err))))) (error (message (error-message-string err)))))
;; disable c-electric-* serial command in YAS fields
(add-hook 'c-mode-common-hook
'(lambda ()
(make-variable-buffer-local 'yas/keymap)
(dolist (k '(":" ">" ";" "<" "{" "}"))
(define-key yas/keymap
k 'self-insert-command))))
;;; yasnippet.el ends here