Compare commits

...

106 Commits

Author SHA1 Message Date
Xiyue Deng
c1e6ff23e9
Drop use of `yas--version' in doc/yas-doc-helper.el
- No longer available since 0.14.3
2025-06-04 01:29:16 -07:00
Stefan Monnier
dd570a6b22 yasnippet.el: Bump version to trigger release
* yasnippet-tests.el (string-suffix-p): Remove fallback definition.
2025-06-02 09:42:36 -04:00
Stefan Monnier
272b6067f1 Try and fix issue #1214
* yasnippet.el (yas--load-directory-1): Add a `lexical-binding` cookie
to the compiled-snippet files, and silence warnings if it's absent from them.
(yas--letenv-f): New function extracted from `yas--letenv`.
(yas--letenv): Use it.
2025-06-01 18:43:13 -04:00
Stefan Monnier
2384fe1655 yasnippet.el (yas--version): Delete variable.
(yas-about): Fall back to the Git description only if the package
version is not available.
(yas--make-menu-binding): Don't quote lambdas.
2025-04-03 15:26:13 -04:00
Stefan Monnier
81a59d1a85 yasnippet.el: Bug fix release 0.14.2 2025-04-03 12:43:37 -04:00
Stefan Monnier
2c20b10fc3 Misc minor pending tweaks
* yasnippet.el (yas-minor-mode): Fix docstring (issue#1210).
(yas--save-restriction-and-widen): Use workaround only for the old
Emacsen where it was needed.
(yas--snippet-create): Adjust Emacs version where CC-mode needed
a workaround.
(help-snippet-def): Remove useless use of `purecopy`.
2025-04-03 12:40:54 -04:00
Stefan Monnier
5b315f1753 Misc fixes found via compilation warnings
* yasnippet-debug.el (yas-debug-snippets): Improve commit 009322196cfa.
* yasnippet-tests.el (test-rebindings): Avoid `copy-keymap`.
2025-01-12 17:51:54 -05:00
Stefan Monnier
03b1b11547 yasnippet.el (yas--font-lock-keywords): Avoid font-lock-*-face vars 2025-01-12 10:04:11 -05:00
Stefan Monnier
37d0b2790f yasnippet.el (yas-maybe-load-snippet-buffer): Don't move point (#1146) 2025-01-12 09:59:50 -05:00
monnier
fe1f4e0e96
Merge pull request #1149 from pestctrl/quit-undo-tree
Push modifications to buffer-undo-list, even if unwinding
2024-10-13 11:57:55 -04:00
Benson Chu
ce54f1958f Push modifications to buffer-undo-list, even if unwinding 2024-10-13 10:48:59 -05:00
monnier
eb5ba2664c
Merge pull request #1196 from VitoVan/master
(yas--all-parents): delete-dups for fundamental-mode
2024-04-06 09:14:51 -04:00
Vito Van
e23a80177a
(yas--all-parents): delete-dups for fundamental-mode
Before this commit,

(yas--all-parents 'lisp-mode) would return:

`(lisp-mode lisp-data-mode prog-mode fundamental-mode fundamental-mode)`

which would cause duplicated entries when prompting,
if the snippet were for fundamental-mode.
2024-04-06 17:34:18 +08:00
Stefan Monnier
33587a8551 (yas-reload-all): Flush the all-parents caches (issue #1194)
* yasnippet.el (yas--flush-all-parents): New function.
(yas-reload-all): Use it.

* yasnippet.el (issue-492-and-494): Don't flush the all=parents cache any
more since `yas-reload-all` does it for us.
2024-03-08 03:15:33 -05:00
monnier
15065c36b4
Merge pull request #1194 from gutron/master
Undo all-parents memoization in test
2024-03-01 18:27:46 -05:00
Ron Gut
ab03a754e7 Undo all-parents memoization in test
yas-reload-all does not undo the memoization done in yas--all-parents, which
causes the issue-492-and-494 test to fail when run after any tests that
expands yas-with-some-interesting-snippet-dirs.

With the memoization enabled, c++-mode is considered a parent of c-mode,
causing the issue-492-and-494 test to fail.  With the memoization reset,
this does not occur.
2024-02-28 19:26:45 -05:00
Stefan Monnier
5b565c54b0 NEWS: Give a few more details 2024-02-15 15:34:45 -05:00
Stefan Monnier
1ec7e3b6f7 (yas--all-parents): Obey derived-mode-extra-parents (Issue #1193) 2024-02-15 14:09:24 -05:00
Stefan Monnier
8e9ce76f7a yasnippet.el: Recognize ${N} as an alternative syntax for $N
(yas-define-snippets): Warn about identity conflicts.
(yas--one-simple-fom): New fun, extracted from `yas--simple-fom-create`.
(yas--simple-fom-create): Use it.
(yas--field-parse-create): Use it for ${N}.
2024-02-12 11:45:51 -05:00
Stefan Monnier
297546f085 yasnippet.el: Bug fix release 0.14.1 2024-01-23 21:58:24 -05:00
Stefan Monnier
b8f3f11ee5 yasnippet.el (yas--indent-region): Workaround for issue #1183 2024-01-22 13:46:51 -05:00
Stefan Monnier
47b38b2133 yasnippet.el (yas-define-snippets): Remove costly no-op 2024-01-22 13:46:05 -05:00
monnier
5af84cdb94
Merge pull request #1184 from martenlienen/local-condition-closure
Allow closures in yas-buffer-local-condition
2024-01-22 08:23:30 -05:00
Marten Lienen
9228fd983b * yasnippel.el (yas-buffer-local-condition): Check functionp before consp to allow closures 2024-01-22 11:08:44 +01:00
Stefan Monnier
1d0966ae34 * yasnippet.el (yas-buffer-local-condition): Accept functions
(yas-not-string-or-comment-condition): Make it a function.
(yas--funcall-condition): Rename from `yas--funcall-condition`, change
its calling convention.
(yas--template-can-expand-p, yas--describe-pretty-table):
Adjust accordingly.
(yas--require-template-specific-condition-p): Add support for functions
in `yas-buffer-local-condition`.

* doc/snippet-expansion.org (The condition system <<condition-system>>):
Adjust example to avoid quoted code.
2024-01-19 12:38:21 -05:00
Stefan Monnier
25f5d8808a Avoid shadowing the tab => TAB remapping
* yasnippet.el (yas-keymap): Don't bind `tab`.
(yas--read-keybinding): Prefer the more precise \` and \' regexps.
(yas--parse-template): Use `pcase`.
2024-01-19 08:57:17 -05:00
Stefan Monnier
d7a79d4a96 Fix remaining failing tests
* yasnippet-tests.el (issue-492-and-494): Make the test a bit less picky.
(test-yas-tab-binding, test-yas-in-org): Test TAB rather than `tab`
because at the level at which we do the test, `tab` is not remapped to TAB.
2024-01-19 08:55:17 -05:00
Stefan Monnier
3e14a8534f (yas--on-protection-overlay-modification): Fix thinko 2024-01-18 10:31:17 -05:00
Stefan Monnier
9f253badfb yasnippet.el: Work around Emacs bug#65929 (see also issue#1175)
(yas--on-protection-overlay-modification): Ignore clearly bogus calls.
(yas-keymap-disable-hook): Improve docstring.
2024-01-17 13:24:15 -05:00
Stefan Monnier
23c7a6fa51 yasnippet.el: Minor simplifications
(yas--check-commit-snippet): De Morgan.
(yas-expand-snippet): Use `yas-current-field`.
2024-01-17 13:07:51 -05:00
Stefan Monnier
c6488ac6fb README.mdown: Minor tweaks 2024-01-15 00:55:21 -05:00
Stefan Monnier
d12428082c yasnippet-tests.el: Fix some failures
* yasnippet-tests.el (yas-call-with-saving-variables): Don't `set` when
there's nothing to change.
(yas-with-overriden-buffer-list): Fix `buffer-list` override.
(loading-with-cyclic-parenthood, extra-modes-parenthood): Tweak tests
to be a bit less sensitive to details of ordering and number of
repetitions in `yas--modes-to-activate`.

* yasnippet.el (yas--all-parents): Make sure `mode` is always first in
the output, as is the case for `derived-mode-all-parents`.
(yas--modes-to-activate): Put extra modes first and not reversed, as
required by test `extra-modes-parenthood`.
2024-01-15 00:53:00 -05:00
Stefan Monnier
8ce506e32f * yasnippet.el (yas--all-parents): Don't add fundamental-mode to itself
Rename `yas--all-children` to `yas--cached-children` since it doesn't
contain "all" children.
2024-01-14 00:34:22 -05:00
Stefan Monnier
d7f55c7501 (yas--all-parents): Fix stale cache issue #1180
* yasnippet.el (yas--all-parents): Record children in `yas--all-children`.
(yas--define-parents): Use it to flush the caches of the affected modes.
2024-01-08 11:42:46 -05:00
Stefan Monnier
ae36504a5f yasnippet.el: Use derived-mode-all-parents when available
This allows YASnippet to obey `derived-mode-add-parents`, which should
become the standard way to indicate "loose" relationships (such as
the fact that `js3-mode` is related to `js-mode` or for TS modes).

* yasnippet.el (yas--merge-ordered-lists, yas--all-parents): New functions.
(yas--modes-to-activate): Use them.
2024-01-04 15:13:51 -05:00
Stefan Monnier
bd2fdc8f7d * yasnippet.el (yas--snippet-create): Remove CC-mode workaround for #953 2024-01-01 19:47:31 -05:00
Stefan Monnier
362e9b551d yasnippet.el (yas-about): Use package-get-version 2024-01-01 19:45:05 -05:00
Stefan Monnier
66db827a86 yasnippet.el: Use setq-local and defvar-local 2024-01-01 19:40:47 -05:00
Stefan Monnier
bcefd0a1c1 * yasnippet.el: Remove compatibility for Emacs<24.4
Since we already require Emacs≥24.4, there's not point keeping that
compatibility code.

(yas--modes-to-activate): Remove redundant `fboundp` test.
(yas-activate-extra-mode): Don't bother converting hashtable to alist
to pass to `completing-read`.
(yas-dont-activate-functions): Get rid of Emacs≤23 code.
(snippet-mode): `prog-mode` is always available.
(yas-x-prompt): `posn-at-point` is always available.
(yas--merge-and-drop-dups): `delete-consecutive-dups` is always available.
2024-01-01 19:36:59 -05:00
Stefan Monnier
2b328e563e * yasnippet.el (yas-wrap-around-region): Fix warning
Fix placement of `:tag` arg to `const` custom type.
2024-01-01 19:18:11 -05:00
Stefan Monnier
9596631bde * README.mdown: Tweak install instructions
(Installation): Rename the Git install section to make it sound less
like the "normal&recommanded" way to install YAsnippet.
(Install with `package-install`): Mention GNU ELPA and GNU-devel ELPA.
2024-01-01 19:12:03 -05:00
Stefan Monnier
b86b44cce6 (yas--modes-to-activate): Pay attention to major-mode-remap-alist
Should hopefully fix issue #1169.
2024-01-01 16:17:58 -05:00
Stefan Monnier
52a1c50319 * yasnippet.el (debug-ignored-errors): Don't modify it
(debug-ignored-errors): Remove left over code that became obsolete with
commit 175e0a3a102c22.
(yas--read-lisp): Fix code generation.
(yas-exception): Use `define-error`.
2023-09-14 10:00:37 -04:00
Stefan Monnier
58c92ba393 * yasnippet.el: Cosmetic changes
Prefer #' to quote function names.
(yas-after-exit-snippet-hook, yas-before-expand-snippet-hook)
(yas-after-reload-hook): A hook is not a function, but a symbol
containing functions.  Fix doc accordingly.
(yas-define-snippets, yas-longest-key-from-whitespace)
(yas--field-parse-create): Make the doc fit within 80 columns.
(yas-skip-and-clear-or-delete-char): Fix ordering between `declare` and
`interactive`.
2023-09-14 10:00:37 -04:00
Stefan Monnier
043c52a5a9 * yasnippet.el (yas-minor-mode-map): Don't bind to tab 2023-09-14 10:00:37 -04:00
Stefan Monnier
009322196c * yasnippet-debug.el: Use advice-add i.s.o defadvice.
Now that we use `add-function`, we may as well avoid using the deprecated
`defadvice`

(cl-flet): Remove confusing `cl-flet` fallback, always provided by `cl-lib`.
(yas--snippet-parse-create, yas--commit-snippet):
Use `advice-add` i.s.o `defadvice`.
2023-09-14 10:00:37 -04:00
Stefan Monnier
e991530108 * yasnippet.el: Use add-function and remove left-over debug code
Instead of using `setq` and storing the old value in
`yas--original-auto-fill-function`, use `add-function`.
This makes it virtually impossible for a bug like #873/#919 to appear.
Remove the left-over debug code we had added to try and track down
#873/#919.

This requires bumping the dependency on Emacs≥24.4.

(yas--original-auto-fill-function, yas--watch-auto-fill-backtrace):
Delete variables.
(yas--watch-auto-fill): Delete function.  Don't add it to variable watchers.
(yas--auto-fill-wrapper): Use `add-function`.
(yas-minor-mode): Use `remove-function`.
(yas--auto-fill): Adjust its calling convention for use with `:around`
in `add-function`.  Remove left-over debug code.
(yas--post-command-handler): Remove left-over debug code.
2023-09-14 10:00:37 -04:00
Stefan Monnier
97002af846 * yasnippet.el: Use lexical-binding 2023-09-14 10:00:37 -04:00
Stefan Monnier
b09ab98419 * yasnippet-tests.el: Minor cosmetic changes
Use utf-8 rather than latin-1.
Prefer #' to quote function names.
(special-mode): Remove backward compatibility code which never worked
since it uses `fundamental` which doesn't exist).
2023-09-14 10:00:29 -04:00
Stefan Monnier
6e4de312cf * doc/yas-doc-helper.el: Use cl-lib and lexical-binding
Also silence compiler warnings.
2023-09-14 09:59:23 -04:00
Stefan Monnier
946b27ddca * .gitignore: Add patterns for ELPA-generated files 2023-09-14 09:59:23 -04:00
João Távora
76e1eee654 Merge commit '0650f1989b6da752f60a15aa6b5222e340388cc2' from elpa.git 2023-09-12 11:13:25 -05:00
João Távora
3393975e1c Fix compilation problems of doc/yas-doc-helper.el 2023-09-05 02:05:16 +01:00
João Távora
849a134c2d Unbreak link in org docs
* doc/snippet-expansion.org: Fix a link
2023-09-05 02:03:14 +01:00
João Távora
50ba4f3821 Replace Rakefile with Makefile
* Makefile: New file
* Rakefile: Delete
2023-09-05 01:28:07 +01:00
Philipp Stephani
1ca316fb6d Unbreak unit tests under Emacs 28.
- Emacs 28 has a new mode ‘lisp-data-mode’ for Lisp data.
- A test that was temporarily broken passes again.
- The default for ‘org-adapt-indentation’ has changed.
2023-09-05 00:26:53 +01:00
Morgan Smith
0650f1989b Fix tests failing because of lisp-data-mode
* yasnippet-tests.el (extra-modes-parenthood): Add lisp-data-mode
(bug#48102).
2021-05-02 09:53:02 +02:00
Noam Postavsky
5cbdbf0d20 Handle errors during evaluation properly
* yasnippet.el (yas--eval-for-string): Convert error to a string,
rather than returning the error data (which can only lead to confusing
type errors later when code expecting a string gets a list).
* yasnippet-tests.el (yas-no-memory-of-bad-snippet): Adjust test, now
that snippet expansion swallows errors properly.
2020-06-03 22:46:18 -04:00
João Távora
d3d6d70b1c Correct manual call to after-change-functions
The pre-change-len argument passed to each element of
after-change-fucntions must reflect the length of the affected region
before the change happened.

In Yasnippet's case, the change enacted in yas--snippet-create is the
replacement of a region (which is almost always of length 0) with a
ready-to-navigate snippet template.  The previous implementation
calculated the length of the affected region after that change
happened, which is wrong.

See https://github.com/joaotavora/eglot/issues/462 for a case where
this mattered.

* yasnippet.el (yas--snippet-create): Correct manual call to
after-change-functions.
2020-05-24 23:15:54 +01:00
Noam Postavsky
5b1217ab08 ; Add some notes about narrowing, font-lock cc-mode issues
* yasnippet-tests.el (yas--with-font-locked-temp-buffer)
(example-for-issue-474):
* yasnippet.el (yas--snippet-create): Add commentary.
2020-04-13 18:21:21 -04:00
Noam Postavsky
1cc1996074 Don't bind inhibit-modification-hooks in yas--snippet-create
* yasnippet.el (yas--snippet-create): Bind before-change-functions and
after-change-functions to nil instead of inhibit-modification-hooks to
t while expanding snippet.  The latter also needlessly blocks overlay
and text property modification hooks (which we don't call ourselves
afterwards).  This way we allow packages like iedit to better
co-operate with yasnippet.
2020-04-12 19:50:12 -04:00
Noam Postavsky
291873ee13 ; .travis.yml: Clean up validator warnings/infos 2020-04-04 20:52:38 -04:00
Noam Postavsky
170d13d069 Scan nested fields properly
* yasnippet.el (yas--scan-for-field-end): New function.
(yas--field-parse-create): Use it instead of yas--scan-sexps, which
isn't able to distinguish between ${...} (a nested field) and
{...} (plain old braces in the snippet text).
* yasnippet-tests.el (yas-escaping-close-brace): New test.
2020-04-04 20:47:21 -04:00
Noam Postavsky
7c02bc142c Fix failure on depth 2+ nested snippets
* yasnippet.el (yas--advance-end-maybe-previous-fields): New function.
(yas--commit-snippet, yas--on-field-overlay-modification)
(yas-expand-snippet): Use it, so that all active fields will be
extended properly, even in case of deeply nested snippet expansion.
* yasnippet-tests.el (nested-snippet-expansion-depth-2): New test.
2020-03-29 10:34:42 -04:00
Noam Postavsky
ac03c2f192 ; Test on Emacs 27
* .travis.yml: Add 27-prerelease.  Change 26-prerelease to 26.3.
2020-03-25 22:38:30 -04:00
Noam Postavsky
3bf9a3b1af Release 0.14.0
* NEWS: Update for 0.14.
* yasnippet.el (yas-installed-snippets-dir, yas--version): Bump
version.
2019-12-22 17:06:42 -05:00
Noam Postavsky
4046f61588 * yasnippet.el (yas-field-highlight-face): Remove redundant quote. 2019-12-13 16:01:51 -05:00
João Távora
1bee3a33c7 Fix #979: grok curly braces with LSP-style escaping
* yasnippet-tests.el (escaping-for-lsp-style-snippet-syntax): New
test.

* yasnippet.el (yas--field-parse-create): rework real-match-end-0
calculation.
2019-10-30 13:31:17 +00:00
Bao Haojun
a66f15e6c9 Fix yas-insert-snippet for keyless snippets
* yasnippet.el (yas--table-templates): Get snippets from uuidhash
table too.

Copyright-paperwork-exempt: yes
2019-10-08 22:16:25 -04:00
Stefan Monnier
d91dd66f2a * yasnippet.el (yas--extra-modes): Move alias before def 2019-07-24 08:04:46 -04:00
Noam Postavsky
bd3572a9b3 Handle multiple uses of yas-auto-next
* yasnippet.el (yas--auto-next): Loop again after moving to the next
field.
* yasnippet-tests.el (auto-next-field): Test for multiple
yas-auto-next uses.
2019-07-23 18:05:40 -04:00
Noam Postavsky
476bc77c34 Fix snippet undo
* yasnippet.el (yas--snippet-revive): Add revived snippet to
yas--active-snippets.
* yasnippet-debug.el (yas-debug-snippets): Print yas--active-snippets
length.
* yasnippet-tests.el (undo-revive-and-do-again): New test.
2019-06-30 13:20:19 -04:00
Bill Sacks
e45e3de357 * doc/faq.org: yas-prev should be yas-prev-field
Copyright-paperwork-exempt: yes
2019-05-08 18:42:08 -04:00
Noam Postavsky
f056a4def8 Minor code shuffling and commenting
* yasnippet.el (yas--do-todo-snippet-indent): Renamed from
yas--do-todo-snippet-indent.
2019-05-02 18:14:52 -04:00
Noam Postavsky
55c448b991 Remove redundant arg to yas-expand-snippet
* yasnippet.el (yas--expand-or-visit-from-menu)
(yas--expand-or-prompt-for-template)
(yas-visit-snippet-file, yas-tryout-snippet): Don't pass expand-env
when to yas-expand-snippet when first arg is a yas--template record.
2019-05-02 18:13:15 -04:00
Noam Postavsky
c432e78ffd Fix field adjustment on deletion
For deletion, we need to check the bounds before the deletion happens,
otherwise the overlay may already be moved to wrong place.
* yasnippet.el (yas--before-change-modified-snippets): New variable.
(yas--merge-and-drop-dups): New function.
(yas--gather-active-snippets): New function.
(yas--on-field-overlay-modification): Use it.

* yasnippet.el
2019-05-02 07:34:23 -04:00
Noam Postavsky
ffce236268 Do auto indentation only in post command hook
* yasnippet.el (yas--todo-snippet-indent): New variable.
(yas--on-field-overlay-modification): Save snippet to it, and don't
indent after mirror update.
(yas--do-todo-field-updates): New function.
(yas--post-command-handler): Call it.
(yas--snippet-field-mirrors, yas--indent-mirrors-of-snippet): New
functions, split out from...
(yas--snippet-field-mirrors): ...here.
* yasnippet-tests.el (yas-test-delete-and-insert-command)
(indent-mirrors-on-complex-update): New test and helper function.
2019-05-01 17:52:26 -04:00
Noam Postavsky
6a738b581f ; doc/faq.org: Fix example keybinding code. 2019-04-30 20:44:40 -04:00
Noam Postavsky
fc33b2fbae Make overlay-modification protection optional
* yasnippet.el (yas-inhibit-overlay-modification-protection): New
variable.
(yas--on-protection-overlay-modification): Consult it.
2019-04-22 22:06:40 -04:00
Noam Postavsky
bae20af3de ; * doc/faq.org: Linkify bug reference. 2019-04-22 11:23:49 -04:00
Noam Postavsky
189f7375b6 * doc/faq.org: Note that Flyspell problem is (now fixed) Emacs bug. 2019-04-21 16:18:01 -04:00
Noam Postavsky
9cedd596ec Allow disabling snippet keybindings from hook
* yasnippet.el (yas-keymap-disable-hook): New hook.
(yas-filtered-definition): New function.
(yas-keymap): Use it.
* doc/faq.org: Update key redefinition example.
2019-04-21 16:11:44 -04:00
Noam Postavsky
7612bc1b70 Don't check this-command in yas-not-string-or-comment-condition
Since we now check conditions in conditional keybindings, it can be
evaluated before 'this-command' has been assigned.
* yasnippet.el (yas-not-string-or-comment-condition): Remove check of
'this-command'.
2019-04-21 15:25:02 -04:00
Noam Postavsky
6a3619b4f2 Fix additional corner case with org source block integration
* yasnippet.el (yas--on-buffer-kill): Check if the org-marker still points
to a buffer.
2019-04-21 14:18:14 -04:00
Noam Postavsky
048d030b68 Fix line-relative snapshotting for org src blocks
There was some half-backed code getting confused between "plain"
snapshort info and line+snapshot info leading to some type errors when
expanding snippets in org-mode src blocks.  I had wrongly assumed the
failures were only due to org version 9 changes (in fact, the org
changes only affect snippet expansion for text-mode (and probably
other non-fontifying modes too)).  Reorganize the snapshotting
functions so that line+snaphot has the line info after the marker,
next to the rest of the snapshot info.  This removes the need for list
manipulation and simplifies the code.  Furthermore, let the
restoration functions take the info as a list, rather than separate
arguments, this removes the need for several uses of `apply'.
* yasnippet.el (yas--snapshot-location): Renamed from
yas--snapshot-marker-location, don't return marker.
(yas--snapshot-line-location): New function.
(yas--goto-saved-location): Take single list arg.  Return point.
(yas--restore-marker-location): Remove, open code callers.
(yas--goto-saved-line-location)
(yas--restore-overlay-line-location): New functions.
(yas--prepare-snippets-for-move, yas--finish-moving-snippets)
(yas--auto-fill, yas--indent-region): Adjust callers of previously
mentioned functions accordingly.
* yasnippet-tests.el (yas-org-native-tab-in-source-block-text):
Renamed from yas-org-native-tab-in-source-block.
(yas-org-native-tab-in-source-block-emacs-lisp): New test.
(do-yas-org-native-tab-in-source-block): Take MODE parameter.
2019-04-14 12:06:44 -04:00
Noam Postavsky
dabc719921 Don't turn on yas-minor-mode in temp buffers
Generally, the user won't be interacting with, or creating snippets in
temporary buffers.
* yasnippet.el (yas-temp-buffer-p): New function.
(yas-dont-activate-functions): Add it to default value.
* yasnippet-tests.el (complicated-yas-key-syntaxes)
(test-yas-activate-extra-modes): Call yas-minor-mode instead of
yas-minor-mode-on, to ensure activation.
2019-04-10 08:06:25 -04:00
Martin Harrigan
8b25d627a4 * doc/snippet-development.org: Fix typos.
Copyright-paperwork-exempt: yes
2019-03-31 21:54:38 -04:00
Benjamin Hipple
03aa5618ae * doc/snippet-organization.org: Fix typo.
Copyright-paperwork-exempt: yes
2019-03-31 21:39:07 -04:00
Noam Postavsky
1d96da2e08 Don't call before/after change-functions twice
* yasnippet.el (yas--snippet-create): Let-bind
inhibit-modification-hooks for snippet insertion, so that we don't
call change functions automatically, we already call them manually
after insertion and parsing.
2018-10-15 08:12:51 -04:00
Noam Postavsky
9f51cf29c9 Register snippet movement comments for eldoc
* yasnippet.el (top-level): Call eldoc-add-command.
2018-10-13 17:22:12 -04:00
James Nguyen
bceb65ba29 Make backspace/DEL clear field (#957)
* yasnippet.el (yas-clear-field): New command.
(yas-maybe-clear-field): New conditional binding value.
(yas-keymap): Bind it to DEL.
2018-10-13 17:12:48 -04:00
Noam Postavsky
fb253ac607 New public function yas-maybe-expand-abbrev-key-filter
* yasnippet.el (yas-maybe-expand-abbrev-key-filter): Renamed from
yas--maybe-expand-key-filter.
2018-10-13 17:08:32 -04:00
Noam Postavsky
0f05a7555a Add yas-completing-read
* yasnippet.el (yas-completing-read): New function.
(yas-verify-value): Simplify with `member' instead of `cl-notany'.
* doc/snippet-development.org (Template Syntax): Show
`yas-completing-read' instead of `yas-choose-value' in the example.
2018-10-13 17:04:50 -04:00
Noam Postavsky
845222774b Consider fundamental-mode as ultimate ancestor
* yasnippet.el (yas--modes-to-activate): If a mode doesn't have a
`derived-mode-parent' property, use `fundamental-mode'.
* yasnippet-tests.el (loading-with-cyclic-parenthood)
(issue-492-and-494): Expect fundamental-mode to be active.
* doc/snippet-expansion.org (Eligible snippets): Mention that
fundamental-mode is a fallback parent mode.
2018-10-13 17:02:10 -04:00
Kofi Laing
760f77afb9 Test for mirroring more than one field
* yasnippet-tests.el (yas-mirror-many-fields): New test.
2018-10-08 22:51:28 -04:00
Noam Postavsky
3c0be40e21 Update FAQ
* doc/faq.org: Add two questions about yas-key-syntaxes.  Remove
reference to obsolete Google Groups.  Remove question about turning
off minor mode in some buffers, it was out of date, and not frequently
asked.
* yasnippet.el (yas-key-syntaxes): Fix docstring.
2018-10-07 18:30:44 -04:00
Noam Postavsky
eeb05f0910 Handle field adjust of pending active fields
* yasnippet.el (yas--on-field-overlay-modification): Call
yas--advance-end-maybe on all pending active snippets in case of
stacked expansion.
(yas-next-field): Get current snippet according to
active field bounds.
* yasnippet-tests.el (nested-snippet-expansion-4): New test.
2018-10-07 15:06:51 -04:00
Noam Postavsky
ffc733d4cf ; Debug code fixes
* yasnippet-debug.el (yas-debug-live-range): Consider an overlay as
live, not dead even though it has integer bounds.
(yas-debug-with-tracebuf): Add debug declaration.
2018-10-07 15:06:51 -04:00
Noam Postavsky
8328c38d77 Fix another failure of cc-mode indentation
Suggested by OGAWA Hirofumi in
https://github.com/joaotavora/yasnippet/issues/953.
* yasnippet.el (yas--snippet-create): Call before and after change
functions around yas--snippet-parse-create.
* yasnippet-tests.el (indent-cc-mode-2): New test.
2018-10-07 05:55:20 -04:00
Noam Postavsky
7a178a2ca0 Remove spurious change of before-change-functions
Found by OGAWA Hirofumi in
<https://github.com/joaotavora/yasnippet/issues/953>.
* yasnippet.el (yas--save-backquotes): Don't remove first entry of
before-change-functions.
2018-09-16 17:15:26 -04:00
João Távora
1e71360868
Per #947: fix typo in README.md
* README.md (Where are the snippets?): package-install, 
not install-package.
2018-07-22 18:31:33 +01:00
Noam Postavsky
d3bb879356 Remove last-buffer-undo-list compat definition
* yasnippet.el (last-buffer-undo-list): Remove, apparently it works
around some bug in "Carbon Emacs", but yasnippet is probably not the
right place for such a workaround anyway (yasnippet does not use
last-buffer-undo-list).
2018-06-20 20:50:52 -04:00
Noam Postavsky
79b90c9489 Remove compatibility code for Emacs 22 and earlier
* yasnippet.el (region-active-p, locate-dominating-stop-dir-regexp)
(locate-dominating-file): Remove.
2018-06-20 20:50:52 -04:00
Noam Postavsky
e67592ce1b Don't use overlays to find active snippets
* yasnippet.el (yas--active-snippets): New buffer-local variable.
(yas-active-snippets): Use it, when asked for all active snippets.
(yas--commit-snippet): Remove finished snippet from list of active
snippets.
(yas--snippet-create): Add new snippet to list of active snippets.
(yas--check-commit-snippet): Consult list of active snippetes.
2018-06-06 20:22:57 -04:00
Noam Postavsky
4af33546d8 Make less garbage in overlay heavy buffers
* yasnippet.el (yas-active-snippets): Use dolist+when-push instead of
mapcar+delq.
2018-06-06 08:22:58 -04:00
João Távora
4f78d03f85 Close #937: Officially support automatically moving to next field
* yasnippet-tests.el (auto-next-field): New test.
(yas-saving-variables): Move up in the file.

* yasnippet.el (yas--auto-next): New helper.
(yas-auto-next): New user-visible snippet helper.

* doc/snippet-development.org (Choosing fields value from a list
and other tricks): Add mention of yas-auto-next.
2018-05-26 19:33:52 +01:00
14 changed files with 1362 additions and 999 deletions

4
.gitignore vendored
View File

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

View File

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

46
Makefile Normal file
View File

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

85
NEWS
View File

@ -1,8 +1,91 @@
Yasnippet NEWS -- history of user-visible changes.
Copyright (C) 2017-2018 Free Software Foundation, Inc.
Copyright (C) 2017-2025 Free Software Foundation, Inc.
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

View File

@ -15,7 +15,7 @@ YASnippet. Watch [a demo on YouTube][youtube-demo].
# Installation
## Install the most recent version
## Manual install from Git
Clone this repository somewhere
@ -33,12 +33,16 @@ Add your own snippets to `~/.emacs.d/snippets` by placing files there or invokin
## Install with `package-install`
In a recent emacs `M-x list-packages` is the recommended way to list and install packages.
[MELPA][melpa] keeps a very recent snapshot of YASnippet, see http://melpa.org/#installing.
In a recent emacs `M-x list-packages` is the recommended way to list
and install packages.
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
El-get is a nice way to get the most recent version, too. See
El-get is another nice way to get the most recent version, too. See
https://github.com/dimitri/el-get for instructions.
## Use `yas-minor-mode` on a per-buffer basis
@ -61,7 +65,7 @@ get some!
1. [yasnippet-snippets] - a snippet collection package maintained by
[AndreaCrotti](https://github.com/AndreaCrotti).
It can be installed with `M-x install-package RET
It can be installed with `M-x package-install RET
yasnippet-snippets` if you have added MELPA to your package
sources.
@ -71,10 +75,6 @@ get some!
To use these snippets you have to run the tool first, so
[see its doc][yasmate]), and then point the `yas-snippet-dirs`
variable to the `.../yasmate/snippets` subdir.
If you have a working ruby environment, you can probably get lucky
directly with `rake convert-bundles`.
3. [textmate-to-yas.el]
This is another textmate bundle converting tool using Elisp
@ -103,8 +103,9 @@ common problems and practical snippet examples.
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 the main Emacs bug list,
bug-gnu-emacs@gnu.org, putting "yasnippet" somewhere in the subject.
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
@ -160,6 +161,8 @@ Finally, thank you very much for using YASnippet!
[googlecode tracker]: http://code.google.com/p/yasnippet/issues/list
[forum]: http://groups.google.com/group/smart-snippet
[melpa]: http://melpa.milkbox.net/
[gnuelpa]: http://elpa.gnu.org/packages/yasnippet.html
[gnudevel]: http://elpa.gnu.org/devel/yasnippet.html
[yasmate]: http://github.com/joaotavora/yasmate
[textmate-to-yas.el]: https://github.com/mattfidler/textmate-to-yas.el
[yasnippet-snippets]: http://github.com/AndreaCrotti/yasnippet-snippets

130
Rakefile
View File

@ -1,130 +0,0 @@
# -*- 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
# rake doc[../htmlize]
#
# To do this interactively, load doc/yas-doc-helper, open one of the
# org files, and do `C-c C-e P'.
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

@ -7,6 +7,16 @@
the Github issue tracker. It might be more up-to-date than this
list.
* Why are my snippet abbrev keys triggering when I don't want them too?
Expansion of abbrev keys is controlled by [[sym:yas-key-syntaxes][=yas-key-syntaxes=]]. Try
removing entries which correspond to the abbrev key character syntax.
For example, if you have a snippet with abbrev key "bar", that you
don't want to trigger when point follows the text =foo_bar=, remove
the ="w"= entry (since "bar" has only word syntax characters).
* Why aren't my snippet abbrev keys triggering when I want them too?
See previous question, but in reverse.
* Why is there an extra newline?
If there is a newline at the end of a snippet definition file,
@ -20,27 +30,22 @@ final newline automatically.
* Why doesn't TAB navigation work with flyspell
A workaround is to inhibit flyspell overlays while the snippet is
active:
This is [[https://debbugs.gnu.org/26672][Emacs Bug#26672]], so you should upgrade to version 25.3 or
better. Otherwise, a workaround is to inhibit flyspell overlays while
the snippet is active:
#+BEGIN_SRC emacs-lisp
(add-hook 'flyspell-incorrect-hook
#'(lambda (dummy1 dummy2 dymmy3)
#'(lambda (&rest _)
(and yas-active-field-overlay
(overlay-buffer yas-active-field-overlay))))
#+END_SRC
This is apparently related to overlay priorities. For some reason, the
=keymap= property of flyspell's overlays always takes priority over the
same property in YASnippet's overlays, even if one sets the latter's
=priority= property to something big. If you know emacs-lisp and can
solve this problem, drop a line in the
[[http://groups.google.com/group/smart-snippet][discussion group]].
* How do I use alternative keys, i.e. not TAB?
Edit the keymaps [[sym:yas-minor-mode-map][=yas-minor-mode-map=]] and
[[sym:yas-keymap][=yas-keymap=]] as you would any other keymap:
Edit the keymaps [[sym:yas-minor-mode-map][=yas-minor-mode-map=]] and [[sym:yas-keymap][=yas-keymap=]] as you would
any other keymap, but use [[sym:yas-filtered-definition][=yas-filtered-definition=]] on the definition
if you want to respect [[sym:yas-keymap-disable-hook][=yas-keymap-disable-hook=]]:
#+begin_src emacs-lisp :exports code
(define-key yas-minor-mode-map (kbd "<tab>") nil)
@ -52,26 +57,12 @@ Edit the keymaps [[sym:yas-minor-mode-map][=yas-minor-mode-map=]] and
(define-key yas-keymap (kbd "TAB") nil)
(define-key yas-keymap [(shift tab)] nil)
(define-key yas-keymap [backtab] nil)
(define-key yas-keymap (kbd "<new-next-field-key>") 'yas-next-field-or-maybe-expand)
(define-key yas-keymap (kbd "<new-prev-field-key>") 'yas-prev)
(define-key yas-keymap (kbd "<new-next-field-key>")
(yas-filtered-definition 'yas-next-field-or-maybe-expand))
(define-key yas-keymap (kbd "<new-prev-field-key>")
(yas-filtered-definition 'yas-prev-field))
#+end_src
* How do I turn off the minor mode where in some buffers?
The best way, since version 0.6.1c, is to set the default value of the
variable [[sym:yas-dont-activate][=yas-dont-activate=]] to a lambda function like so:
#+BEGIN_SRC emacs-lisp
(set-default 'yas-dont-activate
#'(lambda ()
(and yas-root-directory
(null (yas-get-snippet-tables)))))
#+END_SRC
This is also the default value starting for that version. It skips the
minor mode in buffers where it is not applicable (no snippet tables),
but only once you have setup your yas-root-directory.
* How do I define an abbrev key containing characters not supported by the filesystem?
- *Note*: This question applies if you're still defining snippets

View File

@ -8,7 +8,7 @@
There are some ways you can quickly find a snippet file or create a new one:
- =M-x yas-new-snippet=, key bindind: =C-c & C-n=
- =M-x yas-new-snippet=, key binding: =C-c & C-n=
Creates a new buffer with a template for making a new snippet. The
buffer is in =snippet-mode= (see [[snippet-mode][below]]). When you are done editing
@ -62,7 +62,7 @@ expanded.
Optionally, if the file contains a line of =# --=, the lines above it
count as comments, some of which can be /directives/ (or meta data).
Snippet directives look like =# property: value= and tweak certain
snippets properties described below. If no =# --= is found, the whole
snippet properties described below. If no =# --= is found, the whole
file is considered the snippet template.
Here's a typical example:
@ -94,7 +94,7 @@ was loaded from.
** =# 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
non-nil value.
@ -113,14 +113,14 @@ achieved by grouping snippets into sub-directories and using the
=.yas-make-groups= special file (for this see
[[./snippet-organization.org][Organizing Snippets]]
Refer to the bundled snippets for =ruby-mode= for examples on the
Refer to the bundled snippets for =ruby-mode= for examples of the
=# group:= directive. Group can also be nested, e.g.
=control structure.loops= tells that the snippet is under the =loops=
=control structure.loops= indicates that the snippet is under the =loops=
group which is under the =control structure= group.
** =# expand-env:= expand environment
This is another piece of Emacs-lisp code in the form of a =let= /varlist
This is another piece of Emacs Lisp code in the form of a =let= /varlist
form/, i.e. a list of lists assigning values to variables. It can be
used to override variable values while the snippet is being expanded.
@ -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
named after the major mode the snippet is active for.
Additionally a variable [[sym:yas-prefix][=yas-prefix=]] is set to to the prefix argument
Additionally a variable [[sym:yas-prefix][=yas-prefix=]] is set to the prefix argument
you normally use for a command. This allows for small variations on the
same snippet, for example in this "html-mode" snippet.
same snippet, for example in this =html-mode= snippet.
#+BEGIN_SRC snippet
# name: <p>...</p>
@ -172,7 +172,7 @@ will expand the paragraph tag without newlines.
** =# type:= =snippet= or =command=
If the =type= directive is set to =command=, the body of the snippet
is interpreted as lisp code to be evaluated when the snippet is
is interpreted as Lisp code to be evaluated when the snippet is
triggered.
If it's =snippet= (the default when there is no =type= directive), the
@ -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
escaped as =\\= sometimes.
** Embedded Emacs-lisp code
** Embedded Emacs Lisp code
Emacs-Lisp code can be embedded inside the template, written inside
back-quotes (=`=). The lisp forms are evaluated when the snippet is
Emacs Lisp code can be embedded inside the template, written inside
back-quotes (=`=). The Lisp forms are evaluated when the snippet is
being expanded. The evaluation is done in the same buffer as the
snippet being expanded.
Here's an example for c-mode to calculate the header file guard
Here's an example for =c-mode= to calculate the header file guard
dynamically:
#+BEGIN_SRC snippet
@ -221,8 +221,8 @@ dynamically:
#endif /* $1 */
#+END_SRC
From version 0.6, snippets expansions are run with some special
Emacs-lisp variables bound. One of this is [[sym:yas-selected-text][=yas-selected-text=]]. You can
From version 0.6, snippet expansions are run with some special
Emacs Lisp variables bound. One of these is [[sym:yas-selected-text][=yas-selected-text=]]. You can
therefore define a snippet like:
#+BEGIN_SRC snippet
@ -237,7 +237,7 @@ Alternatively, you can also customize the variable
*** 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
doing
@ -284,7 +284,7 @@ The number can be omitted if you don't want to create [[mirrors-fields][mirrors]
** Mirrors <<mirrors-fields>>
We refer the tab stops with placeholders as a /field/. A field can
We refer to tab stops with placeholders as a /field/. A field can
have mirrors. *All* mirrors get updated whenever you update any field
text. Here's an example:
@ -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]]).
The tab stops with the same number to the field act as its mirrors. If
none of the tab stops has an initial value, the first one is selected as
the field and others mirrors.
none of the tab stops have an initial value, the first one is selected as
the field and the others are its mirrors.
** Mirrors with transformations <<mirror-transformations>>
If the value of an =${n:=-construct starts with and contains =$(=,
then it is interpreted as a mirror for field =n= with a
transformation. The mirror's text content is calculated according to
this transformation, which is Emacs-lisp code that gets evaluated in
this transformation, which is Emacs Lisp code that gets evaluated in
an environment where the variable [[sym:yas-text][=yas-text=]] is bound to the text
content (string) contained in the field =n=. Here's an example for
Objective-C:
@ -378,7 +378,7 @@ due to incomplete format codes.
** 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
are evaluated when you first enter the field, after each change you
make to the field and also just before you exit the field.
@ -412,25 +412,38 @@ the field, and with some useful variables bound, notably
can place a transformation in the primary field that lets you select
default values for it.
The [[sym:yas-choose-value][=yas-choose-value=]] does this work for you. For example:
For example, the [[sym:yas-choose-value][=yas-completing-read=]] function is version of
=completing-read= which checks these variables. For example, asking
the user for the initial value of a field:
#+BEGIN_SRC snippet
<div align="${2:$$(yas-choose-value '("right" "center" "left"))}">
<div align="${2:$$(yas-completing-read "Alignment? " '("right" "center" "left"))}">
$0
</div>
#+END_SRC
See the definition of [[sym:yas-choose-value][=yas-choose-value=]] to see how it was written using
the two variables.
See the definition of [[sym:yas-choose-value][=yas-completing-read=]] to see how it was written
using the two variables. If you're really lazy :) and can't spare a
tab keypress, you can automatically move to the next field (or exit)
after choosing the value with [[sym:yas-auto-next][=yas-auto-next=]]. The snippet above
becomes:
Here's another use, for LaTeX-mode, which calls reftex-label just as you
#+BEGIN_SRC snippet
<div align="${2:$$(yas-auto-next
(yas-completing-read
"Alignment? "
'("right" "center" "left")))}">
$0
</div>
#+END_SRC
Here's another use, for =LaTeX-mode=, which calls reftex-label just as you
enter snippet field 2. This one makes use of [[sym:yas-modified-p][=yas-modified-p=]] directly.
#+BEGIN_SRC snippet
\section{${1:"Titel der Tour"}}%
\index{$1}%
\label{{2:"waiting for reftex-label call..."$(unless yas-modified-p (reftex-label nil 'dont-
insert))}}%
\label{{2:"waiting for reftex-label call..."$(unless yas-modified-p (reftex-label nil 'dont-insert))}}%
#+END_SRC
The function [[sym:yas-verify-value][=yas-verify-value=]] has another neat trick, and makes use

View File

@ -141,7 +141,7 @@ See the internal documentation on [[sym:yas-expand-snippet][=yas-expand-snippet=
* Controlling expansion
** Eligible snippets
** Eligible snippets<<eligible-snippets>>
YASnippet does quite a bit of filtering to find out which snippets are
eligible for expanding at the current cursor position.
@ -163,9 +163,11 @@ In particular, the following things matter:
- Parent tables
Snippet tables defined as the parent of some other eligible table are
also considered. This works recursively, i.e. parents of parents of
eligible tables are also considered.
Snippet tables defined as the parent of some other eligible table
are also considered. This works recursively, i.e., parents of
parents of eligible tables are also considered. As a special case,
if a mode doesn't have a parent, then =fundamental-mode= is
considered to be its parent.
- Buffer-local list of extra modes
@ -210,9 +212,10 @@ inside a comment? Set [[sym:yas-buffer-local-condition][=yas-buffer-local-condi
(add-hook 'python-mode-hook
(lambda ()
(setq yas-buffer-local-condition
'(if (python-syntax-comment-or-string-p)
(lambda ()
(if (python-syntax-comment-or-string-p)
'(require-snippet-condition . force-in-comment)
t))))
t)))))
#+END_SRC
... and for a snippet that you want to expand in comments, specify a
@ -225,7 +228,7 @@ For the full set of possible conditions, see the documentation for
** Multiples snippet with the same key
The rules outlined [[Eligible%20snippets][above]] can return more than
The rules outlined [[eligible-snippets][above]] can return more than
one snippet to be expanded at point.
When there are multiple candidates, YASnippet will let you select one.

View File

@ -33,7 +33,7 @@
The default considers:
- a personal collection that lives in =~/.emacs.d/snippets=
- the bundled collection, taken as a relative path to =yasnippet.el= localtion
- the bundled collection, taken as a relative path to =yasnippet.el= location
When you come across other snippet collections, do the following to try them
out:

View File

@ -1,6 +1,6 @@
;;; yas-doc-helper.el --- Help generate documentation for YASnippet
;;; yas-doc-helper.el --- Help generate documentation for YASnippet -*- lexical-binding: t; -*-
;; Copyright (C) 2012, 2013 Free Software Foundation, Inc.
;; Copyright (C) 2012-2023 Free Software Foundation, Inc.
;; Author: João Távora <joaotavora@gmail.com>
;; Keywords: convenience
@ -25,12 +25,17 @@
;;; Code:
(eval-when-compile
(require 'cl))
(require 'cl-lib))
(require 'org)
(or (require 'org-publish nil t)
(require 'ox-publish))
(require 'ox-publish)
(require 'yasnippet) ; docstrings must be loaded
;; Presumably one of org/ox-publish provided the following vars:
(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
;; http://orgmode.org/worg/org-8.0.html#sec-8-1
@ -132,13 +137,13 @@
(defun yas--document-symbols (level &rest names-and-predicates)
(let ((sym-lists (make-vector (length names-and-predicates) nil))
(stars (make-string level ?*)))
(loop for sym in yas--exported-syms
do (loop for test in (mapcar #'cdr names-and-predicates)
(cl-loop for sym in yas--exported-syms
do (cl-loop for test in (mapcar #'cdr names-and-predicates)
for i from 0
do (when (funcall test sym)
(push sym (aref sym-lists i))
(return))))
(loop for slist across sym-lists
(cl-return))))
(cl-loop for slist across sym-lists
for name in (mapcar #'car names-and-predicates)
concat (format "\n%s %s\n" stars name)
concat (mapconcat (lambda (sym)
@ -149,7 +154,7 @@
(interactive)
(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
;; `org-publish-current-project' (C-c C-e P).
@ -194,7 +199,7 @@ But replace link to \"current\" page with a span element."
;;:with-broken-links mark
:html-postamble
,(concat "<hr><p class='creator'>Generated by %c from "
(or rev yas--version) " " date "</p>\n"
rev " " date "</p>\n"
"<p class='xhtml-validation'>%v</p>\n")))
(project (assoc "yasnippet" org-publish-project-alist)))
(when rev ;; Rakefile :doc:upload uses "html-revision".

View File

@ -1,6 +1,6 @@
;;; yasnippet-debug.el --- debug functions for yasnippet -*- lexical-binding: t -*-
;; Copyright (C) 2010, 2013-2014, 2017-2018 Free Software Foundation, Inc.
;; Copyright (C) 2010-2025 Free Software Foundation, Inc.
;; Author: João Távora
;; Keywords: emulations, convenience
@ -40,9 +40,6 @@
;; Don't require '-L <path>' when debugging.
(expand-file-name "yasnippet" yas--loaddir)))
(require 'cl-lib)
(eval-when-compile
(unless (fboundp 'cl-flet)
(defalias 'cl-flet 'flet)))
(require 'color nil t)
(require 'edebug)
(eval-when-compile
@ -141,7 +138,9 @@
(decorator-end (overlay-get ov 'after-string))
(beg (yas-debug-ov-fom-start range))
(end (yas-debug-ov-fom-end range)))
(if (and beg end (not (integerp beg)) (not (integerp end)))
(if (and beg end (or (overlayp range)
(and (not (integerp beg))
(not (integerp end)))))
(propertize (format "from %d to %d" (+ beg) (+ end))
'cursor-sensor-functions
`(,(lambda (_window _oldpos dir)
@ -155,7 +154,7 @@
"<dead>")))
(defmacro yas-debug-with-tracebuf (outbuf &rest body)
(declare (indent 1))
(declare (indent 1) (debug (sexp body)))
(let ((tracebuf-var (make-symbol "tracebuf")))
`(let ((,tracebuf-var (or ,outbuf (get-buffer-create "*YASnippet trace*"))))
(unless (eq ,tracebuf-var (current-buffer))
@ -222,13 +221,13 @@
(setq yas-debug-undo value)
(yas--message 3 "debug undo %sabled" (if yas-debug-undo "en" "dis")))
(defadvice yas--snippet-parse-create (before yas-debug-target-snippet (snippet))
(defun yas-debug--target-snippet (snippet)
(add-to-list 'yas-debug-target-snippets snippet))
(defadvice yas--commit-snippet (after yas-debug-untarget-snippet (snippet))
(defun yas-debug--untarget-snippet (snippet)
(setq 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)))
yas-debug-live-indicators)
(clrhash yas-debug-live-indicators))
@ -252,6 +251,8 @@ buffer-locally, otherwise install it globally. If HOOK is
(setq yas-debug-target-snippets
(cl-delete-if-not #'yas--snippet-p yas-debug-target-snippets)))
(let ((yas-debug-recently-live-indicators nil))
(printf "(length yas--snippets-snippets) => %d\n"
(length yas--active-snippets))
(dolist (snippet (or yas-debug-target-snippets
(yas-active-snippets)))
(printf "snippet %d\n" (yas--snippet-id snippet))
@ -267,10 +268,8 @@ buffer-locally, otherwise install it globally. If HOOK is
do (printf "%S\n" undo-elem))))
(when hook
(setq yas-debug-target-buffer (current-buffer))
(ad-enable-advice 'yas--snippet-parse-create 'before 'yas-debug-target-snippet)
(ad-activate 'yas--snippet-parse-create)
(ad-enable-advice 'yas--commit-snippet 'after 'yas-debug-untarget-snippet)
(ad-activate 'yas--commit-snippet)
(advice-add 'yas--snippet-parse-create :before #'yas-debug--target-snippet)
(advice-add 'yas--commit-snippet :after #'yas-debug--untarget-snippet)
(add-hook 'post-command-hook #'yas-debug-snippets
nil (eq hook 'snippet-navigation))
;; Window management is slapped together, it does what I

View File

@ -1,8 +1,8 @@
;;; yasnippet-tests.el --- some yasnippet tests -*- lexical-binding: t -*-
;; Copyright (C) 2012-2015, 2017-2018 Free Software Foundation, Inc.
;; Copyright (C) 2012-2025 Free Software Foundation, Inc.
;; Author: João Távora <joaot@siscog.pt>
;; Author: João Távora <joaot@siscog.pt>
;; Keywords: emulations, convenience
;; This program is free software; you can redistribute it and/or modify
@ -121,7 +121,8 @@ This lets `yas--maybe-expand-from-keymap-filter' work as expected."
(funcall fn)
(cl-loop for var in vars
for saved in saved-values
do (set var saved)))))
do (unless (eq (symbol-value var) saved) ;Beware read-only vars!
(set var saved))))))
(defun yas-call-with-snippet-dirs (dirs fn)
(let* ((default-directory (make-temp-file "yasnippet-fixture" t))
@ -136,20 +137,6 @@ This lets `yas--maybe-expand-from-keymap-filter' work as expected."
;;; 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
@ -193,6 +180,20 @@ attention to case differences."
(should (string= (yas--buffer-contents)
"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 ()
"Test interaction of autofill with mirror transforms"
(let ((words "one two three four five")
@ -332,6 +333,31 @@ attention to case differences."
(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)))
@ -517,11 +543,14 @@ XXXXX ------------------------"))))
(yas-mock-insert "foo bar")
(ert-simulate-command '(yas-next-field))
(goto-char (point-min))
(let ((expected (with-temp-buffer
;; The default value of `org-adapt-indentation' changed between Org-mode 9.4
;; and 9.5, so force a specific value.
(let* ((org-adapt-indentation nil)
(expected (with-temp-buffer
(insert (format (concat "* Test foo bar\n"
" " org-property-format "\n"
" " org-property-format "\n"
" " org-property-format)
org-property-format "\n"
org-property-format "\n"
org-property-format)
":PROPERTIES:" ""
":ID:" "foo bar-after"
":END:" ""))
@ -556,6 +585,22 @@ int foo()
}
}" (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 ()
"Handling of snippet-mode indentation."
;; This is an interesting case because newlines match [[:space:]] in
@ -578,6 +623,28 @@ int foo()
;; Assuming 2 space indent.
(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 ()
"In issue 665, a multi-line mirror is attempted."
@ -603,9 +670,37 @@ mapconcat #'(lambda (arg)
(ert-simulate-command '(yas-next-field))
(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
;;; Thanks to @zw963 (Billy) for the testing
;; Thanks to @zw963 (Billy) for the testing
;;;
(ert-deftest escape-dollar ()
(with-temp-buffer
@ -676,6 +771,20 @@ mapconcat #'(lambda (arg)
(yas-expand-snippet "Look ma! ${1:`(yas-selected-text)`} 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).
@ -728,7 +837,7 @@ mapconcat #'(lambda (arg)
;; See https://github.com/joaotavora/yasnippet/issues/800.
(with-temp-buffer
(yas-minor-mode 1)
(should-error (yas-expand-snippet "```foo\n\n```"))
(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\\`\\`\\`")
@ -736,6 +845,8 @@ mapconcat #'(lambda (arg)
(defmacro yas--with-font-locked-temp-buffer (&rest body)
"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))
(let ((temp-buffer (make-symbol "temp-buffer")))
;; NOTE: buffer name must not start with a space, otherwise
@ -754,11 +865,9 @@ mapconcat #'(lambda (arg)
(and (buffer-name ,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 ()
;; 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
(c-mode)
(yas-minor-mode 1)
@ -832,6 +941,18 @@ mapconcat #'(lambda (arg)
(yas-mock-insert "baz")
(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
;;;
@ -948,7 +1069,7 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
("'quote" . "OKquoteOK"))))
(yas-reload-all)
(emacs-lisp-mode)
(yas-minor-mode-on)
(yas-minor-mode +1)
(let ((yas-key-syntaxes '("w" "w_")))
(let ((yas--barbaz t))
(yas-should-expand '(("foo-barbaz" . "foo-OKbarbazOK")
@ -984,6 +1105,24 @@ 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 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 ()
(let ((yas-triggers-in-field t))
(yas-with-snippet-dirs
@ -1030,20 +1169,64 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(ert-simulate-command '(yas-next-field-or-maybe-expand))
(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
;;;
(defmacro yas-with-overriden-buffer-list (&rest body)
(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 (symbol-function 'buffer-list)))
(cl-letf (((symbol-function 'buffer-list)
(lambda ()
(lambda (&rest args)
(cl-remove-if (lambda (buf)
(with-current-buffer buf
(eq major-mode 'lisp-interaction-mode)))
(funcall ,saved-sym)))))
(apply ,saved-sym args)))))
,@body))))
@ -1122,7 +1305,7 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(yas-minor-mode +1)
(should (equal (yas--template-content (yas-lookup-snippet "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
'text-mode '(("_1" "one!" "won" nil nil nil nil nil "uuid-1")))
(should (null (yas-lookup-snippet "one" nil 'noerror)))
@ -1190,19 +1373,20 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(yas-reload-all)
(with-temp-buffer
(let* ((major-mode 'c-mode)
(expected `(c-mode
(expected `(fundamental-mode
c-mode
cc-mode
yet-another-c-mode
and-also-this-one
and-that-one
;; prog-mode doesn't exist in emacs 23.4
,@(if (fboundp 'prog-mode)
'(prog-mode))
prog-mode
,@(if (fboundp 'lisp-data-mode) ;Emacs≥28
'(lisp-data-mode))
emacs-lisp-mode
lisp-interaction-mode))
(observed (yas--modes-to-activate)))
(should (equal major-mode (car observed)))
(should (equal (sort expected #'string<) (sort observed #'string<))))))))
(should-not (cl-set-exclusive-or expected observed)))))))
(ert-deftest extra-modes-parenthood ()
"Test activation of parents of `yas--extra-modes'."
@ -1219,37 +1403,42 @@ hello ${1:$(when (stringp yas-text) (funcall func yas-text))} foo${1:$$(concat \
(yas-activate-extra-mode 'and-that-one)
(let* ((expected-first `(and-that-one
yet-another-c-mode
c-mode
,major-mode))
c-mode))
(expected-rest `(cc-mode
;; prog-mode doesn't exist in emacs 23.4
,@(if (fboundp 'prog-mode)
'(prog-mode))
prog-mode
,@(if (fboundp 'lisp-data-mode) ;Emacs≥28
'(lisp-data-mode))
emacs-lisp-mode
and-also-this-one
lisp-interaction-mode))
(observed (yas--modes-to-activate)))
(should (equal expected-first
(observed (remq 'fundamental-mode (yas--modes-to-activate))))
(should-not (cl-set-exclusive-or
expected-first
(cl-subseq observed 0 (length expected-first))))
(should (equal (sort expected-rest #'string<)
(sort (cl-subseq observed (length expected-first)) #'string<))))))))
(should-not (cl-set-exclusive-or
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 ()
"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")
(yas-with-snippet-dirs '((".emacs.d/snippets"
("yas--test-mode")))
(yas-reload-all)
(with-temp-buffer
(let* ((major-mode 'yas--test-mode)
(expected `(c-mode
,@(if (fboundp 'prog-mode)
'(prog-mode))
(expected `(fundamental-mode
c-mode
yas--phony-c-mode
yas--test-mode))
(observed (yas--modes-to-activate)))
(should (null (cl-set-exclusive-or expected observed)))
;; The set of mode depends on some external factors:
;; `prog-mode': if cc-mode.el has been loaded.
;; `cc-mode': if we added `cc-mode' as yas--parent of `c-mode'.
(observed (cl-set-difference (yas--modes-to-activate)
'(prog-mode cc-mode))))
(should-not (cl-set-exclusive-or expected observed))
(should (= (length expected)
(length observed)))))))
@ -1455,31 +1644,31 @@ TODO: be meaner"
(with-temp-buffer
(yas-minor-mode -1)
(insert "foo")
(should (not (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand)))
(should-not (eq (key-binding (kbd "TAB")) #'yas-expand))
(yas-minor-mode 1)
(should (eq (key-binding (yas--read-keybinding "<tab>")) 'yas-expand))
(should (eq (key-binding (kbd "TAB")) #'yas-expand))
(yas-expand-snippet "$1 $2 $3")
(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 [(shift tab)]) 'yas-prev-field))
(should (eq (key-binding [backtab]) 'yas-prev-field))))))
;; (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 [(shift tab)]) #'yas-prev-field))
(should (eq (key-binding [backtab]) #'yas-prev-field))))))
(ert-deftest test-rebindings ()
(let* ((yas-minor-mode-map (copy-keymap yas-minor-mode-map))
(let* ((test-map (make-composed-keymap nil yas-minor-mode-map))
(minor-mode-map-alist
(cons `(yas-minor-mode . ,yas-minor-mode-map)
(cons `(yas-minor-mode . ,test-map)
(cl-remove 'yas-minor-mode minor-mode-map-alist
:test #'eq :key #'car))))
(define-key yas-minor-mode-map [tab] nil)
(define-key yas-minor-mode-map (kbd "TAB") nil)
(define-key yas-minor-mode-map (kbd "SPC") 'yas-expand)
(define-key test-map [tab] nil)
(define-key test-map (kbd "TAB") nil)
(define-key test-map (kbd "SPC") #'yas-expand)
(with-temp-buffer
(yas-minor-mode 1)
(should-not (eq (key-binding (kbd "TAB")) 'yas-expand))
(should (eq (key-binding (kbd "SPC")) 'yas-expand))
(should-not (eq (key-binding (kbd "TAB")) #'yas-expand))
(should (eq (key-binding (kbd "SPC")) #'yas-expand))
(yas-reload-all)
(should-not (eq (key-binding (kbd "TAB")) 'yas-expand))
(should (eq (key-binding (kbd "SPC")) 'yas-expand)))))
(should-not (eq (key-binding (kbd "TAB")) #'yas-expand))
(should (eq (key-binding (kbd "SPC")) #'yas-expand)))))
(ert-deftest test-yas-in-org ()
(yas-saving-variables
@ -1492,20 +1681,40 @@ TODO: be meaner"
(org-mode)
(yas-minor-mode 1)
(insert "foo")
(should (eq (key-binding [(tab)]) 'yas-expand))
(should (eq (key-binding (kbd "TAB")) 'yas-expand))))))
;; (should (eq (key-binding [tab]) #'yas-expand))
(should (eq (key-binding (kbd "TAB")) #'yas-expand))))))
(ert-deftest yas-org-native-tab-in-source-block ()
(ert-deftest yas-org-native-tab-in-source-block-text ()
"Test expansion of snippets in org source blocks."
:expected-result (if (and (fboundp 'org-in-src-block-p) (version< (org-version) "9"))
;; 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."
:expected-result (if (fboundp 'org-in-src-block-p)
: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-with-snippet-dirs
'((".emacs.d/snippets"
("text-mode"
`((".emacs.d/snippets"
(,(concat mode "-mode")
("T" . "${1:one} $1\n${2:two} $2\n<<$0>> done!"))))
(let ((text-mode-hook '(yas-minor-mode))
(org-src-tab-acts-natively t)
;; Binding both text and prog mode hook should cover everything.
(let ((org-src-tab-acts-natively t)
;; Org 8.x requires this in order for
;; `org-src-tab-acts-natively' to have effect.
(org-src-fontify-natively t))
@ -1514,8 +1723,8 @@ TODO: be meaner"
(yas--with-font-locked-temp-buffer
(org-mode)
(yas-minor-mode 1)
(insert "#+BEGIN_SRC text\nT\n#+END_SRC")
(if (fboundp 'font-lock-ensure)
(insert "#+BEGIN_SRC " mode "\nT\n#+END_SRC")
(if (fboundp 'font-lock-ensure) ;Emacs≥25
(font-lock-ensure)
(jit-lock-fontify-now))
(re-search-backward "^T$") (goto-char (match-end 0))
@ -1530,9 +1739,9 @@ TODO: be meaner"
;; Check snippet expansion, ignore leading whitespace due to
;; `org-edit-src-content-indentation'.
(should (looking-at "\
[[:space:]]*one one
[[:space:]]*two two
[[:space:]]*<<>> done!")))))))
\[[:space:]]*one one
\[[:space:]]*two two
\[[:space:]]*<<>> done!")))))))
(ert-deftest test-yas-activate-extra-modes ()
@ -1548,7 +1757,7 @@ add the snippets associated with the given mode."
("car" . "(car )"))))
(yas-reload-all)
(emacs-lisp-mode)
(yas-minor-mode-on)
(yas-minor-mode +1)
(yas-activate-extra-mode 'markdown-mode)
(should (eq 'markdown-mode (car yas--extra-modes)))
(yas-should-expand '(("_" . "_Text_ ")))

File diff suppressed because it is too large Load Diff