mirror of
https://github.com/joaotavora/yasnippet.git
synced 2025-10-14 05:23:04 +00:00
more powerful condition system
This commit is contained in:
parent
21c98d141a
commit
67dc9d7518
@ -261,6 +261,122 @@ customization code instead of the default ``(yas/initialize)``. For
|
|||||||
example, you can set ``yas/trigger-key`` to ``(kbd "SPC")`` here if
|
example, you can set ``yas/trigger-key`` to ``(kbd "SPC")`` here if
|
||||||
you like.
|
you like.
|
||||||
|
|
||||||
|
yas/define
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
The basic syntax for ``yas/define`` is
|
||||||
|
|
||||||
|
.. sourcecode:: common-lisp
|
||||||
|
|
||||||
|
(yas/define mode key template &optional name condition)
|
||||||
|
|
||||||
|
This is only a syntax sugar for
|
||||||
|
|
||||||
|
.. sourcecode:: common-lisp
|
||||||
|
|
||||||
|
(yas/define-snippets mode
|
||||||
|
(list (list key template name condition)))
|
||||||
|
|
||||||
|
The strategy to select a snippet
|
||||||
|
================================
|
||||||
|
|
||||||
|
When user press the ``yas/trigger-key``, YASnippet try to find a
|
||||||
|
proper snippet to expand. The strategy to find such a snippet is
|
||||||
|
explained here.
|
||||||
|
|
||||||
|
Finding the key
|
||||||
|
---------------
|
||||||
|
|
||||||
|
YASnippet search from current point backward trying to find the
|
||||||
|
snippet to be expanded. The default searching strategy is quite
|
||||||
|
powerful. For example, in ``c-mode``, ``"bar"``, ``"foo_bar"``,
|
||||||
|
``"#foo_bar"`` can all be recognized as a template key. Further more,
|
||||||
|
the searching is in that order. In other words, if ``"bar"`` is found
|
||||||
|
to be a key to some *valid* snippet, then ``"foo_bar"`` and
|
||||||
|
``"#foobar"`` won't be searched.
|
||||||
|
|
||||||
|
However, this strategy can also be customized easily from the
|
||||||
|
``yas/key-syntaxes`` variable. It is a list of syntax rules, the
|
||||||
|
default value is ``("w" "w_" "w_." "^ ")``. Which means search the
|
||||||
|
following thing until found one:
|
||||||
|
|
||||||
|
* a word.
|
||||||
|
* a symbol. In lisp, ``-`` and ``?`` can all be part of a symbol.
|
||||||
|
* a sequence of characters of either word, symbol or punctuation.
|
||||||
|
* a sequence of characters of non-whitespace characters.
|
||||||
|
|
||||||
|
But you'd better keep the default value unless you understand what
|
||||||
|
Emacs's syntax rule mean.
|
||||||
|
|
||||||
|
The condition system
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
I write forked snippet.el to make the smart-snippet.el. I call it
|
||||||
|
*smart*-snippet because a condition can be attached to a snippet. This
|
||||||
|
is really a good idea. However, writing condition for a snippet
|
||||||
|
usually needs good elisp and Emacs knowledge, so it is strange to many
|
||||||
|
user.
|
||||||
|
|
||||||
|
Later I write YASnippet and persuade people to use it instead of
|
||||||
|
smart-snippet.el. However, some user still love smart-snippet because
|
||||||
|
it is smart. So I make YASnippet smart. Even smarter than
|
||||||
|
smart-snippet.el. :p
|
||||||
|
|
||||||
|
Consider this scenario: you are an old Emacs hacker. You like the
|
||||||
|
abbrev-way and set ``yas/trigger-key`` to ``(kbd "SPC")``. However,
|
||||||
|
you don't want ``if`` to be expanded as a snippet when you are typing
|
||||||
|
in a comment block or a string (e.g. in ``python-mode``).
|
||||||
|
|
||||||
|
It's OK, just specify the condition for ``if`` to be ``(not
|
||||||
|
(python-in-string/comment))``. But how about ``while``, ``for``,
|
||||||
|
etc. ? Writing the same condition for all the snippets is just
|
||||||
|
boring. So YASnippet introduce a buffer local variable
|
||||||
|
``yas/buffer-local-condition``. You can set this variable to ``(not
|
||||||
|
(python-in-string/comment))`` in ``python-mode-hook``. There's no way
|
||||||
|
to do this in smart-snippet.el!
|
||||||
|
|
||||||
|
Then, what if you really want some snippet even in comment? This is
|
||||||
|
also possible! But let's stop telling the story and look at the rules:
|
||||||
|
|
||||||
|
* If ``yas/buffer-local-condition`` evaluate to nil, snippet won't be
|
||||||
|
expanded.
|
||||||
|
* If it evaluate to the a cons cell where the ``car`` is the symbol
|
||||||
|
``require-snippet-condition`` and the ``cdr`` is a symbol (let's
|
||||||
|
call it ``requirement``):
|
||||||
|
|
||||||
|
* If the snippet has no condition, then it won't be expanded.
|
||||||
|
* If the snippet has a condition but evaluate to nil or error
|
||||||
|
occured during evaluation, it won't be expanded.
|
||||||
|
* If the snippet has a condition that evaluate to non-nil (let's
|
||||||
|
call it ``result``):
|
||||||
|
|
||||||
|
* If ``requirement`` is ``t``, the snippet is ready to be
|
||||||
|
expanded.
|
||||||
|
* If ``requirement`` is ``eq`` to ``result``, the snippet is ready
|
||||||
|
to be expanded.
|
||||||
|
* Otherwise the snippet won't be expanded.
|
||||||
|
|
||||||
|
* If it evaluate to other non-nil value:
|
||||||
|
|
||||||
|
* If the snippet has no condition, or has a condition that evaluate
|
||||||
|
to non-nil, it is ready to be expanded.
|
||||||
|
* Otherwise, it won't be expanded.
|
||||||
|
|
||||||
|
So set ``yas/buffer-local-condition`` like this
|
||||||
|
|
||||||
|
.. sourcecode:: common-lisp
|
||||||
|
|
||||||
|
(add-hook 'python-mode-hook
|
||||||
|
'(lambda ()
|
||||||
|
(setq yas/buffer-local-condition
|
||||||
|
'(if (python-in-string/comment)
|
||||||
|
'(require-snippet-condition . force-in-comment)
|
||||||
|
t))))
|
||||||
|
|
||||||
|
And specify the condition for a snippet that you're going to expand in
|
||||||
|
comment to be evaluated to the symbol ``force-in-comment``. Then it
|
||||||
|
can be expanded as you expected.
|
||||||
|
|
||||||
The Syntax of the Template
|
The Syntax of the Template
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
40
yasnippet.el
40
yasnippet.el
@ -124,11 +124,11 @@ proper values:
|
|||||||
|
|
||||||
(defvar yas/buffer-local-condition t
|
(defvar yas/buffer-local-condition t
|
||||||
"Condition to yasnippet local to each buffer.
|
"Condition to yasnippet local to each buffer.
|
||||||
If this eval to nil, no snippet can be expanded.
|
If this eval to nil, no snippet can be expanded. If this eval to
|
||||||
If this eval to 'require-snippet-condition, then a snippet can be expanded
|
the symbol require-snippet-condition, then a snippet can be
|
||||||
if and only if it has a condition attached and that condition eval to non-nil.
|
expanded if and only if it has a condition attached and that
|
||||||
Otherwise, if a snippet has no condition or its conditin eval to non-nil, it
|
condition eval to non-nil. Otherwise, if a snippet has no
|
||||||
will be expanded.
|
condition or its conditin eval to non-nil, it will be expanded.
|
||||||
|
|
||||||
Here's an example:
|
Here's an example:
|
||||||
|
|
||||||
@ -319,14 +319,18 @@ have, compare through the start point of the overlay."
|
|||||||
* If the template has no condition, it is kept.
|
* If the template has no condition, it is kept.
|
||||||
* If the template's condition eval to non-nil, it is kept.
|
* If the template's condition eval to non-nil, it is kept.
|
||||||
* Otherwise (eval error or eval to nil) it is filtered."
|
* Otherwise (eval error or eval to nil) it is filtered."
|
||||||
(remove-if-not '(lambda (pair)
|
(remove-if '(lambda (pair)
|
||||||
(let ((condition (yas/template-condition (cdr pair))))
|
(let ((condition (yas/template-condition (cdr pair))))
|
||||||
(if (null condition)
|
(if (null condition)
|
||||||
(if yas/require-template-condition
|
(if yas/require-template-condition
|
||||||
nil
|
t
|
||||||
t)
|
nil)
|
||||||
(yas/template-condition-predicate condition))))
|
(let ((result
|
||||||
templates))
|
(yas/template-condition-predicate condition)))
|
||||||
|
(if (eq yas/require-template-condition t)
|
||||||
|
result
|
||||||
|
(not (eq result yas/require-template-condition)))))))
|
||||||
|
templates))
|
||||||
|
|
||||||
(defun yas/snippet-table-fetch (table key)
|
(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,
|
||||||
@ -1059,10 +1063,12 @@ when the condition evaluated to non-nil."
|
|||||||
(let ((local-condition (yas/template-condition-predicate
|
(let ((local-condition (yas/template-condition-predicate
|
||||||
yas/buffer-local-condition)))
|
yas/buffer-local-condition)))
|
||||||
(if local-condition
|
(if local-condition
|
||||||
(let ((yas/require-template-condition (if (eq local-condition
|
(let ((yas/require-template-condition
|
||||||
'require-snippet-condition)
|
(if (and (consp local-condition)
|
||||||
t
|
(eq 'require-snippet-condition (car local-condition))
|
||||||
nil)))
|
(symbolp (cdr local-condition)))
|
||||||
|
(cdr local-condition)
|
||||||
|
nil)))
|
||||||
(multiple-value-bind (key start end) (yas/current-key)
|
(multiple-value-bind (key start end) (yas/current-key)
|
||||||
(let ((templates (yas/snippet-table-fetch (yas/current-snippet-table)
|
(let ((templates (yas/snippet-table-fetch (yas/current-snippet-table)
|
||||||
key)))
|
key)))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user