Compare commits

..

No commits in common. "master" and "0.12.1" have entirely different histories.

21 changed files with 1320 additions and 2128 deletions

4
.gitignore vendored
View File

@ -9,7 +9,3 @@ extras/imported/**
*.elc *.elc
ert-x.* ert-x.*
ert.* ert.*
# ELPA-generated files
/yasnippet-autoloads.el
/yasnippet-pkg.el

7
.gitmodules vendored
View File

@ -0,0 +1,7 @@
[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

View File

@ -1,7 +1,5 @@
language: generic language: generic
os: linux sudo: false
dist: xenial
git: git:
submodules: false submodules: false
@ -10,15 +8,13 @@ env:
- Wlexical=t - Wlexical=t
- Werror=t - Werror=t
- tests_Werror=t # For yasnippet-tests.el - tests_Werror=t # For yasnippet-tests.el
jobs: matrix:
- EMACS_VERSION=23.4 - EMACS_VERSION=23.4
# 24.3 gives a bunch of 'value returned from (car value-N) is # 24.3 gives a bunch of 'value returned from (car value-N) is
# unused' warnings. # unused' warnings.
- EMACS_VERSION=24.3 tests_Werror=nil - EMACS_VERSION=24.3 tests_Werror=nil
- EMACS_VERSION=24.5 - EMACS_VERSION=24.5
- EMACS_VERSION=25.3 - EMACS_VERSION=25.2
- EMACS_VERSION=26.3
- EMACS_VERSION=27-prerelease
install: install:

View File

@ -1,46 +0,0 @@
### Makefile for Yasnippet (stolen from Eglot)
# Variables
#
EMACS?=emacs
SELECTOR?=t
ERROR_ON_WARN=nil
LOAD_PATH=-L .
ELFILES := yasnippet.el yasnippet-tests.el
ELCFILES := $(ELFILES:.el=.elc)
BYTECOMP_ERROR_ON_WARN := \
--eval '(setq byte-compile-error-on-warn $(ERROR_ON_WARN))'
all: compile
%.elc: %.el
$(EMACS) -Q $(BYTECOMP_ERROR_ON_WARN) $(LOAD_PATH) \
--batch -f batch-byte-compile $<
compile: $(ELCFILES)
# Automated tests
#
yasnippet-check: compile
$(EMACS) -Q --batch \
$(LOAD_PATH) \
-l yasnippet \
-l yasnippet-tests \
--eval '(setq ert-batch-backtrace-right-margin 200)' \
--eval '(ert-run-tests-batch-and-exit (quote $(SELECTOR)))'
interactive: compile
$(EMACS) -Q \
$(LOAD_PATH) \
-l yasnippet \
-l yasnippet-tests \
check: yasnippet-check
# Cleanup
#
clean:
find . -iname '*.elc' -exec rm {} \;
.PHONY: all compile clean check

167
NEWS
View File

@ -1,174 +1,9 @@
Yasnippet NEWS -- history of user-visible changes. Yasnippet NEWS -- history of user-visible changes.
Copyright (C) 2017-2025 Free Software Foundation, Inc. Copyright (C) 2016 Free Software Foundation, Inc.
See the end of the file for license conditions. See the end of the file for license conditions.
Changes since 0.14.0:
- Silence warning about missing lexical-binding cookie.
- Bug fixes and code cleanups.
- Accept ${N} as another syntax for $N (issue #1012).
- Understand the new AUCTeX modes hierarchy (issue #1193).
- Try and use `major-mode-remap-alist` to find the right snippets for
Tree Sitter modes (issue #1169).
* 0.14.0 (Dec 22, 2019)
** Changes
*** New 'yas-auto-next' macro, automatically moves to next field.
See Github #937.
*** Yasnippet now officially requires Emacs 23 or greater.
See Github #940.
*** Snippets for 'fundamental-mode' are available in all modes.
See Github #949, and #936.
*** New function for snippets, 'yas-completing-read'.
See Github #934.
*** New function 'yas-maybe-expand-abbrev-key-filter'.
This can be used for making conditional keybindings for snippets.
Promoted from 'yas--maybe-expand-key-filter'. See Github #943.
*** DEL can now be used to clear fields, similar <delete>.
It is bound to the new conditional command 'yas-maybe-clear-field', which may
be bound to other keys as well. See Github #960 and #957.
*** Snippet field movement commands may now trigger eldoc.
See Github #952.
*** New variable 'yas-keymap-disable-hook'.
Can be used (e.g., for company-mode) to temporarily disable
'yas-keymap' bindings, or any binding made by the new function
'yas-filtered-definition'. See Github #987.
*** New variable 'yas-inhibit-overlay-modification-protection'.
This allows a snippet to remain active, even if some commands make
modifications outside the expected area (i.e., the active snippet
field).
*** 'yas-minor-mode' is no longer enabled in temp buffers.
That is, buffers whose name starts with a space. This setting may be
undone by removing 'yas-temp-buffer-p' from
'yas-dont-activate-functions'. See Github #985.
*** Accept unescaped '{', for LSP compatibility.
See Github #979.
** Fixed bugs
*** 'yas-not-string-or-comment-condition' no longer relies on 'this-command'.
This lets it work correctly with conditional key-bindings. See Github
#973, #991.
*** Fix snippet expansion in org src buffers.
Note that this still doesn't work in text-mode blocks.
See Github #976, #989.
*** Fix snippet insertion for keyless snippets.
See Github #1014.
*** Fix errors with company-mode completion within snippet fields.
See Github #995.
*** Fix errors with cc-mode.
See Github #962.
*** Fix problems with lsp-mode.
**** Improve performance in overlay heavy buffers (Github #926).
**** Fix double call of 'before/after-change-functions' (Github #966).
*** Fix errors with nested snippet expansion.
See Github #961, #1002.
*** Stop yas-field-highlight-face inheriting from bogus 'quote' face.
* 0.13.0 (May 13, 2018)
** Changes
*** Snippets for Yasnippet must now be installed separately. The
submodule linking to yasnippet-snippets was removed, as were the
"classic" snippets that came with the GNU ELPA package. The latter
can now be installed via the 'yasnippet-classic-snippets' package from
GNU ELPA.
See Github #848, #858, #834, #775.
*** 'snippet-mode' no longer derives from 'text-mode'.
It will derive from 'prog-mode' where available (Emacs 24.1 and newer)
or 'fundamental-mode' otherwise. See Github #826.
*** The default value of 'yas-key-syntaxes' is changed
Longer snippet abbrev keys are now preferred over shorter ones.
See Github #805.
*** New snippets are now created for the current major mode by default
Previously, extra activated modes could be guessed first.
See Github #875.
*** Yasnippet supports 'unload-feature' via 'yasnippet-unload-function'
See Github #753, #891.
*** New command 'yas-skip-and-clear-field' conditionally bound to 'C-d'
replaces obsoleted 'yas-skip-and-clear-or-delete-char'. The new
function may be bound to any key via the conditional binding value
'yas-maybe-skip-and-clear-field', instead of hardcoding the
'delete-char' fallback action. See Github #408, #892.
*** 'yas-lookup-snippet' now returns a struct
This allows 'yas-expand-snippet' to take looked up snippet's
environment into account. 'yas-expand-snippet' handles both
structured snippets, and plain text snippet bodies.
See Github #897.
** Fixed bugs
*** Avoid crashing due to Emacs Bug#30931
This prevents yasnippet's routines from triggering the bug, although
it is still possible to trigger it independently.
*** Don't enable undo when it's disabled
*** yas-also-auto-indent-first-line is once again respected
Yasnippet was behaving as if it was always t for single line snippets.
See Github #912.
*** Fixed handling of fixed indent with fields at beginning of line
See Github #906, #908.
*** Fixed incorrect snippets leaving "bad memory"
and possibly corrupting future expansions.
See Github #800.
*** 'global-whitespace-mode' now functions in new snippet buffers.
To fix this, the buffer name for new snippet buffers is now '+new
snippet+' instead of '*new snippet*'. See Github #842.
*** Nest snippet expansion may clear default field text
See Github #844.
*** Fixed undo list corruption snippet expand+indent.
See Github #869.
*** The '# --' marker in snippets now allows trailing whitespace.
See Github #862.
*** Fixed handling of nested simple $n fields
See Github #824, #894.
* 0.12.2 (Aug 28, 2017)
** The new option 'yas-also-auto-indent-empty-lines' allows restoring
the old indent behavior. See Github #850, #710, #685, #679.
** Keybinding triggered snippets once again deactivate the mark.
See Github #840.
* 0.12.1 (Jul 23, 2017) * 0.12.1 (Jul 23, 2017)
This is a quick bugfix release. This is a quick bugfix release.

View File

@ -15,7 +15,7 @@ YASnippet. Watch [a demo on YouTube][youtube-demo].
# Installation # Installation
## Manual install from Git ## Install the most recent version
Clone this repository somewhere Clone this repository somewhere
@ -33,16 +33,12 @@ Add your own snippets to `~/.emacs.d/snippets` by placing files there or invokin
## Install with `package-install` ## Install with `package-install`
In a recent emacs `M-x list-packages` is the recommended way to list In a recent emacs `M-x list-packages` is the recommended way to list and install packages.
and install packages. [MELPA][melpa] keeps a very recent snapshot of YASnippet, see http://melpa.org/#installing.
It's available from [GNU ELPA][gnuelpa].
If you need a very recent snapshot, you can get it from
[GNU-devel ELPA][gnudevel] as well as [MELPA][melpa]
(see http://melpa.org/#installing).
## Install with el-get ## Install with el-get
El-get is another nice way to get the most recent version, too. See El-get is a nice way to get the most recent version, too. See
https://github.com/dimitri/el-get for instructions. https://github.com/dimitri/el-get for instructions.
## Use `yas-minor-mode` on a per-buffer basis ## Use `yas-minor-mode` on a per-buffer basis
@ -59,22 +55,33 @@ where you want YASnippet enabled.
<a name="import"></a> <a name="import"></a>
YASnippet no longer bundles snippets directly, but it's very easy to Yasnippet no longer bundles snippets directly, but it's very easy to
get some! get some!
1. [yasnippet-snippets] - a snippet collection package maintained by 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] the snippet collection of
[AndreaCrotti](https://github.com/AndreaCrotti). [AndreaCrotti](https://github.com/AndreaCrotti).
It can be installed with `M-x package-install RET The default configuraiton already points to this dir, so to use
yasnippet-snippets` if you have added MELPA to your package them, just make sure the submodule really was downloaded
sources. (i.e. there are some files under `snippets/`)
2. [yasmate] a tool which is dedicated to converting textmate bundles 2. `yasmate/`
into yasnippet snippets.
Points to a github repo of the [yasmate] tool, which is dedicated
to converting textmate bundles into yasnippet snippets.
To use these snippets you have to run the tool first, so To use these snippets you have to run the tool first, so
[see its doc][yasmate]), and then point the `yas-snippet-dirs` [see its doc][yasmate]), and then point the `yas-snippet-dirs`
variable to the `.../yasmate/snippets` subdir. variable to the `.../yasmate/snippets` subdir.
If you have a working ruby environment, you can probably get lucky
directly with `rake convert-bundles`.
3. [textmate-to-yas.el] 3. [textmate-to-yas.el]
This is another textmate bundle converting tool using Elisp This is another textmate bundle converting tool using Elisp
@ -89,23 +96,18 @@ should be added like this to `yas-snippet-dirs`:
'("~/.emacs.d/snippets" ;; personal snippets '("~/.emacs.d/snippets" ;; personal snippets
"/path/to/some/collection/" ;; foo-mode and bar-mode snippet collection "/path/to/some/collection/" ;; foo-mode and bar-mode snippet collection
"/path/to/yasnippet/yasmate/snippets" ;; the yasmate 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. (yas-global-mode 1) ;; or M-x yas-reload-all if you've started YASnippet already.
# Manual, issues etc # Manual, issues etc
There's comprehensive [documentation][docs] on using and customising Please refer to the comprehensive [documentation][docs] for full
YASnippet. customisation and support. If you find a bug in the code or in the
documentation, please report it to the main Emacs bug list,
There's a [list of support issues][support-issues], with solutions to bug-gnu-emacs@gnu.org, and put "yasnippet" somewhere in the subject.
common problems and practical snippet examples. Alternatively, you may use the [Github issue tracker][issues].
The [Github issue tracker][issues] is where most YASnippet-related
discussion happens. Nevertheless, since YASnippet is a part of Emacs,
you may alternatively report bugs to Emacs via `M-x report-emacs-bug` or
sending an email to `bug-gnu-emacs@gnu.org`, putting "yasnippet"
somewhere in the subject.
## Important note regarding bug reporting ## Important note regarding bug reporting
@ -153,16 +155,19 @@ do `git log -1` in the dir).
Any more info is welcome, but don't just paste a backtrace or an error Any more info is welcome, but don't just paste a backtrace or an error
message string you got, unless we ask for it. 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 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! Finally, thank you very much for using YASnippet!
[docs]: http://joaotavora.github.io/yasnippet/ [docs]: http://joaotavora.github.io/yasnippet/
[issues]: https://github.com/joaotavora/yasnippet/issues [issues]: https://github.com/joaotavora/yasnippet/issues
[support-issues]: https://github.com/joaotavora/yasnippet/issues?q=label%3Asupport
[googlecode tracker]: http://code.google.com/p/yasnippet/issues/list [googlecode tracker]: http://code.google.com/p/yasnippet/issues/list
[forum]: http://groups.google.com/group/smart-snippet [forum]: http://groups.google.com/group/smart-snippet
[melpa]: http://melpa.milkbox.net/ [melpa]: http://melpa.milkbox.net/
[gnuelpa]: http://elpa.gnu.org/packages/yasnippet.html
[gnudevel]: http://elpa.gnu.org/devel/yasnippet.html
[yasmate]: http://github.com/joaotavora/yasmate [yasmate]: http://github.com/joaotavora/yasmate
[textmate-to-yas.el]: https://github.com/mattfidler/textmate-to-yas.el [textmate-to-yas.el]: https://github.com/mattfidler/textmate-to-yas.el
[yasnippet-snippets]: http://github.com/AndreaCrotti/yasnippet-snippets [yasnippet-snippets]: http://github.com/AndreaCrotti/yasnippet-snippets

126
Rakefile Normal file
View File

@ -0,0 +1,126 @@
# -*- Ruby -*-
require 'fileutils'
$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.]+?) *$/
$version = $1
end
find_version
FileUtils.mkdir_p('pkg')
desc "run tests in batch mode"
task :tests do
sh "#{$EMACS} -Q -L . -l yasnippet-tests.el" +
" --batch -f ert-run-tests-batch-and-exit"
end
desc "run test in interactive mode"
task :itests do
sh "#{$EMACS} -Q -L . -l yasnippet-tests.el" +
" --eval \"(call-interactively 'ert)\""
end
desc "create a release package"
task :package do
release_dir = "pkg/yasnippet-#{$version}"
FileUtils.mkdir_p(release_dir)
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
(define-package "yasnippet"
"#{$version}"
"A template system for Emacs")
END
end
sh "git clean -f snippets"
FileUtils.cd 'pkg' do
sh "tar cf yasnippet-#{$version}.tar yasnippet-#{$version}"
end
end
desc "create a release package and upload it to google code"
task :release => [:package, 'doc:archive'] do
raise "Not implemented for github yet!"
end
desc "Generate document"
task :doc, [:htmlize] do |t, args|
load_path = '-L .'
if args[:htmlize]
load_path += " -L #{args[:htmlize]}"
end
sh "#{$EMACS} -Q #{load_path} --batch -l doc/yas-doc-helper.el" +
" -f yas--generate-html-batch"
end
namespace :doc do
task :archive do
release_dir = "pkg/yasnippet-#{$version}"
FileUtils.mkdir_p(release_dir)
sh "tar cjf pkg/yasnippet-doc-#{$version}.tar.bz2 " +
"--exclude=doc/.svn --exclude=doc/images/.svn doc/*.html doc/images"
end
task :upload do
if File.exists? 'doc/gh-pages'
Dir.chdir 'doc/gh-pages' do
sh "git checkout gh-pages"
end
Dir.glob("doc/*.{html,css}").each do |file|
FileUtils.cp file, 'doc/gh-pages'
end
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 describe`.chomp()
expRev = IO.read('doc/html-revision').chomp()
if curRev != expRev
raise ("The HTML rev: #{expRev},\n" +
"current rev: #{curRev}!\n")
end
Dir.chdir 'doc/gh-pages' do
sh "git commit -a -m 'Automatic documentation update.\n\n" +
"From #{curRev.chomp()}'"
sh "git push"
end
end
end
end
desc "Compile yasnippet.el into yasnippet.elc"
rule '.elc' => '.el' do |t|
cmdline = $EMACS + ' --batch -L .'
if ENV['warnings']
cmdline += " --eval \"(setq byte-compile-warnings #{ENV['warnings']})\""
end
if ENV['Werror']
cmdline += " --eval \"(setq byte-compile-error-on-warn #{ENV['Werror']})\""
end
if ENV['Wlexical']
cmdline += " --eval \"(setq byte-compile-force-lexical-warnings #{ENV['Wlexical']})\""
end
cmdline +=" -f batch-byte-compile #{t.source}"
sh cmdline
end
task :compile => FileList["yasnippet.el"].ext('elc')
task :compile_all => FileList["*.el"].ext('elc')
task :default => :doc
desc "use yasmate to convert textmate bundles"
task :convert_bundles do
cd "yasmate"
sh "rake convert_bundles"
end

View File

@ -2,21 +2,6 @@
#+TITLE: Frequently Asked Questions #+TITLE: Frequently Asked Questions
- *Note*: In addition to the questions and answers presented here,
you might also with to visit the list of [[https://github.com/joaotavora/yasnippet/issues?q=label%3Asupport][solved support issues]] in
the Github issue tracker. It might be more up-to-date than this
list.
* Why are my snippet abbrev keys triggering when I don't want them too?
Expansion of abbrev keys is controlled by [[sym:yas-key-syntaxes][=yas-key-syntaxes=]]. Try
removing entries which correspond to the abbrev key character syntax.
For example, if you have a snippet with abbrev key "bar", that you
don't want to trigger when point follows the text =foo_bar=, remove
the ="w"= entry (since "bar" has only word syntax characters).
* Why aren't my snippet abbrev keys triggering when I want them too?
See previous question, but in reverse.
* Why is there an extra newline? * Why is there an extra newline?
If there is a newline at the end of a snippet definition file, If there is a newline at the end of a snippet definition file,
@ -30,39 +15,58 @@ final newline automatically.
* Why doesn't TAB navigation work with flyspell * Why doesn't TAB navigation work with flyspell
This is [[https://debbugs.gnu.org/26672][Emacs Bug#26672]], so you should upgrade to version 25.3 or A workaround is to inhibit flyspell overlays while the snippet is
better. Otherwise, a workaround is to inhibit flyspell overlays while active:
the snippet is active:
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(add-hook 'flyspell-incorrect-hook (add-hook 'flyspell-incorrect-hook
#'(lambda (&rest _) #'(lambda (dummy1 dummy2 dymmy3)
(and yas-active-field-overlay (and yas-active-field-overlay
(overlay-buffer yas-active-field-overlay)))) (overlay-buffer yas-active-field-overlay))))
#+END_SRC #+END_SRC
* How do I use alternative keys, i.e. not TAB? 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]].
Edit the keymaps [[sym:yas-minor-mode-map][=yas-minor-mode-map=]] and [[sym:yas-keymap][=yas-keymap=]] as you would * How to I use alternative keys, i.e. not TAB?
any other keymap, but use [[sym:yas-filtered-definition][=yas-filtered-definition=]] on the definition
if you want to respect [[sym:yas-keymap-disable-hook][=yas-keymap-disable-hook=]]: 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 #+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 "TAB") nil) (define-key yas-minor-mode-map (kbd "TAB") nil)
(define-key yas-minor-mode-map (kbd "<the new key>") yas-maybe-expand) (define-key yas-minor-mode-map (kbd "<the new key>") yas-maybe-expand)
;;keys for navigation ;;keys for navigation
(define-key yas-keymap [(tab)] nil) (define-key yas-keymap [(tab)] nil)
(define-key yas-keymap (kbd "TAB") nil) (define-key yas-keymap (kbd "TAB") nil)
(define-key yas-keymap [(shift tab)] nil) (define-key yas-keymap [(shift tab)] nil)
(define-key yas-keymap [backtab] nil) (define-key yas-keymap [backtab] nil)
(define-key yas-keymap (kbd "<new-next-field-key>") (define-key yas-keymap (kbd "<new-next-field-key>") 'yas-next-field-or-maybe-expand)
(yas-filtered-definition 'yas-next-field-or-maybe-expand)) (define-key yas-keymap (kbd "<new-prev-field-key>") 'yas-prev)
(define-key yas-keymap (kbd "<new-prev-field-key>")
(yas-filtered-definition 'yas-prev-field))
#+end_src #+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? * How do I define an abbrev key containing characters not supported by the filesystem?
- *Note*: This question applies if you're still defining snippets - *Note*: This question applies if you're still defining snippets

View File

@ -3,8 +3,8 @@
<li> <a href="index.html">Overview</a> <li> <a href="index.html">Overview</a>
<li> <a href="https://github.com/joaotavora/yasnippet/blob/master/README.mdown"> <li> <a href="https://github.com/joaotavora/yasnippet/blob/master/README.mdown">
Intro and Tutorial</a> Intro and Tutorial</a>
<li class="center border">Snippet <li class="center">Snippet
<ul class="nopad"> <ul>
<li> <a href="snippet-organization.html">Organization</a> <li> <a href="snippet-organization.html">Organization</a>
<li> <a href="snippet-expansion.html">Expansion</a> <li> <a href="snippet-expansion.html">Expansion</a>
<li> <a href="snippet-development.html">Development</a> <li> <a href="snippet-development.html">Development</a>

View File

@ -8,7 +8,7 @@
There are some ways you can quickly find a snippet file or create a new one: There are some ways you can quickly find a snippet file or create a new one:
- =M-x yas-new-snippet=, key binding: =C-c & C-n= - =M-x yas-new-snippet=, key bindind: =C-c & C-n=
Creates a new buffer with a template for making a new snippet. The Creates a new buffer with a template for making a new snippet. The
buffer is in =snippet-mode= (see [[snippet-mode][below]]). When you are done editing buffer is in =snippet-mode= (see [[snippet-mode][below]]). When you are done editing
@ -62,7 +62,7 @@ expanded.
Optionally, if the file contains a line of =# --=, the lines above it Optionally, if the file contains a line of =# --=, the lines above it
count as comments, some of which can be /directives/ (or meta data). count as comments, some of which can be /directives/ (or meta data).
Snippet directives look like =# property: value= and tweak certain Snippet directives look like =# property: value= and tweak certain
snippet properties described below. If no =# --= is found, the whole snippets properties described below. If no =# --= is found, the whole
file is considered the snippet template. file is considered the snippet template.
Here's a typical example: Here's a typical example:
@ -80,7 +80,7 @@ Here's a list of currently supported directives:
This is the probably the most important directive, it's the This is the probably the most important directive, it's the
abbreviation you type to expand a snippet just before hitting the key 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, that runs [[sym:yas-expand][=yas-expand=]]. If you don't specify this
the snippet will not be expandable through the trigger mechanism. the snippet will not be expandable through the trigger mechanism.
** =# name:= snippet name ** =# name:= snippet name
@ -89,12 +89,12 @@ 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 -- the menu. It's a good idea to select a descriptive name for a snippet --
especially distinguishable among similar snippets. especially distinguishable among similar snippets.
If you omit this name, it will default to the file name the snippet If you omit this name it will default to the file name the snippet was
was loaded from. loaded from.
** =# condition:= snippet condition ** =# condition:= snippet condition
This is a piece of Emacs Lisp code. If a snippet has a condition, then 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 it will only be expanded when the condition code evaluate to some
non-nil value. non-nil value.
@ -104,7 +104,7 @@ See also [[sym:yas-buffer-local-condition][=yas-buffer-local-condition=]] in
** =# group:= snippet menu grouping ** =# group:= snippet menu grouping
When expanding/visiting snippets from the menu-bar menu, snippets for a 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 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. many snippets for a mode which will make the menu too long.
The =# group:= property only affect menu construction (See The =# group:= property only affect menu construction (See
@ -113,14 +113,14 @@ achieved by grouping snippets into sub-directories and using the
=.yas-make-groups= special file (for this see =.yas-make-groups= special file (for this see
[[./snippet-organization.org][Organizing Snippets]] [[./snippet-organization.org][Organizing Snippets]]
Refer to the bundled snippets for =ruby-mode= for examples of the Refer to the bundled snippets for =ruby-mode= for examples on the
=# group:= directive. Group can also be nested, e.g. =# group:= directive. Group can also be nested, e.g.
=control structure.loops= indicates that the snippet is under the =loops= =control structure.loops= tells that the snippet is under the =loops=
group which is under the =control structure= group. group which is under the =control structure= group.
** =# expand-env:= expand environment ** =# expand-env:= expand environment
This is another piece of Emacs Lisp code in the form of a =let= /varlist 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 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. used to override variable values while the snippet is being expanded.
@ -154,9 +154,9 @@ You can use this directive to expand a snippet directly from a normal
Emacs keybinding. The keybinding will be registered in the Emacs keymap Emacs keybinding. The keybinding will be registered in the Emacs keymap
named after the major mode the snippet is active for. named after the major mode the snippet is active for.
Additionally a variable [[sym:yas-prefix][=yas-prefix=]] is set to the prefix argument 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 you normally use for a command. This allows for small variations on the
same snippet, for example in this =html-mode= snippet. same snippet, for example in this "html-mode" snippet.
#+BEGIN_SRC snippet #+BEGIN_SRC snippet
# name: <p>...</p> # name: <p>...</p>
@ -172,7 +172,7 @@ will expand the paragraph tag without newlines.
** =# type:= =snippet= or =command= ** =# type:= =snippet= or =command=
If the =type= directive is set to =command=, the body of the snippet 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 is interpreted as lisp code to be evaluated when the snippet is
triggered. triggered.
If it's =snippet= (the default when there is no =type= directive), the If it's =snippet= (the default when there is no =type= directive), the
@ -202,14 +202,14 @@ usually interpreted as plain text, except =$= and =`=. You need to
use =\= to escape them: =\$= and =\`=. The =\= itself may also needed to be use =\= to escape them: =\$= and =\`=. The =\= itself may also needed to be
escaped as =\\= sometimes. escaped as =\\= sometimes.
** Embedded Emacs Lisp code ** Embedded Emacs-lisp code
Emacs Lisp code can be embedded inside the template, written inside Emacs-Lisp code can be embedded inside the template, written inside
back-quotes (=`=). The Lisp forms are evaluated when the snippet is back-quotes (=`=). The lisp forms are evaluated when the snippet is
being expanded. The evaluation is done in the same buffer as the being expanded. The evaluation is done in the same buffer as the
snippet being expanded. snippet being expanded.
Here's an example for =c-mode= to calculate the header file guard Here's an example for c-mode to calculate the header file guard
dynamically: dynamically:
#+BEGIN_SRC snippet #+BEGIN_SRC snippet
@ -221,8 +221,8 @@ dynamically:
#endif /* $1 */ #endif /* $1 */
#+END_SRC #+END_SRC
From version 0.6, snippet expansions are run with some special From version 0.6, snippets expansions are run with some special
Emacs Lisp variables bound. One of these is [[sym:yas-selected-text][=yas-selected-text=]]. You can Emacs-lisp variables bound. One of this is [[sym:yas-selected-text][=yas-selected-text=]]. You can
therefore define a snippet like: therefore define a snippet like:
#+BEGIN_SRC snippet #+BEGIN_SRC snippet
@ -237,7 +237,7 @@ Alternatively, you can also customize the variable
*** Note: backquote expressions should not modify the buffer *** Note: backquote expressions should not modify the buffer
Please note that the Lisp forms in backquotes should *not* modify the Please note that the lisp forms in backquotes should *not* modify the
buffer, doing so will trigger a warning. For example, instead of buffer, doing so will trigger a warning. For example, instead of
doing doing
@ -277,16 +277,16 @@ like this:
${N:default value} ${N:default value}
#+END_SRC #+END_SRC
They act as the default value for a tab stop. But when you first 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. type at a tab stop, the default value will be replaced by your typing.
The number can be omitted if you don't want to create [[mirrors-fields][mirrors]] or The number can be omitted if you don't want to create [[mirrors-fields][mirrors]] or
[[mirror-transformations][transformations]] for this field. [[mirror-transformations][transformations]] for this field.
** Mirrors <<mirrors-fields>> ** Mirrors <<mirrors-fields>>
We refer to tab stops with placeholders as a /field/. A field can We refer the tab stops with placeholders as a /field/. A field can have
have mirrors. *All* mirrors get updated whenever you update any field mirrors. Its mirrors will get updated when you change the text of a
text. Here's an example: field. Here's an example:
#+BEGIN_SRC snippet #+BEGIN_SRC snippet
\begin{${1:enumerate}} \begin{${1:enumerate}}
@ -299,15 +299,15 @@ 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]]). 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 The tab stops with the same number to the field act as its mirrors. If
none of the tab stops have an initial value, the first one is selected as none of the tab stops has an initial value, the first one is selected as
the field and the others are its mirrors. the field and others mirrors.
** Mirrors with transformations <<mirror-transformations>> ** Mirrors with transformations <<mirror-transformations>>
If the value of an =${n:=-construct starts with and contains =$(=, If the value of an =${n:=-construct starts with and contains =$(=,
then it is interpreted as a mirror for field =n= with a then it is interpreted as a mirror for field =n= with a
transformation. The mirror's text content is calculated according to transformation. The mirror's text content is calculated according to
this transformation, which is Emacs Lisp code that gets evaluated in 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 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 content (string) contained in the field =n=. Here's an example for
Objective-C: Objective-C:
@ -362,26 +362,12 @@ is not. Here's an snippet for rst title:
$0 $0
#+END_SRC #+END_SRC
Note that a mirror with a transform is not restricted to the text of
the field it is mirroring. By making use of [[sym:yas-field-value][=yas-field-value=]], a
mirror can look at any of the snippet's field (as mentioned above, all
mirrors are updated when any field is updated). Here is an example
which shows a "live" result of calling format:
#+BEGIN_SRC snippet
(format "${1:formatted %s}" "${2:value}")
=> "${1:$(ignore-errors (format (yas-field-value 1) (yas-field-value 2)))}"
#+END_SRC
To keep the example simple, it uses =ignore-errors= to suppress errors
due to incomplete format codes.
** Fields with transformations ** Fields with transformations
From version 0.6 on, you can also have Lisp transformation inside From version 0.6 on, you can also have lisp transformation inside
fields. These work mostly like mirror transformations. However, they fields. These work mostly mirror transformations but are evaluated when
are evaluated when you first enter the field, after each change you you first enter the field, after each change you make to the field and
make to the field and also just before you exit the field. also just before you exit the field.
The syntax is also a tiny bit different, so that the parser can The syntax is also a tiny bit different, so that the parser can
distinguish between fields and mirrors. In the following example distinguish between fields and mirrors. In the following example
@ -412,38 +398,25 @@ the field, and with some useful variables bound, notably
can place a transformation in the primary field that lets you select can place a transformation in the primary field that lets you select
default values for it. default values for it.
For example, the [[sym:yas-choose-value][=yas-completing-read=]] function is version of The [[sym:yas-choose-value][=yas-choose-value=]] does this work for you. For example:
=completing-read= which checks these variables. For example, asking
the user for the initial value of a field:
#+BEGIN_SRC snippet #+BEGIN_SRC snippet
<div align="${2:$$(yas-completing-read "Alignment? " '("right" "center" "left"))}"> <div align="${2:$$(yas-choose-value '("right" "center" "left"))}">
$0 $0
</div> </div>
#+END_SRC #+END_SRC
See the definition of [[sym:yas-choose-value][=yas-completing-read=]] to see how it was written See the definition of [[sym:yas-choose-value][=yas-choose-value=]] to see how it was written using
using the two variables. If you're really lazy :) and can't spare a the two variables.
tab keypress, you can automatically move to the next field (or exit)
after choosing the value with [[sym:yas-auto-next][=yas-auto-next=]]. The snippet above
becomes:
#+BEGIN_SRC snippet Here's another use, for LaTeX-mode, which calls reftex-label just as you
<div align="${2:$$(yas-auto-next
(yas-completing-read
"Alignment? "
'("right" "center" "left")))}">
$0
</div>
#+END_SRC
Here's another use, for =LaTeX-mode=, which calls reftex-label just as you
enter snippet field 2. This one makes use of [[sym:yas-modified-p][=yas-modified-p=]] directly. enter snippet field 2. This one makes use of [[sym:yas-modified-p][=yas-modified-p=]] directly.
#+BEGIN_SRC snippet #+BEGIN_SRC snippet
\section{${1:"Titel der Tour"}}% \section{${1:"Titel der Tour"}}%
\index{$1}% \index{$1}%
\label{{2:"waiting for reftex-label call..."$(unless yas-modified-p (reftex-label nil 'dont-insert))}}% \label{{2:"waiting for reftex-label call..."$(unless yas-modified-p (reftex-label nil 'dont-
insert))}}%
#+END_SRC #+END_SRC
The function [[sym:yas-verify-value][=yas-verify-value=]] has another neat trick, and makes use The function [[sym:yas-verify-value][=yas-verify-value=]] has another neat trick, and makes use
@ -458,7 +431,7 @@ From version 0.6 on, you can also have nested placeholders of the type:
#+END_SRC #+END_SRC
This allows you to choose if you want to give this =div= an =id= 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 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= "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 (which executes [[sym:yas-skip-and-clear-or-delete-char][=yas-skip-and-clear-or-delete-char=]]) and go straight to
the exit marker. the exit marker.

View File

@ -21,7 +21,7 @@
- Using hippie-expand - Using hippie-expand
- Call [[sym:yas-insert-snippet][=yas-insert-snippet=]] (use =M-x yas-insert-snippet= or its - Call [[sym:yas-insert-snippet][=yas-insert-snippet=]] (use =M-x yas-insert-snippet== or its
keybinding =C-c & C-s=). keybinding =C-c & C-s=).
- Use m2m's excellent auto-complete - Use m2m's excellent auto-complete
@ -77,7 +77,7 @@ obsolete.
** Insert at point ** Insert at point
The command [[sym:yas-insert-snippet][=yas-insert-snippet=]] lets you insert snippets 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 /for your current major mode/. It prompts you for the snippet key
first, and then for a snippet template if more than one template first, and then for a snippet template if more than one template
exists for the same key. exists for the same key.
@ -94,7 +94,7 @@ The prompting methods used are again controlled by
It's often useful to inject already written text in the middle of a It's often useful to inject already written text in the middle of a
snippet. The variable [[sym:yas-wrap-around-region][=yas-wrap-around-region=]] when to t substitute snippet. The variable [[sym:yas-wrap-around-region][=yas-wrap-around-region=]] when to t substitute
the region contents into the =$0= placeholder of a snippet expanded by the region contents into the =$0= placeholder of a snippet expanded by
[[sym:yas-insert-snippet][=yas-insert-snippet=]]. Setting it to a character value (e.g. =?0=) [[#yas-insert-snippet][=yas-insert-snippet=]]. Setting it to a character value (e.g. =?0=)
will insert the contents of corresponding register. will insert the contents of corresponding register.
Older (versions 0.9.1 and below) of Yasnippet, supported a setting of Older (versions 0.9.1 and below) of Yasnippet, supported a setting of
@ -141,7 +141,7 @@ See the internal documentation on [[sym:yas-expand-snippet][=yas-expand-snippet=
* Controlling expansion * Controlling expansion
** Eligible snippets<<eligible-snippets>> ** Eligible snippets
YASnippet does quite a bit of filtering to find out which snippets are YASnippet does quite a bit of filtering to find out which snippets are
eligible for expanding at the current cursor position. eligible for expanding at the current cursor position.
@ -161,17 +161,15 @@ In particular, the following things matter:
=M-x describe-variable RET major-mode RET= to find out which major =M-x describe-variable RET major-mode RET= to find out which major
mode you are in currently. mode you are in currently.
- Parent tables - Parent tables
Snippet tables defined as the parent of some other eligible table Snippet tables defined as the parent of some other eligible table are
are also considered. This works recursively, i.e., parents of also considered. This works recursively, i.e. parents of parents of
parents of eligible tables are also considered. As a special case, eligible tables are also considered.
if a mode doesn't have a parent, then =fundamental-mode= is
considered to be its parent.
- Buffer-local list of extra modes - Buffer-local list of extra modes
Use [[sym:yas-activate-extra-mode][=yas-activate-extra-mode=]] to Use [[#yas-activate-extra-mode][=yas-activate-extra-mode=]] to
consider snippet tables whose name does not correspond to a major consider snippet tables whose name does not correspond to a major
mode. Typically, you call this from a minor mode hook, for example: mode. Typically, you call this from a minor mode hook, for example:
@ -210,12 +208,11 @@ inside a comment? Set [[sym:yas-buffer-local-condition][=yas-buffer-local-condi
#+BEGIN_SRC emacs-lisp #+BEGIN_SRC emacs-lisp
(add-hook 'python-mode-hook (add-hook 'python-mode-hook
(lambda () (lambda ()
(setq yas-buffer-local-condition (setq yas-buffer-local-condition
(lambda () '(if (python-syntax-comment-or-string-p)
(if (python-syntax-comment-or-string-p) '(require-snippet-condition . force-in-comment)
'(require-snippet-condition . force-in-comment) t))))
t)))))
#+END_SRC #+END_SRC
... and for a snippet that you want to expand in comments, specify a ... and for a snippet that you want to expand in comments, specify a
@ -228,7 +225,7 @@ For the full set of possible conditions, see the documentation for
** Multiples snippet with the same key ** Multiples snippet with the same key
The rules outlined [[eligible-snippets][above]] can return more than The rules outlined [[Eligible%20snippets][above]] can return more than
one snippet to be expanded at point. one snippet to be expanded at point.
When there are multiple candidates, YASnippet will let you select one. When there are multiple candidates, YASnippet will let you select one.

View File

@ -24,7 +24,7 @@ In this menu, you can find
Invoking "Load snippets..." from the menu invokes [[sym:yas-load-directory][=yas-load-directory=]] Invoking "Load snippets..." from the menu invokes [[sym:yas-load-directory][=yas-load-directory=]]
and prompts you for a snippet directory hierarchy to load. and prompts you for a snippet directory hierarchy to load.
Also useful is the "Reload everything" item to invoke [[sym:yas-reload-all][=yas-reload-all=]] Also useful is the "Reload everything" item to invoke [[#yas-reload-all][=yas-reload-all=]]
which uncondionally reloads all the snippets directories defined in which uncondionally reloads all the snippets directories defined in
[[sym:yas-snippet-dirs][=yas-snippet-dirs=]] and rebuilds the menus. [[sym:yas-snippet-dirs][=yas-snippet-dirs=]] and rebuilds the menus.

View File

@ -4,9 +4,8 @@
* Basic structure * Basic structure
Snippet collections can be stored in plain text files. They are Snippet collections can be stored in plain text files. They are arranged by
arranged by sub-directories naming *snippet tables*. These mostly sub-directories naming *snippet tables*. These mostly name Emacs major names.
name Emacs major mode names.
#+begin_example #+begin_example
. .
@ -33,7 +32,7 @@
The default considers: The default considers:
- a personal collection that lives in =~/.emacs.d/snippets= - a personal collection that lives in =~/.emacs.d/snippets=
- the bundled collection, taken as a relative path to =yasnippet.el= location - 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 When you come across other snippet collections, do the following to try them
out: out:
@ -82,7 +81,7 @@
If you place an empty plain text file =.yas-make-groups= inside one If you place an empty plain text file =.yas-make-groups= inside one
of the mode directories, the names of these sub-directories are of the mode directories, the names of these sub-directories are
considered groups of snippets and [[file:snippet-menu.org][the menu]] is organized much more considered groups of snippets and [[snippet-menu.org][the menu]] is organized much more
cleanly: cleanly:
[[./images/menu-groups.png]] [[./images/menu-groups.png]]

View File

@ -1,14 +1,5 @@
.center { margin-left: auto; margin-right: auto; text-align: center; } nav > ul > li.center > ul {
.current { padding: 0;
font-weight: bold;
background-color: #E0E8F0;
}
body { background-color: #E4F0F4 }
div#content {
max-width: 20cm;
margin-left: auto;
margin-right: auto;
} }
nav li { nav li {
@ -18,22 +9,20 @@ nav li {
list-style-type: none; list-style-type: none;
padding: 0.5em; padding: 0.5em;
} }
nav > ul > li { nav > ul > li {
display: inline-block; display: inline-block;
} }
.nopad {
padding: 0; /* match org's css for <pre> */
} code {
li.border { background-color: #F3F5F7;
border: solid; font-family: courier, monospace;
border-width: 1px;
} }
pre, code{ background-color: #F3F5F7; } #content {
code { margin-left: 5%;
/* http://neugierig.org/software/chromium/notes/2009/09/monospace-fonts-workaround.html */ margin-right: 10%;
font-family: WorkAroundWebKitAndMozilla, monospace;
white-space: nowrap;
} }
/* Styles for htmlize.el fontification. */ /* Styles for htmlize.el fontification. */

View File

@ -0,0 +1,93 @@
@media all
{
body {
margin: 1em auto;
/*margin: 10px 18% 10px 18%;*/
font-family: Arial;
/*text-align: justify;*/
font-size: 14pt;
padding: 10px;
line-height: 1.2em;
max-width: 600pt;
}
div#table-of-contents {
position: fixed;
left: 0%;
right: 0%;
top: 0px;
z-index: 100;
background: black;
}
div#table-of-contents h2 {
display: none;
}
div#table-of-contents a {
text-decoration: none;
color: white;
}
div#table-of-contents a:visited {
color: white;
}
div#table-of-contents a:hover {
color: orange;
}
div.outline-2 h2{
padding-top: 50px;
}
div#text-table-of-contents {
text-color: white;
text-align: center;
margin-left: 30%;
margin-right: 30%;
}
div#text-table-of-contents ul {
height: 2em;
width: 500px;
list-style: none;
margin: auto;
}
div#text-table-of-contents ul li {
float: left;
margin-left:auto;
margin-right: auto;
padding-left: 10px;
}
div#postamble{
position: fixed;
width: 800px;
height: 250px;
left: 50%;
right: 50%;
margin:-75px 0 0 -400px;
bottom: -20px;
font-size: 10pt;
color: grey;
background: url('siscog-bottom-logo.png') no-repeat;
/* background-size: 100% 100%; */
}
div#postamble *{
display: none;
}
div#postamble p.date{
position: relative;
bottom: -200px;
text-align: center;
display: block;
}
}

View File

@ -1,6 +1,6 @@
;;; yas-doc-helper.el --- Help generate documentation for YASnippet -*- lexical-binding: t; -*- ;;; yas-doc-helper.el --- Help generate documentation for YASnippet
;; Copyright (C) 2012-2023 Free Software Foundation, Inc. ;; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
;; Author: João Távora <joaotavora@gmail.com> ;; Author: João Távora <joaotavora@gmail.com>
;; Keywords: convenience ;; Keywords: convenience
@ -25,25 +25,19 @@
;;; Code: ;;; Code:
(eval-when-compile (eval-when-compile
(require 'cl-lib)) (require 'cl))
(require 'org) (require 'org)
(require 'ox-publish) (or (require 'org-publish nil t)
(require 'ox-publish))
(require 'yasnippet) ; docstrings must be loaded (require 'yasnippet) ; docstrings must be loaded
;; Presumably one of org/ox-publish provided the following vars: (defun yas--org-raw-html (tag content)
(defvar org-publish-project-alist)
(defvar org-publish-use-timestamps-flag)
(defvar org-export-copy-to-kill-ring)
(defvar org-html-htmlize-output-type)
(defun yas--org-raw-html (tag content &optional attrs)
;; in version 8.0 org-mode changed the export syntax, see ;; in version 8.0 org-mode changed the export syntax, see
;; http://orgmode.org/worg/org-8.0.html#sec-8-1 ;; http://orgmode.org/worg/org-8.0.html#sec-8-1
(format (if (version< org-version "8.0.0") (format (if (version< org-version "8.0.0")
"@<%s>%s@</%s>" ; old: @<tag> "@<%s>%s@</%s>" ; old: @<tag>
"@@html:<%s>@@%s@@html:</%s>@@") ; new: @@html:<tag>@@ "@@html:<%s>@@%s@@html:</%s>@@") ; new: @@html:<tag>@@
(concat tag (if attrs " ") attrs) tag content tag))
content tag))
(defun yas--document-symbol (symbol level) (defun yas--document-symbol (symbol level)
(let* ((stars (make-string level ?*)) (let* ((stars (make-string level ?*))
@ -51,17 +45,14 @@
(mapcar #'symbol-name (help-function-arglist symbol t)))) (mapcar #'symbol-name (help-function-arglist symbol t))))
(heading (cond ((fboundp symbol) (heading (cond ((fboundp symbol)
(format (format
"%s %s (%s)\n" stars (yas--org-raw-html "code" symbol "class='function'") "%s =%s= (%s)" stars symbol
(mapconcat (lambda (a) (mapconcat (lambda (a)
(format (if (string-prefix-p "&" a) (format (if (string-prefix-p "&" a)
"/%s/" "=%s=") "/%s/" "=%s=") a))
a))
args " "))) args " ")))
(t (t
(format "%s %s\n" stars (format "%s =%s=\n" stars symbol))))
(yas--org-raw-html "code" symbol "class='variable'")))))
(after-heading (format ":PROPERTIES:\n:CUSTOM_ID: %s\n:END:" symbol)) (after-heading (format ":PROPERTIES:\n:CUSTOM_ID: %s\n:END:" symbol))
(text-quoting-style 'grave)
(body (or (cond ((fboundp symbol) (body (or (cond ((fboundp symbol)
(let ((doc-synth (car-safe (get symbol 'function-documentation)))) (let ((doc-synth (car-safe (get symbol 'function-documentation))))
(if (functionp doc-synth) (if (functionp doc-synth)
@ -73,17 +64,10 @@
(format "*WARNING*: no symbol named =%s=" symbol))) (format "*WARNING*: no symbol named =%s=" symbol)))
(format "*WARNING*: no doc for symbol =%s=" symbol))) (format "*WARNING*: no doc for symbol =%s=" symbol)))
(case-fold-search nil)) (case-fold-search nil))
;; Do some transformations on the body: ;; do some transformations on the body:
;; ARGxxx becomes @<code>arg@</code>xxx ;; ARGxxx becomes @<code>arg@</code>xxx
;; FOO becomes /foo/ ;; FOO becomes /foo/
;; `bar' becomes [[#bar][=bar=]] ;; `bar' becomes [[#bar][=bar=]]
;; (...) becomes #+BEGIN_SRC elisp (...) #+END_SRC
;; Info node `(some-manual) Node Name' becomes
;; [[https://www.gnu.org/software/emacs/manual/html_node/some-manual/Node-Name.html]
;; [(some-manual) Node Name]]
;;
;; This is fairly fragile, though it seems to be working for
;; now...
(setq body (replace-regexp-in-string (setq body (replace-regexp-in-string
"\\<\\([A-Z][-A-Z0-9]+\\)\\(\\sw+\\)?\\>" "\\<\\([A-Z][-A-Z0-9]+\\)\\(\\sw+\\)?\\>"
#'(lambda (match) #'(lambda (match)
@ -98,83 +82,42 @@
match1))) match1)))
body t t 1) body t t 1)
body (replace-regexp-in-string body (replace-regexp-in-string
"\\\\{[^}]+}" "`\\([a-z-]+\\)'"
(lambda (match)
(concat "#+BEGIN_EXAMPLE\n"
(substitute-command-keys match)
"#+END_EXAMPLE\n"))
body t t)
body (substitute-command-keys body)
body (replace-regexp-in-string
"Info node `(\\([-a-z]+\\)) \\([A-Za-z0-9 ]+\\)'"
(lambda (match)
(let* ((manual (match-string 1 match))
(node (match-string 2 match))
(html-node (replace-regexp-in-string " " "-" node t t)))
(format "Info node\
[[https://www.gnu.org/software/emacs/manual/html_node/%s/%s.html][(%s) %s]]"
manual html-node manual node)))
body t t)
body (replace-regexp-in-string
"`\\([-a-z]+\\)'"
#'(lambda (match) #'(lambda (match)
(let* ((name (downcase (match-string 1 match))) (let* ((name (downcase (match-string 1 match)))
(sym (intern-soft name))) (sym (intern name)))
(if (memq sym yas--exported-syms) (if (memq sym yas--exported-syms)
(format "[[#%s][=%s=]]" name name) (format "[[#%s][=%s=]]" name name)
(format "=%s=" name)))) (format "=%s=" name))))
body t t) body t))
body (replace-regexp-in-string
"\n\n +(.+\\(?:\n +.+\\)*"
(lambda (match)
(concat "\n#+BEGIN_SRC elisp\n"
match
"\n#+END_SRC\n"))
body t t))
;; output the paragraph ;; output the paragraph
(concat heading after-heading "\n" body))) (concat heading "\n" after-heading "\n" body)))
(defun yas--document-symbols (level &rest names-and-predicates) (defun yas--document-symbols (level &rest names-and-predicates)
(let ((sym-lists (make-vector (length names-and-predicates) nil)) (let ((sym-lists (make-vector (length names-and-predicates) nil))
(stars (make-string level ?*))) (stars (make-string level ?*)))
(cl-loop for sym in yas--exported-syms (loop for sym in yas--exported-syms
do (cl-loop for test in (mapcar #'cdr names-and-predicates) do (loop for test in (mapcar #'cdr names-and-predicates)
for i from 0 for i from 0
do (when (funcall test sym) do (when (funcall test sym)
(push sym (aref sym-lists i)) (push sym (aref sym-lists i))
(cl-return)))) (return))))
(cl-loop for slist across sym-lists (loop for slist across sym-lists
for name in (mapcar #'car names-and-predicates) for name in (mapcar #'car names-and-predicates)
concat (format "\n%s %s\n" stars name) concat (format "\n%s %s\n" stars name)
concat (mapconcat (lambda (sym) concat (mapconcat (lambda (sym)
(yas--document-symbol sym (1+ level))) (yas--document-symbol sym (1+ level)))
slist "\n\n")))) slist "\n\n"))))
(defun yas--internal-link-snippet () (defun yas--internal-link-snippet ()
(interactive) (interactive)
(yas-expand-snippet "[[#$1][=${1:`yas/selected-text`}=]]")) (yas-expand-snippet "[[#$1][=${1:`yas/selected-text`}=]]"))
(define-key org-mode-map [M-f8] #'yas--internal-link-snippet) (define-key org-mode-map [M-f8] 'yas--internal-link-snippet)
;; This lets all the org files be exported to HTML with ;; This lets all the org files be exported to HTML with
;; `org-publish-current-project' (C-c C-e P). ;; `org-publish-current-project' (C-c C-e P).
(defun yas--make-preamble (props)
"Return contents of nav-menu-html.inc.
But replace link to \"current\" page with a span element."
(with-temp-buffer
(let ((dir (file-name-directory (plist-get props :input-file))))
(insert-file-contents (expand-file-name "nav-menu.html.inc" dir))
(goto-char (point-min))
(search-forward (concat "<a href=\""
(file-name-nondirectory
(plist-get props :output-file))
"\">"))
(replace-match "<span class='current'>")
(search-forward "</a>")
(replace-match "</span>")
(buffer-string))))
(let* ((dir (if load-file-name (file-name-directory load-file-name) (let* ((dir (if load-file-name (file-name-directory load-file-name)
default-directory)) default-directory))
(src-epoch (getenv "SOURCE_DATE_EPOCH")) (src-epoch (getenv "SOURCE_DATE_EPOCH"))
@ -195,11 +138,13 @@ But replace link to \"current\" page with a span element."
`(,@(when (fboundp 'org-html-publish-to-html) `(,@(when (fboundp 'org-html-publish-to-html)
'(:publishing-function org-html-publish-to-html)) '(:publishing-function org-html-publish-to-html))
:base-directory ,dir :publishing-directory ,dir :base-directory ,dir :publishing-directory ,dir
:html-preamble yas--make-preamble :html-preamble
;;:with-broken-links mark ,(with-temp-buffer
(insert-file-contents (expand-file-name "nav-menu.html.inc" dir))
(buffer-string))
:html-postamble :html-postamble
,(concat "<hr><p class='creator'>Generated by %c from " ,(concat "<hr><p class='creator'>Generated by %c from "
rev " " date "</p>\n" (or rev yas--version) " " date "</p>\n"
"<p class='xhtml-validation'>%v</p>\n"))) "<p class='xhtml-validation'>%v</p>\n")))
(project (assoc "yasnippet" org-publish-project-alist))) (project (assoc "yasnippet" org-publish-project-alist)))
(when rev ;; Rakefile :doc:upload uses "html-revision". (when rev ;; Rakefile :doc:upload uses "html-revision".

1
snippets Submodule

@ -0,0 +1 @@
Subproject commit 885050d34737e2fb36a3e7759d60c09347bd4ce0

1
yasmate Submodule

@ -0,0 +1 @@
Subproject commit 0543618bd34a6715918992f01161c118f136bb37

View File

@ -1,6 +1,6 @@
;;; yasnippet-debug.el --- debug functions for yasnippet -*- lexical-binding: t -*- ;;; yasnippet-debug.el --- debug functions for yasnippet -*- lexical-binding: t -*-
;; Copyright (C) 2010-2025 Free Software Foundation, Inc. ;; Copyright (C) 2010, 2013, 2014, 2017 Free Software Foundation, Inc.
;; Author: João Távora ;; Author: João Távora
;; Keywords: emulations, convenience ;; Keywords: emulations, convenience
@ -40,22 +40,19 @@
;; Don't require '-L <path>' when debugging. ;; Don't require '-L <path>' when debugging.
(expand-file-name "yasnippet" yas--loaddir))) (expand-file-name "yasnippet" yas--loaddir)))
(require 'cl-lib) (require 'cl-lib)
(eval-when-compile
(unless (fboundp 'cl-flet)
(defalias 'cl-flet 'flet)))
(require 'color nil t) (require 'color nil t)
(require 'edebug) (require 'edebug)
(eval-when-compile (eval-when-compile
(require 'subr-x nil t) (unless (and (require 'subr-x nil t) (fboundp 'when-let))
(cond ((fboundp 'when-let*) nil) ; Introduced in 26. ;; Introduced in 25.1
((fboundp 'when-let) ; Introduced in 25.1, (defmacro when-let (key-val &rest body)
(defalias 'when-let* 'when-let)) ; deprecated in 26. (declare (indent 1) (debug ((symbolp form) body)))
(t (defmacro when-let* (key-vals &rest body) `(let ((,(car key-val) ,(cadr key-val)))
(declare (indent 1) (debug ((symbolp form) body))) (when ,(car key-val)
(let ((key-val (pop key-vals))) ,@body)))))
(if key-val
`(let ((,(car key-val) ,(cadr key-val)))
(if ,(car key-val)
(when-let* ,key-vals
,@body)))
`(progn ,@body)))))))
(defvar yas-debug-live-indicators (defvar yas-debug-live-indicators
(make-hash-table :test #'eq)) (make-hash-table :test #'eq))
@ -76,7 +73,7 @@
(setq beg (setq end (marker-position location))) (setq beg (setq end (marker-position location)))
(setq beg (yas-debug-ov-fom-start location) (setq beg (yas-debug-ov-fom-start location)
end (yas-debug-ov-fom-end location))) end (yas-debug-ov-fom-end location)))
(or (when-let* ((color-ov (gethash location yas-debug-live-indicators))) (or (when-let (color-ov (gethash location yas-debug-live-indicators))
(if (and beg end) (move-overlay (cdr color-ov) beg end) (if (and beg end) (move-overlay (cdr color-ov) beg end)
(delete-overlay (cdr color-ov))) (delete-overlay (cdr color-ov)))
color-ov) color-ov)
@ -138,9 +135,7 @@
(decorator-end (overlay-get ov 'after-string)) (decorator-end (overlay-get ov 'after-string))
(beg (yas-debug-ov-fom-start range)) (beg (yas-debug-ov-fom-start range))
(end (yas-debug-ov-fom-end range))) (end (yas-debug-ov-fom-end range)))
(if (and beg end (or (overlayp range) (if (and beg end (not (integerp beg)) (not (integerp end)))
(and (not (integerp beg))
(not (integerp end)))))
(propertize (format "from %d to %d" (+ beg) (+ end)) (propertize (format "from %d to %d" (+ beg) (+ end))
'cursor-sensor-functions 'cursor-sensor-functions
`(,(lambda (_window _oldpos dir) `(,(lambda (_window _oldpos dir)
@ -154,7 +149,7 @@
"<dead>"))) "<dead>")))
(defmacro yas-debug-with-tracebuf (outbuf &rest body) (defmacro yas-debug-with-tracebuf (outbuf &rest body)
(declare (indent 1) (debug (sexp body))) (declare (indent 1))
(let ((tracebuf-var (make-symbol "tracebuf"))) (let ((tracebuf-var (make-symbol "tracebuf")))
`(let ((,tracebuf-var (or ,outbuf (get-buffer-create "*YASnippet trace*")))) `(let ((,tracebuf-var (or ,outbuf (get-buffer-create "*YASnippet trace*"))))
(unless (eq ,tracebuf-var (current-buffer)) (unless (eq ,tracebuf-var (current-buffer))
@ -175,34 +170,30 @@
(defun yas-debug-snippet (snippet &optional outbuf) (defun yas-debug-snippet (snippet &optional outbuf)
(yas-debug-with-tracebuf outbuf (yas-debug-with-tracebuf outbuf
(when-let* ((overlay (yas--snippet-control-overlay snippet))) (when-let (overlay (yas--snippet-control-overlay snippet))
(printf "\tsid: %d control overlay %s\n" (printf "\tsid: %d control overlay %s\n"
(yas--snippet-id snippet) (yas--snippet-id snippet)
(yas-debug-live-range overlay))) (yas-debug-live-range overlay)))
(when-let* ((active-field (yas--snippet-active-field snippet))) (when-let (active-field (yas--snippet-active-field snippet))
(unless (consp (yas--field-start active-field)) (unless (consp (yas--field-start active-field))
(printf "\tactive field: #%d %s %s covering \"%s\"\n" (printf "\tactive field: #%d %s %s covering \"%s\"\n"
(or (yas--field-number active-field) -1) (yas--field-number active-field)
(if (yas--field-modified-p active-field) "**" "--") (if (yas--field-modified-p active-field) "**" "--")
(yas-debug-live-range active-field) (yas-debug-live-range active-field)
(buffer-substring-no-properties (yas--field-start active-field) (yas--field-end active-field))))) (buffer-substring-no-properties (yas--field-start active-field) (yas--field-end active-field)))))
(when-let* ((exit (yas--snippet-exit snippet))) (when-let (exit (yas--snippet-exit snippet))
(printf "\tsnippet-exit: %s next: %s\n" (printf "\tsnippet-exit: %s next: %s\n"
(yas-debug-live-marker (yas--exit-marker exit)) (yas-debug-live-marker (yas--exit-marker exit))
(yas--exit-next exit))) (yas--exit-next exit)))
(dolist (field (yas--snippet-fields snippet)) (dolist (field (yas--snippet-fields snippet))
(unless (consp (yas--field-start field)) (unless (consp (yas--field-start field))
(printf "\tfield: %d %s %s covering \"%s\" next: %s%s\n" (printf "\tfield: %d %s %s covering \"%s\" next: %s%s\n"
(or (yas--field-number field) -1) (yas--field-number field)
(if (yas--field-modified-p field) "**" "--") (if (yas--field-modified-p field) "**" "--")
(yas-debug-live-range field) (yas-debug-live-range field)
(buffer-substring-no-properties (yas--field-start field) (yas--field-end field)) (buffer-substring-no-properties (yas--field-start field) (yas--field-end field))
(yas--debug-format-fom-concise (yas--field-next field)) (yas--debug-format-fom-concise (yas--field-next field))
(if (yas--field-parent-field field) (if (yas--field-parent-field field) "(has a parent)" "")))
(format " parent: %s"
(yas--debug-format-fom-concise
(yas--field-parent-field field)))
"")))
(dolist (mirror (yas--field-mirrors field)) (dolist (mirror (yas--field-mirrors field))
(unless (consp (yas--mirror-start mirror)) (unless (consp (yas--mirror-start mirror))
(printf "\t\tmirror: %s covering \"%s\" next: %s\n" (printf "\t\tmirror: %s covering \"%s\" next: %s\n"
@ -221,26 +212,18 @@
(setq yas-debug-undo value) (setq yas-debug-undo value)
(yas--message 3 "debug undo %sabled" (if yas-debug-undo "en" "dis"))) (yas--message 3 "debug undo %sabled" (if yas-debug-undo "en" "dis")))
(defun yas-debug--target-snippet (snippet) (defadvice yas--snippet-parse-create (before yas-debug-target-snippet (snippet))
(add-to-list 'yas-debug-target-snippets snippet)) (add-to-list 'yas-debug-target-snippets snippet))
(defun yas-debug--untarget-snippet (snippet) (defadvice yas--commit-snippet (after yas-debug-untarget-snippet (snippet))
(setq yas-debug-target-snippets (setq yas-debug-target-snippets
(remq snippet yas-debug-target-snippets)) (remq snippet yas-debug-target-snippets))
(maphash (lambda (_k color-ov) (maphash (lambda (k color-ov)
(delete-overlay (cdr color-ov))) (delete-overlay (cdr color-ov)))
yas-debug-live-indicators) yas-debug-live-indicators)
(clrhash yas-debug-live-indicators)) (clrhash yas-debug-live-indicators))
(defun yas-debug-snippets (&optional outbuf hook) (defun yas-debug-snippets (&optional outbuf hook)
"Print debug information on active snippets to buffer OUTBUF.
If OUTBUF is nil, use a buffer named \"*YASsnippet trace*\".
If HOOK is non-nil, install `yas-debug-snippets' in
`post-command-hook' to update the information on every command
after this one. If it is `snippet-navigation' then install hook
buffer-locally, otherwise install it globally. If HOOK is
`edebug-create', also instrument the function
`yas--snippet-parse-create' with `edebug' and show its source."
(interactive (list nil t)) (interactive (list nil t))
(condition-case err (condition-case err
(yas-debug-with-tracebuf outbuf (yas-debug-with-tracebuf outbuf
@ -251,8 +234,6 @@ buffer-locally, otherwise install it globally. If HOOK is
(setq yas-debug-target-snippets (setq yas-debug-target-snippets
(cl-delete-if-not #'yas--snippet-p yas-debug-target-snippets))) (cl-delete-if-not #'yas--snippet-p yas-debug-target-snippets)))
(let ((yas-debug-recently-live-indicators nil)) (let ((yas-debug-recently-live-indicators nil))
(printf "(length yas--snippets-snippets) => %d\n"
(length yas--active-snippets))
(dolist (snippet (or yas-debug-target-snippets (dolist (snippet (or yas-debug-target-snippets
(yas-active-snippets))) (yas-active-snippets)))
(printf "snippet %d\n" (yas--snippet-id snippet)) (printf "snippet %d\n" (yas--snippet-id snippet))
@ -268,14 +249,15 @@ buffer-locally, otherwise install it globally. If HOOK is
do (printf "%S\n" undo-elem)))) do (printf "%S\n" undo-elem))))
(when hook (when hook
(setq yas-debug-target-buffer (current-buffer)) (setq yas-debug-target-buffer (current-buffer))
(advice-add 'yas--snippet-parse-create :before #'yas-debug--target-snippet) (ad-enable-advice 'yas--snippet-parse-create 'before 'yas-debug-target-snippet)
(advice-add 'yas--commit-snippet :after #'yas-debug--untarget-snippet) (ad-activate 'yas--snippet-parse-create)
(add-hook 'post-command-hook #'yas-debug-snippets (ad-enable-advice 'yas--commit-snippet 'after 'yas-debug-untarget-snippet)
nil (eq hook 'snippet-navigation)) (ad-activate 'yas--commit-snippet)
(add-hook 'post-command-hook #'yas-debug-snippets)
;; Window management is slapped together, it does what I ;; Window management is slapped together, it does what I
;; want when the caller has a single window open. Good ;; want when the caller has a single window open. Good
;; enough for now. ;; enough for now.
(when (eq hook 'edebug-create) (when (eq hook 'create)
(edebug-instrument-function 'yas--snippet-parse-create) (edebug-instrument-function 'yas--snippet-parse-create)
(let ((buf-point (find-function-noselect 'yas--snippet-parse-create))) (let ((buf-point (find-function-noselect 'yas--snippet-parse-create)))
(with-current-buffer (car buf-point) (with-current-buffer (car buf-point)
@ -313,15 +295,15 @@ buffer-locally, otherwise install it globally. If HOOK is
while (and opt (not (equal opt "--")) while (and opt (not (equal opt "--"))
(string-prefix-p "-" opt)) (string-prefix-p "-" opt))
collect opt))) collect opt)))
(when-let* ((mode (cl-member "-M:" options :test #'string-prefix-p))) (when-let (mode (cl-member "-M:" options :test #'string-prefix-p))
(setq snippet-mode (intern (concat (substring (car mode) 3) "-mode")))) (setq snippet-mode (intern (concat (substring (car mode) 3) "-mode"))))
(when-let* ((mode (cl-member "-M." options :test #'string-prefix-p))) (when-let (mode (cl-member "-M." options :test #'string-prefix-p))
(setq snippet-mode (setq snippet-mode
(cdr (cl-assoc (substring (car mode) 2) auto-mode-alist (cdr (cl-assoc (substring (car mode) 2) auto-mode-alist
:test (lambda (ext regexp) (string-match-p regexp ext)))))) :test (lambda (ext regexp) (string-match-p regexp ext))))))
(switch-to-buffer (get-buffer-create "*yas test*")) (switch-to-buffer (get-buffer-create "*yas test*"))
(funcall snippet-mode) (funcall snippet-mode)
(when-let* ((snippet-file (cl-member "-S:" options :test #'string-prefix-p))) (when-let (snippet-file (cl-member "-S:" options :test #'string-prefix-p))
(setq snippet-file (substring (car snippet-file) 3)) (setq snippet-file (substring (car snippet-file) 3))
(if (file-exists-p snippet-file) (if (file-exists-p snippet-file)
(with-temp-buffer (with-temp-buffer
@ -336,19 +318,26 @@ buffer-locally, otherwise install it globally. If HOOK is
(error "No such snippet `%s'" snippet-file))))) (error "No such snippet `%s'" snippet-file)))))
(display-buffer (find-file-noselect (display-buffer (find-file-noselect
(expand-file-name "yasnippet.el" yas--loaddir))) (expand-file-name "yasnippet.el" yas--loaddir)))
(when-let* ((verbosity (car (or (member "-v" options) (member "-vv" options))))) (when-let (verbosity (car (or (member "-v" options) (member "-vv" options))))
(set-window-buffer (set-window-buffer
(split-window) (yas-debug-snippets (split-window) (yas-debug-snippets
nil (if (equal verbosity "-vv") 'edebug-create t)))) nil (if (equal verbosity "-vv") 'create t))))
(yas-minor-mode +1) (yas-minor-mode +1)
(when snippet-key (insert snippet-key)))) (when snippet-key (insert snippet-key))))
(when command-line-args-left (when command-line-args-left
(yas-debug-process-command-line)) (yas-debug-process-command-line))
(defun yas-exterminate-package ()
(interactive)
(yas-global-mode -1)
(yas-minor-mode -1)
(mapatoms #'(lambda (atom)
(when (string-match "yas[-/]" (symbol-name atom))
(unintern atom obarray)))))
(provide 'yasnippet-debug) (provide 'yasnippet-debug)
;; Local Variables: ;; Local Variables:
;; indent-tabs-mode: nil ;; indent-tabs-mode: nil
;; autoload-compute-prefixes: nil
;; End: ;; End:
;;; yasnippet-debug.el ends here ;;; yasnippet-debug.el ends here

View File

@ -1,8 +1,8 @@
;;; yasnippet-tests.el --- some yasnippet tests -*- lexical-binding: t -*- ;;; yasnippet-tests.el --- some yasnippet tests -*- lexical-binding: t -*-
;; Copyright (C) 2012-2025 Free Software Foundation, Inc. ;; Copyright (C) 2012, 2013, 2014, 2015, 2017 Free Software Foundation, Inc.
;; Author: João Távora <joaot@siscog.pt> ;; Author: João Távora <joaot@siscog.pt>
;; Keywords: emulations, convenience ;; Keywords: emulations, convenience
;; This program is free software; you can redistribute it and/or modify ;; This program is free software; you can redistribute it and/or modify
@ -121,8 +121,7 @@ This lets `yas--maybe-expand-from-keymap-filter' work as expected."
(funcall fn) (funcall fn)
(cl-loop for var in vars (cl-loop for var in vars
for saved in saved-values for saved in saved-values
do (unless (eq (symbol-value var) saved) ;Beware read-only vars! do (set var saved)))))
(set var saved))))))
(defun yas-call-with-snippet-dirs (dirs fn) (defun yas-call-with-snippet-dirs (dirs fn)
(let* ((default-directory (make-temp-file "yasnippet-fixture" t)) (let* ((default-directory (make-temp-file "yasnippet-fixture" t))
@ -137,6 +136,20 @@ This lets `yas--maybe-expand-from-keymap-filter' work as expected."
;;; Older emacsen ;;; Older emacsen
;;; ;;;
(unless (fboundp 'special-mode)
;; FIXME: Why provide this default definition here?!?
(defalias 'special-mode 'fundamental))
(unless (fboundp 'string-suffix-p)
;; introduced in Emacs 24.4
(defun string-suffix-p (suffix string &optional ignore-case)
"Return non-nil if SUFFIX is a suffix of STRING.
If IGNORE-CASE is non-nil, the comparison is done without paying
attention to case differences."
(let ((start-pos (- (length string) (length suffix))))
(and (>= start-pos 0)
(eq t (compare-strings suffix nil nil
string start-pos nil ignore-case))))))
;;; Snippet mechanics ;;; Snippet mechanics
@ -180,20 +193,6 @@ This lets `yas--maybe-expand-from-keymap-filter' work as expected."
(should (string= (yas--buffer-contents) (should (string= (yas--buffer-contents)
"bla from another BLA")))) "bla from another BLA"))))
(ert-deftest yas-mirror-many-fields ()
(with-temp-buffer
(yas-minor-mode 1)
(yas-expand-snippet "${1:brother} and ${2:brother} are${1:$(if (string= (yas-field-value 1) (yas-field-value 2)) \" \" \" not \")}the same word")
(should (string= (yas--buffer-contents)
"brother and brother are the same word"))
(yas-mock-insert "bla")
(should (string= (yas--buffer-contents)
"bla and brother are not the same word"))
(ert-simulate-command '(yas-next-field-or-maybe-expand))
(yas-mock-insert "bla")
(should (string= (yas--buffer-contents)
"bla and bla are the same word"))))
(ert-deftest mirror-with-transformation-and-autofill () (ert-deftest mirror-with-transformation-and-autofill ()
"Test interaction of autofill with mirror transforms" "Test interaction of autofill with mirror transforms"
(let ((words "one two three four five") (let ((words "one two three four five")
@ -275,19 +274,8 @@ This lets `yas--maybe-expand-from-keymap-filter' work as expected."
(ert-simulate-command '(yas-next-field-or-maybe-expand)) (ert-simulate-command '(yas-next-field-or-maybe-expand))
(should (looking-at "testblable")) (should (looking-at "testblable"))
(ert-simulate-command '(yas-next-field-or-maybe-expand)) (ert-simulate-command '(yas-next-field-or-maybe-expand))
(ert-simulate-command '(yas-skip-and-clear-field))
(should (looking-at "ble"))
(should (null (yas-active-snippets)))))
(ert-deftest delete-nested-simple-field-issue-824 ()
"Test deleting a field with a nested simple field in it."
(with-temp-buffer
(yas-minor-mode 1)
(yas-expand-snippet "${3:so-$4and}$0${2:-so}")
(ert-simulate-command '(yas-next-field-or-maybe-expand))
(should (looking-at "so-and-so"))
(ert-simulate-command '(yas-skip-and-clear-or-delete-char)) (ert-simulate-command '(yas-skip-and-clear-or-delete-char))
(should (looking-at "-so")) (should (looking-at "ble"))
(should (null (yas-active-snippets))))) (should (null (yas-active-snippets)))))
(ert-deftest ignore-trailing-whitespace () (ert-deftest ignore-trailing-whitespace ()
@ -309,100 +297,40 @@ This lets `yas--maybe-expand-from-keymap-filter' work as expected."
;; (should (string= (yas--buffer-contents) ;; (should (string= (yas--buffer-contents)
;; "brother from another mother!")))) ;; "brother from another mother!"))))
(ert-deftest undo-redo () (ert-deftest undo-indentation ()
"Check redoing of snippet undo." "Check undoing works when only line of snippet is indented."
(yas-with-snippet-dirs '((".emacs.d/snippets" (let ((yas-also-auto-indent-first-line t))
("emacs-lisp-mode" ("x" . "${1:one},and done")))) (yas-with-snippet-dirs
(with-temp-buffer '((".emacs.d/snippets" ("emacs-lisp-mode" ("s" . "(setq $0)"))))
(emacs-lisp-mode) (with-temp-buffer
(yas-reload-all) (emacs-lisp-mode)
(yas-minor-mode 1) (yas-reload-all)
(yas-expand-snippet "x$0") (yas-minor-mode 1)
(let ((pre-expand-string (buffer-string))) (insert "(let\n(while s")
(setq buffer-undo-list nil)
(ert-simulate-command '(yas-expand))
(push nil buffer-undo-list)
(ert-simulate-command '(yas-next-field)) ; $1 -> exit snippet.
(should (string-match-p "\\`one,and done" (buffer-string)))
(push nil buffer-undo-list)
(ert-simulate-command '(undo)) ; Revive snippet.
(ert-simulate-command '(undo)) ; Undo expansion.
(should (string= (buffer-string) pre-expand-string))
(ert-simulate-command '(move-end-of-line 1))
(push nil buffer-undo-list)
(ert-simulate-command '(undo)) ; Redo (re-expand snippet).
(should (string-match-p "\\`one,and done" (buffer-string)))))))
(ert-deftest undo-revive-and-do-again ()
"Check undo-revived snippet is properly ended."
;; See https://github.com/joaotavora/yasnippet/issues/1006.
(yas-with-snippet-dirs '((".emacs.d/snippets"
("emacs-lisp-mode" ("x" . "${1:one},and done"))))
(with-temp-buffer
(emacs-lisp-mode)
(yas-reload-all)
(yas-minor-mode 1)
(yas-expand-snippet "x$0")
(setq buffer-undo-list nil)
(ert-simulate-command '(yas-expand))
(push nil buffer-undo-list)
(ert-simulate-command '(yas-next-field)) ; $1 -> exit snippet.
(should (string-match-p "\\`one,and done" (buffer-string)))
(push nil buffer-undo-list)
(ert-simulate-command '(undo)) ; Revive snippet.
(yas-mock-insert "abc")
(ert-simulate-command '(yas-next-field)) ; $1 -> exit snippet again.
(should (string-match-p "\\`abc,and done" (buffer-string)))
;; We should have exited snippet and cleaned up any overlays.
(should-not (cl-some (lambda (o) (overlay-get o 'yas--snippet))
(overlays-in (point-min) (point-max)))))))
(defun yas-test-expand-and-undo (mode snippet-entry initial-contents)
(yas-with-snippet-dirs
`((".emacs.d/snippets" (,(symbol-name mode) ,snippet-entry)))
(with-temp-buffer
(funcall mode)
(yas-reload-all)
(yas-minor-mode 1)
(yas-expand-snippet initial-contents)
(let ((pre-expand-string (buffer-string)))
(setq buffer-undo-list ()) (setq buffer-undo-list ())
(ert-simulate-command '(yas-expand)) (ert-simulate-command '(yas-expand))
;; Need undo barrier, I think command loop puts it normally. ;; Need undo barrier, I think command loop puts it normally.
(push nil buffer-undo-list) (push nil buffer-undo-list)
(should (string= (buffer-string) "(let\n (while (setq )"))
(ert-simulate-command '(undo)) (ert-simulate-command '(undo))
(should (string= (buffer-string) pre-expand-string)))))) (should (string= (buffer-string) "(let\n(while s"))))))
(ert-deftest undo-indentation-1 () (ert-deftest undo-indentation-multiline ()
"Check undoing works when only line of snippet is indented." "Check undoing works when first line of multi-line snippet is indented."
(let ((yas-also-auto-indent-first-line t)) (yas-with-snippet-dirs
(yas-test-expand-and-undo '((".emacs.d/snippets" ("js-mode" ("if" . "if ($1) {\n\n}\n"))))
'emacs-lisp-mode '("s" . "(setq $0)") "(let\n(while s$0"))) (with-temp-buffer
(js-mode)
(ert-deftest undo-indentation-2 () (yas-reload-all)
"Check undoing works when only line of snippet is indented." (yas-minor-mode 1)
(let ((yas-also-auto-indent-first-line t) (insert "if\nabc = 123456789 + abcdef;")
(indent-tabs-mode nil)) (setq buffer-undo-list ())
(yas-test-expand-and-undo (goto-char (point-min))
'emacs-lisp-mode '("t" . "; TODO") "t$0"))) (search-forward "if")
(ert-simulate-command '(yas-expand))
(ert-deftest undo-indentation-multiline-1 () (push nil buffer-undo-list) ; See test above.
"Check undoing works when 1st line of multi-line snippet is indented." (ert-simulate-command '(undo))
(let ((yas-also-auto-indent-first-line t) (should (string= (buffer-string) "if\nabc = 123456789 + abcdef;")))))
(indent-tabs-mode nil))
(yas-test-expand-and-undo
'js-mode '("if" . "if ($1) {\n\n}\n")
"if$0\nabc = 123456789 + abcdef;")))
(ert-deftest undo-indentation-multiline-2 ()
"Check undoing works when 2nd line of multi-line snippet is indented."
(let ((yas-also-auto-indent-first-line t)
(indent-tabs-mode nil))
(yas-test-expand-and-undo
'js-mode '("if" . "if (true) {\n${1:foo};\n}\n")
"if$0\nabc = 123456789 + abcdef;")))
(ert-deftest dont-clear-on-partial-deletion-issue-515 () (ert-deftest dont-clear-on-partial-deletion-issue-515 ()
"Ensure fields are not cleared when user doesn't really mean to." "Ensure fields are not cleared when user doesn't really mean to."
@ -456,47 +384,6 @@ end" (buffer-string)))
end" (buffer-string))) end" (buffer-string)))
(should (= 4 (current-column))))) (should (= 4 (current-column)))))
(ert-deftest yas-also-indent-empty-lines ()
"Respect `yas-also-indent-empty-lines' setting."
(with-temp-buffer
(ruby-mode)
(yas-minor-mode 1)
(set (make-local-variable 'yas-indent-line) 'auto)
(set (make-local-variable 'yas-also-auto-indent-first-line) t)
(set (make-local-variable 'yas-also-indent-empty-lines) t)
(yas-expand-snippet "def foo\n\nend")
(should (string= "def foo\n \nend" (buffer-string)))
;; Test that it keeps working without setting
;; `yas-also-auto-indent-first-line'.
(setq yas-also-auto-indent-first-line nil)
(erase-buffer)
(yas-expand-snippet "def foo\n\nend")
(should (string= "def foo\n \nend" (buffer-string)))))
(ert-deftest yas-indent-first-line ()
(with-temp-buffer
(ruby-mode)
(yas-minor-mode 1)
(set (make-local-variable 'yas-indent-line) 'auto)
(set (make-local-variable 'yas-also-auto-indent-first-line) nil)
(set (make-local-variable 'yas-also-indent-empty-lines) nil)
(yas-expand-snippet "def foo\n$0\nend\n")
;; First (and only) line should not indent.
(yas-expand-snippet "#not indented")
(should (equal "def foo\n#not indented\nend\n" (buffer-string)))))
(ert-deftest yas-indent-first-line-fixed ()
(with-temp-buffer
(ruby-mode)
(yas-minor-mode 1)
(set (make-local-variable 'yas-indent-line) 'fixed)
(set (make-local-variable 'yas-also-auto-indent-first-line) nil)
(set (make-local-variable 'yas-also-indent-empty-lines) nil)
(yas-expand-snippet " def foo\n $0\n end\n")
;; First (and only) line should not indent.
(yas-expand-snippet "#not more indented")
(should (equal " def foo\n #not more indented\n end\n" (buffer-string)))))
(ert-deftest indentation-markers () (ert-deftest indentation-markers ()
"Test a snippet with indentation markers (`$<')." "Test a snippet with indentation markers (`$<')."
(with-temp-buffer (with-temp-buffer
@ -543,19 +430,16 @@ XXXXX ------------------------"))))
(yas-mock-insert "foo bar") (yas-mock-insert "foo bar")
(ert-simulate-command '(yas-next-field)) (ert-simulate-command '(yas-next-field))
(goto-char (point-min)) (goto-char (point-min))
;; The default value of `org-adapt-indentation' changed between Org-mode 9.4 (let ((expected (with-temp-buffer
;; and 9.5, so force a specific value. (insert (format (concat "* Test foo bar\n"
(let* ((org-adapt-indentation nil) " " org-property-format "\n"
(expected (with-temp-buffer " " org-property-format "\n"
(insert (format (concat "* Test foo bar\n" " " org-property-format)
org-property-format "\n" ":PROPERTIES:" ""
org-property-format "\n" ":ID:" "foo bar-after"
org-property-format) ":END:" ""))
":PROPERTIES:" "" (delete-trailing-whitespace)
":ID:" "foo bar-after" (buffer-string))))
":END:" ""))
(delete-trailing-whitespace)
(buffer-string))))
;; Some org-mode versions leave trailing whitespace, some don't. ;; Some org-mode versions leave trailing whitespace, some don't.
(delete-trailing-whitespace) (delete-trailing-whitespace)
(should (equal expected (buffer-string)))))) (should (equal expected (buffer-string))))))
@ -585,22 +469,6 @@ int foo()
} }
}" (buffer-string))))) }" (buffer-string)))))
(ert-deftest indent-cc-mode-2 ()
"Handling of cc-mode's preprocessor indentation."
(with-temp-buffer
(c-mode)
(yas-minor-mode +1)
(yas-expand-snippet "\
#ifndef `\"FOO\"`
#define FOO
#endif
")
(should (string= "\
#ifndef FOO
#define FOO
#endif
" (buffer-substring-no-properties (point-min) (point-max))))))
(ert-deftest indent-snippet-mode () (ert-deftest indent-snippet-mode ()
"Handling of snippet-mode indentation." "Handling of snippet-mode indentation."
;; This is an interesting case because newlines match [[:space:]] in ;; This is an interesting case because newlines match [[:space:]] in
@ -623,28 +491,6 @@ int foo()
;; Assuming 2 space indent. ;; Assuming 2 space indent.
(should (string= "def xxx\n xxx\nend" (buffer-string))))) (should (string= "def xxx\n xxx\nend" (buffer-string)))))
(defun yas-test-delete-and-insert-command (beg end new)
"Simulate a completion command (similar to company-mode)."
(interactive "r\ns")
;; Simulate a completion command (like what company-mode does)
;; which deletes the "xxx" and then replaces it with something
;; else.
(delete-region beg end)
(insert new))
(ert-deftest indent-mirrors-on-complex-update ()
"Don't get messed up by command that deletes and then inserts."
(with-temp-buffer
(ruby-mode)
(yas-minor-mode 1)
(yas-expand-snippet "def foo\n ${1:slice} = append($1)\nend")
(yas-mock-insert "xxx")
(ert-simulate-command `(yas-test-delete-and-insert-command
,(- (point) 3) ,(point) ,"yyy"))
;; Assuming 2 space indent.
(should (string= "def foo\n yyy = append(yyy)\nend" (buffer-string)))))
(ert-deftest snippet-with-multiline-mirrors-issue-665 () (ert-deftest snippet-with-multiline-mirrors-issue-665 ()
"In issue 665, a multi-line mirror is attempted." "In issue 665, a multi-line mirror is attempted."
@ -670,37 +516,9 @@ mapconcat #'(lambda (arg)
(ert-simulate-command '(yas-next-field)) (ert-simulate-command '(yas-next-field))
(should (looking-at (concat "blo" expected)))))) (should (looking-at (concat "blo" expected))))))
(defmacro yas-saving-variables (&rest body)
(declare (debug t))
`(yas-call-with-saving-variables #'(lambda () ,@body)))
(ert-deftest auto-next-field ()
"Automatically exit a field after evaluating its transform."
(with-temp-buffer
(yas-saving-variables
(yas-with-snippet-dirs
`((".emacs.d/snippets"
("ruby-mode" ("snip" . ,(concat "foo ${1:$$"
(prin1-to-string '(yas-auto-next
(yas-choose-value
"bar" "foo")))
"} ${2:$$"
(prin1-to-string '(yas-auto-next
(yas-choose-value
"too" "foo")))
"} baz ${3:quinn} quinn")))))
(yas-reload-all)
(ruby-mode)
(yas-minor-mode 1)
(set (make-local-variable 'yas-prompt-functions) `(yas-no-prompt))
(yas-mock-insert "snip")
(ert-simulate-command '(yas-expand))
(yas-mock-insert "quux")
(should (equal "foo bar too baz quux quinn" (buffer-string)))))))
;;; Snippet expansion and character escaping ;;; Snippet expansion and character escaping
;; Thanks to @zw963 (Billy) for the testing ;;; Thanks to @zw963 (Billy) for the testing
;;; ;;;
(ert-deftest escape-dollar () (ert-deftest escape-dollar ()
(with-temp-buffer (with-temp-buffer
@ -771,57 +589,6 @@ mapconcat #'(lambda (arg)
(yas-expand-snippet "Look ma! ${1:`(yas-selected-text)`} OK?") (yas-expand-snippet "Look ma! ${1:`(yas-selected-text)`} OK?")
(should (string= (yas--buffer-contents) "Look ma! He)}o world! OK?"))))) (should (string= (yas--buffer-contents) "Look ma! He)}o world! OK?")))))
(ert-deftest escaping-for-lsp-style-snippet-syntax ()
"See Github #979."
(should
(string= (with-temp-buffer
(yas-minor-mode 1)
(yas-expand-snippet
"Printf(${1:format string}, ${2:args ...interface{\\}})${0}")
(yas--buffer-contents))
(with-temp-buffer
(yas-minor-mode 1)
(yas-expand-snippet
"Printf(${1:format string}, ${2:args ...interface\\{\\}})${0}")
(yas--buffer-contents)))))
(ert-deftest insert-snippet-with-backslashes-in-active-field ()
;; This test case fails if `yas--inhibit-overlay-hooks' is not bound
;; in `yas-expand-snippet' (see Github #844).
(with-temp-buffer
(yas-minor-mode 1)
(yas-expand-snippet "${1:$$(if (not yas-modified-p) \"a\")}")
(yas-expand-snippet "\\\\alpha")))
(ert-deftest expand-with-unused-yas-selected-text ()
(with-temp-buffer
(yas-with-snippet-dirs
'((".emacs.d/snippets"
("emacs-lisp-mode"
("foo" . "expanded `yas-selected-text`foo"))))
(yas-reload-all)
(emacs-lisp-mode)
(yas-minor-mode +1)
(insert "foo")
(ert-simulate-command '(yas-expand))
(should (equal (buffer-string) "expanded foo")))))
(ert-deftest yas-expand-command-snippet ()
(with-temp-buffer
(yas-with-snippet-dirs
'((".emacs.d/snippets"
("emacs-lisp-mode"
("foo" . "\
# type: command
# --
\(insert \"expanded foo\")"))))
(yas-reload-all)
(emacs-lisp-mode)
(yas-minor-mode +1)
(insert "foo")
(ert-simulate-command '(yas-expand))
(should (equal (buffer-string) "expanded foo")))))
(ert-deftest example-for-issue-271 () (ert-deftest example-for-issue-271 ()
(with-temp-buffer (with-temp-buffer
(yas-minor-mode 1) (yas-minor-mode 1)
@ -832,21 +599,8 @@ mapconcat #'(lambda (arg)
(yas-mock-insert "bbb") (yas-mock-insert "bbb")
(should (string= (yas--buffer-contents) "if condition\naaa\nelse\nbbb\nend"))))) (should (string= (yas--buffer-contents) "if condition\naaa\nelse\nbbb\nend")))))
(ert-deftest yas-no-memory-of-bad-snippet ()
"Expanding an incorrect snippet should not influence future expansions."
;; See https://github.com/joaotavora/yasnippet/issues/800.
(with-temp-buffer
(yas-minor-mode 1)
(yas-expand-snippet "```foo\n\n```")
(erase-buffer) ; Bad snippet may leave wrong text.
;; But expanding the corrected snippet should work fine.
(yas-expand-snippet "\\`\\`\\`foo\n\n\\`\\`\\`")
(should (equal (buffer-string) "```foo\n\n```"))))
(defmacro yas--with-font-locked-temp-buffer (&rest body) (defmacro yas--with-font-locked-temp-buffer (&rest body)
"Like `with-temp-buffer', but ensure `font-lock-mode'." "Like `with-temp-buffer', but ensure `font-lock-mode'."
;; NOTE: Replace all uses of this with `font-lock-ensure' when we
;; drop support for Emacs 24.
(declare (indent 0) (debug t)) (declare (indent 0) (debug t))
(let ((temp-buffer (make-symbol "temp-buffer"))) (let ((temp-buffer (make-symbol "temp-buffer")))
;; NOTE: buffer name must not start with a space, otherwise ;; NOTE: buffer name must not start with a space, otherwise
@ -865,9 +619,11 @@ mapconcat #'(lambda (arg)
(and (buffer-name ,temp-buffer) (and (buffer-name ,temp-buffer)
(kill-buffer ,temp-buffer)))))))) (kill-buffer ,temp-buffer))))))))
(defmacro yas-saving-variables (&rest body)
(declare (debug t))
`(yas-call-with-saving-variables #'(lambda () ,@body)))
(ert-deftest example-for-issue-474 () (ert-deftest example-for-issue-474 ()
;; This issue only reproduces in Emacs 24.3, most likely due to some
;; bug in the cc-mode included with that Emacs version.
(yas--with-font-locked-temp-buffer (yas--with-font-locked-temp-buffer
(c-mode) (c-mode)
(yas-minor-mode 1) (yas-minor-mode 1)
@ -941,18 +697,6 @@ mapconcat #'(lambda (arg)
(yas-mock-insert "baz") (yas-mock-insert "baz")
(should (string= (yas--buffer-contents) "foobaaarbazok"))))) (should (string= (yas--buffer-contents) "foobaaarbazok")))))
(ert-deftest yas-escaping-close-brace ()
"Close braces may be escaped with braces, reduction from eglot issue.
See https://github.com/joaotavora/eglot/issues/336."
(with-temp-buffer
(yas-minor-mode +1)
;; NOTE: put a period at the end to avoid the bug tested by
;; `protection-overlay-no-cheating'.
(yas-expand-snippet "${1:one{\\}}, ${2:two{\\}}.")
(yas-next-field)
(yas-next-field)
(should (string= (buffer-string) "one{}, two{}."))))
;;; Misc tests ;;; Misc tests
;;; ;;;
@ -1069,7 +813,7 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
("'quote" . "OKquoteOK")))) ("'quote" . "OKquoteOK"))))
(yas-reload-all) (yas-reload-all)
(emacs-lisp-mode) (emacs-lisp-mode)
(yas-minor-mode +1) (yas-minor-mode-on)
(let ((yas-key-syntaxes '("w" "w_"))) (let ((yas-key-syntaxes '("w" "w_")))
(let ((yas--barbaz t)) (let ((yas--barbaz t))
(yas-should-expand '(("foo-barbaz" . "foo-OKbarbazOK") (yas-should-expand '(("foo-barbaz" . "foo-OKbarbazOK")
@ -1105,24 +849,6 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(should (= (length (yas--snippet-fields (nth 0 snippets))) 2)) (should (= (length (yas--snippet-fields (nth 0 snippets))) 2))
(should (= (length (yas--snippet-fields (nth 1 snippets))) 1)))))) (should (= (length (yas--snippet-fields (nth 1 snippets))) 1))))))
(ert-deftest nested-snippet-expansion-depth-2 ()
(with-temp-buffer
(yas-with-snippet-dirs
'((".emacs.d/snippets"
("text-mode"
("nest" . "( $1"))))
(let ((yas-triggers-in-field t))
(yas-reload-all)
(text-mode)
(yas-minor-mode +1)
(dotimes (_ 3)
(yas-mock-insert "nest")
(ert-simulate-command '(yas-expand)))
(dotimes (_ 3)
(yas-mock-insert ")")
(ert-simulate-command '(yas-next-field-or-maybe-expand)))
))))
(ert-deftest nested-snippet-expansion-2 () (ert-deftest nested-snippet-expansion-2 ()
(let ((yas-triggers-in-field t)) (let ((yas-triggers-in-field t))
(yas-with-snippet-dirs (yas-with-snippet-dirs
@ -1169,64 +895,20 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(ert-simulate-command '(yas-next-field-or-maybe-expand)) (ert-simulate-command '(yas-next-field-or-maybe-expand))
(should (string= (buffer-string) "\\sqrt[3]{\\sqrt[5]{2}}"))))) (should (string= (buffer-string) "\\sqrt[3]{\\sqrt[5]{2}}")))))
(ert-deftest nested-snippet-expansion-4 ()
"See Github #959."
(let ((yas-triggers-in-field t))
(yas-with-snippet-dirs
'((".emacs.d/snippets"
("text-mode"
("ch" . "<-${1:ch}"))))
(yas-reload-all)
(text-mode)
(yas-minor-mode +1)
(yas-expand-snippet "ch$0\n")
(ert-simulate-command '(yas-expand))
(ert-simulate-command '(forward-char 2))
(ert-simulate-command '(yas-expand))
(yas-mock-insert "abc")
(ert-simulate-command '(yas-next-field-or-maybe-expand))
(yas-mock-insert "def")
(ert-simulate-command '(yas-next-field-or-maybe-expand))
(should (string= (buffer-string) "<-<-abcdef\n")))))
(ert-deftest nested-snippet-expansion-5-nested-delete ()
"See Github #996."
(let ((yas-triggers-in-field t))
(yas-with-snippet-dirs
'((".emacs.d/snippets"
("text-mode"
("sel" . "${1:ch}")
("ch" . "<-${1:ch}"))))
(yas-reload-all)
(text-mode)
(yas-minor-mode +1)
(insert "sel")
(ert-simulate-command '(yas-expand))
(ert-simulate-command '(forward-word 1))
(ert-simulate-command '(yas-expand))
(ert-simulate-command '(forward-word 1))
;; The (cl-assert (memq pfield (yas--snippet-fields psnippet)))
;; in `yas--on-field-overlay-modification' failed here.
(ert-simulate-command '(delete-backward-char 1))
(should (string= (buffer-string) "<-c\n")))))
;;; Loading ;;; Loading
;;; ;;;
(defmacro yas-with-overriden-buffer-list (&rest body) (defmacro yas-with-overriden-buffer-list (&rest body)
(declare (debug t)) (declare (debug t))
;; FIXME: This macro was added by commit 185c771dedea as part of the
;; fix for https://github.com/joaotavora/yasnippet/issues/253,
;; but I don't know why it was/is needed.
(let ((saved-sym (make-symbol "yas--buffer-list"))) (let ((saved-sym (make-symbol "yas--buffer-list")))
`(let ((,saved-sym (symbol-function 'buffer-list))) `(let ((,saved-sym (symbol-function 'buffer-list)))
(cl-letf (((symbol-function 'buffer-list) (cl-letf (((symbol-function 'buffer-list)
(lambda (&rest args) (lambda ()
(cl-remove-if (lambda (buf) (cl-remove-if (lambda (buf)
(with-current-buffer buf (with-current-buffer buf
(eq major-mode 'lisp-interaction-mode))) (eq major-mode 'lisp-interaction-mode)))
(apply ,saved-sym args))))) (funcall ,saved-sym)))))
,@body)))) ,@body))))
@ -1254,28 +936,11 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
"Test `yas-lookup-snippet'." "Test `yas-lookup-snippet'."
(yas-with-some-interesting-snippet-dirs (yas-with-some-interesting-snippet-dirs
(yas-reload-all 'no-jit) (yas-reload-all 'no-jit)
(should (equal (yas--template-content (yas-lookup-snippet "printf" 'c-mode)) (should (equal (yas-lookup-snippet "printf" 'c-mode) "printf($1);"))
"printf($1);")) (should (equal (yas-lookup-snippet "def" 'c-mode) "# define"))
(should (equal (yas--template-content (yas-lookup-snippet "def" 'c-mode))
"# define"))
(should-not (yas-lookup-snippet "no such snippet" nil 'noerror)) (should-not (yas-lookup-snippet "no such snippet" nil 'noerror))
(should-not (yas-lookup-snippet "printf" 'emacs-lisp-mode 'noerror)))) (should-not (yas-lookup-snippet "printf" 'emacs-lisp-mode 'noerror))))
(ert-deftest yas-lookup-snippet-with-env ()
(with-temp-buffer
(yas-with-snippet-dirs
'((".emacs.d/snippets"
("emacs-lisp-mode"
("foo" . "\
# expand-env: ((foo \"bar\"))
# --
`foo`"))))
(yas-reload-all)
(emacs-lisp-mode)
(yas-minor-mode +1)
(yas-expand-snippet (yas-lookup-snippet "foo"))
(should (equal (buffer-string) "bar")))))
(ert-deftest basic-jit-loading () (ert-deftest basic-jit-loading ()
"Test basic loading and expansion of snippets" "Test basic loading and expansion of snippets"
(yas-with-some-interesting-snippet-dirs (yas-with-some-interesting-snippet-dirs
@ -1303,15 +968,13 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(with-temp-buffer (with-temp-buffer
(text-mode) (text-mode)
(yas-minor-mode +1) (yas-minor-mode +1)
(should (equal (yas--template-content (yas-lookup-snippet "one")) (should (equal (yas-lookup-snippet "one") "one"))
"one")) (should (eq (yas--key-binding "\C-c1") 'yas-expand-from-keymap))
(should (eq (yas--key-binding "\C-c1") #'yas-expand-from-keymap))
(yas-define-snippets (yas-define-snippets
'text-mode '(("_1" "one!" "won" nil nil nil nil nil "uuid-1"))) 'text-mode '(("_1" "one!" "won" nil nil nil nil nil "uuid-1")))
(should (null (yas-lookup-snippet "one" nil 'noerror))) (should (null (yas-lookup-snippet "one" nil 'noerror)))
(should (null (yas--key-binding "\C-c1"))) (should (null (yas--key-binding "\C-c1")))
(should (equal (yas--template-content(yas-lookup-snippet "won")) (should (equal (yas-lookup-snippet "won") "one!")))))
"one!")))))
(ert-deftest snippet-save () (ert-deftest snippet-save ()
"Make sure snippets can be saved correctly." "Make sure snippets can be saved correctly."
@ -1331,13 +994,13 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(yas-minor-mode +1) (yas-minor-mode +1)
(save-current-buffer (save-current-buffer
(yas-new-snippet t) (yas-new-snippet t)
(with-current-buffer yas-new-snippet-buffer-name (with-current-buffer "*new snippet*"
(snippet-mode) (snippet-mode)
(insert "# name: foo\n# key: bar\n# --\nsnippet foo") (insert "# name: foo\n# key: bar\n# --\nsnippet foo")
(call-interactively 'yas-load-snippet-buffer-and-close))) (call-interactively 'yas-load-snippet-buffer-and-close)))
(save-current-buffer (save-current-buffer
(yas-new-snippet t) (yas-new-snippet t)
(with-current-buffer yas-new-snippet-buffer-name (with-current-buffer "*new snippet*"
(snippet-mode) (snippet-mode)
(insert "# name: bar\n# key: bar\n# --\nsnippet bar") (insert "# name: bar\n# key: bar\n# --\nsnippet bar")
(call-interactively 'yas-load-snippet-buffer-and-close))) (call-interactively 'yas-load-snippet-buffer-and-close)))
@ -1373,20 +1036,19 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(yas-reload-all) (yas-reload-all)
(with-temp-buffer (with-temp-buffer
(let* ((major-mode 'c-mode) (let* ((major-mode 'c-mode)
(expected `(fundamental-mode (expected `(c-mode
c-mode
cc-mode cc-mode
yet-another-c-mode yet-another-c-mode
and-also-this-one and-also-this-one
and-that-one and-that-one
prog-mode ;; prog-mode doesn't exist in emacs 24.3
,@(if (fboundp 'lisp-data-mode) ;Emacs≥28 ,@(if (fboundp 'prog-mode)
'(lisp-data-mode)) '(prog-mode))
emacs-lisp-mode emacs-lisp-mode
lisp-interaction-mode)) lisp-interaction-mode))
(observed (yas--modes-to-activate))) (observed (yas--modes-to-activate)))
(should (equal major-mode (car observed))) (should (equal major-mode (car observed)))
(should-not (cl-set-exclusive-or expected observed))))))) (should (equal (sort expected #'string<) (sort observed #'string<))))))))
(ert-deftest extra-modes-parenthood () (ert-deftest extra-modes-parenthood ()
"Test activation of parents of `yas--extra-modes'." "Test activation of parents of `yas--extra-modes'."
@ -1403,44 +1065,39 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(yas-activate-extra-mode 'and-that-one) (yas-activate-extra-mode 'and-that-one)
(let* ((expected-first `(and-that-one (let* ((expected-first `(and-that-one
yet-another-c-mode yet-another-c-mode
c-mode)) c-mode
,major-mode))
(expected-rest `(cc-mode (expected-rest `(cc-mode
prog-mode ;; prog-mode doesn't exist in emacs 24.3
,@(if (fboundp 'lisp-data-mode) ;Emacs≥28 ,@(if (fboundp 'prog-mode)
'(lisp-data-mode)) '(prog-mode))
emacs-lisp-mode emacs-lisp-mode
and-also-this-one and-also-this-one
lisp-interaction-mode)) lisp-interaction-mode))
(observed (remq 'fundamental-mode (yas--modes-to-activate)))) (observed (yas--modes-to-activate)))
(should-not (cl-set-exclusive-or (should (equal expected-first
expected-first (cl-subseq observed 0 (length expected-first))))
(cl-subseq observed 0 (length expected-first)))) (should (equal (sort expected-rest #'string<)
(should-not (cl-set-exclusive-or (sort (cl-subseq observed (length expected-first)) #'string<))))))))
expected-rest
(cl-subseq observed (length expected-first)))))))))
(defalias 'yas--phony-c-mode #'c-mode) (defalias 'yas--phony-c-mode 'c-mode)
(ert-deftest issue-492-and-494 () (ert-deftest issue-492-and-494 ()
"Aliases like `yas--phony-c-mode' should be considered as \"derived\"."
(define-derived-mode yas--test-mode yas--phony-c-mode "Just a test mode") (define-derived-mode yas--test-mode yas--phony-c-mode "Just a test mode")
(yas-with-snippet-dirs '((".emacs.d/snippets" (yas-with-snippet-dirs '((".emacs.d/snippets"
("yas--test-mode"))) ("yas--test-mode")))
(yas-reload-all) (yas-reload-all)
(with-temp-buffer (with-temp-buffer
(let* ((major-mode 'yas--test-mode) (let* ((major-mode 'yas--test-mode)
(expected `(fundamental-mode (expected `(c-mode
c-mode ,@(if (fboundp 'prog-mode)
yas--phony-c-mode '(prog-mode))
yas--test-mode)) yas--phony-c-mode
;; The set of mode depends on some external factors: yas--test-mode))
;; `prog-mode': if cc-mode.el has been loaded. (observed (yas--modes-to-activate)))
;; `cc-mode': if we added `cc-mode' as yas--parent of `c-mode'. (should (null (cl-set-exclusive-or expected observed)))
(observed (cl-set-difference (yas--modes-to-activate) (should (= (length expected)
'(prog-mode cc-mode)))) (length observed)))))))
(should-not (cl-set-exclusive-or expected observed))
(should (= (length expected)
(length observed)))))))
(define-derived-mode yas--test-mode c-mode "Just a test mode") (define-derived-mode yas--test-mode c-mode "Just a test mode")
(define-derived-mode yas--another-test-mode c-mode "Another test mode") (define-derived-mode yas--another-test-mode c-mode "Another test mode")
@ -1483,34 +1140,6 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
("def" . "# define"))) ("def" . "# define")))
(yas-should-not-expand '("sc" "dolist" "ert-deftest")))) (yas-should-not-expand '("sc" "dolist" "ert-deftest"))))
;;; Unloading
(ert-deftest yas-unload ()
"Test unloading and reloading."
(with-temp-buffer
(let ((status (call-process
(concat invocation-directory invocation-name)
nil '(t t) nil
"-Q" "--batch" "-L" yas--loaddir "-l" "yasnippet"
"--eval"
(prin1-to-string
'(condition-case err
(progn
(yas-minor-mode +1)
(unload-feature 'yasnippet)
;; Unloading leaves `yas-minor-mode' bound,
;; harmless, though perhaps surprising.
(when (bound-and-true-p yas-minor-mode)
(error "`yas-minor-mode' still enabled"))
(when (fboundp 'yas-minor-mode)
(error "`yas-minor-mode' still fboundp"))
(require 'yasnippet)
(unless (fboundp 'yas-minor-mode)
(error "Failed to reload")))
(error (message "%S" (error-message-string err))
(kill-emacs 1)))))))
(ert-info ((buffer-string)) (should (eq status 0))))))
;;; Menu ;;; Menu
;;; ;;;
@ -1644,31 +1273,31 @@ TODO: be meaner"
(with-temp-buffer (with-temp-buffer
(yas-minor-mode -1) (yas-minor-mode -1)
(insert "foo") (insert "foo")
(should-not (eq (key-binding (kbd "TAB")) #'yas-expand)) (should (not (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand)))
(yas-minor-mode 1) (yas-minor-mode 1)
(should (eq (key-binding (kbd "TAB")) #'yas-expand)) (should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand))
(yas-expand-snippet "$1 $2 $3") (yas-expand-snippet "$1 $2 $3")
;; (should (eq (key-binding [tab]) #'yas-next-field-or-maybe-expand)) (should (eq (key-binding [(tab)]) 'yas-next-field-or-maybe-expand))
(should (eq (key-binding (kbd "TAB")) #'yas-next-field-or-maybe-expand)) (should (eq (key-binding (kbd "TAB")) 'yas-next-field-or-maybe-expand))
(should (eq (key-binding [(shift tab)]) #'yas-prev-field)) (should (eq (key-binding [(shift tab)]) 'yas-prev-field))
(should (eq (key-binding [backtab]) #'yas-prev-field)))))) (should (eq (key-binding [backtab]) 'yas-prev-field))))))
(ert-deftest test-rebindings () (ert-deftest test-rebindings ()
(let* ((test-map (make-composed-keymap nil yas-minor-mode-map)) (let* ((yas-minor-mode-map (copy-keymap yas-minor-mode-map))
(minor-mode-map-alist (minor-mode-map-alist
(cons `(yas-minor-mode . ,test-map) (cons `(yas-minor-mode . ,yas-minor-mode-map)
(cl-remove 'yas-minor-mode minor-mode-map-alist (cl-remove 'yas-minor-mode minor-mode-map-alist
:test #'eq :key #'car)))) :test #'eq :key #'car))))
(define-key test-map [tab] nil) (define-key yas-minor-mode-map [tab] nil)
(define-key test-map (kbd "TAB") nil) (define-key yas-minor-mode-map (kbd "TAB") nil)
(define-key test-map (kbd "SPC") #'yas-expand) (define-key yas-minor-mode-map (kbd "SPC") 'yas-expand)
(with-temp-buffer (with-temp-buffer
(yas-minor-mode 1) (yas-minor-mode 1)
(should-not (eq (key-binding (kbd "TAB")) #'yas-expand)) (should-not (eq (key-binding (kbd "TAB")) 'yas-expand))
(should (eq (key-binding (kbd "SPC")) #'yas-expand)) (should (eq (key-binding (kbd "SPC")) 'yas-expand))
(yas-reload-all) (yas-reload-all)
(should-not (eq (key-binding (kbd "TAB")) #'yas-expand)) (should-not (eq (key-binding (kbd "TAB")) 'yas-expand))
(should (eq (key-binding (kbd "SPC")) #'yas-expand))))) (should (eq (key-binding (kbd "SPC")) 'yas-expand)))))
(ert-deftest test-yas-in-org () (ert-deftest test-yas-in-org ()
(yas-saving-variables (yas-saving-variables
@ -1681,40 +1310,20 @@ TODO: be meaner"
(org-mode) (org-mode)
(yas-minor-mode 1) (yas-minor-mode 1)
(insert "foo") (insert "foo")
;; (should (eq (key-binding [tab]) #'yas-expand)) (should (eq (key-binding [(tab)]) 'yas-expand))
(should (eq (key-binding (kbd "TAB")) #'yas-expand)))))) (should (eq (key-binding (kbd "TAB")) 'yas-expand))))))
(ert-deftest yas-org-native-tab-in-source-block-text () (ert-deftest yas-org-native-tab-in-source-block ()
"Test expansion of snippets in org source blocks."
;; org 9+ no longer runs fontification for text-mode, so our hacks
;; don't work. Note that old ert doesn't have skipping, so we have
;; to expect failure instead. Starting with Org-mode 9.5 this seems
;; to work again.
:expected-result (if (and (fboundp 'org-in-src-block-p)
(or (version< (org-version) "9")
(version<= "9.5" (org-version))))
:passed :failed)
(let ((text-mode-hook #'yas-minor-mode))
(do-yas-org-native-tab-in-source-block "text")))
(ert-deftest yas-org-native-tab-in-source-block-emacs-lisp ()
"Test expansion of snippets in org source blocks." "Test expansion of snippets in org source blocks."
:expected-result (if (fboundp 'org-in-src-block-p) :expected-result (if (fboundp 'org-in-src-block-p)
:passed :failed) :passed :failed)
(let ((emacs-lisp-mode-hook #'yas-minor-mode)
;; This makes the test a bit less comprehensive, but it's
;; needed to avoid bumping into Emacs Bug#35264.
(org-src-preserve-indentation t))
(do-yas-org-native-tab-in-source-block "emacs-lisp")))
(defun do-yas-org-native-tab-in-source-block (mode)
(yas-saving-variables (yas-saving-variables
(yas-with-snippet-dirs (yas-with-snippet-dirs
`((".emacs.d/snippets" '((".emacs.d/snippets"
(,(concat mode "-mode") ("text-mode"
("T" . "${1:one} $1\n${2:two} $2\n<<$0>> done!")))) ("T" . "${1:one} $1\n${2:two} $2\n<<$0>> done!"))))
;; Binding both text and prog mode hook should cover everything. (let ((text-mode-hook '(yas-minor-mode))
(let ((org-src-tab-acts-natively t) (org-src-tab-acts-natively t)
;; Org 8.x requires this in order for ;; Org 8.x requires this in order for
;; `org-src-tab-acts-natively' to have effect. ;; `org-src-tab-acts-natively' to have effect.
(org-src-fontify-natively t)) (org-src-fontify-natively t))
@ -1723,8 +1332,8 @@ TODO: be meaner"
(yas--with-font-locked-temp-buffer (yas--with-font-locked-temp-buffer
(org-mode) (org-mode)
(yas-minor-mode 1) (yas-minor-mode 1)
(insert "#+BEGIN_SRC " mode "\nT\n#+END_SRC") (insert "#+BEGIN_SRC text\nT\n#+END_SRC")
(if (fboundp 'font-lock-ensure) ;Emacs≥25 (if (fboundp 'font-lock-ensure)
(font-lock-ensure) (font-lock-ensure)
(jit-lock-fontify-now)) (jit-lock-fontify-now))
(re-search-backward "^T$") (goto-char (match-end 0)) (re-search-backward "^T$") (goto-char (match-end 0))
@ -1739,9 +1348,9 @@ TODO: be meaner"
;; Check snippet expansion, ignore leading whitespace due to ;; Check snippet expansion, ignore leading whitespace due to
;; `org-edit-src-content-indentation'. ;; `org-edit-src-content-indentation'.
(should (looking-at "\ (should (looking-at "\
\[[:space:]]*one one [[:space:]]*one one
\[[:space:]]*two two [[:space:]]*two two
\[[:space:]]*<<>> done!"))))))) [[:space:]]*<<>> done!")))))))
(ert-deftest test-yas-activate-extra-modes () (ert-deftest test-yas-activate-extra-modes ()
@ -1757,7 +1366,7 @@ add the snippets associated with the given mode."
("car" . "(car )")))) ("car" . "(car )"))))
(yas-reload-all) (yas-reload-all)
(emacs-lisp-mode) (emacs-lisp-mode)
(yas-minor-mode +1) (yas-minor-mode-on)
(yas-activate-extra-mode 'markdown-mode) (yas-activate-extra-mode 'markdown-mode)
(should (eq 'markdown-mode (car yas--extra-modes))) (should (eq 'markdown-mode (car yas--extra-modes)))
(yas-should-expand '(("_" . "_Text_ "))) (yas-should-expand '(("_" . "_Text_ ")))
@ -1772,6 +1381,5 @@ add the snippets associated with the given mode."
(provide 'yasnippet-tests) (provide 'yasnippet-tests)
;; Local Variables: ;; Local Variables:
;; indent-tabs-mode: nil ;; indent-tabs-mode: nil
;; autoload-compute-prefixes: nil
;; End: ;; End:
;;; yasnippet-tests.el ends here ;;; yasnippet-tests.el ends here

File diff suppressed because it is too large Load Diff