|
HowtoDefineSnippet
Explains how to define a snippet.
snippets are defined through the function yas/define. Or you can put your snippets in files and use yas/load-directory to load them. There's also yas/compile-bundle to compile your customized snippets into a stand-alone bundle. A stand-alone bundle is convenient to load (just require it) and faster than parsing the directory hierarchy every time. Functionsyas/defineThe basic syntax of yas/define is: (yas/define MODE KEY TEMPLATE &optional NAME) The parameters are:
(yas/define 'c-mode "if" "if (${condition})
{
$0
}" "if (...) { ... }")On what's the syntax of TEMPLATE, see later section. You can have multiple snippets with the same KEY. For example: (yas/define 'c-mode "if.one-stmt" "if (${condition})
$0" "if (...) ...")The tricky here is that when defining a snippet, the KEY is treated like a file name, and the extension is stripped. I.e. .one-stmt is stripped and if becomes the really key. If you define a snippet with exactly the same KEY as an earlier one, it will overwrite the old one. But if you add a different suffix (or extension ), there can be multiple snippets bind to the same KEY. A popup menu will be shown to let you select which one to expand if there are multiple snippets bind to the KEY. The NAME of the snippets will be shown in the menu, so it is a good idea to keep the NAME descriptive. yas/define-snippetsYou can use yas/define-snippets to define a bunch of snippet for a mode at a time. The basic syntax is: (yas/define-snippets MODE SNIPPETS &optional parent) Here's an example: (yas/define-snippets 'text-mode
'(("email" "`user-mail-address`" "User's email address")
("time" "`(current-time-string)`" "Current Time")
("foo" "blablablabla")))As you see from the example. SNIPPETS is a list of snippet definition. The syntax of each definition is identical to yas/define. The last optional parameter PARENT can be used to specify the parent mode. The search strategy for a snippet is: search in current mode snippet table, then recursively search the parent snippet table if any. yas/load-directoryThe basic syntax of yas/load-directory is: (yas/load-directory DIRECTORY) It's very simple to use: (yas/load-directory "~/.emacs.d/snippets/") You can also use M-x yas/load-directory to interactively select which directory to load. The directory should contains subdirectories whose names correspond to particular modes. And under those subdirectories are snippets definition for each mode. A typical directory hierarchy look like this: snippets/
+-- c-mode
| +-- if
| +-- for
| `-- main
+-- java-mode
| +-- if
| `-- class
`-- ruby-mode
+-- each
`-- selectThe snippet file name acts as KEY of the snippet. The TEMPLATE and NAME are parsed from the file content. A typical snippet file looks like this: #name : select { |...| ... }
# --
select { |${1:element}| $0 }If there's a line of # -- (exactly), then all contents above (includes) that line are treated as comments. And all contents below that line are treated as the TEMPLATE. We can specify variables in comment section. Here's a list of supported variables (only one currently):
#variable-name : variable-value However, if there's no # -- line, the contents of the whole file is treated as the TEMPLATE. Note the newline at the end of file counts as the TEMPLATE content. So please don't add a newline (and don't let your editor to automatically add one for you) at the end of the buffer if you don't want your snippet to insert a newline at the end. From version 0.2.0, the directory hierarchy can also contains recursive subdirectories. E.g (only show directories): snippets/ +-- cc-mode/ | +-- c-mode/ | +-- c++-mode/ | +-- java-mode/ `-- text-mode/ Here cc-mode will become the parent mode of c-mode, c++-mode and java-mode automatically. yas/compile-bundleThe basic syntax for yas/compile-bundle is: (yas/compile-bundle YASNIPPET YASNIPPET-BUNDLE SNIPPET-ROOTS) The parameters are:
(yas/compile-bundle "~/.emacs.d/plugins/yasnippet/yasnippet.el"
"~/.emacs.d/plugins/yasnippet-bundle.el"
'("~/.emacs.d/plugins/yasnippet/snippets"))Note if you have only one root directory for snippets, you can simple write the last parameter like this: (yas/compile-bundle "~/.emacs.d/plugins/yasnippet/yasnippet.el"
"~/.emacs.d/plugins/yasnippet-bundle.el"
"~/.emacs.d/plugins/yasnippet/snippets")It will
SyntaxHere we explain the syntax for the snippet TEMPLATE. Plain textWhen a snippet is expanded. The key is replaced by its template. A template can contains arbitrary text. Except $ and `. They are special characters, needed to be escaped by adding a \ in front. Here's an example for perl-mode: eval {
${1:# do something risky...}
};
if (\$@) {
${2:# handle failure...}
}Note in the line if (\$@) {, the $ is escaped. Sometimes it is also necessary to escape \ itself. For example, if you want \$, you need to use \\$ instead. Embedded elisp codeElisp code can be embedded inside the template. They are written inside back-quotes (`): `some elisp arbitrary code` They are evaluated when the snippet is being expanded. The evaluation is done in the same buffer as the snippet being expanded, so here's an example for c-mode: #ifndef ${1:_`(upcase (file-name-nondirectory (file-name-sans-extension (buffer-file-name))))`_H_}
#define $1
$0
#endif /* $1 */It get the current buffer-file-name, strip the directory part and extension part, and upcase it to produce the guard macro definition for a header file. Tab StopsTab stops are fields that you can navigate back and forth by TAB and S-TAB. They are written by $ followed a number: $N $0 have 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: <div$1>
$0
</div>When you expand a snippet, the point is firstly placed at $1. You can optionally insert some text and press TAB to go to $0. PlaceholdersTab stops can have default values -- a.k.a placeholders. The syntax is like this: ${N:default value}They acts as the default value for a tab stop. But when you firstly type at a tab stop, the default value will be replaced by your typing. MirrorsWe refer the tab stops with placeholders as a field. A field can have mirrors. Its mirrors will get updated when you change the text of a field. Here's an example: \begin{${1:enumerate}}
$0
\end{$1}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(YouTube or avi video). The tab stops with the same number to the field act as its mirrors. If none of the tab stops has an initial value, the first one is selected as the field and others mirrors. There can also be un-numbered fields. like this: if (${condition})
{
$0
}They'll never have any mirrors, since no tab stops will have the same number to it. Two un-numbered fields act as they have a different number. TransformationsIf the default value of a field starts with $, then it is interpreted as the transformation code instead of default value. A transformation is some arbitrary elisp code that will get evaluated in an environment when the variable text is bind to the inputted text of the field. Here's an example for Objective-C: - (${1:id})${2:foo}
{
return $2;
}
- (void)set${2:$(capitalize text)}:($1)aValue
{
[$2 autorelease];
$2 = [aValue retain];
}
$0Look at ${2:$(capitalize text)}, it is a transformation instead of a placeholder. The actual placeholder 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 transformated 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 ===== Title ===== is a valid title but === Title === is not. Here's an snippet for rst title: ${1:$(make-string (string-width text) ?\=)}
${1:Title}
${1:$(make-string (string-width text) ?\=)}
$0The "=" will be adjusted automatically according to the title string you typed. |
Sign in to add a comment

Hi! This is great! Do you know why I can't use groups with string-match? Try this snippet:
Primary field: ${1:foo} Mirror field : $1 Upcase field : ${1:$(upcase text)} First number : ${1:$(if (string-match "[0-9]*" text) (match-string 0 text) "no match")} Non-working : ${1:$(if (string-match "\\([0-9]*\\)" text) (match-string 1 text) "no match")}Eval and try to type 123abc.. the example on the bottom does not work.. Lets fix it! I'm pumped!
I have several suggestions to you, and if you need I could also code some elisp (would need some pointers to get started, of course) Could we talk on email/irc during weekend, or should I use the google groups?
@hugows: You can post to the discussion group. Or you can directly email to me. :) But I haven't gotten used to IRC yet.
@hugows: Hi! I'm sorry I didn't see this comment until now. I'm not notified by commenting on wiki pages. I've setup the notifier now. So I'll be notified by all upcoming comments.
As to the problem, I think it works fine (at least for 0.3.1). Except \ need to be escaped, try:
Primary field: ${1:foo} Mirror field : $1 Upcase field : ${1:$(upcase text)} First number : ${1:$(if (string-match "[0-9]" text) (match-string 0 text) "no match")} Now-working : ${1:$(if (string-match "\\\\([0-9]\\\\)" text) (match-string 1 text) "no match")}Works fine for me! :)