- [submodule "extras/bundles/ruby-tmbundle"]
- path = extras/bundles/ruby-tmbundle
- url = http://github.com/drnic/ruby-tmbundle.git
- [submodule "extras/bundles/html-tmbundle"]
- path = extras/bundles/html-tmbundle
- url = http://github.com/drnic/html-tmbundle.git
- [submodule "extras/bundles/rails-tmbundle"]
- path = extras/bundles/rails-tmbundle
- url = http://github.com/drnic/ruby-on-rails-tmbundle.git
+ [submodule "snippets"]
+ path = snippets
+ url = https://github.com/AndreaCrotti/yasnippet-snippets.git
+ branch = master
+ [submodule "yasmate"]
+ path = yasmate
+ url = https://github.com/capitaomorte/yasmate.git
--- /dev/null
+ language: emacs
+
+ env:
+ - "EMACS=emacs23"
+ - "EMACS=emacs24"
+
+ install:
+ - if [ "$EMACS" = "emacs23" ]; then
+ sudo apt-get -qq update &&
+ sudo apt-get -qq -f install &&
+ sudo apt-get -qq install emacs23-nox &&
+ curl -LO https://raw.githubusercontent.com/ohler/ert/c619b56c5bc6a866e33787489545b87d79973205/lisp/emacs-lisp/ert.el &&
+ curl -LO https://raw.githubusercontent.com/ohler/ert/c619b56c5bc6a866e33787489545b87d79973205/lisp/emacs-lisp/ert-x.el &&
+ curl -Lo cl-lib.el http://elpa.gnu.org/packages/cl-lib-0.5.el;
+ fi
+ - if [ "$EMACS" = "emacs24" ]; then
+ sudo add-apt-repository -y ppa:cassou/emacs &&
+ sudo apt-get -qq update &&
+ sudo apt-get -qq -f install &&
+ sudo apt-get -qq install emacs24-nox;
+ fi
+
+ script:
+ - rake compile; rake tests
--- /dev/null
+ # Submitting Bug Reports\r
+ \r
+ Please read [Important note regarding bug reporting][bugnote].\r
+ \r
+ # Contributing to Yasnippet\r
+ \r
+ ## Copyright Assignment\r
+ \r
+ Yasnippet is part of GNU ELPA, so it falls under the same copyright\r
+ assignment policy as the rest of Emacs (see "Copyright Assignment" in\r
+ https://www.gnu.org/software/emacs/CONTRIBUTE). A copyright assignment\r
+ for Emacs also covers Yasnippet.\r
+ \r
+ ## Commit message format\r
+ \r
+ The commit message format roughly follows Emacs conventions, although\r
+ there is no separate Changelog file.\r
+ \r
+ The commit message's first sentence should be capitalized, no period\r
+ \r
+ It may be followed by a paragraph with a longer explanation. The\r
+ changelog style entry goes at the end of the message.\r
+ \r
+ * foo.el (a-function): Terse summary of per-function changes.\r
+ \r
+ \r
+ [bugnote]: https://github.com/capitaomorte/yasnippet#important-note-regarding-bug-reporting\r
+ [![Build Status](https://travis-ci.org/capitaomorte/yasnippet.png)](https://travis-ci.org/capitaomorte/yasnippet)
+
# Intro
**YASnippet** is a template system for Emacs. It allows you to
templates. Bundled language templates include: C, C++, C#, Perl,
Python, Ruby, SQL, LaTeX, HTML, CSS and more. The snippet syntax
is inspired from [TextMate's][textmate-snippets] syntax, you can
- even [import][import-docs] most TextMate templates to
+ even [import](#import) most TextMate templates to
YASnippet. Watch [a demo on YouTube][youtube-demo] or download a
[higher resolution version][high-res-demo].
[textmate-snippets]: http://manual.macromates.com/en/snippets
- [import-docs]: http://yasnippet.googlecode.com/svn/trunk/doc/snippet-development.html#importing-textmate-snippets
[youtube-demo]: http://www.youtube.com/watch?v=ZCGmZK4V7Sg
[high-res-demo]: http://yasnippet.googlecode.com/files/yas_demo.avi
Clone this repository somewhere
$ cd ~/.emacs.d/plugins
- $ git clone https://github.com/capitaomorte/yasnippet
+ $ git clone --recursive https://github.com/capitaomorte/yasnippet
Add the following in your `.emacs` file:
'(lambda ()
(yas-minor-mode)))
- # (NOT) Contributing snippets
+ # Where are the snippets?
+
+ <a name="import"></a>
+
+ Yasnippet no longer bundles snippets directly, but it's very easy to
+ get some!
+
+ If you git-cloned yasnippet with the `--recursive` option you'll also
+ download "git submodules" and find two subdirs under the main tree.
+
+ 1. `snippets/`
+
+ Points to [yasnippet-snippets][yasnippet-snippets] the snippet
+ collection of [AndreaCrotti](https://github.com/AndreaCrotti).
+
+ The default configuraiton already points to this dir, so to use
+ them, just make sure the submodule really was downloaded
+ (i.e. there are some files under `snippets/`)
+
+ 2. `yasmate/`
- Please **do not** open pull requests or ask me to add snippets to
- YASnippet.
+ Points to a github repo of the [yasmate][yasmate] tool, which is
+ dedicated to converting textmate bundles into yasnippet snippets.
- The bundled collection under `/snippets` is considered frozen: **I
- will not add more snippets to it**.
+ To use these snippets you have to run the tool first, so
+ [see its doc][yasmate]), and then point the `yas-snippet-dirs`
+ variable to the `.../yasmate/snippets` subdir.
- You can point `yas-snippet-dirs` to good snippet collections out
+ If you have a working ruby environment, you can probably get lucky
+ directly with `rake convert-bundles`.
+
+ Naturally, you can point `yas-snippet-dirs` to good snippet collections out
there. If you have created snippets for a mode, or multiple modes,
consider creating a repository to host them, then tell users that it
should be added like this to `yas-snippet-dirs`:
(setq yas-snippet-dirs
- '("~/.emacs.d/snippets" ;; personal snippets
- "/path/to/some/collection/" ;; just some foo-mode snippets
- "/path/to/some/othercollection/" ;; some more foo-mode and a complete baz-mode
- "/path/to/yasnippet/snippets" ;; the default collection
+ '("~/.emacs.d/snippets" ;; personal snippets
+ "/path/to/some/collection/" ;; foo-mode and bar-mode snippet collection
+ "/path/to/yasnippet/yasmate/snippets" ;; the yasmate collection
+ "/path/to/yasnippet/snippets" ;; the default collection
))
(yas-global-mode 1) ;; or M-x yas-reload-all if you've started YASnippet already.
- # Importing TextMate snippets
-
- There is a tool `extras/textmate-import.rb` than can import many
- actual TextMate snippets. These can be quite complex so the
- `extras/imported/*-mode/.yas-setup.el` files help it with the more
- difficult importation.
+ # Manual, issues etc
- I'm focusing on developing `textmate-import.rb` tool and some
- `yas-setup.el` files. In the future `/snippets` snippets will be
- deprecated and might be replaced with `extras/imported`.
+ Please refer to the comprehensive [documentation][docs] for full
+ customisation and support. If you find a bug in the code or in the
+ documentation, please report it on [the GitHub issue tracker][issues].
- ## Example importation of rails snippets
+ ## Important note regarding bug reporting
- To start using [drnic's](https://github.com/drnic) snippets for rails
- development, follow this example. It will convert `ruby`, `rails` and
- `html` bundles from github repositories. The importation will be
- guided by the `.yas-setup.el` files.
+ Your bug reports are very valuable.
- After cloning this repository to `~/.emacs.d/plugins/yasnippet`
+ The most important thing when reporting bugs is making sure that we have
+ a way to reproduce the problem exactly like it happened to you.
- cd ~/.emacs.d/plugins/yasnippet
- git submodule init
- git submodule update
- gem install plist trollop
- rake convert_bundles # will convert ruby, rails and html bundles
+ To do this, we need to rule out interference from external factors
+ like other Emacs extensions or your own customisations.
- Then, in your `.emacs` file
+ Here's an example report that "sandboxes" an Emacs session just for
+ reproducing a bug.
- (add-to-list 'load-path
- "~/.emacs.d/plugins/yasnippet")
- (require 'yasnippet)
- (setq yas-snippet-dirs '("~/.emacs.d/snippets" "~/.emacs.d/plugins/yasnippet/extras/imported"))
- (yas-global-mode 1)
+ ```
+ $ emacs --version
+ Emacs 24.3
+ $ cd /tmp/
+ $ git clone https://github.com/capitaomorte/yasnippet.git yasnippet-bug
+ $ cd yasnippet-bug
+ $ git log -1 --oneline
+ 6053db0 Closes #527: Unbreak case where yas-fallback-behaviour is a list
+ $ HOME=$PWD emacs -L # This "sandboxes" your emacs, melpa configuration, etc
- Open some rails file (model, app, etc) and start using the textmate
- snippets. Note that in the example above we have abandoned the
- default snippet collection on `~/.emacs.d/plugins/yasnippet/snippets`
+ (require 'yasnippet)
+ (yas-global-mode 1)
- # Documentation, issues, etc
+ When I open a foo-mode file I can't expand foo-mode snippets!
+ OR
+ I can't get yasnippet to load because frankinbogen!
+ ```
- Please refer to the comprehensive (albeit slightly outdated)
- [documentation][docs] for full customization
- and support. If you find a bug, please report it on
- [the GitHub issue tracker][issues]. (please **do not** submit new issues to the old
- [googlecode tracker][googlecode tracker])
+ Using `emacs -Q` or temporarily moving your `.emacs` init file to the side
+ is another way to achieve good reproducibility.
- ## Important note regarding bug reporting
- If you think have found a bug, please report it clearly. Yasnippet
- does have (lots of) bugs and your reports are very valuable. Here's
- a [great example](https://github.com/capitaomorte/yasnippet/issues/318)
- of a bug report. It has everything needed for a sucessfull analysis and
- speedy resolution:
-
- *Before* reporting try to reproduce the bug **without** your usual
- `.emacs` (or whatever startup file you use). Do so either by starting
- emacs from the command line with the `-Q` switch, or by temporarily
- moving away your `.emacs` and creating a new smaller one just for
- reproducing the bug. Paste that file in your bug report. Paste any sequence
- of relevant shell commands before you launch Emacs.
-
- *Then*, describe steps taken to reproduce from an
- end-user perspective. Try to be as unambiguous as possible.
+ Here's a
+ [another example](https://github.com/capitaomorte/yasnippet/issues/318)
+ of a bug report. It has everything needed for a successful analysis
+ and speedy resolution.
Also, don't forget to state the Emacs version (use `M-x emacs-version`) and
the yasnippet version you are using (if using the latest from github,
do `git log -1` in the dir).
Any more info is welcome, but don't just paste a backtrace or an error
- message string you got. I'm not saying your analysis might not be
- useful but following the instructions above immediately gives me a
- clear picture of what is happening.
+ message string you got, unless we ask for it.
There is also a [YASnippet google group][forum]. I will keep the group
- open for reference and for discussion among users, unfortunately I
- can't guarantee a timely response, so maybe creating a github issue
- clearly marking your intent (user support/bug/feature request).
+ open for reference and for discussion among users. Unfortunately I
+ can't guarantee a timely response, so maybe it's better to create a
+ github issue clearly marking your intent (user support/bug/feature
+ request).
Finally, thank you very much for using YASnippet!
[googlecode tracker]: http://code.google.com/p/yasnippet/issues/list
[forum]: http://groups.google.com/group/smart-snippet
[melpa]: http://melpa.milkbox.net/
+ [yasmate]: http://github.com/capitaomorte/yasmate
+ [yasnippet-snippets]: http://github.com/AndreaCrotti/yasnippet-snippets
require 'fileutils'
- $EMACS=ENV["EMACS"] || "emacs"
+ $EMACS = ENV["EMACS"]
+ if not $EMACS or $EMACS == 't'
+ $EMACS = "emacs"
+ end
def find_version
File.read("yasnippet.el", :encoding => "UTF-8") =~ /;; Package-version: *([0-9.]+?) *$/
desc "run tests in batch mode"
task :tests do
- sh "#{$EMACS} -Q -L . -l yasnippet-tests.el -nw --batch -e yas/ert"
- end
-
- desc "convert some textmate bundles to yasnippets"
- task :convert_bundles do
- Dir.glob "extras/bundles/*-tmbundle" do |bundle_dir|
- puts "Converting from #{bundle_dir}"
- mode_prefix = File.basename(bundle_dir).match(/[^-]*/)[0]
- raise "Couldn't guess mode name for #{bundle_dir}" unless mode_prefix
- output = "./extras/imported/#{mode_prefix}-mode"
- FileUtils.mkdir_p output
- sh "./extras/textmate_import.rb -d #{bundle_dir} -o #{output} -q"
- end
+ sh "#{$EMACS} -Q -L . -l yasnippet-tests.el" +
+ " --batch -f ert-run-tests-batch-and-exit"
end
desc "create a release package"
task :package do
release_dir = "pkg/yasnippet-#{$version}"
FileUtils.mkdir_p(release_dir)
- files = ['snippets', 'yasnippet.el', 'dropdown-list.el']
+ files = ['snippets', 'yasnippet.el']
FileUtils.cp_r files, release_dir
File.open(File.join(release_dir,'yasnippet-pkg.el'), 'w') do |file|
file.puts <<END
raise "Not implemented for github yet!"
end
- rule '.html' => '.rst' do |t|
- sh "doc/compile-doc.py #{t.source} > #{t.name}"
- end
desc "Generate document"
- task :doc => FileList['doc/*.rst'].ext('html')
+ task :doc do
+ sh "#{$EMACS} -Q -L . --batch -l doc/yas-doc-helper.el" +
+ " -f yas--generate-html-batch"
+ end
namespace :doc do
task :archive do
Dir.glob("doc/images/*").each do |file|
FileUtils.cp file, 'doc/gh-pages/images'
end
+ Dir.glob("doc/stylesheets/*.css").each do |file|
+ FileUtils.cp file, 'doc/gh-pages/stylesheets'
+ end
+ curRev = `git rev-parse --verify HEAD`.chomp()
+ expRev = IO.read('doc/html-revision').chomp()
+ if curRev != expRev
+ raise ("The HTML rev: #{expRev},\n" +
+ "current rev: #{curRev}!\n")
+ end
+ if !system "git diff-index --quiet HEAD"
+ system "git status --untracked-files=no"
+ raise "You have uncommitted changes!"
+ end
Dir.chdir 'doc/gh-pages' do
- sh "git commit -a -m 'Automatic documentation update.'"
+ sh "git commit -a -m 'Automatic documentation update.\n\n" +
+ "From #{curRev.chomp()}'"
sh "git push"
end
end
rule '.elc' => '.el' do |t|
sh "#{$EMACS} --batch -L . --eval \"(byte-compile-file \\\"#{t.source}\\\")\""
end
- task :compile => FileList["yasnippet.el", "dropdown-list.el"].ext('elc')
+ task :compile => FileList["yasnippet.el"].ext('elc')
task :default => :doc
+
+ desc "use yasmate to convert textmate bundles"
+ task :convert_bundles do
+ cd "yasmate"
+ sh "rake convert_bundles"
+ end
--- /dev/null
+ #+SETUPFILE: org-setup.inc
+
+ #+TITLE: Frequently Asked Questions
+
+ * Why is there an extra newline?
+
+ If you have a newline at the end of the snippet definition file, then
+ YASnippet will add a newline when you expanding a snippet. Please don't
+ add a newline at the end if you don't want it when you saving the
+ snippet file.
+
+ Note 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
+ for you automatically.
+
+ * Why doesn't TAB expand a snippet?
+
+ First check the mode line to see if there's =yas=. If not, then try
+ =M-x yas-minor-mode= to manually turn on the minor mode and try to
+ expand the snippet again. If it works, then, you can add the following
+ code to your =.emacs= /before/ loading YASnippet:
+
+ #+BEGIN_SRC emacs-lisp
+ (add-hook 'the-major-mode-hook 'yas-minor-mode-on)
+ #+END_SRC
+
+ where =the-major-mode= is the major mode in which [[sym:yas-minor-mode][=yas-minor-mode=]] isn't
+ enabled by default.
+
+ From YASnippet 0.6 you can also use the command =M-x yas-global-mode= to
+ turn on YASnippet automatically for /all/ major modes.
+
+ If [[sym:yas-minor-mode][=yas-minor-mode=]] is on but the snippet still not expanded. Then try
+ to see what command is bound to the =TAB= key: press =C-h k= and then
+ press =TAB=. Emacs will show you the result.
+
+ You'll see a buffer prompted by Emacs saying that
+ =TAB runs the command ...=. Alternatively, you might see
+ =<tab> runs the command ...=, note the difference between =TAB= and
+ =<tab>= where the latter has priority. If you see =<tab>= bound to a
+ command other than [[sym:yas-expand][=yas-expand=]], (e.g. in =org-mode=) you can try the
+ following code to work around:
+
+ #+BEGIN_SRC emacs-lisp
+ (add-hook 'org-mode-hook
+ (let ((original-command (lookup-key org-mode-map [tab])))
+ `(lambda ()
+ (setq yas-fallback-behavior
+ '(apply ,original-command))
+ (local-set-key [tab] 'yas-expand))))
+ #+END_SRC
+
+ replace =org-mode-hook= and =org-mode-map= with the major mode hook you
+ are dealing with (Use =C-h m= to see what major mode you are in).
+
+ As an alternative, you can also try
+
+ #+BEGIN_SRC emacs-lisp
+ (defun yas-advise-indent-function (function-symbol)
+ (eval `(defadvice ,function-symbol (around yas-try-expand-first activate)
+ ,(format
+ "Try to expand a snippet before point, then call `%s' as usual"
+ function-symbol)
+ (let ((yas-fallback-behavior nil))
+ (unless (and (interactive-p)
+ (yas-expand))
+ ad-do-it)))))
+
+ (yas-advise-indent-function 'ruby-indent-line)
+ #+END_SRC
+
+ To /advise/ the modes indentation function bound to TAB, (in this case
+ =ruby-indent-line=) to first try to run [[sym:yas-expand][=yas-expand=]].
+
+ If the output of =C-h k RET <tab>= tells you that =<tab>= is indeed
+ bound to [[sym:yas-expand][=yas-expand=]] but YASnippet still doesn't work, check your
+ configuration and you may also ask for help on the [[http://groups.google.com/group/smart-snippet][discussion group]].
+ See this particular [[http://code.google.com/p/yasnippet/issues/detail?id=93&can=1][thread]] for quite some solutions and alternatives.
+
+ Don't forget to attach the information on what command is bound to TAB
+ as well as the mode information (Can be obtained by =C-h m=).
+
+ * Why doesn't TAB navigation work with flyspell
+
+ A workaround is to inhibit flyspell overlays while the snippet is
+ active:
+
+ #+BEGIN_SRC emacs-lisp
+ (add-hook 'flyspell-incorrect-hook
+ #'(lambda (dummy1 dummy2 dymmy3)
+ (and yas-active-field-overlay
+ (overlay-buffer yas-active-field-overlay))))
+ #+END_SRC
+
+ This is apparently related to overlay priorities. For some reason, the
+ =keymap= property of flyspell's overlays always takes priority over the
+ same property in YASnippet's overlays, even if one sets the latter's
+ =priority= property to something big. If you know emacs-lisp and can
+ solve this problem, drop a line in the
+ [[http://groups.google.com/group/smart-snippet][discussion group]].
+
+ * How to 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:
+
+ #+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-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-next-field-or-maybe-expand)
+ (define-key yas-keymap (kbd "<new-prev-field-key>") 'yas-prev)
+ #+end_src
+
+ * How do I turn off the minor mode where in some buffers?
+
+ The best way, since version 0.6.1c, is to set the default value of the
+ variable [[sym:yas-dont-activate][=yas-dont-activate=]] to a lambda function like so:
+
+ #+BEGIN_SRC emacs-lisp
+ (set-default 'yas-dont-activate
+ #'(lambda ()
+ (and yas-root-directory
+ (null (yas-get-snippet-tables)))))
+ #+END_SRC
+
+ This is also the default value starting for that version. It skips the
+ minor mode in buffers where it is not applicable (no snippet tables),
+ but only once you have setup your yas-root-directory.
+
+ * 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
--- /dev/null
+ #+SETUPFILE: org-setup.inc
+ #+TITLE: Yet another snippet extension
+
+ The YASnippet documentation has been split into separate parts:
+
+ 0. [[https://github.com/capitaomorte/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:
--- /dev/null
+ <nav>
+ <ul class="center">
+ <li> <a href="index.html">Overview</a>
+ <li> <a href="https://github.com/capitaomorte/yasnippet/blob/master/README.mdown">
+ Intro and Tutorial</a>
+ <li class="center">Snippet
+ <ul>
+ <li> <a href="snippet-organization.html">Organization</a>
+ <li> <a href="snippet-expansion.html">Expansion</a>
+ <li> <a href="snippet-development.html">Development</a>
+ <li> <a href="snippet-menu.html">Menu</a>
+ </ul>
+ <li> <a href="faq.html">FAQ</a>
+ <li> <a href="snippet-reference.html">Reference</a>
+ </ul>
+ </nav>
--- /dev/null
+ # -*- mode: org -*-
+
+ #+STARTUP: showall
+
+ #+LINK: sym file:snippet-reference.org::#%s
+
+ #+OPTIONS: author:nil num:nil
+ #+AUTHOR:
+ # org < 8.0 use +STYLE, after use +HTML_HEAD
+ #+STYLE: <link rel="stylesheet" type="text/css" href="stylesheets/manual.css" />
+ #+HTML_HEAD: <link rel="stylesheet" type="text/css" href="stylesheets/manual.css" />
--- /dev/null
+ #+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=
+
+ Creates a new buffer with a template for making a new snippet.
+ The buffer is in =snippet-mode= (see below). When you are done
+ editing the new snippet, use =C-c C-c= to save it. This will
+ prompt for a directory two steps: first, the snippet table
+ (with a default based on the major mode you started in), and then
+ then snippet collection directory (defaults 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-find-snippets=
+
+ Lets you find the snippet file in the directory the snippet was
+ loaded from (if it exists) like =find-file-other-window=. The
+ directory searching logic is similar to =M-x yas-new-snippet=.
+
+ - =M-x yas-visit-snippet-file=
+
+ 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 ahead) and
+ you can start editing your snippet.
+
+ ** Using the =snippet-mode= major 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.
+
+ Two commands are defined in this mode:
+
+ - =M-x yas-load-snippet-buffer=
+
+ When editing a snippet, this loads the snippet into the correct
+ mode and menu. Bound to =C-c C-c= by default while in
+ =snippet-mode=.
+
+ - =M-x yas-tryout-snippet=
+
+ 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. This is bound to =C-c C-t= while in
+ =snippet-mode=.
+
+ 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
+ snippets 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 on the
+ =# group:= directive. Group can also be nested, e.g.
+ =control structure.loops= tells 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 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, snippets expansions are run with some special
+ Emacs-lisp variables bound. One of this 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.
+
+ ** 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 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.
+ The number can be omitted if you don't want to create [[mirrors]] or
+ [[transformations]] for this field.
+
+ ** <<Mirrors>>
+
+ We 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_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 has an initial value, the first one is selected as
+ the field and others mirrors.
+
+ ** Mirrors with <<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
+
+ ** Fields with transformations
+
+ From version 0.6 on, you can also have lisp transformation inside
+ fields. These work mostly mirror transformations but 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.
+
+ The [[sym:yas-choose-value][=yas-choose-value=]] does this work for you. For example:
+
+ #+BEGIN_SRC snippet
+ <div align="${2:$$(yas-choose-value '("right" "center" "left"))}">
+ $0
+ </div>
+ #+END_SRC
+
+ See the definition of [[sym:yas-choose-value][=yas-choose-value=]] to see how it was written using
+ the two variables.
+
+ 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.
--- /dev/null
+ #+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.
+
+ When [[sym:yas-minor-mode][=yas-minor-mode=]] is enabled, it binds [[sym:yas-expand][=yas-expand=]] to =TAB= and
+ =<tab>= by default, however, you can freely set it to some other key:
+
+ #+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-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 setting the buffer-local variable
+ [[sym:yas-dont-active][=yas-dont-active=]] in the buffer's mode hook.
+
+ *** Fallback behaviour
+
+ [[sym:yas-fallback-behaviour][=yas-fallback-behaviour=]] is a customization variable bound to
+ '=call-other-command= by default. If [[sym:yas-expand][=yas-expand=]] failed to find any
+ suitable snippet to expand, it will disable the minor mode temporarily
+ and find if there's any other command bound to the same key.
+
+ If found, the command will be called. Usually this works very well
+ --when there's a snippet, expand it, otherwise, call whatever command
+ originally bind to the trigger key.
+
+ However, you can change this behavior by customizing the
+ [[sym:yas-fallback-behavior][=yas-fallback-behavior=]] variable. If you set this variable to
+ '=return-nil=, it will return =nil= instead of trying to call the
+ /original/ command when no snippet is found.
+
+ ** Insert at point
+
+ The command [[#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=]].
+
+ ** 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 you own
+ elisp code. You should call
+ [[sym:yas-expand-snippet][=yas-expand-snippet=]] instead of
+ [[sym:yas-expand][=yas-expand=]] in this case.
+
+ As with expanding from the menubar, the condition system and multiple
+ candidates doesn't affect expansion. 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=]] for more
+ information.
+
+ * Controlling expansion
+
+ ** 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.
+
+ - Buffer-local list of extra modes
+
+ Use [[#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. The default value won't let you
+ expand snippets inside comments or string literals for example. See
+ The condition system\_ for more info.
+
+ ** The 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-in-string/comment))=. But how
+ about =while=, =for=, etc. ? Writing the same condition for all the
+ snippets is just boring. So has a buffer local variable
+ [[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]]. You can set this variable to
+ =(not (python-in-string/comment))= 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
+ '(if (python-in-string/comment)
+ '(require-snippet-condition . force-in-comment)
+ t))))
+ #+END_SRC
+
+ ... 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, while other snippets like =if= still can't
+ expanded in comment.
+
+ 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%20snippets][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=]]
--- /dev/null
+ #+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 [[#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.
--- /dev/null
+ #+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 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= localtion
+
+ 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 shadow 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 [[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
+
+ * TODO The =.yas-setup.el= file
+
+ ** TODO
+
+ * TODO The =.yas-compiled-snippet.el= file
+
+ ** TODO
+
+ * TODO The =.yas-skip= file
+
+ ** TODO
--- /dev/null
+ #+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
--- /dev/null
+ nav > ul > li.center > ul {
+ padding: 0;
+ }
+
+ nav li {
+ vertical-align: top;
+
+ display: inline;
+ list-style-type: none;
+ padding: 0.5em;
+ }
+
+ nav > ul > li {
+ display: inline-block;
+ }
+
+ /* match org's css for <pre> */
+ code {
+ background-color: #F3F5F7;
+ font-family: courier, monospace;
+ }
+
+ #content {
+ margin-left: 5%;
+ margin-right: 10%;
+ }
;;; yas-doc-helper.el --- Help generate documentation for YASnippet
-;; Copyright (C) 2012 João Távora
+;; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
;; Author: João Távora <joaotavora@gmail.com>
;; Keywords: convenience
;;; Code:
+ (eval-when-compile
+ (require 'cl))
+ (require 'org)
+ (or (require 'org-publish nil t)
+ (require 'ox-publish))
+ (require 'yasnippet) ; docstrings must be loaded
+
+ (defun yas--org-raw-html (tag content)
+ ;; in version 8.0 org-mode changed the export syntax, see
+ ;; http://orgmode.org/worg/org-8.0.html#sec-8-1
+ (format (if (version< org-version "8.0.0")
+ "@<%s>%s@</%s>" ; old: @<tag>
+ "@@html:<%s>@@%s@@html:</%s>@@") ; new: @@html:<tag>@@
+ tag content tag))
+
(defun yas--document-symbol (symbol level)
(flet ((concat-lines (&rest lines)
(mapconcat #'identity lines "\n")))
(let* ((stars (make-string level ?*))
+ (args (and (fboundp symbol)
+ (mapcar #'symbol-name (help-function-arglist symbol t))))
(heading (cond ((fboundp symbol)
- (format "%s =%s= (%s)"
- stars
- symbol
- (mapconcat #'symbol-name
- (help-function-arglist symbol t) " ")))
+ (format
+ "%s =%s= (%s)" stars symbol
+ (mapconcat (lambda (a)
+ (format (if (string-prefix-p "&" a)
+ "/%s/" "=%s=") a))
+ args " ")))
(t
(format "%s =%s=\n" stars symbol))))
(after-heading
(concat-lines ":PROPERTIES:"
(format ":CUSTOM_ID: %s" symbol)
":END:"))
- (body (or (cond ((boundp symbol)
+ (body (or (cond ((fboundp symbol)
+ (let ((doc-synth (car-safe (get symbol 'function-documentation))))
+ (if (functionp doc-synth)
+ (funcall doc-synth nil)
+ (documentation symbol t))))
+ ((boundp symbol)
(documentation-property symbol 'variable-documentation t))
- ((fboundp symbol)
- (documentation-property symbol 'function-documentation t))
(t
(format "*WARNING*: no symbol named =%s=" symbol)))
(format "*WARNING*: no doc for symbol =%s=" symbol)))
(case-fold-search nil))
- ;; do some transformations on the body: FOO becomes /foo/ and
+ ;; do some transformations on the body:
+ ;; ARGxxx becomes @<code>arg@</code>xxx
+ ;; FOO becomes /foo/
;; `bar' becomes [[#bar][=bar=]]
(setq body (replace-regexp-in-string
- "[A-Z][A-Z-]+" #'(lambda (match)
- (format "/%s/" (downcase match)))
- body)
- body (replace-regexp-in-string "`\\([a-z-]+\\)'" #'(lambda (match)
- (let* ((name (downcase (match-string 1 match)))
- (sym (intern name)))
- (if (and (or (boundp sym)
- (fboundp sym))
- (save-match-data
- (string-match "^yas-" name)))
- (format "[[#%s][=%s=]]"
- name name)
- (format "=%s=" name))))
- body))
+ "\\<\\([A-Z][-A-Z0-9]+\\)\\(\\sw+\\)?\\>"
+ #'(lambda (match)
+ (let* ((match1 (match-string 1 match))
+ (prefix (downcase match1))
+ (suffix (match-string 2 match))
+ (fmt (cond
+ ((member prefix args)
+ (yas--org-raw-html "code" "%s"))
+ ((null suffix) "/%s/"))))
+ (if fmt (format fmt prefix)
+ match1)))
+ body t t 1)
+ body (replace-regexp-in-string
+ "`\\([a-z-]+\\)'"
+ #'(lambda (match)
+ (let* ((name (downcase (match-string 1 match)))
+ (sym (intern name)))
+ (if (memq sym yas--exported-syms)
+ (format "[[#%s][=%s=]]" name name)
+ (format "=%s=" name))))
+ body t))
;; output the paragraph
;;
(concat-lines heading
body))))
(defun yas--document-symbols (level &rest names-and-predicates)
- (let ((sym-lists (make-vector (length names-and-predicates) (list)))
- (retval ""))
+ (let ((sym-lists (make-vector (length names-and-predicates) nil))
+ (stars (make-string level ?*)))
(loop for sym in yas--exported-syms
do (loop for test in (mapcar #'cdr names-and-predicates)
for i from 0
(return))))
(loop for slist across sym-lists
for name in (mapcar #'car names-and-predicates)
- do (progn
- (setq retval
- (concat retval
- (format "\n** %s\n" name)
- (mapconcat #'yas--document-symbol slist "\n\n")))))
- retval))
+ concat (format "\n%s %s\n" stars name)
+ concat (mapconcat (lambda (sym)
+ (yas--document-symbol sym (1+ level)))
+ slist "\n\n"))))
(defun yas--internal-link-snippet ()
(interactive)
(define-key org-mode-map [M-f8] 'yas--internal-link-snippet)
+ ;; This lets all the org files be exported to HTML with
+ ;; `org-publish-current-project' (C-c C-e P).
+
+ (let* ((dir (if load-file-name (file-name-directory load-file-name)
+ default-directory))
+ (rev (with-temp-file (expand-file-name "html-revision" dir)
+ (or (when (eq (call-process "git" nil t nil
+ "rev-parse" "--verify" "HEAD") 0)
+ (buffer-string))
+ (princ yas--version (current-buffer)))))
+ (proj-plist
+ `(,@(when (fboundp 'org-html-publish-to-html)
+ '(:publishing-function 'org-html-publish-to-html))
+ :base-directory ,dir :publishing-directory ,dir
+ :html-preamble
+ ,(with-temp-buffer
+ (insert-file-contents (expand-file-name "nav-menu.html.inc" dir))
+ (buffer-string))
+ :html-postamble
+ ,(concat "<hr><p class='creator'>Generated by %c on %d from "
+ rev "</p>\n"
+ "<p class='xhtml-validation'>%v</p>\n")))
+ (project (assoc "yasnippet" org-publish-project-alist)))
+ (if project
+ (setcdr project proj-plist)
+ (push `("yasnippet" . ,proj-plist)
+ org-publish-project-alist)))
+
+ (defun yas--generate-html-batch ()
+ (let ((org-publish-use-timestamps-flag nil)
+ (org-export-copy-to-kill-ring nil)
+ (org-confirm-babel-evaluate nil)
+ (make-backup-files nil))
+ (org-publish "yasnippet" 'force)))
+
+
+
(provide 'yas-doc-helper)
- ;;; yas-doc-helper.el ends here
;; Local Variables:
+ ;; indent-tabs-mode: nil
;; coding: utf-8
;; End:
+ ;;; yas-doc-helper.el ends here
;;; yasnippet-debug.el --- debug functions for yasnippet
-;; Copyright (C) 2010 João Távora
+;; Copyright (C) 2010, 2013, 2014 Free Software Foundation, Inc.
;; Author: João Távora
;; Keywords: emulations, convenience
;;; Code:
(require 'yasnippet)
+(require 'cl)
(defun yas-debug-snippet-vars ()
"Debug snippets, fields, mirrors and the `buffer-undo-list'."
(add-hook 'post-command-hook 'yas-debug-snippet-vars 't 'local)))
(provide 'yasnippet-debug)
+ ;; Local Variables:
+ ;; indent-tabs-mode: nil
+ ;; byte-compile-warnings: (not cl-functions)
+ ;; End:
;;; yasnippet-debug.el ends here
-;;; yasnippet-tests.el --- some yasnippet tests
+;;; yasnippet-tests.el --- some yasnippet tests -*- lexical-binding: t -*-
-;; Copyright (C) 2012 João Távora
+;; Copyright (C) 2012, 2013, 2014 Free Software Foundation, Inc.
;; Author: João Távora <joaot@siscog.pt>
;; Keywords: emulations, convenience
(require 'yasnippet)
(require 'ert)
(require 'ert-x)
+(require 'cl)
\f
;;; Snippet mechanics
(ert-deftest primary-field-transformation ()
(with-temp-buffer
(yas-minor-mode 1)
- (let ((snippet "${1:$$(upcase yas/text)}${1:$(concat \"bar\" yas/text)}"))
+ (let ((snippet "${1:$$(upcase yas-text)}${1:$(concat \"bar\" yas-text)}"))
(yas-expand-snippet snippet)
(should (string= (yas--buffer-contents) "bar"))
(ert-simulate-command `(yas-mock-insert "foo"))
(ert-simulate-command `(yas-mock-insert "abc"))
(should (string= (yas--buffer-contents) "abcabcabcabc"))))
+ (ert-deftest delete-numberless-inner-snippet-issue-562 ()
+ (with-temp-buffer
+ (yas-minor-mode 1)
+ (yas-expand-snippet "${3:${test}bla}$0${2:ble}")
+ (ert-simulate-command '(yas-next-field-or-maybe-expand))
+ (should (looking-at "testblable"))
+ (ert-simulate-command '(yas-next-field-or-maybe-expand))
+ (ert-simulate-command '(yas-skip-and-clear-or-delete-char))
+ (should (looking-at "ble"))
+ (should (null (yas--snippets-at-point)))))
+
;; (ert-deftest in-snippet-undo ()
;; (with-temp-buffer
;; (yas-minor-mode 1)
(ert-deftest be-careful-when-escaping-in-yas-selected-text ()
(with-temp-buffer
(yas-minor-mode 1)
- (let ((yas/selected-text "He\\\\o world!"))
- (yas-expand-snippet "Look ma! `(yas/selected-text)`")
+ (let ((yas-selected-text "He\\\\o world!"))
+ (yas-expand-snippet "Look ma! `(yas-selected-text)`")
(should (string= (yas--buffer-contents) "Look ma! He\\\\o world!")))
(yas-exit-all-snippets)
(erase-buffer)
- (let ((yas/selected-text "He\"o world!"))
- (yas-expand-snippet "Look ma! `(yas/selected-text)`")
+ (let ((yas-selected-text "He\"o world!"))
+ (yas-expand-snippet "Look ma! `(yas-selected-text)`")
(should (string= (yas--buffer-contents) "Look ma! He\"o world!")))
(yas-exit-all-snippets)
(erase-buffer)
- (let ((yas/selected-text "He\"\)\\o world!"))
- (yas-expand-snippet "Look ma! `(yas/selected-text)`")
+ (let ((yas-selected-text "He\"\)\\o world!"))
+ (yas-expand-snippet "Look ma! `(yas-selected-text)`")
(should (string= (yas--buffer-contents) "Look ma! He\"\)\\o world!")))
(yas-exit-all-snippets)
(erase-buffer)))
(ert-deftest be-careful-when-escaping-in-yas-selected-text-2 ()
(with-temp-buffer
- (let ((yas/selected-text "He)}o world!"))
- (yas-expand-snippet "Look ma! ${1:`(yas/selected-text)`} OK?")
+ (yas-minor-mode 1)
+ (let ((yas-selected-text "He)}o world!"))
+ (yas-expand-snippet "Look ma! ${1:`(yas-selected-text)`} OK?")
(should (string= (yas--buffer-contents) "Look ma! He)}o world! OK?")))))
(ert-deftest example-for-issue-271 ()
(with-temp-buffer
(yas-minor-mode 1)
(let ((yas-selected-text "aaa")
- (snippet "if ${1:condition}\n`yas/selected-text`\nelse\n$3\nend"))
+ (snippet "if ${1:condition}\n`yas-selected-text`\nelse\n$3\nend"))
(yas-expand-snippet snippet)
(yas-next-field)
(ert-simulate-command `(yas-mock-insert "bbb"))
(should (string= (yas--buffer-contents) "if condition\naaa\nelse\nbbb\nend")))))
+ (defmacro yas--with-font-locked-temp-buffer (&rest body)
+ "Like `with-temp-buffer', but ensure `font-lock-mode'."
+ (declare (indent 0) (debug t))
+ (let ((temp-buffer (make-symbol "temp-buffer")))
+ ;; NOTE: buffer name must not start with a space, otherwise
+ ;; `font-lock-mode' doesn't turn on.
+ `(let ((,temp-buffer (generate-new-buffer "*yas-temp*")))
+ (with-current-buffer ,temp-buffer
+ ;; pretend we're interactive so `font-lock-mode' turns on
+ (let ((noninteractive nil)
+ ;; turn on font locking after major mode change
+ (change-major-mode-after-body-hook #'font-lock-mode))
+ (unwind-protect
+ (progn (require 'font-lock)
+ ;; turn on font locking before major mode change
+ (font-lock-mode +1)
+ ,@body)
+ (and (buffer-name ,temp-buffer)
+ (kill-buffer ,temp-buffer))))))))
+
+ (ert-deftest example-for-issue-474 ()
+ (yas--with-font-locked-temp-buffer
+ (c-mode)
+ (yas-minor-mode 1)
+ (insert "#include <foo>\n")
+ (let ((yas-good-grace nil)) (yas-expand-snippet "`\"TODO: \"`"))
+ (should (string= (yas--buffer-contents) "#include <foo>\nTODO: "))))
+
+ (ert-deftest example-for-issue-404 ()
+ (yas--with-font-locked-temp-buffer
+ (c++-mode)
+ (yas-minor-mode 1)
+ (insert "#include <foo>\n")
+ (let ((yas-good-grace nil)) (yas-expand-snippet "main"))
+ (should (string= (yas--buffer-contents) "#include <foo>\nmain"))))
+
+ (ert-deftest example-for-issue-404-c-mode ()
+ (yas--with-font-locked-temp-buffer
+ (c-mode)
+ (yas-minor-mode 1)
+ (insert "#include <foo>\n")
+ (let ((yas-good-grace nil)) (yas-expand-snippet "main"))
+ (should (string= (yas--buffer-contents) "#include <foo>\nmain"))))
+
+ (ert-deftest middle-of-buffer-snippet-insertion ()
+ (with-temp-buffer
+ (yas-minor-mode 1)
+ (insert "beginning")
+ (save-excursion (insert "end"))
+ (yas-expand-snippet "-middle-")
+ (should (string= (yas--buffer-contents) "beginning-middle-end"))))
+
(ert-deftest another-example-for-issue-271 ()
;; expect this to fail in batch mode since `region-active-p' doesn't
;; used by `yas-expand-snippet' doesn't make sense in that context.
:passed)
(with-temp-buffer
(yas-minor-mode 1)
- (let ((snippet "\\${${1:1}:`yas/selected-text`}"))
+ (let ((snippet "\\${${1:1}:`yas-selected-text`}"))
(insert "aaabbbccc")
(set-mark 4)
(goto-char 7)
(yas-minor-mode 1)
;; the rule here is: To use regexps in embedded `(elisp)` expressions,
;; escape backslashes once, i.e. to use \\( \\) constructs, write \\\\( \\\\).
- (let ((snippet "$1${1:$(if (string-match \"foo\\\\\\\\(ba+r\\\\\\\\)baz\" yas/text)
+ (let ((snippet "$1${1:$(if (string-match \"foo\\\\\\\\(ba+r\\\\\\\\)baz\" yas-text)
\"ok\"
\"fail\")}"))
(yas-expand-snippet snippet)
(should (string= (yas--buffer-contents)
"brother from another mother") ;; no newline should be here!
)))
+
+ ;; See issue #497. To understand this test, follow the example of the
+ ;; `yas-key-syntaxes' docstring.
+ ;;
+ (ert-deftest complicated-yas-key-syntaxes ()
+ (with-temp-buffer
+ (yas-saving-variables
+ (yas-with-snippet-dirs
+ '((".emacs.d/snippets"
+ ("emacs-lisp-mode"
+ ("foo-barbaz" . "# condition: yas--foobarbaz\n# --\nOKfoo-barbazOK")
+ ("barbaz" . "# condition: yas--barbaz\n# --\nOKbarbazOK")
+ ("baz" . "OKbazOK")
+ ("'quote" . "OKquoteOK"))))
+ (yas-reload-all)
+ (emacs-lisp-mode)
+ (yas-minor-mode-on)
+ (let ((yas-key-syntaxes '("w" "w_")))
+ (let ((yas--barbaz t))
+ (yas-should-expand '(("foo-barbaz" . "foo-OKbarbazOK")
+ ("barbaz" . "OKbarbazOK"))))
+ (let ((yas--foobarbaz t))
+ (yas-should-expand '(("foo-barbaz" . "OKfoo-barbazOK"))))
+ (let ((yas-key-syntaxes
+ (cons #'(lambda (_start-point)
+ (unless (looking-back "-")
+ (backward-char)
+ 'again))
+ yas-key-syntaxes))
+ (yas--foobarbaz t))
+ (yas-should-expand '(("foo-barbaz" . "foo-barOKbazOK")))))
+ (let ((yas-key-syntaxes '(yas-try-key-from-whitespace)))
+ (yas-should-expand '(("xxx\n'quote" . "xxx\nOKquoteOK")
+ ("xxx 'quote" . "xxx OKquoteOK"))))
+ (let ((yas-key-syntaxes '(yas-shortest-key-until-whitespace))
+ (yas--foobarbaz t) (yas--barbaz t))
+ (yas-should-expand '(("foo-barbaz" . "foo-barOKbazOK")))
+ (setq yas-key-syntaxes '(yas-longest-key-from-whitespace))
+ (yas-should-expand '(("foo-barbaz" . "OKfoo-barbazOK")
+ ("foo " . "foo "))))))))
+
\f
;;; Loading
;;;
;; saving all definitions before overriding anything ensures FDEFINITION
;; errors don't cause accidental permanent redefinitions.
;;
- (labels ((set-fdefinitions (names functions)
- (loop for name in names
- for fn in functions
- do (fset name fn))))
+ (cl-labels ((set-fdefinitions (names functions)
+ (loop for name in names
+ for fn in functions
+ do (fset name fn))))
(set-fdefinitions definition-names overriding-functions)
(unwind-protect (funcall function)
(set-fdefinitions definition-names saved-functions)))))
(lambda ,@(rest thingy))))
fdefinitions)))
- (put 'yas--with-temporary-redefinitions 'lisp-indent-function 1)
- (put 'yas--with-temporary-redefinitions 'edebug-form-spec '((&rest (defun*)) cl-declarations body))
-
(defmacro yas-with-overriden-buffer-list (&rest body)
(let ((saved-sym (make-symbol "yas--buffer-list")))
`(let ((,saved-sym (symbol-function 'buffer-list)))
(funcall ,saved-sym))))
,@body))))
+
(defmacro yas-with-some-interesting-snippet-dirs (&rest body)
`(yas-saving-variables
(yas-with-overriden-buffer-list
("lisp-interaction-mode" ("sc" . "brother from another mother"))))
,@body))))
+
(ert-deftest basic-jit-loading ()
"Test basic loading and expansion of snippets"
(yas-with-some-interesting-snippet-dirs
("c-mode"
(".yas-parents" . "cc-mode"))
("cc-mode"
- (".yas-parents" . "yet-another-c-mode"))
+ (".yas-parents" . "yet-another-c-mode and-that-one"))
("yet-another-c-mode"
- (".yas-parents" . "c-mode"))))
+ (".yas-parents" . "c-mode and-also-this-one lisp-interaction-mode"))))
(yas-reload-all)
- (condition-case nil
- (yas--all-parents 'c-mode)
- (error
- (ert-fail "cyclic parenthood test failed"))))))
+ (with-temp-buffer
+ (let* ((major-mode 'c-mode)
+ (expected `(c-mode
+ cc-mode
+ yet-another-c-mode
+ and-also-this-one
+ and-that-one
+ ;; prog-mode doesn't exit in emacs 24.3
+ ,@(if (fboundp 'prog-mode)
+ '(prog-mode))
+ emacs-lisp-mode
+ lisp-interaction-mode))
+ (observed (yas--modes-to-activate)))
+ (should (null (cl-set-exclusive-or expected observed)))
+ (should (= (length expected)
+ (length observed))))))))
+
+ (ert-deftest issue-492-and-494 ()
+ (defalias 'yas--phony-c-mode 'c-mode)
+ (define-derived-mode yas--test-mode yas--phony-c-mode "Just a test mode")
+ (yas-with-snippet-dirs '((".emacs.d/snippets"
+ ("yas--test-mode")))
+ (yas-reload-all)
+ (with-temp-buffer
+ (let* ((major-mode 'yas--test-mode)
+ (expected `(c-mode
+ ,@(if (fboundp 'prog-mode)
+ '(prog-mode))
+ yas--phony-c-mode
+ yas--test-mode))
+ (observed (yas--modes-to-activate)))
+ (should (null (cl-set-exclusive-or expected observed)))
+ (should (= (length expected)
+ (length observed)))))))
+
+ (ert-deftest issue-504-tricky-jit ()
+ (define-derived-mode yas--test-mode c-mode "Just a test mode")
+ (define-derived-mode yas--another-test-mode c-mode "Another test mode")
+ (yas-with-snippet-dirs
+ '((".emacs.d/snippets"
+ ("yas--another-test-mode"
+ (".yas-parents" . "yas--test-mode"))
+ ("yas--test-mode")))
+ (let ((b (with-current-buffer (generate-new-buffer "*yas-test*")
+ (yas--another-test-mode)
+ (current-buffer))))
+ (unwind-protect
+ (progn
+ (yas-reload-all)
+ (should (= 0 (hash-table-count yas--scheduled-jit-loads))))
+ (kill-buffer b)))))
(defun yas--basic-jit-loading-1 ()
(with-temp-buffer
(yas-reload-all)
(should (not (eq (key-binding (yas--read-keybinding "TAB")) 'yas-expand)))
(should (eq (key-binding (yas--read-keybinding "SPC")) 'yas-expand))))
- (setcdr yas-minor-mode-map (cdr (yas--init-minor-keymap)))))
+ ;; FIXME: actually should restore to whatever saved values where there.
+ ;;
+ (define-key yas-minor-mode-map [tab] 'yas-expand)
+ (define-key yas-minor-mode-map (kbd "TAB") 'yas-expand)
+ (define-key yas-minor-mode-map (kbd "SPC") nil)))
(ert-deftest test-yas-in-org ()
(with-temp-buffer
(should (eq (key-binding [(tab)]) 'yas-expand))
(should (eq (key-binding (kbd "TAB")) 'yas-expand))))
+ (ert-deftest test-yas-activate-extra-modes ()
+ "Given a symbol, `yas-activate-extra-mode' should be able to
+ add the snippets associated with the given mode."
+ (with-temp-buffer
+ (yas-saving-variables
+ (yas-with-snippet-dirs
+ '((".emacs.d/snippets"
+ ("markdown-mode"
+ ("_" . "_Text_ "))
+ ("emacs-lisp-mode"
+ ("car" . "(car )"))))
+ (yas-reload-all)
+ (emacs-lisp-mode)
+ (yas-minor-mode-on)
+ (yas-activate-extra-mode 'markdown-mode)
+ (should (eq 'markdown-mode (car yas--extra-modes)))
+ (yas-should-expand '(("_" . "_Text_ ")))
+ (yas-should-expand '(("car" . "(car )")))
+ (yas-deactivate-extra-mode 'markdown-mode)
+ (should-not (eq 'markdown-mode (car yas--extra-modes)))
+ (yas-should-not-expand '("_"))
+ (yas-should-expand '(("car" . "(car )")))))))
+
\f
;;; Helpers
;;;
- (defun yas/ert ()
- (interactive)
- (with-temp-buffer
- (yas--with-temporary-redefinitions
- ((message (&rest _args) nil))
- (ert t (buffer-name (current-buffer)))
- (princ (buffer-string)))))
-
-
(defun yas-should-expand (keys-and-expansions)
(dolist (key-and-expansion keys-and-expansions)
(yas-exit-all-snippets)
- (erase-buffer)
+ (narrow-to-region (point) (point))
(insert (car key-and-expansion))
(let ((yas-fallback-behavior nil))
(ert-simulate-command '(yas-expand)))
- (should (string= (yas--buffer-contents) (cdr key-and-expansion))))
+ (unless (string= (yas--buffer-contents) (cdr key-and-expansion))
+ (ert-fail (format "\"%s\" should have expanded to \"%s\" but got \"%s\""
+ (car key-and-expansion)
+ (cdr key-and-expansion)
+ (yas--buffer-contents)))))
(yas-exit-all-snippets))
(defun yas-should-not-expand (keys)
(dolist (key keys)
(yas-exit-all-snippets)
- (erase-buffer)
+ (narrow-to-region (point) (point))
(insert key)
(let ((yas-fallback-behavior nil))
(ert-simulate-command '(yas-expand)))
- (should (string= (yas--buffer-contents) key))))
+ (unless (string= (yas--buffer-contents) key)
+ (ert-fail (format "\"%s\" should have stayed put, but instead expanded to \"%s\""
+ key
+ (yas--buffer-contents))))))
(defun yas-mock-insert (string)
(interactive)
;;; /usr/bin/emacs -nw -Q -L . -l yasnippet-tests.el --batch -e ert
+ (put 'yas-saving-variables 'edebug-form-spec t)
+ (put 'yas-with-snippet-dirs 'edebug-form-spec t)
+ (put 'yas-with-overriden-buffer-list 'edebug-form-spec t)
+ (put 'yas-with-some-interesting-snippet-dirs 'edebug-form-spec t)
+
+
+ (put 'yas--with-temporary-redefinitions 'lisp-indent-function 1)
+ (put 'yas--with-temporary-redefinitions 'edebug-form-spec '((&rest (defun*)) cl-declarations body))
+
+
+
+
(provide 'yasnippet-tests)
-;; lexical-binding: t
+ ;; Local Variables:
+ ;; indent-tabs-mode: nil
+ ;; byte-compile-warnings: (not cl-functions)
+ ;; End:
;;; yasnippet-tests.el ends here
;;; yasnippet.el --- Yet another snippet extension for Emacs.
- ;; Copyright (C) 2008-2013 Free Software Foundation, Inc.
+ ;; Copyright (C) 2008-2013, 2015 Free Software Foundation, Inc.
;; Authors: pluskid <pluskid@gmail.com>, João Távora <joaotavora@gmail.com>
;; Maintainer: João Távora <joaotavora@gmail.com>
- ;; Version: 0.8.0
+ ;; Version: 0.8.1
;; Package-version: 0.8.0
;; X-URL: http://github.com/capitaomorte/yasnippet
;; Keywords: convenience, emulation
;; The deprecated `yas/root-directory' aliases this variable
;; for backward-compatibility.
;;
- ;; `yas-extra-modes'
- ;;
- ;; A local variable that you can set in a hook to override
- ;; snippet-lookup based on major mode. It is a symbol (or
- ;; list of symbols) that correspond to subdirectories of
- ;; `yas-snippet-dirs' and is used for deciding which
- ;; snippets to consider for the active buffer.
- ;;
- ;; Deprecated `yas/mode-symbol' aliases this variable for
- ;; backward-compatibility.
;;
;; Major commands are:
;;
;;
;; Prompts you for a directory hierarchy of snippets to load.
;;
+ ;; M-x yas-activate-extra-mode
+ ;;
+ ;; Prompts you for an extra mode to add snippets for in the
+ ;; current buffer.
+ ;;
;; M-x yas-insert-snippet
;;
;; Prompts you for possible snippet expansion if that is
;;; Code:
(require 'cl)
+ (require 'cl-lib)
(require 'easymenu)
(require 'help-mode)
(defgroup yasnippet nil
"Yet Another Snippet extension"
+ :prefix "yas-"
:group 'editing)
- (defvar yas--load-file-name load-file-name
- "Store the filename that yasnippet.el was originally loaded from.")
+ (defvar yas-installed-snippets-dir nil)
+ (setq yas-installed-snippets-dir
+ (when load-file-name
+ (concat (file-name-directory load-file-name) "snippets")))
(defcustom yas-snippet-dirs (remove nil
(list "~/.emacs.d/snippets"
- (when yas--load-file-name
- (concat (file-name-directory yas--load-file-name) "snippets"))))
- "Directory or list of snippet dirs for each major mode.
-
- The directory where user-created snippets are to be stored. Can
- also be a list of directories. In that case, when used for
- bulk (re)loading of snippets (at startup or via
- `yas-reload-all'), directories appearing earlier in the list
- shadow other dir's snippets. Also, the first directory is taken
- as the default for storing the user's new snippets."
+ 'yas-installed-snippets-dir))
+ "List of top-level snippet directories.
+
+ Each element, a string or a symbol whose value is a string,
+ designates a top-level directory where per-mode snippet
+ directories can be found.
+
+ Elements appearing earlier in the list shadow later elements'
+ snippets.
+
+ The first directory is taken as the default for storing snippet's
+ created with `yas-new-snippet'. "
:type '(choice (string :tag "Single directory (string)")
(repeat :args (string) :tag "List of directories (strings)"))
:group 'yasnippet
(yas-reload-all)))))
(defun yas-snippet-dirs ()
- "Return `yas-snippet-dirs' (which see) as a list."
- (if (listp yas-snippet-dirs) yas-snippet-dirs (list yas-snippet-dirs)))
+ "Return variable `yas-snippet-dirs' as list of strings."
+ (cl-loop for e in (if (listp yas-snippet-dirs)
+ yas-snippet-dirs
+ (list yas-snippet-dirs))
+ collect
+ (cond ((stringp e) e)
+ ((and (symbolp e)
+ (boundp e)
+ (stringp (symbol-value e)))
+ (symbol-value e))
+ (t
+ (error "[yas] invalid element %s in `yas-snippet-dirs'" e)))))
(defvaralias 'yas/root-directory 'yas-snippet-dirs)
(defcustom yas-new-snippet-default "\
- # -*- mode: snippet -*-
+ # -*- mode: snippet; require-final-newline: nil -*-
# name: $1
# key: ${2:${1:$(yas--key-from-desc yas-text)}}${3:
- # binding: ${4:direct-keybinding}}${5:
- # expand-env: ((${6:some-var} ${7:some-value}))}${8:
- # type: command}
+ # binding: ${4:direct-keybinding}}
# --
$0"
"Default snippet to use when creating a new snippet.
`yas-expand' returns nil)
- A Lisp form (apply COMMAND . ARGS) means interactively call
- COMMAND, if ARGS is non-nil, call COMMAND non-interactively
+ COMMAND. If ARGS is non-nil, call COMMAND non-interactively
with ARGS as arguments."
:type '(choice (const :tag "Call previous command" call-other-command)
(const :tag "Do nothing" return-nil))
under the menu \"Yasnippet\".
- If set to `abbreviate', only the current major-mode
- menu and the modes set in `yas-extra-modes' are listed.
+ menu and the modes set in `yas--extra-modes' are listed.
- If set to `full', every submenu is listed
- - It set to nil, don't display a menu at all (this requires a
- `yas-reload-all' call if the menu is already visible).
+ - If set to `nil', hide the menu.
Any other non-nil value, every submenu is listed."
:type '(choice (const :tag "Full" full)
map)
"The active keymap while a snippet expansion is in progress.")
- (defvar yas-key-syntaxes (list "w" "w_" "w_." "w_.()" "^ ")
- "List of character syntaxes used to find a trigger key before point.
- The list is tried in the order while scanning characters
- backwards from point. For example, if the list is '(\"w\" \"w_\")
- first look for trigger keys which are composed exclusively of
- \"word\"-syntax characters, and then, if that fails, look for
- keys which are either of \"word\" or \"symbol\"
- syntax. Triggering after
+ (defvar yas-key-syntaxes (list "w" "w_" "w_." "w_.()"
+ #'yas-try-key-from-whitespace)
+ "Syntaxes and functions to help look for trigger keys before point.
+
+ Each element in this list specifies how to skip buffer positions
+ backwards and look for the start of a trigger key.
+
+ Each element can be either a string or a function receiving the
+ original point as an argument. A string element is simply passed
+ to `skip-syntax-backward' whereas a function element is called
+ with no arguments and should also place point before the original
+ position.
+
+ The string between the resulting buffer position and the original
+ point is matched against the trigger keys in the active snippet
+ tables.
+
+ If no expandable snippets are found, the next element is the list
+ is tried, unless a function element returned the symbol `again',
+ in which case it is called again from the previous position and
+ may once more reposition point.
+
+ For example, if `yas-key-syntaxes'' value is '(\"w\" \"w_\"),
+ trigger keys composed exclusively of \"word\"-syntax characters
+ are looked for first. Failing that, longer keys composed of
+ \"word\" or \"symbol\" syntax are looked for. Therefore,
+ triggering after
foo-bar
- will, according to the \"w\" element first try \"bar\". If that
- isn't a trigger key, \"foo-bar\" is tried, respecting a second
- \"w_\" element.")
+ will, according to the \"w\" element first try \"barbaz\". If
+ that isn't a trigger key, \"foo-barbaz\" is tried, respecting the
+ second \"w_\" element. Notice that even if \"baz\" is a trigger
+ key for an active snippet, it won't be expanded, unless a
+ function is added to `yas-key-syntaxes' that eventually places
+ point between \"bar\" and \"baz\".
+
+ See also Info node `(elisp) Syntax Descriptors'.")
(defvar yas-after-exit-snippet-hook
'()
(defvar yas--menu-table (make-hash-table)
"A hash table of MAJOR-MODE symbols to menu keymaps.")
- (defvar yas--known-modes
- '(ruby-mode rst-mode markdown-mode)
- "A list of mode which is well known but not part of Emacs.")
-
(defvar yas--escaped-characters
'(?\\ ?` ?\" ?' ?$ ?} ?{ ?\( ?\))
"List of characters which *might* need to be escaped.")
(defun yas--snippet-next-id ()
(let ((id yas--snippet-id-seed))
- (incf yas--snippet-id-seed)
+ (cl-incf yas--snippet-id-seed)
id))
\f
(defvar yas--minor-mode-menu nil
"Holds the YASnippet menu.")
- (defun yas--init-minor-keymap ()
- "Set up the `yas-minor-mode' keymap."
+ (defvar yas-minor-mode-map
(let ((map (make-sparse-keymap)))
- (when yas-use-menu
- (easy-menu-define yas--minor-mode-menu
- map
- "Menu used when `yas-minor-mode' is active."
- '("YASnippet"
- "----"
- ["Expand trigger" yas-expand
- :help "Possibly expand tab trigger before point"]
- ["Insert at point..." yas-insert-snippet
- :help "Prompt for an expandable snippet and expand it at point"]
- ["New snippet..." yas-new-snippet
- :help "Create a new snippet in an appropriate directory"]
- ["Visit snippet file..." yas-visit-snippet-file
- :help "Prompt for an expandable snippet and find its file"]
- "----"
- ("Snippet menu behaviour"
- ["Visit snippets" (setq yas-visit-from-menu t)
- :help "Visit snippets from the menu"
- :active t :style radio :selected yas-visit-from-menu]
- ["Expand snippets" (setq yas-visit-from-menu nil)
- :help "Expand snippets from the menu"
- :active t :style radio :selected (not yas-visit-from-menu)]
- "----"
- ["Show all known modes" (setq yas-use-menu 'full)
- :help "Show one snippet submenu for each loaded table"
- :active t :style radio :selected (eq yas-use-menu 'full)]
- ["Abbreviate according to current mode" (setq yas-use-menu 'abbreviate)
- :help "Show only snippet submenus for the current active modes"
- :active t :style radio :selected (eq yas-use-menu 'abbreviate)])
- ("Indenting"
- ["Auto" (setq yas-indent-line 'auto)
- :help "Indent each line of the snippet with `indent-according-to-mode'"
- :active t :style radio :selected (eq yas-indent-line 'auto)]
- ["Fixed" (setq yas-indent-line 'fixed)
- :help "Indent the snippet to the current column"
- :active t :style radio :selected (eq yas-indent-line 'fixed)]
- ["None" (setq yas-indent-line 'none)
- :help "Don't apply any particular snippet indentation after expansion"
- :active t :style radio :selected (not (member yas-indent-line '(fixed auto)))]
- "----"
- ["Also auto indent first line" (setq yas-also-auto-indent-first-line
- (not yas-also-auto-indent-first-line))
- :help "When auto-indenting also, auto indent the first line menu"
- :active (eq yas-indent-line 'auto)
- :style toggle :selected yas-also-auto-indent-first-line]
- )
- ("Prompting method"
- ["System X-widget" (setq yas-prompt-functions
- (cons 'yas-x-prompt
- (remove 'yas-x-prompt
- yas-prompt-functions)))
- :help "Use your windowing system's (gtk, mac, windows, etc...) default menu"
- :active t :style radio :selected (eq (car yas-prompt-functions)
- 'yas-x-prompt)]
- ["Dropdown-list" (setq yas-prompt-functions
- (cons 'yas-dropdown-prompt
- (remove 'yas-dropdown-prompt
- yas-prompt-functions)))
- :help "Use a special dropdown list"
- :active t :style radio :selected (eq (car yas-prompt-functions)
- 'yas-dropdown-prompt)]
- ["Ido" (setq yas-prompt-functions
- (cons 'yas-ido-prompt
- (remove 'yas-ido-prompt
- yas-prompt-functions)))
- :help "Use an ido-style minibuffer prompt"
- :active t :style radio :selected (eq (car yas-prompt-functions)
- 'yas-ido-prompt)]
- ["Completing read" (setq yas-prompt-functions
- (cons 'yas-completing-prompt
- (remove 'yas-completing-prompt
- yas-prompt-functions)))
- :help "Use a normal minibuffer prompt"
- :active t :style radio :selected (eq (car yas-prompt-functions)
- 'yas-completing-prompt)]
- )
- ("Misc"
- ["Wrap region in exit marker"
- (setq yas-wrap-around-region
- (not yas-wrap-around-region))
- :help "If non-nil automatically wrap the selected text in the $0 snippet exit"
- :style toggle :selected yas-wrap-around-region]
- ["Allow stacked expansions "
- (setq yas-triggers-in-field
- (not yas-triggers-in-field))
- :help "If non-nil allow snippets to be triggered inside other snippet fields"
- :style toggle :selected yas-triggers-in-field]
- ["Revive snippets on undo "
- (setq yas-snippet-revival
- (not yas-snippet-revival))
- :help "If non-nil allow snippets to become active again after undo"
- :style toggle :selected yas-snippet-revival]
- ["Good grace "
- (setq yas-good-grace
- (not yas-good-grace))
- :help "If non-nil don't raise errors in bad embedded elisp in snippets"
- :style toggle :selected yas-good-grace]
- )
- "----"
- ["Load snippets..." yas-load-directory
- :help "Load snippets from a specific directory"]
- ["Reload everything" yas-reload-all
- :help "Cleanup stuff, reload snippets, rebuild menus"]
- ["About" yas-about
- :help "Display some information about YASnippet"])))
-
- ;; Now for the stuff that has direct keybindings
- ;;
(define-key map [(tab)] 'yas-expand)
(define-key map (kbd "TAB") 'yas-expand)
(define-key map "\C-c&\C-s" 'yas-insert-snippet)
(define-key map "\C-c&\C-n" 'yas-new-snippet)
(define-key map "\C-c&\C-v" 'yas-visit-snippet-file)
- map))
-
- (defvar yas-minor-mode-map (yas--init-minor-keymap)
+ map)
"The keymap used when `yas-minor-mode' is active.")
+ (easy-menu-define yas--minor-mode-menu
+ yas-minor-mode-map
+ "Menu used when `yas-minor-mode' is active."
+ '("YASnippet" :visible yas-use-menu
+ "----"
+ ["Expand trigger" yas-expand
+ :help "Possibly expand tab trigger before point"]
+ ["Insert at point..." yas-insert-snippet
+ :help "Prompt for an expandable snippet and expand it at point"]
+ ["New snippet..." yas-new-snippet
+ :help "Create a new snippet in an appropriate directory"]
+ ["Visit snippet file..." yas-visit-snippet-file
+ :help "Prompt for an expandable snippet and find its file"]
+ "----"
+ ("Snippet menu behaviour"
+ ["Visit snippets" (setq yas-visit-from-menu t)
+ :help "Visit snippets from the menu"
+ :active t :style radio :selected yas-visit-from-menu]
+ ["Expand snippets" (setq yas-visit-from-menu nil)
+ :help "Expand snippets from the menu"
+ :active t :style radio :selected (not yas-visit-from-menu)]
+ "----"
+ ["Show all known modes" (setq yas-use-menu 'full)
+ :help "Show one snippet submenu for each loaded table"
+ :active t :style radio :selected (eq yas-use-menu 'full)]
+ ["Abbreviate according to current mode" (setq yas-use-menu 'abbreviate)
+ :help "Show only snippet submenus for the current active modes"
+ :active t :style radio :selected (eq yas-use-menu 'abbreviate)])
+ ("Indenting"
+ ["Auto" (setq yas-indent-line 'auto)
+ :help "Indent each line of the snippet with `indent-according-to-mode'"
+ :active t :style radio :selected (eq yas-indent-line 'auto)]
+ ["Fixed" (setq yas-indent-line 'fixed)
+ :help "Indent the snippet to the current column"
+ :active t :style radio :selected (eq yas-indent-line 'fixed)]
+ ["None" (setq yas-indent-line 'none)
+ :help "Don't apply any particular snippet indentation after expansion"
+ :active t :style radio :selected (not (member yas-indent-line '(fixed auto)))]
+ "----"
+ ["Also auto indent first line" (setq yas-also-auto-indent-first-line
+ (not yas-also-auto-indent-first-line))
+ :help "When auto-indenting also, auto indent the first line menu"
+ :active (eq yas-indent-line 'auto)
+ :style toggle :selected yas-also-auto-indent-first-line]
+ )
+ ("Prompting method"
+ ["System X-widget" (setq yas-prompt-functions
+ (cons 'yas-x-prompt
+ (remove 'yas-x-prompt
+ yas-prompt-functions)))
+ :help "Use your windowing system's (gtk, mac, windows, etc...) default menu"
+ :active t :style radio :selected (eq (car yas-prompt-functions)
+ 'yas-x-prompt)]
+ ["Dropdown-list" (setq yas-prompt-functions
+ (cons 'yas-dropdown-prompt
+ (remove 'yas-dropdown-prompt
+ yas-prompt-functions)))
+ :help "Use a special dropdown list"
+ :active t :style radio :selected (eq (car yas-prompt-functions)
+ 'yas-dropdown-prompt)]
+ ["Ido" (setq yas-prompt-functions
+ (cons 'yas-ido-prompt
+ (remove 'yas-ido-prompt
+ yas-prompt-functions)))
+ :help "Use an ido-style minibuffer prompt"
+ :active t :style radio :selected (eq (car yas-prompt-functions)
+ 'yas-ido-prompt)]
+ ["Completing read" (setq yas-prompt-functions
+ (cons 'yas-completing-prompt
+ (remove 'yas-completing-prompt
+ yas-prompt-functions)))
+ :help "Use a normal minibuffer prompt"
+ :active t :style radio :selected (eq (car yas-prompt-functions)
+ 'yas-completing-prompt)]
+ )
+ ("Misc"
+ ["Wrap region in exit marker"
+ (setq yas-wrap-around-region
+ (not yas-wrap-around-region))
+ :help "If non-nil automatically wrap the selected text in the $0 snippet exit"
+ :style toggle :selected yas-wrap-around-region]
+ ["Allow stacked expansions "
+ (setq yas-triggers-in-field
+ (not yas-triggers-in-field))
+ :help "If non-nil allow snippets to be triggered inside other snippet fields"
+ :style toggle :selected yas-triggers-in-field]
+ ["Revive snippets on undo "
+ (setq yas-snippet-revival
+ (not yas-snippet-revival))
+ :help "If non-nil allow snippets to become active again after undo"
+ :style toggle :selected yas-snippet-revival]
+ ["Good grace "
+ (setq yas-good-grace
+ (not yas-good-grace))
+ :help "If non-nil don't raise errors in bad embedded elisp in snippets"
+ :style toggle :selected yas-good-grace]
+ )
+ "----"
+ ["Load snippets..." yas-load-directory
+ :help "Load snippets from a specific directory"]
+ ["Reload everything" yas-reload-all
+ :help "Cleanup stuff, reload snippets, rebuild menus"]
+ ["About" yas-about
+ :help "Display some information about YASnippet"]))
+
+ (defvar yas--extra-modes nil
+ "An internal list of modes for which to also lookup snippets.
+
+ This variable probably makes more sense as buffer-local, so
+ ensure your use `make-local-variable' when you set it.")
+ (define-obsolete-variable-alias 'yas-extra-modes 'yas--extra-modes "0.8.1")
+
(defvar yas--tables (make-hash-table)
"A hash table of mode symbols to `yas--table' objects.")
`derived-mode-parent' property of some mode symbols, but that is
not recorded here.")
- (defvar yas--ancestors (make-hash-table)
- "A hash table of mode symbols do lists of all parent mode symbols.
-
- A cache managed by `yas--all-parents'")
-
(defvar yas--direct-keymaps (list)
"Keymap alist supporting direct snippet keybindings.
(defun yas--modes-to-activate ()
"Compute list of mode symbols that are active for `yas-expand'
and friends."
- (let ((modes-to-activate (list major-mode))
- (mode major-mode))
- (while (setq mode (get mode 'derived-mode-parent))
- (push mode modes-to-activate))
- (dolist (mode (yas-extra-modes))
- (push mode modes-to-activate))
- (remove-duplicates
- (append modes-to-activate
- (mapcan #'(lambda (mode)
- (yas--all-parents mode))
- modes-to-activate)))))
+ (let (dfs)
+ (setq dfs (lambda (mode &optional explored)
+ (push mode explored)
+ (cons mode
+ (loop for neighbour
+ in (cl-list* (get mode 'derived-mode-parent)
+ (ignore-errors (symbol-function mode))
+ (gethash mode yas--parents))
+ when (and neighbour
+ (not (memq neighbour explored))
+ (symbolp neighbour))
+ append (funcall dfs neighbour explored)))))
+ (remove-duplicates (append yas--extra-modes
+ (funcall dfs major-mode)))))
(defvar yas-minor-mode-hook nil
"Hook run when `yas-minor-mode' is turned on.")
(remove-hook 'post-command-hook 'yas--post-command-handler t)
(remove-hook 'emulation-mode-map-alists 'yas--direct-keymaps))))
+ (defun yas-activate-extra-mode (mode)
+ "Activates the snippets for the given `mode' in the buffer.
+
+ The function can be called in the hook of a minor mode to
+ activate snippets associated with that mode."
+ (interactive
+ (let (modes
+ symbol)
+ (maphash (lambda (k _)
+ (setq modes (cons (list k) modes)))
+ yas--parents)
+ (setq symbol (completing-read
+ "Activate mode: " modes nil t))
+ (list
+ (when (not (string= "" symbol))
+ (intern symbol)))))
+ (when mode
+ (add-to-list (make-local-variable 'yas--extra-modes) mode)
+ (yas--load-pending-jits)))
+
+ (defun yas-deactivate-extra-mode (mode)
+ "Deactivates the snippets for the given `mode' in the buffer."
+ (interactive
+ (list (intern
+ (completing-read
+ "Deactivate mode: " (mapcar #'list yas--extra-modes) nil t))))
+ (set (make-local-variable 'yas--extra-modes)
+ (remove mode
+ yas--extra-modes)))
+
(defvar yas-dont-activate '(minibufferp)
"If non-nil don't let `yas-global-mode' affect some buffers.
(defvar yas--font-lock-keywords
(append '(("^#.*$" . font-lock-comment-face))
- lisp-font-lock-keywords
- lisp-font-lock-keywords-1
lisp-font-lock-keywords-2
'(("$\\([0-9]+\\)"
(0 font-lock-keyword-face)
("${\\([0-9]+\\):?"
(0 font-lock-keyword-face)
(1 font-lock-warning-face t))
- ("${" font-lock-keyword-face)
- ("$[0-9]+?" font-lock-preprocessor-face)
+ ("${" . font-lock-keyword-face)
+ ("$[0-9]+?" . font-lock-preprocessor-face)
("\\(\\$(\\)" 1 font-lock-preprocessor-face)
("}"
(0 font-lock-keyword-face)))))
(when (third ent)
(define-key map (third ent) (second ent)))
(vector (first ent) (second ent) t))
- '(("Load this snippet" yas-load-snippet-buffer "\C-c\C-c")
+ '(("Load this snippet" yas-load-snippet-buffer "\C-c\C-l")
+ ("Load and quit window" yas-load-snippet-buffer-and-close "\C-c\C-c")
("Try out this snippet" yas-tryout-snippet "\C-c\C-t")))))
map)
"The keymap used when `snippet-mode' is active.")
\f
;;; Internal structs for template management
- (defstruct (yas--template (:constructor yas--make-blank-template))
+ (defstruct (yas--template (:constructor yas--make-template))
"A template for a snippet."
key
content
table
)
- (defun yas--populate-template (template &rest args)
- "Helper function to populate TEMPLATE with properties."
- (while args
- (aset template
- (position (intern (substring (symbol-name (car args)) 1))
- (mapcar #'car (get 'yas--template 'cl-struct-slots)))
- (second args))
- (setq args (cddr args)))
- template)
-
(defstruct (yas--table (:constructor yas--make-snippet-table (name)))
"A table to store snippets for a particular mode.
`yas--table-name'
A symbol name normally corresponding to a major mode, but can
- also be a pseudo major-mode to be referenced in
- `yas-extra-modes', for example.
+ also be a pseudo major-mode to be used in
+ `yas-activate-extra-mode', for example.
`yas--table-hash'
(yas--add-template table template)
;; Take care of the menu
;;
- (when yas-use-menu
- (yas--update-template-menu table template)))
+ (yas--update-template-menu table template))
(defun yas--update-template-menu (table template)
"Update every menu-related for TEMPLATE."
(t
(eq requirement result)))))
- (defun yas--all-parents (mode)
- "Return a list of all parent modes of MODE."
- (or (gethash mode yas--ancestors)
- (let ((seen '()))
- (labels ((yas--all-parents-1
- (m)
- (cond ((memq m seen)
- (yas--message 1
- "Cyclic parenthood: mode %s has already seen as a parent of mode %s"
- m mode)
- nil)
- (t
- (let* ((parents (gethash m yas--parents)))
- (setq seen (append seen parents))
- (append parents (mapcan #'yas--all-parents-1 parents)))))))
- (puthash mode (yas--all-parents-1 mode)
- yas--ancestors)))))
-
(defun yas--table-templates (table)
(when table
(let ((acc (list)))
(yas--table-hash table))
(yas--filter-templates-by-condition acc))))
- (defun yas--current-key ()
- "Get the key under current position.
- A key is used to find the template of a snippet in the current snippet-table."
- (let ((start (point))
- (end (point))
- (syntaxes yas-key-syntaxes)
- syntax
- done
- templates)
- (while (and (not done) syntaxes)
- (setq syntax (car syntaxes))
- (setq syntaxes (cdr syntaxes))
- (save-excursion
- (skip-syntax-backward syntax)
- (setq start (point)))
- (setq templates
- (mapcan #'(lambda (table)
- (yas--fetch table (buffer-substring-no-properties start end)))
- (yas--get-snippet-tables)))
- (if templates
- (setq done t)
- (setq start end)))
- (list templates
- start
- end)))
-
+ (defun yas--templates-for-key-at-point ()
+ "Find `yas--template' objects for any trigger keys preceding point.
+ Returns (TEMPLATES START END). This function respects
+ `yas-key-syntaxes', which see."
+ (save-excursion
+ (let ((original (point))
+ (methods yas-key-syntaxes)
+ (templates)
+ (method))
+ (while (and methods
+ (not templates))
+ (unless (eq method (car methods))
+ ;; TRICKY: `eq'-ness test means we can only be here if
+ ;; `method' is a function that returned `again', and hence
+ ;; don't revert back to original position as per
+ ;; `yas-key-syntaxes'.
+ (goto-char original))
+ (setq method (car methods))
+ (cond ((stringp method)
+ (skip-syntax-backward method)
+ (setq methods (cdr methods)))
+ ((functionp method)
+ (unless (eq (funcall method original)
+ 'again)
+ (setq methods (cdr methods))))
+ (t
+ (yas--warning "Warning invalid element %s in `yas-key-syntaxes'" method)))
+ (let ((possible-key (buffer-substring-no-properties (point) original)))
+ (save-excursion
+ (goto-char original)
+ (setq templates
+ (mapcan #'(lambda (table)
+ (yas--fetch table possible-key))
+ (yas--get-snippet-tables))))))
+ (when templates
+ (list templates (point) original)))))
(defun yas--table-all-keys (table)
"Get trigger keys of all active snippets in TABLE."
\f
;;; Internal functions and macros:
- (defun yas--real-mode? (mode)
- "Try to find out if MODE is a real mode.
-
- The MODE bound to a function (like `c-mode') is considered real
- mode. Other well known mode like `ruby-mode' which is not part of
- Emacs might not bound to a function until it is loaded. So
- yasnippet keeps a list of modes like this to help the judgment."
- (or (fboundp mode)
- (find mode yas--known-modes)))
+ (defun yas--handle-error (err)
+ "Handle error depending on value of `yas-good-grace'."
+ (let ((msg (yas--format "elisp error: %s" (error-message-string err))))
+ (if yas-good-grace msg
+ (error "%s" msg))))
(defun yas--eval-lisp (form)
"Evaluate FORM and convert the result to string."
(let ((result (eval form)))
(when result
(format "%s" result))))))
- (error (if yas-good-grace
- (yas--format "elisp error! %s" (error-message-string err))
- (error (yas--format "elisp error: %s"
- (error-message-string err)))))))))
+ (error (yas--handle-error err))))))
(when (and (consp retval)
(eq 'yas--exception (car retval)))
(error (cdr retval)))
(defun yas--eval-lisp-no-saves (form)
(condition-case err
(eval form)
- (error (if yas-good-grace
- (yas--format "elisp error! %s" (error-message-string err))
- (error (yas--format "elisp error: %s"
- (error-message-string err)))))))
+ (error (message "%s" (yas--handle-error err)))))
(defun yas--read-lisp (string &optional nil-on-error)
"Read STRING as a elisp expression and return it.
keybinding (error-message-string err))
nil))))
- (defvar yas-extra-modes nil
- "If non-nil, also lookup snippets for this/these modes.
-
- Can be a symbol or a list of symbols.
-
- This variable probably makes more sense as buffer-local, so
- ensure your use `make-local-variable' when you set it.")
- (defun yas-extra-modes ()
- (if (listp yas-extra-modes) yas-extra-modes (list yas-extra-modes)))
- (defvaralias 'yas/mode-symbol 'yas-extra-modes)
-
(defun yas--table-get-create (mode)
"Get or create the snippet table corresponding to MODE."
(let ((table (gethash mode
\f
;;; Popping up for keys and templates
- (defvar yas--x-pretty-prompt-templates nil
- "If non-nil, attempt to prompt for templates like TextMate.")
-
-
(defun yas--prompt-for-template (templates &optional prompt)
"Interactively choose a template from the list TEMPLATES.
(sort templates #'(lambda (t1 t2)
(< (length (yas--template-name t1))
(length (yas--template-name t2))))))
- (if yas--x-pretty-prompt-templates
- (yas--x-pretty-prompt-templates "Choose a snippet" templates)
- (some #'(lambda (fn)
- (funcall fn (or prompt "Choose a snippet: ")
- templates
- #'yas--template-name))
- yas-prompt-functions))))
+ (some #'(lambda (fn)
+ (funcall fn (or prompt "Choose a snippet: ")
+ templates
+ #'yas--template-name))
+ yas-prompt-functions)))
(defun yas--prompt-for-keys (keys &optional prompt)
"Interactively choose a template key from the list KEYS.
(defun yas-x-prompt (prompt choices &optional display-fn)
"Display choices in a x-window prompt."
- ;; FIXME: HACK: if we notice that one of the objects in choices is
- ;; actually a `yas--template', defer to `yas--x-prompt-pretty-templates'
- ;;
- ;; This would be better implemented by passing CHOICES as a
- ;; structured tree rather than a list. Modifications would go as far
- ;; up as `yas--all-templates' I think.
- ;;
(when (and window-system choices)
- (let ((chosen
- (let (menu d) ;; d for display
- (dolist (c choices)
- (setq d (or (and display-fn (funcall display-fn c))
- c))
- (cond ((stringp d)
- (push (cons (concat " " d) c) menu))
- ((listp d)
- (push (car d) menu))))
- (setq menu (list prompt (push "title" menu)))
- (x-popup-menu (if (fboundp 'posn-at-point)
- (let ((x-y (posn-x-y (posn-at-point (point)))))
- (list (list (+ (car x-y) 10)
- (+ (cdr x-y) 20))
- (selected-window)))
- t)
- menu))))
- (or chosen
- (keyboard-quit)))))
-
- (defun yas--x-pretty-prompt-templates (prompt templates)
- "Display TEMPLATES, grouping neatly by table name."
- (let ((organized (make-hash-table :test #'equal))
- menu
- more-than-one-table
- prefix)
- (dolist (tl templates)
- (puthash (yas--template-table tl)
- (cons tl
- (gethash (yas--template-table tl) organized))
- organized))
- (setq more-than-one-table (> (hash-table-count organized) 1))
- (setq prefix (if more-than-one-table
- " " ""))
- (if more-than-one-table
- (maphash #'(lambda (table templates)
- (push (yas--table-name table) menu)
- (dolist (tl templates)
- (push (cons (concat prefix (yas--template-name tl)) tl) menu))) organized)
- (setq menu (mapcar #'(lambda (tl) (cons (concat prefix (yas--template-name tl)) tl)) templates)))
-
- (setq menu (nreverse menu))
- (or (x-popup-menu (if (fboundp 'posn-at-point)
- (let ((x-y (posn-x-y (posn-at-point (point)))))
- (list (list (+ (car x-y) 10)
- (+ (cdr x-y) 20))
- (selected-window)))
- t)
- (list prompt (push "title" menu)))
- (keyboard-quit))))
+ (or
+ (x-popup-menu
+ (if (fboundp 'posn-at-point)
+ (let ((x-y (posn-x-y (posn-at-point (point)))))
+ (list (list (+ (car x-y) 10)
+ (+ (cdr x-y) 20))
+ (selected-window)))
+ t)
+ `(,prompt ("title"
+ ,@(mapcar* (lambda (c d) `(,(concat " " d) . ,c))
+ choices
+ (if display-fn (mapcar display-fn choices) choices)))))
+ (keyboard-quit))))
(defun yas-ido-prompt (prompt choices &optional display-fn)
(when (and (fboundp 'ido-completing-read)
(defun yas-dropdown-prompt (_prompt choices &optional display-fn)
(when (fboundp 'dropdown-list)
- (let (formatted-choices
- filtered-choices
- d
- n)
- (dolist (choice choices)
- (setq d (or (and display-fn (funcall display-fn choice))
- choice))
- (when (stringp d)
- (push d formatted-choices)
- (push choice filtered-choices)))
-
- (setq n (and formatted-choices (dropdown-list formatted-choices)))
- (if n
- (nth n filtered-choices)
+ (let* ((formatted-choices
+ (if display-fn (mapcar display-fn choices) choices))
+ (n (dropdown-list formatted-choices)))
+ (if n (nth n choices)
(keyboard-quit)))))
(defun yas-completing-prompt (prompt choices &optional display-fn completion-fn)
- (let (formatted-choices
- filtered-choices
+ (let* ((formatted-choices
+ (if display-fn (mapcar display-fn choices) choices))
+ (chosen (funcall (or completion-fn #'completing-read)
+ prompt formatted-choices
+ nil 'require-match nil nil)))
+ (if (eq choices formatted-choices)
chosen
- d
- (completion-fn (or completion-fn
- #'completing-read)))
- (dolist (choice choices)
- (setq d (or (and display-fn (funcall display-fn choice))
- choice))
- (when (stringp d)
- (push d formatted-choices)
- (push choice filtered-choices)))
- (setq chosen (and formatted-choices
- (funcall completion-fn prompt
- formatted-choices
- nil
- 'require-match
- nil
- nil)))
- (let ((position (or (and chosen
- (position chosen formatted-choices :test #'string=))
- 0)))
- (nth position filtered-choices))))
+ (nth (or (position chosen formatted-choices :test #'string=) 0)
+ choices))))
(defun yas-no-prompt (_prompt choices &optional _display-fn)
(first choices))
(uuid (or (ninth snippet)
name))
(template (or (gethash uuid (yas--table-uuidhash snippet-table))
- (yas--make-blank-template))))
+ (yas--make-template :uuid uuid
+ :table snippet-table))))
;; X) populate the template object
;;
- (yas--populate-template template
- :table snippet-table
- :key key
- :content (second snippet)
- :name (or name key)
- :group group
- :condition condition
- :expand-env (sixth snippet)
- :file (seventh snippet)
- :keybinding keybinding
- :uuid uuid)
+ (setf (yas--template-key template) key)
+ (setf (yas--template-content template) (second snippet))
+ (setf (yas--template-name template) (or name key))
+ (setf (yas--template-group template) group)
+ (setf (yas--template-condition template) condition)
+ (setf (yas--template-expand-env template) (sixth snippet))
+ (setf (yas--template-file template) (seventh snippet))
+ (setf (yas--template-keybinding template) keybinding)
+
;; X) Update this template in the appropriate table. This step
;; also will take care of adding the key indicators in the
;; templates menu entry, if any
FILE is probably of very little use if you're programatically
defining snippets.
- UUID is the snippets \"unique-id\". Loading a second snippet file
- with the same uuid replaced the previous snippet.
+ UUID is the snippet's \"unique-id\". Loading a second snippet
+ file with the same uuid would replace the previous snippet.
You can use `yas--parse-template' to return such lists based on
the current buffers contents."
Below TOP-LEVEL-DIR each directory should be a mode name.
- Optional USE-JIT use jit-loading of snippets."
- (interactive "DSelect the root directory: ni\np")
+ With prefix argument USE-JIT do jit-loading of snippets."
+ (interactive
+ (list (read-directory-name "Select the root directory: " nil nil t)
+ current-prefix-arg t))
(unless yas-snippet-dirs
(setq yas-snippet-dirs top-level-dir))
- (dolist (dir (yas--subdirs top-level-dir))
- (let* ((major-mode-and-parents (yas--compute-major-mode-and-parents
- (concat dir "/dummy")))
- (mode-sym (car major-mode-and-parents))
- (parents (cdr major-mode-and-parents)))
- ;; Attention: The parents and the menus are already defined
- ;; here, even if the snippets are later jit-loaded.
- ;;
- ;; * We need to know the parents at this point since entering a
- ;; given mode should jit load for its parents
- ;; immediately. This could be reviewed, the parents could be
- ;; discovered just-in-time-as well
- ;;
- ;; * We need to create the menus here to support the `full'
- ;; option to `yas-use-menu' (all known snippet menus are shown to the user)
- ;;
- (yas--define-parents mode-sym parents)
- (yas--menu-keymap-get-create mode-sym)
- (let ((fun `(lambda () ;; FIXME: Simulating lexical-binding.
- (yas--load-directory-1 ',dir ',mode-sym))))
- (if (and use-jit
- (not (some #'(lambda (buffer)
- (with-current-buffer buffer
- ;; FIXME: Shouldn't this use derived-mode-p?
- (when (eq major-mode mode-sym)
- (yas--message 3 "Discovered there was already %s in %s" buffer mode-sym)
- t)))
- (buffer-list))))
- (yas--schedule-jit mode-sym fun)
- (funcall fun)))))
+ (let ((impatient-buffers))
+ (dolist (dir (yas--subdirs top-level-dir))
+ (let* ((major-mode-and-parents (yas--compute-major-mode-and-parents
+ (concat dir "/dummy")))
+ (mode-sym (car major-mode-and-parents))
+ (parents (cdr major-mode-and-parents)))
+ ;; Attention: The parents and the menus are already defined
+ ;; here, even if the snippets are later jit-loaded.
+ ;;
+ ;; * We need to know the parents at this point since entering a
+ ;; given mode should jit load for its parents
+ ;; immediately. This could be reviewed, the parents could be
+ ;; discovered just-in-time-as well
+ ;;
+ ;; * We need to create the menus here to support the `full'
+ ;; option to `yas-use-menu' (all known snippet menus are shown to the user)
+ ;;
+ (yas--define-parents mode-sym parents)
+ (yas--menu-keymap-get-create mode-sym)
+ (let ((fun `(lambda () ;; FIXME: Simulating lexical-binding.
+ (yas--load-directory-1 ',dir ',mode-sym))))
+ (if use-jit
+ (yas--schedule-jit mode-sym fun)
+ (funcall fun)))
+ ;; Look for buffers that are already in `mode-sym', and so
+ ;; need the new snippets immediately...
+ ;;
+ (when use-jit
+ (cl-loop for buffer in (buffer-list)
+ do (with-current-buffer buffer
+ (when (eq major-mode mode-sym)
+ (yas--message 3 "Discovered there was already %s in %s" buffer mode-sym)
+ (push buffer impatient-buffers)))))))
+ ;; ...after TOP-LEVEL-DIR has been completely loaded, call
+ ;; `yas--load-pending-jits' in these impatient buffers.
+ ;;
+ (cl-loop for buffer in impatient-buffers
+ do (with-current-buffer buffer (yas--load-pending-jits))))
(when interactive
(yas--message 3 "Loaded snippets from %s." top-level-dir)))
(call-interactively 'yas-load-directory))
errors))
- (defun yas-reload-all (&optional interactive)
+ (defun yas-reload-all (&optional no-jit interactive)
"Reload all snippets and rebuild the YASnippet menu.
- When called interactively force immediate reload of all known
+ When NO-JIT is non-nil force immediate reload of all known
snippets under `yas-snippet-dirs', otherwise use just-in-time
- loading."
- (interactive "p")
+ loading.
+
+ When called interactively, use just-in-time loading when given a
+ prefix argument."
+ (interactive (list (not current-prefix-arg) t))
(catch 'abort
(let ((errors)
(snippet-editing-buffers
;;
(setq yas--tables (make-hash-table))
(setq yas--parents (make-hash-table))
- (setq yas--ancestors (make-hash-table))
;; Before killing `yas--menu-table' use its keys to cleanup the
;; mode menu parts of `yas--minor-mode-menu' (thus also cleaning
;; Reload the directories listed in `yas-snippet-dirs' or prompt
;; the user to select one.
;;
- (setq errors (yas--load-snippet-dirs interactive))
+ (setq errors (yas--load-snippet-dirs no-jit))
;; Reload the direct keybindings
;;
(yas-direct-keymaps-reload)
+ (run-hooks 'yas-after-reload-hook)
(yas--message 3 "Reloaded everything%s...%s."
- (if interactive "" " (snippets will load just-in-time)")
+ (if no-jit "" " (snippets will load just-in-time)")
(if errors " (some errors, check *Messages*)" "")))))
+ (defvar yas-after-reload-hook nil
+ "Hooks run after `yas-reload-all'.")
+
(defun yas--load-pending-jits ()
(dolist (mode (yas--modes-to-activate))
(let ((funs (reverse (gethash mode yas--scheduled-jit-loads))))
\f
;;; Snippet compilation function
- (defun yas--initialize ()
- "For backward compatibility, enable `yas-minor-mode' globally."
- (yas-global-mode 1))
-
(defun yas-compile-directory (top-level-dir)
"Create .yas-compiled-snippets.el files under subdirs of TOP-LEVEL-DIR.
(mapcar #'(lambda (table)
(yas--table-mode table))
(yas--get-snippet-tables))))
- ((eq yas-use-menu 'full)
- t)
- ((eq yas-use-menu t)
- t)))
+ (yas-use-menu t)))
(defun yas--delete-from-keymap (keymap uuid)
"Recursively delete items with UUID from KEYMAP and its submenus."
list of groups of the snippets defined thereafter.
OMIT-ITEMS is a list of snippet uuid's that will always be
- omitted from MODE's menu, even if they're manually loaded.
-
- This function does nothing if `yas-use-menu' is nil."
- (when yas-use-menu
- (let* ((table (yas--table-get-create mode))
- (hash (yas--table-uuidhash table)))
- (yas--define-menu-1 table
- (yas--menu-keymap-get-create mode)
- menu
- hash)
- (dolist (uuid omit-items)
- (let ((template (or (gethash uuid hash)
- (yas--populate-template (puthash uuid
- (yas--make-blank-template)
- hash)
- :table table
- :uuid uuid))))
- (setf (yas--template-menu-binding-pair template) (cons nil :none)))))))
+ omitted from MODE's menu, even if they're manually loaded."
+ (let* ((table (yas--table-get-create mode))
+ (hash (yas--table-uuidhash table)))
+ (yas--define-menu-1 table
+ (yas--menu-keymap-get-create mode)
+ menu
+ hash)
+ (dolist (uuid omit-items)
+ (let ((template (or (gethash uuid hash)
+ (puthash uuid
+ (yas--make-template :table table
+ :uuid uuid)
+ hash))))
+ (setf (yas--template-menu-binding-pair template) (cons nil :none))))))
(defun yas--define-menu-1 (table menu-keymap menu uuidhash &optional group-list)
"Helper for `yas-define-menu'."
(dolist (e (reverse menu))
(cond ((eq (first e) 'yas-item)
(let ((template (or (gethash (second e) uuidhash)
- (yas--populate-template (puthash (second e)
- (yas--make-blank-template)
- uuidhash)
- :table table
- :perm-group group-list
- :uuid (second e)))))
+ (puthash (second e)
+ (yas--make-template
+ :table table
+ :perm-group group-list
+ :uuid (second e))
+ uuidhash))))
(define-key menu-keymap (vector (gensym))
(car (yas--template-menu-binding-pair-get-create template :stay)))))
((eq (first e) 'yas-submenu)
(save-restriction
(narrow-to-region (yas--field-start field)
(yas--field-end field))
- (yas--current-key))
- (yas--current-key))))
- (if (and templates-and-pos
- (first templates-and-pos))
+ (yas--templates-for-key-at-point))
+ (yas--templates-for-key-at-point))))
+ (if templates-and-pos
(yas--expand-or-prompt-for-template (first templates-and-pos)
- (second templates-and-pos)
- (third templates-and-pos))
+ (second templates-and-pos)
+ (third templates-and-pos))
(yas--fallback))))
(defun yas-expand-from-keymap ()
(interactive)
(setq yas--condition-cache-timestamp (current-time))
(let* ((vec (subseq (this-command-keys-vector) (if current-prefix-arg
- universal-argument-num-events
+ (length (this-command-keys))
0)))
(templates (mapcan #'(lambda (table)
(yas--fetch table vec))
expand immediately. Common gateway for
`yas-expand-from-trigger-key' and `yas-expand-from-keymap'."
(let ((yas--current-template (or (and (rest templates) ;; more than one
- (yas--prompt-for-template (mapcar #'cdr templates)))
- (cdar templates))))
+ (yas--prompt-for-template (mapcar #'cdr templates)))
+ (cdar templates))))
(when yas--current-template
(yas-expand-snippet (yas--template-content yas--current-template)
start
(cond ((eq yas-fallback-behavior 'return-nil)
;; return nil
nil)
+ ((eq yas-fallback-behavior 'yas--fallback)
+ (error (concat "yasnippet fallback loop!\n"
+ "This can happen when you bind `yas-expand' "
+ "outside of the `yas-minor-mode-map'.")))
((eq yas-fallback-behavior 'call-other-command)
- (let* ((beyond-yasnippet (yas--keybinding-beyond-yasnippet)))
+ (let* ((yas-fallback-behavior 'yas--fallback)
+ ;; Also bind `yas-minor-mode' to prevent fallback
+ ;; loops when other extensions use mechanisms similar
+ ;; to `yas--keybinding-beyond-yasnippet'. (github #525
+ ;; and #526)
+ ;;
+ (yas-minor-mode nil)
+ (beyond-yasnippet (yas--keybinding-beyond-yasnippet)))
(yas--message 4 "Falling back to %s" beyond-yasnippet)
(assert (or (null beyond-yasnippet) (commandp beyond-yasnippet)))
(setq this-original-command beyond-yasnippet)
- (call-interactively beyond-yasnippet)))
+ (when beyond-yasnippet
+ (call-interactively beyond-yasnippet))))
((and (listp yas-fallback-behavior)
(cdr yas-fallback-behavior)
(eq 'apply (car yas-fallback-behavior)))
- (if (cddr yas-fallback-behavior)
- (apply (cadr yas-fallback-behavior)
- (cddr yas-fallback-behavior))
- (when (commandp (cadr yas-fallback-behavior))
- (setq this-command (cadr yas-fallback-behavior))
- (call-interactively (cadr yas-fallback-behavior)))))
+ (let ((command-or-fn (cadr yas-fallback-behavior))
+ (args (cddr yas-fallback-behavior))
+ (yas-fallback-behavior 'yas--fallback)
+ (yas-minor-mode nil))
+ (if args
+ (apply command-or-fn args)
+ (when (commandp command-or-fn)
+ (setq this-command command-or-fn)
+ (call-interactively command-or-fn)))))
(t
;; also return nil if all the other fallbacks have failed
nil)))
(defun yas--keybinding-beyond-yasnippet ()
- "Return the ??"
+ "Get current keys's binding as if YASsnippet didn't exist."
(let* ((yas-minor-mode nil)
(yas--direct-keymaps nil)
(keys (this-single-command-keys)))
(defun yas-insert-snippet (&optional no-condition)
"Choose a snippet to expand, pop-up a list of choices according
- to `yas--prompt-function'.
+ to `yas-prompt-functions'.
With prefix argument NO-CONDITION, bypass filtering of snippets
by condition."
TABLE is a symbol naming a passed to `yas--table-get-create'.
- When called interactively, prompt for the table name and
- whether (and where) to save the snippet, then quit the window."
+ When called interactively, prompt for the table name."
(interactive (list (yas--read-table) t))
(cond
;; We have `yas--editing-template', this buffer's content comes from a
(set (make-local-variable 'yas--editing-template)
(yas--define-snippets-1 (yas--parse-template buffer-file-name)
table)))))
+ (when interactive
+ (yas--message 3 "Snippet \"%s\" loaded for %s."
+ (yas--template-name yas--editing-template)
+ (yas--table-name (yas--template-table yas--editing-template)))))
+
+ (defun yas-load-snippet-buffer-and-close (table &optional kill)
+ "Load the snippet with `yas-load-snippet-buffer', possibly
+ save, then `quit-window' if saved.
+
+ If the snippet is new, ask the user whether (and where) to save
+ it. If the snippet already has a file, just save it.
+
+ The prefix argument KILL is passed to `quit-window'.
- (when (and interactive
- (or
+ Don't use this from a Lisp program, call `yas-load-snippet-buffer'
+ and `kill-buffer' instead."
+ (interactive (list (yas--read-table) current-prefix-arg))
+ (yas-load-snippet-buffer table t)
+ (when (and (or
;; Only offer to save this if it looks like a library or new
;; snippet (loaded from elisp, from a dir in `yas-snippet-dirs'
;; which is not the first, or from an unwritable file)
(read-from-minibuffer (format "File name to create in %s? " chosen)
default-file-name)))
(setf (yas--template-file yas--editing-template) buffer-file-name)))))
- (when interactive
- (yas--message 3 "Snippet \"%s\" loaded for %s."
- (yas--template-name yas--editing-template)
- (yas--table-name (yas--template-table yas--editing-template)))
- (quit-window interactive)))
+ (when buffer-file-name
+ (save-buffer)
+ (quit-window kill)))
(defun yas-tryout-snippet (&optional debug)
"Test current buffer's snippet template in other buffer."
(yas--current-template
(and parsed
(fboundp test-mode)
- (yas--populate-template (yas--make-blank-template)
- :table nil ;; no tables for ephemeral snippets
- :key (first parsed)
- :content (second parsed)
- :name (third parsed)
- :expand-env (sixth parsed)))))
+ (yas--make-template :table nil ;; no tables for ephemeral snippets
+ :key (first parsed)
+ :content (second parsed)
+ :name (third parsed)
+ :expand-env (sixth parsed)))))
(cond (yas--current-template
(let ((buffer-name (format "*testing snippet: %s*" (yas--template-name yas--current-template))))
(kill-buffer (get-buffer-create buffer-name))
groups-hash)))
+ \f
+ ;;; User convenience functions, for using in `yas-key-syntaxes'
+
+ (defun yas-try-key-from-whitespace (_start-point)
+ "As `yas-key-syntaxes' element, look for whitespace delimited key.
+
+ A newline will be considered whitespace even if the mode syntax
+ marks it as something else (typically comment ender)."
+ (skip-chars-backward "^[:space:]\n"))
+
+ (defun yas-shortest-key-until-whitespace (_start-point)
+ "Like `yas-longest-key-from-whitespace' but take the shortest key."
+ (when (/= (skip-chars-backward "^[:space:]\n" (1- (point))) 0)
+ 'again))
+
+ (defun yas-longest-key-from-whitespace (start-point)
+ "As `yas-key-syntaxes' element, look for longest key between point and whitespace.
+
+ A newline will be considered whitespace even if the mode syntax
+ marks it as something else (typically comment ender)."
+ (if (= (point) start-point)
+ (yas-try-key-from-whitespace start-point)
+ (forward-char))
+ (unless (<= start-point (1+ (point)))
+ 'again))
+
+
\f
;;; User convenience functions, for using in snippet definitions
The last element of POSSIBILITIES may be a list of strings."
(unless (or yas-moving-away-p
yas-modified-p)
- (setq possibilities (nreverse possibilities))
- (setq possibilities (if (listp (car possibilities))
- (append (reverse (car possibilities)) (rest possibilities))
- possibilities))
+ (let* ((last-link (last possibilities))
+ (last-elem (car last-link)))
+ (when (listp last-elem)
+ (setcar last-link (car last-elem))
+ (setcdr last-link (cdr last-elem))))
(some #'(lambda (fn)
(funcall fn "Choose: " possibilities))
yas-prompt-functions)))
;; field must be zero length
;;
(zerop (- (yas--field-start field) (yas--field-end field)))
- ;; skip if:
+ ;; field must have been modified
+ ;;
+ (yas--field-modified-p field)
+ ;; either:
(or
- ;; 1) is a nested field and it's been modified
+ ;; 1) it's a nested field
;;
- (and (yas--field-parent-field field)
- (yas--field-modified-p field))
+ (yas--field-parent-field field)
;; 2) ends just before the snippet end
;;
(and (eq field (car (last (yas--snippet-fields snippet))))
;; the field numbered 0, just before the exit marker, should
;; never be skipped
;;
- (not (zerop (yas--field-number field)))))
+ (not (and (yas--field-number field)
+ (zerop (yas--field-number field))))))
(defun yas--snippets-at-point (&optional all-snippets)
"Return a sorted list of snippets at point.
;; snippet outside the active field. Actual protection happens in
;; `yas--on-protection-overlay-modification'.
;;
- ;; Currently this signals an error which inhibits the command. For
- ;; commands that move point (like `kill-line'), point is restored in
- ;; the `yas--post-command-handler' using a global
- ;; `yas--protection-violation' variable.
- ;;
- ;; Alternatively, I've experimented with an implementation that
- ;; commits the snippet before actually calling `this-command'
- ;; interactively, and then signals an error, which is ignored. but
- ;; blocks all other million modification hooks. This presented some
- ;; problems with stacked expansion.
- ;;
+ ;; As of github #537 this no longer inhibits the command by issuing an
+ ;; error: all the snippets at point, including nested snippets, are
+ ;; automatically commited and the current command can proceed.
+ ;;
(defun yas--make-move-field-protection-overlays (snippet field)
"Place protection overlays surrounding SNIPPET's FIELD.
;; (overlay-put ov 'evaporate t)
(overlay-put ov 'modification-hooks '(yas--on-protection-overlay-modification)))))))
- (defvar yas--protection-violation nil
- "When non-nil, signals attempts to erroneously exit or modify the snippet.
-
- Functions in the `post-command-hook', for example
- `yas--post-command-handler' can check it and reset its value to
- nil. The variables value is the point where the violation
- originated")
-
(defun yas--on-protection-overlay-modification (_overlay after? _beg _end &optional _length)
"Signals a snippet violation, then issues error.
The error should be ignored in `debug-ignored-errors'"
- (unless yas--inhibit-overlay-hooks
- (cond ((not (or after?
- (yas--undo-in-progress)))
- (setq yas--protection-violation (point))
- (error "Exit the snippet first!")))))
+ (unless (or yas--inhibit-overlay-hooks
+ after?
+ (yas--undo-in-progress))
+ (let ((snippets (yas--snippets-at-point)))
+ (yas--message 3 "Comitting snippets. Action would destroy a protection overlay.")
+ (cl-loop for snippet in snippets
+ do (yas--commit-snippet snippet)))))
(add-to-list 'debug-ignored-errors "^Exit the snippet first!$")
"Expand snippet CONTENT at current point.
Text between START and END will be deleted before inserting
- template. EXPAND-ENV is are let-style variable to value bindings
+ template. EXPAND-ENV is a list of (SYM VALUE) let-style dynamic bindings
considered when expanding the snippet."
+ (cl-assert (and yas-minor-mode
+ (memq 'yas--post-command-handler post-command-hook))
+ nil
+ "[yas] `yas-expand-snippet' needs properly setup `yas-minor-mode'")
(run-hooks 'yas-before-expand-snippet-hook)
;;
;; plain text will get recorded at the end.
;;
;; stacked expansion: also shoosh the overlay modification hooks
- (save-restriction
- (narrow-to-region start start)
- (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
- ;;
- (setq yas--start-column (save-restriction (widen) (current-column)))
- (yas--inhibit-overlay-hooks
- (setq snippet
- (if expand-env
- (eval `(let* ,expand-env
- (insert content)
- (yas--snippet-create (point-min))))
- (insert content)
- (yas--snippet-create (point-min)))))))
+ (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
+ ;;
+ (setq yas--start-column (current-column))
+ (yas--inhibit-overlay-hooks
+ (setq snippet
+ (if expand-env
+ (eval `(let* ,expand-env
+ (insert content)
+ (yas--snippet-create start (point))))
+ (insert content)
+ (yas--snippet-create start (point))))))
;; stacked-expansion: This checks for stacked expansion, save the
;; `yas--previous-active-field' and advance its boundary.
(push `(apply yas--take-care-of-redo ,beg ,end ,snippet)
buffer-undo-list))))
- (defun yas--snippet-create (begin)
- "Create a snippet from a template inserted at BEGIN.
+ (defun yas--snippet-create (begin end)
+ "Create a snippet from a template inserted at BEGIN to END.
Returns the newly created snippet."
- (let ((snippet (yas--make-snippet)))
- (goto-char begin)
- (yas--snippet-parse-create snippet)
+ (save-restriction
+ (narrow-to-region begin end)
+ (let ((snippet (yas--make-snippet)))
+ (goto-char begin)
+ (yas--snippet-parse-create snippet)
- ;; Sort and link each field
- (yas--snippet-sort-fields snippet)
+ ;; Sort and link each field
+ (yas--snippet-sort-fields snippet)
- ;; Create keymap overlay for snippet
- (setf (yas--snippet-control-overlay snippet)
- (yas--make-control-overlay snippet (point-min) (point-max)))
+ ;; Create keymap overlay for snippet
+ (setf (yas--snippet-control-overlay snippet)
+ (yas--make-control-overlay snippet (point-min) (point-max)))
- ;; Move to end
- (goto-char (point-max))
+ ;; Move to end
+ (goto-char (point-max))
- snippet))
+ snippet)))
\f
;;; Apropos adjacencies and "fom's":
(yas--calculate-adjacencies snippet)
;; Delete $-constructs
;;
- (yas--delete-regions yas--dollar-regions)
+ (save-restriction (widen) (yas--delete-regions yas--dollar-regions))
;; restore backquoted expression values
;;
(yas--restore-backquotes)
(n (line-beginning-position)))
(while (or (eql c ?\ )
(eql c ?\t))
- (incf n)
+ (cl-incf n)
(setq c (char-after n)))
n))
with their evaluated value into `yas--backquote-markers-and-strings'."
(while (re-search-forward yas--backquote-lisp-expression-regexp nil t)
(let ((current-string (match-string-no-properties 1)) transformed)
- (delete-region (match-beginning 0) (match-end 0))
+ (save-restriction (widen)
+ (delete-region (match-beginning 0) (match-end 0)))
(setq transformed (yas--eval-lisp (yas--read-lisp (yas--restore-escapes current-string '(?`)))))
(goto-char (match-beginning 0))
(when transformed
(let ((marker (make-marker)))
- (insert "Y") ;; quite horrendous, I love it :)
- (set-marker marker (point))
- (insert "Y")
+ (save-restriction
+ (widen)
+ (insert "Y") ;; quite horrendous, I love it :)
+ (set-marker marker (point))
+ (insert "Y"))
(push (cons marker transformed) yas--backquote-markers-and-strings))))))
(defun yas--restore-backquotes ()
(string (cdr marker-and-string)))
(save-excursion
(goto-char marker)
- (delete-char -1)
- (insert string)
- (delete-char 1)
+ (save-restriction
+ (widen)
+ (delete-char -1)
+ (insert string)
+ (delete-char 1))
(set-marker marker nil)))))
(defun yas--scan-sexps (from count)
;;
(defun yas--post-command-handler ()
"Handles various yasnippet conditions after each command."
- (cond (yas--protection-violation
- (goto-char yas--protection-violation)
- (setq yas--protection-violation nil))
- ((eq 'undo this-command)
+ (cond ((eq 'undo this-command)
;;
;; After undo revival the correct field is sometimes not
;; restored correctly, this condition handles that
;; depending on the context.
;;
(put 'yas-expand 'function-documentation
- '(yas--expand-from-trigger-key-doc))
- (defun yas--expand-from-trigger-key-doc ()
+ '(yas--expand-from-trigger-key-doc t))
+ (defun yas--expand-from-trigger-key-doc (context)
"A doc synthesizer for `yas--expand-from-trigger-key-doc'."
- (let ((fallback-description
- (cond ((eq yas-fallback-behavior 'call-other-command)
- (let* ((fallback (yas--keybinding-beyond-yasnippet)))
- (or (and fallback
- (format " call command `%s'." (pp-to-string fallback)))
- " do nothing (`yas-expand' doesn't shadow\nanything)")))
- ((eq yas-fallback-behavior 'return-nil)
- ", do nothing.")
- (t
- ", defer to `yas-fallback-behaviour' (which see)"))))
+ (let* ((yas-fallback-behavior (and context yas-fallback-behavior))
+ (fallback-description
+ (cond ((eq yas-fallback-behavior 'call-other-command)
+ (let* ((fallback (yas--keybinding-beyond-yasnippet)))
+ (or (and fallback
+ (format "call command `%s'."
+ (pp-to-string fallback)))
+ "do nothing (`yas-expand' doesn't shadow\nanything).")))
+ ((eq yas-fallback-behavior 'return-nil)
+ "do nothing.")
+ (t "defer to `yas-fallback-behavior' (which see)."))))
(concat "Expand a snippet before point. If no snippet
- expansion is possible,"
+ expansion is possible, "
fallback-description
"\n\nOptional argument FIELD is for non-interactive use and is an
object satisfying `yas--field-p' to restrict the expansion to.")))
- (put 'yas-expand-from-keymap 'function-documentation '(yas--expand-from-keymap-doc))
- (defun yas--expand-from-keymap-doc ()
+ (put 'yas-expand-from-keymap 'function-documentation
+ '(yas--expand-from-keymap-doc t))
+ (defun yas--expand-from-keymap-doc (context)
"A doc synthesizer for `yas--expand-from-keymap-doc'."
(add-hook 'temp-buffer-show-hook 'yas--snippet-description-finish-runonce)
(concat "Expand/run snippets from keymaps, possibly falling back to original binding.\n"
- (when (eq this-command 'describe-key)
+ (when (and context (eq this-command 'describe-key))
(let* ((vec (this-single-command-keys))
(templates (mapcan #'(lambda (table)
(yas--fetch table vec))
(when (> yas-verbosity level)
(message "%s" (apply #'yas--format message args))))
+ (defun yas--warning (format-control &rest format-args)
+ (let ((msg (apply #'format format-control format-args)))
+ (display-warning 'yasnippet msg :warning)
+ (yas--message 1 msg)))
+
(defun yas--format (format-control &rest format-args)
(apply #'format (concat "[yas] " format-control) format-args))
(setq file nil))))
root))))
- ;; `c-neutralize-syntax-in-CPP` sometimes fires "End of Buffer" error
- ;; (when it execute forward-char) and interrupt the after change
- ;; hook. Thus prevent the insert-behind hook of yasnippet to be
- ;; invoked. Here's a way to reproduce it:
-
- ;; # open a *new* Emacs.
- ;; # load yasnippet.
- ;; # open a *new* .cpp file.
- ;; # input "inc" and press TAB to expand the snippet.
- ;; # select the `#include <...>` snippet.
- ;; # type inside `<>`
-
- (defadvice c-neutralize-syntax-in-CPP
- (around yas--mp/c-neutralize-syntax-in-CPP activate)
- "Adviced `c-neutralize-syntax-in-CPP' to properly
- handle the `end-of-buffer' error fired in it by calling
- `forward-char' at the end of buffer."
- (condition-case err
- ad-do-it
- (error (message (error-message-string err)))))
-
- ;; disable c-electric-* serial command in YAS fields
- (add-hook 'c-mode-common-hook
- '(lambda ()
- (dolist (k '(":" ">" ";" "<" "{" "}"))
- (define-key (symbol-value (make-local-variable 'yas-keymap))
- k 'self-insert-command))))
\f
;;; Backward compatibility to yasnippet <= 0.7
- (defvar yas--exported-syms '(;; `defcustom's
+ (defun yas-initialize ()
+ "For backward compatibility, enable `yas-minor-mode' globally."
+ (yas-global-mode 1))
+
+ (defvar yas--backported-syms '(;; `defcustom's
;;
yas-snippet-dirs
yas-prompt-functions
yas-exit-snippet
yas-exit-all-snippets
yas-skip-and-clear-or-delete-char
+ yas-initialize
;; symbols that I "exported" for use
;; in snippets and hookage
yas-snippet-end
yas-modified-p
yas-moving-away-p
- yas-text
yas-substr
yas-choose-value
yas-key-to-value
yas-unimplemented
yas-define-condition-cache
yas-hippie-try-expand
- yas-active-keys
;; debug definitions
;; yas-debug-snippet-vars
;; yas-call-with-snippet-dirs
;; yas-with-snippet-dirs
)
- "Exported yasnippet symbols.
-
- i.e. ones that I will try to keep in future yasnippet versions
- and ones that other elisp libraries can more or less safely rely
- upon.")
+ "Backported yasnippet symbols.
- (defvar yas--dont-backport '(yas-active-keys)
- "Exported symbols that don't map back to \"yas/*\" variants.")
+ They are mapped to \"yas/*\" variants.")
- (dolist (sym (set-difference yas--exported-syms yas--dont-backport))
+ (dolist (sym yas--backported-syms)
(let ((backported (intern (replace-regexp-in-string "^yas-" "yas/" (symbol-name sym)))))
(when (boundp sym)
(make-obsolete-variable backported sym "yasnippet 0.8")
(make-obsolete backported sym "yasnippet 0.8")
(defalias backported sym))))
+ (defvar yas--exported-syms
+ (let (exported)
+ (mapatoms (lambda (atom)
+ (if (and (or (and (boundp atom)
+ (not (get atom 'byte-obsolete-variable)))
+ (and (fboundp atom)
+ (not (get atom 'byte-obsolete-info))))
+ (string-match-p "^yas-[^-]" (symbol-name atom)))
+ (push atom exported))))
+ exported)
+ "Exported yasnippet symbols.
+
+ i.e. the ones with \"yas-\" single dash prefix. I will try to
+ keep them in future yasnippet versions and other elisp libraries
+ can more or less safely rely upon them.")
+
\f
(provide 'yasnippet)
-
- ;;; yasnippet.el ends here
;; Local Variables:
;; coding: utf-8
+ ;; indent-tabs-mode: nil
;; byte-compile-warnings: (not cl-functions)
;; End:
+ ;;; yasnippet.el ends here