update packages
This commit is contained in:
87
lisp/yasnippet/doc/faq.org
Normal file
87
lisp/yasnippet/doc/faq.org
Normal file
@@ -0,0 +1,87 @@
|
||||
#+SETUPFILE: org-setup.inc
|
||||
|
||||
#+TITLE: Frequently Asked Questions
|
||||
|
||||
- *Note*: In addition to the questions and answers presented here,
|
||||
you might also with to visit the list of [[https://github.com/joaotavora/yasnippet/issues?q=label%3Asupport][solved support issues]] in
|
||||
the Github issue tracker. It might be more up-to-date than this
|
||||
list.
|
||||
|
||||
* Why are my snippet abbrev keys triggering when I don't want them too?
|
||||
Expansion of abbrev keys is controlled by [[sym:yas-key-syntaxes][=yas-key-syntaxes=]]. Try
|
||||
removing entries which correspond to the abbrev key character syntax.
|
||||
For example, if you have a snippet with abbrev key "bar", that you
|
||||
don't want to trigger when point follows the text =foo_bar=, remove
|
||||
the ="w"= entry (since "bar" has only word syntax characters).
|
||||
|
||||
* Why aren't my snippet abbrev keys triggering when I want them too?
|
||||
See previous question, but in reverse.
|
||||
|
||||
* Why is there an extra newline?
|
||||
|
||||
If there is a newline at the end of a snippet definition file,
|
||||
YASnippet will add a newline when expanding that snippet. When editing
|
||||
or saving a snippet file, please be careful not to accidentally add a
|
||||
terminal newline.
|
||||
|
||||
Note that some editors will automatically add a newline for you. In
|
||||
Emacs, if you set =require-final-newline= to =t=, it will add the
|
||||
final newline automatically.
|
||||
|
||||
* Why doesn't TAB navigation work with flyspell
|
||||
|
||||
This is [[https://debbugs.gnu.org/26672][Emacs Bug#26672]], so you should upgrade to version 25.3 or
|
||||
better. Otherwise, a workaround is to inhibit flyspell overlays while
|
||||
the snippet is active:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-hook 'flyspell-incorrect-hook
|
||||
#'(lambda (&rest _)
|
||||
(and yas-active-field-overlay
|
||||
(overlay-buffer yas-active-field-overlay))))
|
||||
#+END_SRC
|
||||
|
||||
* How do I use alternative keys, i.e. not TAB?
|
||||
|
||||
Edit the keymaps [[sym:yas-minor-mode-map][=yas-minor-mode-map=]] and [[sym:yas-keymap][=yas-keymap=]] as you would
|
||||
any other keymap, but use [[sym:yas-filtered-definition][=yas-filtered-definition=]] on the definition
|
||||
if you want to respect [[sym:yas-keymap-disable-hook][=yas-keymap-disable-hook=]]:
|
||||
|
||||
#+begin_src emacs-lisp :exports code
|
||||
(define-key yas-minor-mode-map (kbd "<tab>") nil)
|
||||
(define-key yas-minor-mode-map (kbd "TAB") nil)
|
||||
(define-key yas-minor-mode-map (kbd "<the new key>") yas-maybe-expand)
|
||||
|
||||
;;keys for navigation
|
||||
(define-key yas-keymap [(tab)] nil)
|
||||
(define-key yas-keymap (kbd "TAB") nil)
|
||||
(define-key yas-keymap [(shift tab)] nil)
|
||||
(define-key yas-keymap [backtab] nil)
|
||||
(define-key yas-keymap (kbd "<new-next-field-key>")
|
||||
(yas-filtered-definition 'yas-next-field-or-maybe-expand))
|
||||
(define-key yas-keymap (kbd "<new-prev-field-key>")
|
||||
(yas-filtered-definition 'yas-prev-field))
|
||||
#+end_src
|
||||
|
||||
* How do I define an abbrev key containing characters not supported by the filesystem?
|
||||
|
||||
- *Note*: This question applies if you're still defining snippets
|
||||
whose key /is/ the filename. This is behavior still provided by
|
||||
version 0.6 for backward compatibilty, but is somewhat
|
||||
deprecated...
|
||||
|
||||
For example, you want to define a snippet by the key =<= which is not a
|
||||
valid character for filename on Windows. This means you can't use the
|
||||
filename as a trigger key in this case.
|
||||
|
||||
You should rather use the =# key:= directive to specify the key of the
|
||||
defined snippet explicitly and name your snippet with an arbitrary valid
|
||||
filename, =lt.YASnippet= for example, using =<= for the =# key:=
|
||||
directive:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
# key: <
|
||||
# name: <...></...>
|
||||
# --
|
||||
<${1:div}>$0</$1>
|
||||
#+END_SRC
|
||||
47
lisp/yasnippet/doc/index.org
Normal file
47
lisp/yasnippet/doc/index.org
Normal file
@@ -0,0 +1,47 @@
|
||||
#+SETUPFILE: org-setup.inc
|
||||
#+TITLE: Yet another snippet extension
|
||||
|
||||
The YASnippet documentation has been split into separate parts:
|
||||
|
||||
0. [[https://github.com/joaotavora/yasnippet/blob/master/README.mdown][README]]
|
||||
|
||||
Contains an introduction, installation instructions and other important
|
||||
notes.
|
||||
|
||||
1. [[file:snippet-organization.org][Organizing Snippets]]
|
||||
|
||||
Describes ways to organize your snippets in the hard disk.
|
||||
|
||||
2. [[file:snippet-expansion.org][Expanding Snippets]]
|
||||
|
||||
Describes how YASnippet chooses snippets for expansion at point.
|
||||
|
||||
Maybe, you'll want some snippets to be expanded in a particular mode,
|
||||
or only under certain conditions, or be prompted using =ido=, etc...
|
||||
|
||||
3. [[file:snippet-development.org][Writing Snippets]]
|
||||
|
||||
Describes the YASnippet definition syntax, which is very close (but
|
||||
not equivalent) to Textmate's. Includes a section about converting
|
||||
TextMate snippets.
|
||||
|
||||
4. [[file:snippet-menu.org][The YASnippet menu]]
|
||||
|
||||
Explains how to use the YASnippet menu to explore, learn and modify
|
||||
snippets.
|
||||
|
||||
5. [[file:faq.org][Frequently asked questions]]
|
||||
|
||||
Answers to frequently asked questions.
|
||||
|
||||
6. [[file:snippet-reference.org][YASnippet Symbol Reference]]
|
||||
|
||||
An automatically generated listing of all YASnippet commands,
|
||||
(customization) variables, and functions.
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# mode: org
|
||||
# fill-column: 80
|
||||
# coding: utf-8
|
||||
# End:
|
||||
474
lisp/yasnippet/doc/snippet-development.org
Normal file
474
lisp/yasnippet/doc/snippet-development.org
Normal file
@@ -0,0 +1,474 @@
|
||||
#+SETUPFILE: org-setup.inc
|
||||
|
||||
#+TITLE: Writing snippets
|
||||
|
||||
* Snippet development
|
||||
|
||||
** Quickly finding snippets
|
||||
|
||||
There are some ways you can quickly find a snippet file or create a new one:
|
||||
|
||||
- =M-x yas-new-snippet=, key binding: =C-c & C-n=
|
||||
|
||||
Creates a new buffer with a template for making a new snippet. The
|
||||
buffer is in =snippet-mode= (see [[snippet-mode][below]]). When you are done editing
|
||||
the new snippet, use [[yas-load-snippet-buffer-and-close][=C-c C-c=]] to save it.
|
||||
|
||||
- =M-x yas-visit-snippet-file=, key binding: =C-c & C-v=
|
||||
|
||||
Prompts you for possible snippet expansions like
|
||||
[[sym:yas-insert-snippet][=yas-insert-snippet=]], but instead of expanding it, takes you directly
|
||||
to the snippet definition's file, if it exists.
|
||||
|
||||
Once you find this file it will be set to =snippet-mode= (see [[snippet-mode][ahead]])
|
||||
and you can start editing your snippet.
|
||||
|
||||
** Using the =snippet-mode= major mode <<snippet-mode>>
|
||||
|
||||
There is a major mode =snippet-mode= to edit snippets. You can set the
|
||||
buffer to this mode with =M-x snippet-mode=. It provides reasonably
|
||||
useful syntax highlighting.
|
||||
|
||||
Three commands are defined in this mode:
|
||||
|
||||
- =M-x yas-load-snippet-buffer=, key binding: =C-c C-l=
|
||||
|
||||
Prompts for a snippet table (with a default based on snippet's
|
||||
major mode) and loads the snippet currently being edited.
|
||||
|
||||
- =M-x yas-load-snippet-buffer-and-close=, key binding: =C-c C-c=
|
||||
<<yas-load-snippet-buffer-and-close>>
|
||||
|
||||
Like =yas-load-snippet-buffer=, but also saves the snippet and
|
||||
calls =quit-window=. The destination is decided based on the
|
||||
chosen snippet table and snippet collection directly (defaulting to
|
||||
the first directory in =yas-snippet-dirs= (see [[file:snippet-organization.org][Organizing Snippets]]
|
||||
for more detail on how snippets are organized).
|
||||
|
||||
- =M-x yas-tryout-snippet=, key binding: =C-c C-t=
|
||||
|
||||
When editing a snippet, this opens a new empty buffer, sets it to
|
||||
the appropriate major mode and inserts the snippet there, so you
|
||||
can see what it looks like.
|
||||
|
||||
There are also /snippets for writing snippets/: =vars=, =$f= and =$m=
|
||||
:-).
|
||||
|
||||
* File content
|
||||
|
||||
A file defining a snippet generally contains the template to be
|
||||
expanded.
|
||||
|
||||
Optionally, if the file contains a line of =# --=, the lines above it
|
||||
count as comments, some of which can be /directives/ (or meta data).
|
||||
Snippet directives look like =# property: value= and tweak certain
|
||||
snippet properties described below. If no =# --= is found, the whole
|
||||
file is considered the snippet template.
|
||||
|
||||
Here's a typical example:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
# contributor: pluskid <pluskid@gmail.com>
|
||||
# name: __...__
|
||||
# --
|
||||
__${init}__
|
||||
#+END_SRC
|
||||
|
||||
Here's a list of currently supported directives:
|
||||
|
||||
** =# key:= snippet abbrev
|
||||
|
||||
This is the probably the most important directive, it's the
|
||||
abbreviation you type to expand a snippet just before hitting the key
|
||||
that runs [[sym:yas-expand][=yas-expand=]]. If you don't specify this,
|
||||
the snippet will not be expandable through the trigger mechanism.
|
||||
|
||||
** =# name:= snippet name
|
||||
|
||||
This is a one-line description of the snippet. It will be displayed in
|
||||
the menu. It's a good idea to select a descriptive name for a snippet --
|
||||
especially distinguishable among similar snippets.
|
||||
|
||||
If you omit this name, it will default to the file name the snippet
|
||||
was loaded from.
|
||||
|
||||
** =# condition:= snippet condition
|
||||
|
||||
This is a piece of Emacs Lisp code. If a snippet has a condition, then
|
||||
it will only be expanded when the condition code evaluate to some
|
||||
non-nil value.
|
||||
|
||||
See also [[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]] in
|
||||
[[./snippet-expansion.org][Expanding snippets]]
|
||||
|
||||
** =# group:= snippet menu grouping
|
||||
|
||||
When expanding/visiting snippets from the menu-bar menu, snippets for a
|
||||
given mode can be grouped into sub-menus. This is useful if one has too
|
||||
many snippets for a mode which will make the menu too long.
|
||||
|
||||
The =# group:= property only affect menu construction (See
|
||||
[[./snippet-menu.org][the YASnippet menu]]) and the same effect can be
|
||||
achieved by grouping snippets into sub-directories and using the
|
||||
=.yas-make-groups= special file (for this see
|
||||
[[./snippet-organization.org][Organizing Snippets]]
|
||||
|
||||
Refer to the bundled snippets for =ruby-mode= for examples of the
|
||||
=# group:= directive. Group can also be nested, e.g.
|
||||
=control structure.loops= indicates that the snippet is under the =loops=
|
||||
group which is under the =control structure= group.
|
||||
|
||||
** =# expand-env:= expand environment
|
||||
|
||||
This is another piece of Emacs Lisp code in the form of a =let= /varlist
|
||||
form/, i.e. a list of lists assigning values to variables. It can be
|
||||
used to override variable values while the snippet is being expanded.
|
||||
|
||||
Interesting variables to override are [[sym:yas-wrap-around-region][=yas-wrap-around-region=]] and
|
||||
[[sym:yas-indent-line][=yas-indent-line=]] (see [[./snippet-expansion.org][Expanding Snippets]]).
|
||||
|
||||
As an example, you might normally have [[sym:yas-indent-line][=yas-indent-line=]] set to '=auto=
|
||||
and [[sym:yas-wrap-around-region][=yas-wrap-around-region=]] set to =t=, but for this particularly
|
||||
brilliant piece of ASCII art these values would mess up your hard work.
|
||||
You can then use:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
# name: ASCII home
|
||||
# expand-env: ((yas-indent-line 'fixed) (yas-wrap-around-region 'nil))
|
||||
# --
|
||||
welcome to my
|
||||
X humble
|
||||
/ \ home,
|
||||
/ \ $0
|
||||
/ \
|
||||
/-------\
|
||||
| |
|
||||
| +-+ |
|
||||
| | | |
|
||||
+--+-+--+
|
||||
#+END_SRC
|
||||
|
||||
** =# binding:= direct keybinding
|
||||
|
||||
You can use this directive to expand a snippet directly from a normal
|
||||
Emacs keybinding. The keybinding will be registered in the Emacs keymap
|
||||
named after the major mode the snippet is active for.
|
||||
|
||||
Additionally a variable [[sym:yas-prefix][=yas-prefix=]] is set to the prefix argument
|
||||
you normally use for a command. This allows for small variations on the
|
||||
same snippet, for example in this =html-mode= snippet.
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
# name: <p>...</p>
|
||||
# binding: C-c C-c C-m
|
||||
# --
|
||||
<p>`(when yas-prefix "\n")`$0`(when yas-prefix "\n")`</p>
|
||||
#+END_SRC
|
||||
|
||||
This binding will be recorded in the keymap =html-mode-map=. To expand a
|
||||
paragraph tag newlines, just press =C-u C-c C-c C-m=. Omitting the =C-u=
|
||||
will expand the paragraph tag without newlines.
|
||||
|
||||
** =# type:= =snippet= or =command=
|
||||
|
||||
If the =type= directive is set to =command=, the body of the snippet
|
||||
is interpreted as Lisp code to be evaluated when the snippet is
|
||||
triggered.
|
||||
|
||||
If it's =snippet= (the default when there is no =type= directive), the
|
||||
snippet body will be parsed according to the [[Template Syntax]],
|
||||
described below.
|
||||
|
||||
** =# uuid:= unique identifier
|
||||
|
||||
This provides to a way to identify a snippet, independent of its name.
|
||||
Loading a second snippet file with the same uuid would replace the
|
||||
previous snippet.
|
||||
|
||||
** =# contributor:= snippet author
|
||||
|
||||
This is optional and has no effect whatsoever on snippet functionality,
|
||||
but it looks nice.
|
||||
|
||||
* Template Syntax
|
||||
|
||||
The syntax of the snippet template is simple but powerful, very similar
|
||||
to TextMate's.
|
||||
|
||||
** Plain Text
|
||||
|
||||
Arbitrary text can be included as the content of a template. They are
|
||||
usually interpreted as plain text, except =$= and =`=. You need to
|
||||
use =\= to escape them: =\$= and =\`=. The =\= itself may also needed to be
|
||||
escaped as =\\= sometimes.
|
||||
|
||||
** Embedded Emacs Lisp code
|
||||
|
||||
Emacs Lisp code can be embedded inside the template, written inside
|
||||
back-quotes (=`=). The Lisp forms are evaluated when the snippet is
|
||||
being expanded. The evaluation is done in the same buffer as the
|
||||
snippet being expanded.
|
||||
|
||||
Here's an example for =c-mode= to calculate the header file guard
|
||||
dynamically:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
#ifndef ${1:_`(upcase (file-name-nondirectory (file-name-sans-extension (buffer-file-name))))`_H_}
|
||||
#define $1
|
||||
|
||||
$0
|
||||
|
||||
#endif /* $1 */
|
||||
#+END_SRC
|
||||
|
||||
From version 0.6, snippet expansions are run with some special
|
||||
Emacs Lisp variables bound. One of these is [[sym:yas-selected-text][=yas-selected-text=]]. You can
|
||||
therefore define a snippet like:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
for ($1;$2;$3) {
|
||||
`yas-selected-text`$0
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
to "wrap" the selected region inside your recently inserted snippet.
|
||||
Alternatively, you can also customize the variable
|
||||
[[sym:yas-wrap-around-region][=yas-wrap-around-region=]] to =t= which will do this automatically.
|
||||
|
||||
*** Note: backquote expressions should not modify the buffer
|
||||
|
||||
Please note that the Lisp forms in backquotes should *not* modify the
|
||||
buffer, doing so will trigger a warning. For example, instead of
|
||||
doing
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
Timestamp: `(insert (current-time-string))`
|
||||
#+END_SRC
|
||||
|
||||
do this:
|
||||
#+BEGIN_SRC snippet
|
||||
Timestamp: `(current-time-string)`
|
||||
#+END_SRC
|
||||
|
||||
The warning may be suppressed with the following code in your init file:
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-to-list 'warning-suppress-types '(yasnippet backquote-change))
|
||||
#+END_SRC
|
||||
|
||||
|
||||
** Tab stop fields
|
||||
|
||||
Tab stops are fields that you can navigate back and forth by =TAB= and
|
||||
=S-TAB=. They are written by =$= followed with a number. =$0= has the
|
||||
special meaning of the /exit point/ of a snippet. That is the last place
|
||||
to go when you've traveled all the fields. Here's a typical example:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
<div$1>
|
||||
$0
|
||||
</div>
|
||||
#+END_SRC
|
||||
** Placeholder fields
|
||||
|
||||
Tab stops can have default values -- a.k.a placeholders. The syntax is
|
||||
like this:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
${N:default value}
|
||||
#+END_SRC
|
||||
|
||||
They act as the default value for a tab stop. But when you first
|
||||
type at a tab stop, the default value will be replaced by your typing.
|
||||
The number can be omitted if you don't want to create [[mirrors-fields][mirrors]] or
|
||||
[[mirror-transformations][transformations]] for this field.
|
||||
|
||||
** Mirrors <<mirrors-fields>>
|
||||
|
||||
We refer to tab stops with placeholders as a /field/. A field can
|
||||
have mirrors. *All* mirrors get updated whenever you update any field
|
||||
text. Here's an example:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
\begin{${1:enumerate}}
|
||||
$0
|
||||
\end{$1}
|
||||
#+END_SRC
|
||||
|
||||
When you type "document" at =${1:enumerate}=, the word "document" will
|
||||
also be inserted at =\end{$1}=. The best explanation is to see the
|
||||
screencast([[http://www.youtube.com/watch?v=vOj7btx3ATg][YouTube]] or [[http://yasnippet.googlecode.com/files/yasnippet.avi][avi video]]).
|
||||
|
||||
The tab stops with the same number to the field act as its mirrors. If
|
||||
none of the tab stops have an initial value, the first one is selected as
|
||||
the field and the others are its mirrors.
|
||||
|
||||
** Mirrors with transformations <<mirror-transformations>>
|
||||
|
||||
If the value of an =${n:=-construct starts with and contains =$(=,
|
||||
then it is interpreted as a mirror for field =n= with a
|
||||
transformation. The mirror's text content is calculated according to
|
||||
this transformation, which is Emacs Lisp code that gets evaluated in
|
||||
an environment where the variable [[sym:yas-text][=yas-text=]] is bound to the text
|
||||
content (string) contained in the field =n=. Here's an example for
|
||||
Objective-C:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
- (${1:id})${2:foo}
|
||||
{
|
||||
return $2;
|
||||
}
|
||||
|
||||
- (void)set${2:$(capitalize yas-text)}:($1)aValue
|
||||
{
|
||||
[$2 autorelease];
|
||||
$2 = [aValue retain];
|
||||
}
|
||||
$0
|
||||
#+END_SRC
|
||||
|
||||
Look at =${2:$(capitalize yas-text)}=, it is a mirror with
|
||||
transformation instead of a field. The actual field is at the first
|
||||
line: =${2:foo}=. When you type text in =${2:foo}=, the transformation
|
||||
will be evaluated and the result will be placed there as the
|
||||
transformed text. So in this example, if you type "baz" in the field,
|
||||
the transformed text will be "Baz". This example is also available in
|
||||
the screencast.
|
||||
|
||||
Another example is for =rst-mode=. In reStructuredText, the document
|
||||
title can be some text surrounded by "===" below and above. The "==="
|
||||
should be at least as long as the text. So
|
||||
|
||||
#+BEGIN_SRC rst
|
||||
=====
|
||||
Title
|
||||
=====
|
||||
#+END_SRC
|
||||
|
||||
is a valid title but
|
||||
|
||||
#+BEGIN_SRC rst
|
||||
===
|
||||
Title
|
||||
===
|
||||
#+END_SRC
|
||||
|
||||
is not. Here's an snippet for rst title:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
${1:$(make-string (string-width yas-text) ?\=)}
|
||||
${1:Title}
|
||||
${1:$(make-string (string-width yas-text) ?\=)}
|
||||
|
||||
$0
|
||||
#+END_SRC
|
||||
|
||||
Note that a mirror with a transform is not restricted to the text of
|
||||
the field it is mirroring. By making use of [[sym:yas-field-value][=yas-field-value=]], a
|
||||
mirror can look at any of the snippet's field (as mentioned above, all
|
||||
mirrors are updated when any field is updated). Here is an example
|
||||
which shows a "live" result of calling format:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
(format "${1:formatted %s}" "${2:value}")
|
||||
=> "${1:$(ignore-errors (format (yas-field-value 1) (yas-field-value 2)))}"
|
||||
#+END_SRC
|
||||
|
||||
To keep the example simple, it uses =ignore-errors= to suppress errors
|
||||
due to incomplete format codes.
|
||||
|
||||
** Fields with transformations
|
||||
|
||||
From version 0.6 on, you can also have Lisp transformation inside
|
||||
fields. These work mostly like mirror transformations. However, they
|
||||
are evaluated when you first enter the field, after each change you
|
||||
make to the field and also just before you exit the field.
|
||||
|
||||
The syntax is also a tiny bit different, so that the parser can
|
||||
distinguish between fields and mirrors. In the following example
|
||||
|
||||
: #define "${1:mydefine$(upcase yas-text)}"
|
||||
|
||||
=mydefine= gets automatically upcased to =MYDEFINE= once you enter the
|
||||
field. As you type text, it gets filtered through the transformation
|
||||
every time.
|
||||
|
||||
Note that to tell this kind of expression from a mirror with a
|
||||
transformation, YASnippet needs extra text between the =:= and the
|
||||
transformation's =$=. If you don't want this extra-text, you can use two
|
||||
=$='s instead.
|
||||
|
||||
: #define "${1:$$(upcase yas-text)}"
|
||||
|
||||
Please note that as soon as a transformation takes place, it changes the
|
||||
value of the field and sets it its internal modification state to
|
||||
=true=. As a consequence, the auto-deletion behaviour of normal fields
|
||||
does not take place. This is by design.
|
||||
|
||||
** Choosing fields value from a list and other tricks
|
||||
|
||||
As mentioned, the field transformation is invoked just after you enter
|
||||
the field, and with some useful variables bound, notably
|
||||
[[sym:yas-modified-p][=yas-modified-p=]] and [[sym:yas-moving-away-p][=yas-moving-away-p=]]. Because of this feature you
|
||||
can place a transformation in the primary field that lets you select
|
||||
default values for it.
|
||||
|
||||
For example, the [[sym:yas-choose-value][=yas-completing-read=]] function is version of
|
||||
=completing-read= which checks these variables. For example, asking
|
||||
the user for the initial value of a field:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
<div align="${2:$$(yas-completing-read "Alignment? " '("right" "center" "left"))}">
|
||||
$0
|
||||
</div>
|
||||
#+END_SRC
|
||||
|
||||
See the definition of [[sym:yas-choose-value][=yas-completing-read=]] to see how it was written
|
||||
using the two variables. If you're really lazy :) and can't spare a
|
||||
tab keypress, you can automatically move to the next field (or exit)
|
||||
after choosing the value with [[sym:yas-auto-next][=yas-auto-next=]]. The snippet above
|
||||
becomes:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
<div align="${2:$$(yas-auto-next
|
||||
(yas-completing-read
|
||||
"Alignment? "
|
||||
'("right" "center" "left")))}">
|
||||
$0
|
||||
</div>
|
||||
#+END_SRC
|
||||
|
||||
Here's another use, for =LaTeX-mode=, which calls reftex-label just as you
|
||||
enter snippet field 2. This one makes use of [[sym:yas-modified-p][=yas-modified-p=]] directly.
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
\section{${1:"Titel der Tour"}}%
|
||||
\index{$1}%
|
||||
\label{{2:"waiting for reftex-label call..."$(unless yas-modified-p (reftex-label nil 'dont-insert))}}%
|
||||
#+END_SRC
|
||||
|
||||
The function [[sym:yas-verify-value][=yas-verify-value=]] has another neat trick, and makes use
|
||||
of [[sym:yas-moving-away-p][=yas-moving-away-p=]]. Try it and see! Also, check out this [[http://groups.google.com/group/smart-snippet/browse_thread/thread/282a90a118e1b662][thread]]
|
||||
|
||||
** Nested placeholder fields
|
||||
|
||||
From version 0.6 on, you can also have nested placeholders of the type:
|
||||
|
||||
#+BEGIN_SRC snippet
|
||||
<div${1: id="${2:some_id}"}>$0</div>
|
||||
#+END_SRC
|
||||
|
||||
This allows you to choose if you want to give this =div= an =id=
|
||||
attribute. If you tab forward after expanding, it will let you change
|
||||
"some\_id" to whatever you like. Alternatively, you can just press =C-d=
|
||||
(which executes [[sym:yas-skip-and-clear-or-delete-char][=yas-skip-and-clear-or-delete-char=]]) and go straight to
|
||||
the exit marker.
|
||||
|
||||
By the way, =C-d= will only clear the field if you cursor is at the
|
||||
beginning of the field /and/ it hasn't been changed yet. Otherwise, it
|
||||
performs the normal Emacs =delete-char= command.
|
||||
|
||||
** Indentation markers
|
||||
|
||||
If [[sym:yas-indent-line][=yas-indent-line=]] is *not* set to '=auto=, it's still possible to
|
||||
indent specific lines by adding an indentation marker, =$>=, somewhere
|
||||
on the line.
|
||||
284
lisp/yasnippet/doc/snippet-expansion.org
Normal file
284
lisp/yasnippet/doc/snippet-expansion.org
Normal file
@@ -0,0 +1,284 @@
|
||||
#+SETUPFILE: org-setup.inc
|
||||
|
||||
#+TITLE: Expanding snippets
|
||||
|
||||
This section describes how YASnippet chooses snippets for expansion at point.
|
||||
|
||||
Maybe, you'll want some snippets to be expanded in a particular
|
||||
mode, or only under certain conditions, or be prompted using
|
||||
|
||||
* Triggering expansion
|
||||
|
||||
You can use YASnippet to expand snippets in different ways:
|
||||
|
||||
- When [[sym:yas-minor-mode][=yas-minor-mode=]] is active:
|
||||
- Type the snippet's *trigger key* then calling [[sym:yas-expand][=yas-expand=]]
|
||||
(bound to =TAB= by default).
|
||||
|
||||
- Use the snippet's *keybinding*.
|
||||
|
||||
- By expanding directly from the "YASnippet" menu in the menu-bar
|
||||
|
||||
- Using hippie-expand
|
||||
|
||||
- Call [[sym:yas-insert-snippet][=yas-insert-snippet=]] (use =M-x yas-insert-snippet= or its
|
||||
keybinding =C-c & C-s=).
|
||||
|
||||
- Use m2m's excellent auto-complete
|
||||
TODO: example for this
|
||||
|
||||
- Expanding from emacs-lisp code
|
||||
|
||||
** Trigger key
|
||||
|
||||
[[sym:yas-expand][=yas-expand=]] tries to expand a /snippet abbrev/ (also known as
|
||||
/snippet key/) before point. YASnippet also provides a /conditional
|
||||
binding/ for this command: the variable [[sym:yas-expand][=yas-maybe-expand=]] contains a
|
||||
special value which, when bound in a keymap, tells Emacs to call
|
||||
[[sym:yas-expand][=yas-expand=]] if and only if there is a snippet abbrev before point.
|
||||
If there is no snippet to expand, Emacs will behave as if [[sym:yas-expand][=yas-expand=]]
|
||||
is unbound and so will run whatever command is bound to that key
|
||||
normally.
|
||||
|
||||
When [[sym:yas-minor-mode][=yas-minor-mode=]] is enabled, it binds [[sym:yas-maybe-expand][=yas-maybe-expand=]] to =TAB=
|
||||
and =<tab>= by default, however, you can freely remove those bindings:
|
||||
|
||||
#+begin_src emacs-lisp :exports code
|
||||
(define-key yas-minor-mode-map (kbd "<tab>") nil)
|
||||
(define-key yas-minor-mode-map (kbd "TAB") nil)
|
||||
#+end_src
|
||||
|
||||
And set your own:
|
||||
|
||||
#+begin_src emacs-lisp :exports code
|
||||
;; Bind `SPC' to `yas-expand' when snippet expansion available (it
|
||||
;; will still call `self-insert-command' otherwise).
|
||||
(define-key yas-minor-mode-map (kbd "SPC") yas-maybe-expand)
|
||||
;; Bind `C-c y' to `yas-expand' ONLY.
|
||||
(define-key yas-minor-mode-map (kbd "C-c y") #'yas-expand)
|
||||
#+end_src
|
||||
|
||||
|
||||
To enable the YASnippet minor mode in all buffers globally use the
|
||||
command [[sym:yas-global-mode][=yas-global-mode=]]. This will enable a modeline indicator,
|
||||
=yas=:
|
||||
|
||||
[[./images/minor-mode-indicator.png]]
|
||||
|
||||
When you use [[sym:yas-global-mode][=yas-global-mode=]] you can also selectively disable
|
||||
YASnippet in some buffers by calling [[sym:yas-minor-mode][=yas-minor-mode=]] with a negative
|
||||
argument in the buffer's mode hook.
|
||||
|
||||
*** Fallback behaviour
|
||||
|
||||
YASnippet used to support a more complicated way of sharing
|
||||
keybindings before [[sym:yas-expand][=yas-maybe-expand=]] was added. This is now
|
||||
obsolete.
|
||||
|
||||
** Insert at point
|
||||
|
||||
The command [[sym:yas-insert-snippet][=yas-insert-snippet=]] lets you insert snippets at point
|
||||
/for your current major mode/. It prompts you for the snippet key
|
||||
first, and then for a snippet template if more than one template
|
||||
exists for the same key.
|
||||
|
||||
The list presented contains the snippets that can be inserted at point,
|
||||
according to the condition system. If you want to see all applicable
|
||||
snippets for the major mode, prefix this command with =C-u=.
|
||||
|
||||
The prompting methods used are again controlled by
|
||||
[[sym:yas-prompt-functions][=yas-prompt-functions=]].
|
||||
|
||||
*** Inserting region or register contents into snippet
|
||||
|
||||
It's often useful to inject already written text in the middle of a
|
||||
snippet. The variable [[sym:yas-wrap-around-region][=yas-wrap-around-region=]] when to t substitute
|
||||
the region contents into the =$0= placeholder of a snippet expanded by
|
||||
[[sym:yas-insert-snippet][=yas-insert-snippet=]]. Setting it to a character value (e.g. =?0=)
|
||||
will insert the contents of corresponding register.
|
||||
|
||||
Older (versions 0.9.1 and below) of Yasnippet, supported a setting of
|
||||
=cua= that is equivalent to =?0= but only worked with =cua-mode=
|
||||
turned on. This setting is still supported for backwards
|
||||
compatibility, but is now entirely equivalent to =?0=.
|
||||
|
||||
** Snippet keybinding
|
||||
|
||||
See the section of the =# binding:= directive in
|
||||
[[./snippet-development.org][Writing Snippets]].
|
||||
|
||||
** Expanding from the menu
|
||||
|
||||
See [[./snippet-menu.org][the YASnippet Menu]].
|
||||
|
||||
** Expanding with =hippie-expand=
|
||||
|
||||
To integrate with =hippie-expand=, just put
|
||||
[[sym:yas-hippie-try-expand][=yas-hippie-try-expand=]] in
|
||||
=hippie-expand-try-functions-list=. This probably makes more sense
|
||||
when placed at the top of the list, but it can be put anywhere you
|
||||
prefer.
|
||||
|
||||
** Expanding from emacs-lisp code
|
||||
|
||||
Sometimes you might want to expand a snippet directly from your own
|
||||
elisp code. You should call [[sym:yas-expand-snippet][=yas-expand-snippet=]] instead of
|
||||
[[sym:yas-expand][=yas-expand=]] in this case. [[sym:yas-expand-snippet][=yas-expand-snippet=]] takes a string in
|
||||
snippet template syntax, if you want to expand an existing snippet you
|
||||
can use [[sym:yas-lookup-snippet][=yas-lookup-snippet=]] to find its contents by name.
|
||||
|
||||
As with expanding from the menubar, the condition system and multiple
|
||||
candidates doesn't affect expansion (the condition system does affect
|
||||
[[sym:yas-lookup-snippet][=yas-lookup-snippet=]] though). In fact, expanding from the YASnippet
|
||||
menu has the same effect of evaluating the follow code:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(yas-expand-snippet template)
|
||||
#+END_SRC
|
||||
|
||||
See the internal documentation on [[sym:yas-expand-snippet][=yas-expand-snippet=]] and
|
||||
[[sym:yas-lookup-snippet][=yas-lookup-snippet=]] for more information.
|
||||
|
||||
* Controlling expansion
|
||||
|
||||
** Eligible snippets<<eligible-snippets>>
|
||||
|
||||
YASnippet does quite a bit of filtering to find out which snippets are
|
||||
eligible for expanding at the current cursor position.
|
||||
|
||||
In particular, the following things matter:
|
||||
|
||||
- Currently loaded snippets tables
|
||||
|
||||
These are loaded from a directory hierarchy in your file system. See
|
||||
[[./snippet-organization.org][Organizing Snippets]]. They are named
|
||||
after major modes like =html-mode=, =ruby-mode=, etc...
|
||||
|
||||
- Major mode of the current buffer
|
||||
|
||||
If the currrent major mode matches one of the loaded snippet tables,
|
||||
then all that table's snippets are considered for expansion. Use
|
||||
=M-x describe-variable RET major-mode RET= to find out which major
|
||||
mode you are in currently.
|
||||
|
||||
- Parent tables
|
||||
|
||||
Snippet tables defined as the parent of some other eligible table
|
||||
are also considered. This works recursively, i.e., parents of
|
||||
parents of eligible tables are also considered. As a special case,
|
||||
if a mode doesn't have a parent, then =fundamental-mode= is
|
||||
considered to be its parent.
|
||||
|
||||
- Buffer-local list of extra modes
|
||||
|
||||
Use [[sym:yas-activate-extra-mode][=yas-activate-extra-mode=]] to
|
||||
consider snippet tables whose name does not correspond to a major
|
||||
mode. Typically, you call this from a minor mode hook, for example:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
;; When entering rinari-minor-mode, consider also the snippets in the
|
||||
;; snippet table "rails-mode"
|
||||
(add-hook 'rinari-minor-mode-hook
|
||||
#'(lambda ()
|
||||
(yas-activate-extra-mode 'rails-mode)))
|
||||
#+END_SRC
|
||||
|
||||
- Buffer-local [[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]] variable
|
||||
|
||||
This variable provides finer grained control over what snippets can
|
||||
be expanded in the current buffer. For example, the constant
|
||||
[[sym:yas-not-string-or-comment-condition][=yas-not-string-or-comment-condition=]] has a value that disables
|
||||
snippet expansion inside comments or string literals. See [[condition-system][the
|
||||
condition system]] for more info.
|
||||
|
||||
** The condition system <<condition-system>>
|
||||
|
||||
Consider this scenario: you are an old Emacs hacker. You like the
|
||||
abbrev-way and bind [[sym:yas-expand][=yas-expand=]] to =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=).
|
||||
|
||||
If you use the =# condition := directive (see [[./snippet-development.org][Writing Snippets]]) you
|
||||
could just specify the condition for =if= to be =(not
|
||||
(python-syntax-comment-or-string-p))=. But how about =while=, =for=,
|
||||
etc? Writing the same condition for all the snippets is just boring.
|
||||
So you can instead set [[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]] to =(not
|
||||
(python-syntax-comment-or-string-p))= in =python-mode-hook=.
|
||||
|
||||
Then, what if you really want some particular snippet to expand even
|
||||
inside a comment? Set [[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]] like this
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(add-hook 'python-mode-hook
|
||||
(lambda ()
|
||||
(setq yas-buffer-local-condition
|
||||
(lambda ()
|
||||
(if (python-syntax-comment-or-string-p)
|
||||
'(require-snippet-condition . force-in-comment)
|
||||
t)))))
|
||||
#+END_SRC
|
||||
|
||||
... and for a snippet that you want to expand in comments, specify a
|
||||
condition which evaluates to the symbol =force-in-comment=. Then it
|
||||
can be expanded as you expected, while other snippets like =if= still
|
||||
can't expanded in comments.
|
||||
|
||||
For the full set of possible conditions, see the documentation for
|
||||
[[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]].
|
||||
|
||||
** Multiples snippet with the same key
|
||||
|
||||
The rules outlined [[eligible-snippets][above]] can return more than
|
||||
one snippet to be expanded at point.
|
||||
|
||||
When there are multiple candidates, YASnippet will let you select one.
|
||||
The UI for selecting multiple candidate can be customized through
|
||||
[[sym:yas-prompt-functions][=yas-prompt-functions=]] , which defines your preferred methods of being
|
||||
prompted for snippets.
|
||||
|
||||
You can customize it with
|
||||
=M-x customize-variable RET yas-prompt-functions RET=. Alternatively you
|
||||
can put in your emacs-file:
|
||||
|
||||
#+BEGIN_SRC emacs-lisp
|
||||
(setq yas-prompt-functions '(yas-x-prompt yas-dropdown-prompt))
|
||||
#+END_SRC
|
||||
|
||||
Currently there are some alternatives solution with YASnippet.
|
||||
|
||||
*** Use the X window system
|
||||
|
||||
[[./images/x-menu.png]]
|
||||
|
||||
The function [[sym:yas-x-prompt][=yas-x-prompt=]] can be used to show a popup menu for you to
|
||||
select. This menu will be part of you native window system widget, which
|
||||
means:
|
||||
|
||||
- It usually looks beautiful. E.g. when you compile Emacs with gtk
|
||||
support, this menu will be rendered with your gtk theme.
|
||||
- Your window system may or may not allow to you use =C-n=, =C-p= to
|
||||
navigate this menu.
|
||||
- This function can't be used when in a terminal.
|
||||
|
||||
*** Minibuffer prompting
|
||||
|
||||
[[./images/ido-menu.png]]
|
||||
|
||||
You can use functions [[sym:yas-completing-prompt][=yas-completing-prompt=]] for the classic emacs
|
||||
completion method or [[sym:yas-ido-prompt][=yas-ido-prompt=]] for a much nicer looking method.
|
||||
The best way is to try it. This works in a terminal.
|
||||
|
||||
*** Use =dropdown-menu.el=
|
||||
|
||||
[[./images/dropdown-menu.png]]
|
||||
|
||||
The function [[sym:yas-dropdown-prompt][=yas-dropdown-prompt=]] can also be placed in the
|
||||
[[sym:yas-prompt-functions][=yas-prompt-functions=]] list.
|
||||
|
||||
This works in both window system and terminal and is customizable, you
|
||||
can use =C-n=, =C-p= to navigate, =q= to quit and even press =6= as a
|
||||
shortcut to select the 6th candidate.
|
||||
|
||||
*** Roll your own
|
||||
|
||||
See the documentation on variable [[sym:yas-prompt-functions][=yas-prompt-functions=]]
|
||||
68
lisp/yasnippet/doc/snippet-menu.org
Normal file
68
lisp/yasnippet/doc/snippet-menu.org
Normal file
@@ -0,0 +1,68 @@
|
||||
#+SETUPFILE: org-setup.inc
|
||||
|
||||
#+TITLE: YASnippet menu
|
||||
|
||||
When [[sym:yas-minor-mode][=yas-minor-mode=]] is active, YASnippet will setup a menu just after
|
||||
the "Buffers" menu in the menubar.
|
||||
|
||||
In this menu, you can find
|
||||
|
||||
- The currently loaded snippet definitions, organized by major mode,
|
||||
and optional grouping.
|
||||
|
||||
- A rundown of the most common commands, (followed by their
|
||||
keybindings) including commands to load directories and reload all
|
||||
snippet definitions.
|
||||
|
||||
- A series of submenus for customizing and exploring YASnippet
|
||||
behavior.
|
||||
|
||||
[[./images/menu-1.png]]
|
||||
|
||||
* Loading snippets from menu
|
||||
|
||||
Invoking "Load snippets..." from the menu invokes [[sym:yas-load-directory][=yas-load-directory=]]
|
||||
and prompts you for a snippet directory hierarchy to load.
|
||||
|
||||
Also useful is the "Reload everything" item to invoke [[sym:yas-reload-all][=yas-reload-all=]]
|
||||
which uncondionally reloads all the snippets directories defined in
|
||||
[[sym:yas-snippet-dirs][=yas-snippet-dirs=]] and rebuilds the menus.
|
||||
|
||||
* Snippet menu behavior
|
||||
|
||||
YASnippet will list in this section all the loaded snippet definitions
|
||||
organized by snippet table name.
|
||||
|
||||
You can use this section to explore currently loaded snippets. If you
|
||||
click on one of them, the default behavior is to expand it,
|
||||
unconditionally, inside the current buffer.
|
||||
|
||||
You can however, customize variable [[sym:yas-visit-from-menu][=yas-visit-from-menu=]] to be =t=
|
||||
which will take you to the snippet definition file when you select it
|
||||
from the menu.
|
||||
|
||||
If you want the menu show only snippet tables whose name corresponds to
|
||||
a "real" major mode. You do this by setting [[sym:yas-use-menu][=yas-use-menu=]] to
|
||||
'=real-modes=.
|
||||
|
||||
Finally, to have the menu show only the tables for the currently active
|
||||
mode, set [[sym:yas-use-menu][=yas-use-menu=]] to =abbreviate=.
|
||||
|
||||
These customizations can also be found in the menu itself, under the
|
||||
"Snippet menu behavior" submenu.
|
||||
|
||||
* Controlling indenting
|
||||
|
||||
The "Indenting" submenu contains options to control the values of
|
||||
[[sym:yas-indent-line][=yas-indent-line=]] and [[sym:yas-also-auto-indent-first-line][=yas-also-auto-indent-first-line=]]. See
|
||||
[[./snippet-development.org][Writing snippets]].
|
||||
|
||||
* Prompting method
|
||||
|
||||
The "Prompting method" submenu contains options to control the value of
|
||||
[[sym:yas-prompt-functions][=yas-prompt-functions=]]. See [[./snippet-expansion.org][Expanding snippets]].
|
||||
|
||||
* Misc
|
||||
|
||||
The "Misc" submenu contains options to control the values of more
|
||||
variables.
|
||||
132
lisp/yasnippet/doc/snippet-organization.org
Normal file
132
lisp/yasnippet/doc/snippet-organization.org
Normal file
@@ -0,0 +1,132 @@
|
||||
#+SETUPFILE: org-setup.inc
|
||||
|
||||
#+TITLE: Organizing snippets
|
||||
|
||||
* Basic structure
|
||||
|
||||
Snippet collections can be stored in plain text files. They are
|
||||
arranged by sub-directories naming *snippet tables*. These mostly
|
||||
name Emacs major mode names.
|
||||
|
||||
#+begin_example
|
||||
.
|
||||
|-- c-mode
|
||||
| `-- printf
|
||||
|-- java-mode
|
||||
| `-- println
|
||||
`-- text-mode
|
||||
|-- email
|
||||
`-- time
|
||||
#+end_example
|
||||
|
||||
The collections are loaded into *snippet tables* which the
|
||||
triggering mechanism (see [[file:snippet-expansion.org][Expanding Snippets]]) looks up and
|
||||
(hopefully) causes the right snippet to be expanded for you.
|
||||
|
||||
* Setting up =yas-snippet-dirs=
|
||||
|
||||
The emacs variable [[sym:yas-snippet-dirs][=yas-snippet-dirs=]] tells YASnippet
|
||||
which collections to consider. It's used when you activate
|
||||
[[sym:yas-global-mode][=yas-global-mode=]] or call
|
||||
[[sym:yas-reload-all][=yas-reload-all=]] interactively.
|
||||
|
||||
The default considers:
|
||||
|
||||
- a personal collection that lives in =~/.emacs.d/snippets=
|
||||
- the bundled collection, taken as a relative path to =yasnippet.el= location
|
||||
|
||||
When you come across other snippet collections, do the following to try them
|
||||
out:
|
||||
|
||||
#+begin_src emacs-lisp :exports code
|
||||
;; Develop in ~/emacs.d/mysnippets, but also
|
||||
;; try out snippets in ~/Downloads/interesting-snippets
|
||||
(setq yas-snippet-dirs '("~/emacs.d/mysnippets"
|
||||
"~/Downloads/interesting-snippets"))
|
||||
|
||||
;; OR, keeping YASnippet defaults try out ~/Downloads/interesting-snippets
|
||||
(setq yas-snippet-dirs (append yas-snippet-dirs
|
||||
'("~/Downloads/interesting-snippets")))
|
||||
#+end_src
|
||||
|
||||
Collections appearing earlier in the list override snippets with same names
|
||||
appearing in collections later in the list. [[sym:yas-new-snippet][=yas-new-snippet=]] always stores
|
||||
snippets in the first collection.
|
||||
|
||||
* The =.yas-parents= file
|
||||
|
||||
It's very useful to have certain modes share snippets between
|
||||
themselves. To do this, choose a mode subdirectory and place a
|
||||
=.yas-parents= containing a whitespace-separated list of other mode
|
||||
names. When you reload those modes become parents of the original
|
||||
mode.
|
||||
|
||||
#+begin_example
|
||||
.
|
||||
|-- c-mode
|
||||
| |-- .yas-parents # contains "cc-mode text-mode"
|
||||
| `-- printf
|
||||
|-- cc-mode
|
||||
| |-- for
|
||||
| `-- while
|
||||
|-- java-mode
|
||||
| |-- .yas-parents # contains "cc-mode text-mode"
|
||||
| `-- println
|
||||
`-- text-mode
|
||||
|-- email
|
||||
`-- time
|
||||
#+end_example
|
||||
|
||||
|
||||
* TODO The =.yas-make-groups= file
|
||||
|
||||
If you place an empty plain text file =.yas-make-groups= inside one
|
||||
of the mode directories, the names of these sub-directories are
|
||||
considered groups of snippets and [[file:snippet-menu.org][the menu]] is organized much more
|
||||
cleanly:
|
||||
|
||||
[[./images/menu-groups.png]]
|
||||
|
||||
Another way to achieve this is to place a =# group:= directive
|
||||
inside the snippet definition. See [[./snippet-development.org][Writing Snippets]].
|
||||
|
||||
#+begin_example
|
||||
$ tree ruby-mode/
|
||||
ruby-mode/
|
||||
|-- .yas-make-groups
|
||||
|-- collections
|
||||
| |-- each
|
||||
| `-- ...
|
||||
|-- control structure
|
||||
| |-- forin
|
||||
| `-- ...
|
||||
|-- definitions
|
||||
| `-- ...
|
||||
`-- general
|
||||
`-- ...
|
||||
#+end_example
|
||||
|
||||
Yet another way to create a nice snippet menu is to write into
|
||||
=.yas-make-groups= a menu definition. TODO
|
||||
|
||||
* The =.yas-setup.el= file
|
||||
|
||||
If there is file named =.yas-setup.el= in a mode's snippet
|
||||
subdirectory, it is loaded along with the snippets. Utility
|
||||
functions used by the snippets can be put here.
|
||||
|
||||
* The =.yas-compiled-snippet.el= file
|
||||
|
||||
You may compile a top-level snippet directory with the
|
||||
=yas-compile-directory= function, which will create a
|
||||
=.yas-compiled-snippets.el= file under each mode subdirectory,
|
||||
which contains definitions for all snippets in the subdirectory.
|
||||
Compilation helps improve loading time.
|
||||
|
||||
Alternatively, you may compile all directories in the list
|
||||
=yas-snippet-dirs= with the =yas-recompile-all= function.
|
||||
|
||||
* The =.yas-skip= file
|
||||
|
||||
A =.yas-skip= file in a mode's snippet subdirectory tells YASnippet
|
||||
not to load snippets from there.
|
||||
12
lisp/yasnippet/doc/snippet-reference.org
Normal file
12
lisp/yasnippet/doc/snippet-reference.org
Normal file
@@ -0,0 +1,12 @@
|
||||
#+SETUPFILE: org-setup.inc
|
||||
|
||||
#+TITLE: Reference
|
||||
|
||||
#+BEGIN_SRC emacs-lisp :exports results :results value raw
|
||||
(yas--document-symbols 1 `("Interactive functions" . ,#'interactive-form)
|
||||
`("Customization variables" . ,#'(lambda (sym)
|
||||
(and (boundp sym)
|
||||
(get sym 'standard-value))))
|
||||
`("Useful functions" . ,#'fboundp)
|
||||
`("Useful variables" . ,#'boundp))
|
||||
#+END_SRC
|
||||
354
lisp/yasnippet/yasnippet-debug.el
Normal file
354
lisp/yasnippet/yasnippet-debug.el
Normal file
@@ -0,0 +1,354 @@
|
||||
;;; yasnippet-debug.el --- debug functions for yasnippet -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2010-2025 Free Software Foundation, Inc.
|
||||
|
||||
;; Author: João Távora
|
||||
;; Keywords: emulations, convenience
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;; Some debug functions. When loaded from the command line, provides
|
||||
;; quick way to test out snippets in a fresh Emacs instance.
|
||||
;;
|
||||
;; emacs -Q -l yasnippet-debug [-v[v]]
|
||||
;; [-M:<modename>] [-M.<filext>] [-S:[<snippet-file|name>]]
|
||||
;; [-- <more-arguments-passed-to-Emacs>...]
|
||||
;;
|
||||
;; See the source in `yas-debug-process-command-line' for meaning of
|
||||
;; args.
|
||||
;;
|
||||
;;; Code:
|
||||
|
||||
(defconst yas--loaddir
|
||||
(file-name-directory (or load-file-name buffer-file-name))
|
||||
"Directory that yasnippet was loaded from.")
|
||||
|
||||
(require 'yasnippet (if (boundp 'yas--loaddir)
|
||||
;; Don't require '-L <path>' when debugging.
|
||||
(expand-file-name "yasnippet" yas--loaddir)))
|
||||
(require 'cl-lib)
|
||||
(require 'color nil t)
|
||||
(require 'edebug)
|
||||
(eval-when-compile
|
||||
(require 'subr-x nil t)
|
||||
(cond ((fboundp 'when-let*) nil) ; Introduced in 26.
|
||||
((fboundp 'when-let) ; Introduced in 25.1,
|
||||
(defalias 'when-let* 'when-let)) ; deprecated in 26.
|
||||
(t (defmacro when-let* (key-vals &rest body)
|
||||
(declare (indent 1) (debug ((symbolp form) body)))
|
||||
(let ((key-val (pop key-vals)))
|
||||
(if key-val
|
||||
`(let ((,(car key-val) ,(cadr key-val)))
|
||||
(if ,(car key-val)
|
||||
(when-let* ,key-vals
|
||||
,@body)))
|
||||
`(progn ,@body)))))))
|
||||
|
||||
(defvar yas-debug-live-indicators
|
||||
(make-hash-table :test #'eq))
|
||||
|
||||
(defun yas-debug-live-colors ()
|
||||
(let ((colors ()))
|
||||
(maphash (lambda (_k v) (push (nth 1 (car v)) colors)) yas-debug-live-indicators)
|
||||
colors))
|
||||
|
||||
(defvar yas-debug-recently-live-indicators)
|
||||
|
||||
(defun yas-debug-get-live-indicator (location)
|
||||
(require 'color)
|
||||
(when (boundp 'yas-debug-recently-live-indicators)
|
||||
(push location yas-debug-recently-live-indicators))
|
||||
(let (beg end)
|
||||
(if (markerp location)
|
||||
(setq beg (setq end (marker-position location)))
|
||||
(setq beg (yas-debug-ov-fom-start location)
|
||||
end (yas-debug-ov-fom-end location)))
|
||||
(or (when-let* ((color-ov (gethash location yas-debug-live-indicators)))
|
||||
(if (and beg end) (move-overlay (cdr color-ov) beg end)
|
||||
(delete-overlay (cdr color-ov)))
|
||||
color-ov)
|
||||
(let* ((live-colors (yas-debug-live-colors))
|
||||
(color
|
||||
(cl-loop with best-color = nil with max-dist = -1
|
||||
for color = (format "#%06X" (random #x1000000))
|
||||
for comp = (if (fboundp 'color-complement)
|
||||
(apply #'color-rgb-to-hex (color-complement color))
|
||||
color)
|
||||
if (< (color-distance color (face-foreground 'default))
|
||||
(color-distance comp (face-foreground 'default)))
|
||||
do (setq color comp)
|
||||
for dist = (cl-loop for c in live-colors
|
||||
minimize (color-distance c color))
|
||||
if (or (not live-colors) (> dist max-dist))
|
||||
do (setq best-color color) (setq max-dist dist)
|
||||
repeat (if live-colors 100 1)
|
||||
finally return `(:background ,best-color)))
|
||||
(ov (make-overlay beg end)))
|
||||
(if (markerp location)
|
||||
(overlay-put ov 'before-string (propertize "↓" 'face color))
|
||||
(overlay-put ov 'before-string (propertize "↘" 'face color))
|
||||
(overlay-put ov 'after-string (propertize "↙" 'face color)))
|
||||
(puthash location (cons color ov) yas-debug-live-indicators)))))
|
||||
|
||||
(defun yas-debug-live-marker (marker)
|
||||
(let* ((color-ov (yas-debug-get-live-indicator marker))
|
||||
(color (car color-ov))
|
||||
(ov (cdr color-ov))
|
||||
(decorator (overlay-get ov 'before-string))
|
||||
(str (format "at %d" (+ marker))))
|
||||
(if (markerp marker)
|
||||
(propertize str
|
||||
'cursor-sensor-functions
|
||||
`(,(lambda (_window _oldpos dir)
|
||||
(overlay-put
|
||||
ov 'before-string
|
||||
(propertize decorator
|
||||
'face (if (eq dir 'entered)
|
||||
'mode-line-highlight color)))))
|
||||
'face color)
|
||||
str)))
|
||||
|
||||
(defun yas-debug-ov-fom-start (ovfom)
|
||||
(cond ((overlayp ovfom) (overlay-start ovfom))
|
||||
((integerp ovfom) ovfom)
|
||||
(t (yas--fom-start ovfom))))
|
||||
(defun yas-debug-ov-fom-end (ovfom)
|
||||
(cond ((overlayp ovfom) (overlay-end ovfom))
|
||||
((integerp ovfom) ovfom)
|
||||
(t (yas--fom-end ovfom))))
|
||||
|
||||
(defun yas-debug-live-range (range)
|
||||
(let* ((color-ov (yas-debug-get-live-indicator range))
|
||||
(color (car color-ov))
|
||||
(ov (cdr color-ov))
|
||||
(decorator-beg (overlay-get ov 'before-string))
|
||||
(decorator-end (overlay-get ov 'after-string))
|
||||
(beg (yas-debug-ov-fom-start range))
|
||||
(end (yas-debug-ov-fom-end range)))
|
||||
(if (and beg end (or (overlayp range)
|
||||
(and (not (integerp beg))
|
||||
(not (integerp end)))))
|
||||
(propertize (format "from %d to %d" (+ beg) (+ end))
|
||||
'cursor-sensor-functions
|
||||
`(,(lambda (_window _oldpos dir)
|
||||
(let ((face (if (eq dir 'entered)
|
||||
'mode-line-highlight color)))
|
||||
(overlay-put ov 'before-string
|
||||
(propertize decorator-beg 'face face))
|
||||
(overlay-put ov 'after-string
|
||||
(propertize decorator-end 'face face)))))
|
||||
'face color)
|
||||
"<dead>")))
|
||||
|
||||
(defmacro yas-debug-with-tracebuf (outbuf &rest body)
|
||||
(declare (indent 1) (debug (sexp body)))
|
||||
(let ((tracebuf-var (make-symbol "tracebuf")))
|
||||
`(let ((,tracebuf-var (or ,outbuf (get-buffer-create "*YASnippet trace*"))))
|
||||
(unless (eq ,tracebuf-var (current-buffer))
|
||||
(cl-flet ((printf (fmt &rest args)
|
||||
(with-current-buffer ,tracebuf-var
|
||||
(insert (apply #'format fmt args)))))
|
||||
(unless ,outbuf
|
||||
(with-current-buffer ,tracebuf-var
|
||||
(erase-buffer)
|
||||
(when (fboundp 'cursor-sensor-mode)
|
||||
(cursor-sensor-mode +1))
|
||||
(setq truncate-lines t)))
|
||||
(setq ,outbuf ,tracebuf-var)
|
||||
(save-restriction
|
||||
(widen)
|
||||
,@body))))))
|
||||
|
||||
|
||||
(defun yas-debug-snippet (snippet &optional outbuf)
|
||||
(yas-debug-with-tracebuf outbuf
|
||||
(when-let* ((overlay (yas--snippet-control-overlay snippet)))
|
||||
(printf "\tsid: %d control overlay %s\n"
|
||||
(yas--snippet-id snippet)
|
||||
(yas-debug-live-range overlay)))
|
||||
(when-let* ((active-field (yas--snippet-active-field snippet)))
|
||||
(unless (consp (yas--field-start active-field))
|
||||
(printf "\tactive field: #%d %s %s covering \"%s\"\n"
|
||||
(or (yas--field-number active-field) -1)
|
||||
(if (yas--field-modified-p active-field) "**" "--")
|
||||
(yas-debug-live-range active-field)
|
||||
(buffer-substring-no-properties (yas--field-start active-field) (yas--field-end active-field)))))
|
||||
(when-let* ((exit (yas--snippet-exit snippet)))
|
||||
(printf "\tsnippet-exit: %s next: %s\n"
|
||||
(yas-debug-live-marker (yas--exit-marker exit))
|
||||
(yas--exit-next exit)))
|
||||
(dolist (field (yas--snippet-fields snippet))
|
||||
(unless (consp (yas--field-start field))
|
||||
(printf "\tfield: %d %s %s covering \"%s\" next: %s%s\n"
|
||||
(or (yas--field-number field) -1)
|
||||
(if (yas--field-modified-p field) "**" "--")
|
||||
(yas-debug-live-range field)
|
||||
(buffer-substring-no-properties (yas--field-start field) (yas--field-end field))
|
||||
(yas--debug-format-fom-concise (yas--field-next field))
|
||||
(if (yas--field-parent-field field)
|
||||
(format " parent: %s"
|
||||
(yas--debug-format-fom-concise
|
||||
(yas--field-parent-field field)))
|
||||
"")))
|
||||
(dolist (mirror (yas--field-mirrors field))
|
||||
(unless (consp (yas--mirror-start mirror))
|
||||
(printf "\t\tmirror: %s covering \"%s\" next: %s\n"
|
||||
(yas-debug-live-range mirror)
|
||||
(buffer-substring-no-properties (yas--mirror-start mirror) (yas--mirror-end mirror))
|
||||
(yas--debug-format-fom-concise (yas--mirror-next mirror))))))))
|
||||
|
||||
(defvar yas-debug-target-buffer nil)
|
||||
(defvar yas-debug-target-snippets nil nil)
|
||||
(make-variable-buffer-local 'yas-debug-target-snippets)
|
||||
|
||||
(defvar yas-debug-undo nil)
|
||||
|
||||
(defun yas-toggle-debug-undo (value)
|
||||
(interactive (list (not yas-debug-undo)))
|
||||
(setq yas-debug-undo value)
|
||||
(yas--message 3 "debug undo %sabled" (if yas-debug-undo "en" "dis")))
|
||||
|
||||
(defun yas-debug--target-snippet (snippet)
|
||||
(add-to-list 'yas-debug-target-snippets snippet))
|
||||
|
||||
(defun yas-debug--untarget-snippet (snippet)
|
||||
(setq yas-debug-target-snippets
|
||||
(remq snippet yas-debug-target-snippets))
|
||||
(maphash (lambda (_k color-ov)
|
||||
(delete-overlay (cdr color-ov)))
|
||||
yas-debug-live-indicators)
|
||||
(clrhash yas-debug-live-indicators))
|
||||
|
||||
(defun yas-debug-snippets (&optional outbuf hook)
|
||||
"Print debug information on active snippets to buffer OUTBUF.
|
||||
If OUTBUF is nil, use a buffer named \"*YASsnippet trace*\".
|
||||
If HOOK is non-nil, install `yas-debug-snippets' in
|
||||
`post-command-hook' to update the information on every command
|
||||
after this one. If it is `snippet-navigation' then install hook
|
||||
buffer-locally, otherwise install it globally. If HOOK is
|
||||
`edebug-create', also instrument the function
|
||||
`yas--snippet-parse-create' with `edebug' and show its source."
|
||||
(interactive (list nil t))
|
||||
(condition-case err
|
||||
(yas-debug-with-tracebuf outbuf
|
||||
(unless (buffer-live-p yas-debug-target-buffer)
|
||||
(setq yas-debug-target-buffer nil))
|
||||
(with-current-buffer (or yas-debug-target-buffer (current-buffer))
|
||||
(when yas-debug-target-snippets
|
||||
(setq yas-debug-target-snippets
|
||||
(cl-delete-if-not #'yas--snippet-p yas-debug-target-snippets)))
|
||||
(let ((yas-debug-recently-live-indicators nil))
|
||||
(printf "(length yas--snippets-snippets) => %d\n"
|
||||
(length yas--active-snippets))
|
||||
(dolist (snippet (or yas-debug-target-snippets
|
||||
(yas-active-snippets)))
|
||||
(printf "snippet %d\n" (yas--snippet-id snippet))
|
||||
(yas-debug-snippet snippet outbuf))
|
||||
(maphash (lambda (loc color-ov)
|
||||
(unless (memq loc yas-debug-recently-live-indicators)
|
||||
(delete-overlay (cdr color-ov))
|
||||
(remhash loc yas-debug-live-indicators)))
|
||||
yas-debug-live-indicators))
|
||||
(when (and yas-debug-undo (listp buffer-undo-list))
|
||||
(printf "Undo list has %s elements:\n" (length buffer-undo-list))
|
||||
(cl-loop for undo-elem in buffer-undo-list
|
||||
do (printf "%S\n" undo-elem))))
|
||||
(when hook
|
||||
(setq yas-debug-target-buffer (current-buffer))
|
||||
(advice-add 'yas--snippet-parse-create :before #'yas-debug--target-snippet)
|
||||
(advice-add 'yas--commit-snippet :after #'yas-debug--untarget-snippet)
|
||||
(add-hook 'post-command-hook #'yas-debug-snippets
|
||||
nil (eq hook 'snippet-navigation))
|
||||
;; Window management is slapped together, it does what I
|
||||
;; want when the caller has a single window open. Good
|
||||
;; enough for now.
|
||||
(when (eq hook 'edebug-create)
|
||||
(edebug-instrument-function 'yas--snippet-parse-create)
|
||||
(let ((buf-point (find-function-noselect 'yas--snippet-parse-create)))
|
||||
(with-current-buffer (car buf-point)
|
||||
(goto-char (cdr buf-point)))))
|
||||
outbuf))
|
||||
((debug error) (signal (car err) (cdr err)))))
|
||||
|
||||
(defun yas-debug-snippet-create ()
|
||||
(yas-debug-snippets nil 'create))
|
||||
|
||||
(defun yas--debug-format-fom-concise (fom)
|
||||
(when fom
|
||||
(cond ((yas--field-p fom)
|
||||
(format "field %s from %d to %d"
|
||||
(yas--field-number fom)
|
||||
(+ (yas--field-start fom))
|
||||
(+ (yas--field-end fom))))
|
||||
((yas--mirror-p fom)
|
||||
(format "mirror from %d to %d"
|
||||
(+ (yas--mirror-start fom))
|
||||
(+ (yas--mirror-end fom))))
|
||||
(t
|
||||
(format "snippet exit at %d"
|
||||
(+ (yas--fom-start fom)))))))
|
||||
|
||||
(defun yas-debug-process-command-line (&optional options)
|
||||
"Implement command line processing."
|
||||
(setq yas-verbosity 99)
|
||||
(setq yas-triggers-in-field t)
|
||||
(setq debug-on-error t)
|
||||
(let* ((snippet-mode 'fundamental-mode)
|
||||
(snippet-key nil))
|
||||
(unless options
|
||||
(setq options (cl-loop for opt = (pop command-line-args-left)
|
||||
while (and opt (not (equal opt "--"))
|
||||
(string-prefix-p "-" opt))
|
||||
collect opt)))
|
||||
(when-let* ((mode (cl-member "-M:" options :test #'string-prefix-p)))
|
||||
(setq snippet-mode (intern (concat (substring (car mode) 3) "-mode"))))
|
||||
(when-let* ((mode (cl-member "-M." options :test #'string-prefix-p)))
|
||||
(setq snippet-mode
|
||||
(cdr (cl-assoc (substring (car mode) 2) auto-mode-alist
|
||||
:test (lambda (ext regexp) (string-match-p regexp ext))))))
|
||||
(switch-to-buffer (get-buffer-create "*yas test*"))
|
||||
(funcall snippet-mode)
|
||||
(when-let* ((snippet-file (cl-member "-S:" options :test #'string-prefix-p)))
|
||||
(setq snippet-file (substring (car snippet-file) 3))
|
||||
(if (file-exists-p snippet-file)
|
||||
(with-temp-buffer
|
||||
(insert-file-contents snippet-file)
|
||||
(let ((snippet-deflist (yas--parse-template snippet-file)))
|
||||
(yas-define-snippets snippet-mode (list snippet-deflist))
|
||||
(setq snippet-key (car snippet-deflist))))
|
||||
(yas-reload-all)
|
||||
(let ((template (yas--lookup-snippet-1 snippet-file snippet-mode)))
|
||||
(if template
|
||||
(setq snippet-key (yas--template-key template))
|
||||
(error "No such snippet `%s'" snippet-file)))))
|
||||
(display-buffer (find-file-noselect
|
||||
(expand-file-name "yasnippet.el" yas--loaddir)))
|
||||
(when-let* ((verbosity (car (or (member "-v" options) (member "-vv" options)))))
|
||||
(set-window-buffer
|
||||
(split-window) (yas-debug-snippets
|
||||
nil (if (equal verbosity "-vv") 'edebug-create t))))
|
||||
(yas-minor-mode +1)
|
||||
(when snippet-key (insert snippet-key))))
|
||||
|
||||
(when command-line-args-left
|
||||
(yas-debug-process-command-line))
|
||||
|
||||
(provide 'yasnippet-debug)
|
||||
;; Local Variables:
|
||||
;; indent-tabs-mode: nil
|
||||
;; autoload-compute-prefixes: nil
|
||||
;; End:
|
||||
;;; yasnippet-debug.el ends here
|
||||
@@ -7,4 +7,7 @@
|
||||
:commit "dd570a6b22364212fff9769cbf4376bdbd7a63c5"
|
||||
:revdesc "dd570a6b2236"
|
||||
:keywords '("convenience" "emulation")
|
||||
:authors '(("pluskid" . "pluskid@gmail.com")
|
||||
("João Távora" . "joaotavora@gmail.com")
|
||||
("Noam Postavsky" . "npostavs@gmail.com"))
|
||||
:maintainers '(("Noam Postavsky" . "npostavs@gmail.com")))
|
||||
|
||||
Reference in New Issue
Block a user