Releases: L3MON4D3/LuaSnip
v2.4.1
This is a relatively minor release, and it is made now because I intend to have a release immediately before merging #1137, which contains many changes to LuaSnip's internals.
This release contains an important performance-improvement, improvements to the Makefile (courtesy of, as usual, @xudyang1, and newly, @GR3YH4TT3R93 🙏), and an update to the bundled jsregexp, which is now supported up to version 0.1.0.
Minor Improvements
- #1345 documents a strategy for getting good
lua-language-serversupport for snippet-files. I highly recommend setting this up if much of your time is spent editing snippets :) - 10092a5 updates the
jsregexpincluded in luasnip (via git-submodule) to0.1.0(we still support all versions that were ever shipped with luasnip, so there's no pressing need to rebuild it) - 21e9fec drastically reduces runtime of
match_snippet, which, if autosnippets are enabled, is called on every keystroke. The credit here goes to @Bekaboo, who investigated this in #1393 - 831a130 makes the vscode-loader respect the
scope-directive only when called viaload_standalone. This could cause missing snippets if a snippet-collection relied on this (as I understand it) non-standard behaviour.
New Contributors
- @MariaSolOs made their first contribution in #1348
- @GR3YH4TT3R93 made their first contribution in #1383
- @derekthecool made their first contribution in #1395
A big Thank You to all old and new contributors ❤️
Full Changelog: v2.4.0...v2.5.0
v2.4.0
Highlights
Fix behaviour in macro-replay (#1247)
While probably not the flashiest change, this makes sure that snippets are replayed correctly in macros (:h macro).
1729689447.mp4
Minor improvements/additions
- #1162 (by @gokberkgunes) introduces the
exit_rootsoption, which, if enabled, makes it impossible to jump back into a snippet once the final tabstop is reached. - #1175 (by @leiserfg) disambiguates treesitter-languages and filetypes. This is relevant with e.g.
latexandtex. - #1180, #1252, #1255, #1282 (by @xudyang1) provide fixes and improve the Makefile for Luasnip on Windows.
- #1211 (by @Vanillma) improves the syntax and ftplugin files for
snipmatefiles. - #1209 (by me :) ) provides API for customising the mappings that populate the
TM_SELECTED_TEXTand related variables (see #1208 for more concrete motivation). - #1231 (by @Diegovsky) improves the log-format with timestamps.
- #1240 (by @Bekaboo) fixes the behaviour of the
max_lenoption for snippets. - #1264 (by @xudyang1) makes it easy to insert real tabs in snippets generated with
fmt. - #1318 (by @bew) lays the groundwork for better lsp-completion and doc for luasnip. Track #1025 for progress on this.
- #1338 (by me!) fixes luasnips usage of the deprecated format of
vim.validate. - 726062b removes an unnecessary redraw, which leads to less flickering!
New Contributors
- @gokberkgunes made their first contribution in #1162
- @xudyang1 made their first contribution in #1180
- @OkelleyDevelopment made their first contribution in #1188
- @raffaem made their first contribution in #1192
- @stroiman made their first contribution in #1198
- @mcustiel made their first contribution in #1201
- @Vanillma made their first contribution in #1211
- @apgrc made their first contribution in #1225
- @Diegovsky made their first contribution in #1231
- @gevhaz made their first contribution in #1239
- @heit0r made their first contribution in #1265
- @caleskog made their first contribution in #1279
- @michaelfortunato made their first contribution in #1288
Thank you to all new and old contributors ❤️!
I'd especially like to highlight @xudyang1, who has done a great job supporting luasnip on windows, Thank You very much!!
Full Changelog: v2.3.0...v2.4.0
v2.3.0
2.3.0
Highlights
Easier event-callbacks (#1092)
Before this change, event-callbacks for some node had to be defined in the snippet/snippetNode that contained it.
Since that is cumbersome, it's now possible to define them in the node-opts:
s("qwer", {t' ', i(1, "asdf", {node_callbacks = {[events.enter] = function() print("enter!!!") end}})})Healthcheck (#1149)
LuaSnip now checks if jsregexp is in working order when :checkhealth is performed.
Try it, but keep in mind that jsregexp is fully optional, and not necessarily required.
New Contributors
- @polirritmico made their first contribution in #1135
- @znd4 made their first contribution in #1149
Full Changelog: v2.2.0...v2.3.0
And, as always, a big Thank You to all new and recurring contributors ❤️
2.2.0
Highlights
Overhaul of vscode/snipmate/lua-loaders
The implementation of the loaders was greatly refactored, and there are a few new features:
- We can now reload files when they are updated in another neovim-instance/in some other editor (via libuv).
This can be enabled by passingfs_event_providers = {libuv=true}to theload-call, like so
require("luasnip.loaders.from_lua").lazy_load({paths = "./luasnippets", fs_event_providers = {libuv=true}})- Files that are created after the load-call will be loaded (which was not the case previously)
- Similarly to the above, it is also possible to "register" a snippet-collection for loading as soon as it is created.
To enable this for some collection, pass it to thelazy_paths-key inload:
require("luasnip.loaders.from_lua").load({lazy_paths = ".luasnippets"})(this example is especially useful since it will load a snippet-collection in the current directory, which could be a project-specific one)
- The lua-loader may define dependencies on files, such that the snippet-files that depend on some file will be reloaded when the file is edited. Load a file via
ls_tracked_dofileor a package vials_tracked_dopackageto make use of this.
All of these features are also documented in DOC.md, take a look for more details.
What's Changed
- Use libuv-file-watcher to update loaded snippet-collections. by @L3MON4D3 in #1033
- add option to skip indent nodes by @TwIStOy in #1072
- feat(builtin): support vscode snippet variable CURRENT_TIMEZONE_OFFSET by @masakichi in #1091
- Minor DOC.md modifications for panvimdoc lists by @Ote-Leo in #1097
- Add quotes to jsregexp make commands by @louis-vs in #1099
New Contributors
- @masakichi made their first contribution in #1091
- @Ote-Leo made their first contribution in #1097
- @louis-vs made their first contribution in #1099
A hearty Thank You! to all contributors :)
Full Changelog: v2.1.1...v2.2.0
2.1.1
Very minor release, the only changes to the previous release are a few small bugfixes and support for jsregexp 0.0.6 in addition to 0.0.5.
Full Changelog: v2.1.0...v2.1.1
2.1.0
Deprecations and Breaking Changes
Only a deprecation in this release: the history-option is superseded by the more granular keep_roots, link_roots, and link_children. Take a look at the documentation for more information on the new options.
Highlights
Snippet-insertion (#941)
Before this PR, a newly-expanded snippet was always set up such that after jumping through it, the node that was active during expansion was entered again. This was very easy to implement, but unfortunately can cause annoying issues when the active node is not close to the expanded snippet (jumping across the whole buffer).
The improved snippet-insertion prevents issues like this by linking the jumps of newly-expanded snippets not based on active node, but based on buffer-position. There is some information on it here.
The following recording shows the new behaviour, for example how snippets are traversed based on buffer-position, and how inserting snippets into a node properly activates it (visible due to orange dots indicating an active choiceNode)
1699875457.mp4
Another nice feature enabled by the datastructures that have to be maintained to allow this behaviour is that given some buffer-position (for example the cursor), we can look for the node that is located there. See this entry in the wiki for an example of this.
Treesitter-postfix (#980)
Another pretty cool feature: where previously postfix-snippets could only capture text matching some pattern, treesitter-postfix-snippets can capture text from treesitter-queries!
Since captures from the query are also made available to the snippet (via snippet.env), this may be a quick way to quickly refactor, see for example the following:
ts_post({ matchTSNode = { query = [[ (function_declaration name: (identifier) @fname parameters: (parameters) @params body: (block) @body ) @prefix ]], query_lang = "lua", }, trig = ".var" }, fmt([[ local {} = function{} {} end ]], { l(l.LS_TSCAPTURE_FNAME), l(l.LS_TSCAPTURE_PARAMS), l(l.LS_TSCAPTURE_BODY), }))
The documentation has another example, and describes the various options.
Luasnip-Luarock (#1050)
Finally, luasnip is now available as a luarock, which means it can be added by rocks.nvim.
What's Changed
- fix: catch undocumented edge case in scandir() by @troiganto in #966
- docs: fix snip-env-src by @b0ae989c in #975
- Update DOC.md Troubleshooting section by @kylefhartzenberg in #981
- feat: Allow
descto set snippet description by @bew in #1005 - [WIP] Treesitter-postfix Support by @TwIStOy in #980
- Add nil for type opt for parse_snippet by @philolo1 in #1016
- Fix lazy install tag in README.md by @pockethook in #1024
- Improve snippet-insertion. by @L3MON4D3 in #941
- Fix links to DOC.md in README.md by @treequin in #1043
- Use event.buf directly to get bufnr by @xu-cheng in #1047
- Consistent backtick use by @Stevenjin8 in #1054
- Use builtin methods for getting selection. by @L3MON4D3 in #1013
- feat: publish tagged releases to luarocks by @mrcjkb in #1050
New Contributors
- @troiganto made their first contribution in #966
- @b0ae989c made their first contribution in #975
- @kylefhartzenberg made their first contribution in #981
- @bew made their first contribution in #1005
- @TwIStOy made their first contribution in #980
- @philolo1 made their first contribution in #1016
- @pockethook made their first contribution in #1024
- @treequin made their first contribution in #1043
- @xu-cheng made their first contribution in #1047
- @Stevenjin8 made their first contribution in #1054
- @mrcjkb made their first contribution in #1050
A big Thank You! to all contributors to LuaSnip ❤️ :)
Full Changelog: v2.0.0...v2.1.0
2.0.0
Breaking Changes
Drop support for neovim < 0.7.
Since this probably affects very few users, and enables access to some better api, this decision was obvious.
Highlights
Multi-Context snippets
This essentially makes it possible to trigger one snippet in different ways. For example, one may want to trigger a snippet with a short trigger manually, but use a longer one as an autotrigger. Or, expand a snippet automatically in comments, and manually otherwise (or, and maybe more likely, vice versa).
The DOC.md-entry is pretty comprehensive, so I won't repeat it here.
Snippet-Source
If loaders_store_source is set to true in ls.setup, the loaders will attach information about the source of a snippet (like file, row, column of its definition).
We of course also include a consumer for this information: luasnip.extras.snip_location can jump to the source of the current snippet!
Combined with auto-reload provided by the loaders, this allows quick edits of the current snippet, for example if it does not behave correctly.
For easy access, create a command for calling the function.
vim.api.nvim_create_user_command("LuaSnipEditS", require("luasnip.extras.snip_location").jump_to_active_snippet, {})1689692600.mp4
To work correctly for all loaders, this needs treesitter, and parsers for json (jsonc if there are snippet-files in that format) and lua.
Key-indexer
This can be used to easily refer to nodes (for example, if their text should be passed to a dynamic/functionNode) several levels deep in a snippet, simply by a unique identifier. Once again, the documentation has some details+examples.
.code-snippets
Support for the .code-snippets-format used by vscode was also added since the last release. It is useful for project-specific snippets, and a bit more compact than the other formats, since only a single file has to be added, not a directory (and god forbid, not a package.json which has to correctly list all files).
More here.
More trigger-types!!
Finally, support for actual regexes as snippet-triggers. Supports ecma and vim-flavoured regex, as well as completely custom behaviour. The documentation (look for the trigEngine-entry in the first list) has some more details.
PR's since last release:
- Move config reference to DOC.md, update links by @runiq in #755
- Update New User Resources on README + Proofread by @evesdropper in #763
- Extend default
snip_envby default. by @L3MON4D3 in #765 - refactor with some newer apis by @max397574 in #777
- Remove vim.fn.json fallbacks by @leiserfg in #778
- Get destination-node of next jump (close #676) by @L3MON4D3 in #740
- Prefer vim.filetype.add over ftdetect scripts by @leiserfg in #782
- Optionally use lua-jsonc parser for parsing vscode-snippets. by @L3MON4D3 in #783
- Multi-context-snippets by @L3MON4D3 in #774
- Fix a loader bug: from_lua by @dwainm in #820
- add
ft_filtertoedit_snippet_filetypes(close #635). by @L3MON4D3 in #812 - Reformat doc a bit by @L3MON4D3 in #808
- Parameterise LuaJIT path on OSX by @giang-nghg in #824
- Add nix support to Makefile by @chuwy in #842
- fix:
expand_or_locally_jumpable()checks the next node by @loichyan in #860 - delete has_selected_text.lua + move contents to show.lua by @JxJxxJxJ in #849
- fix(makefile):compile jsregexp with luajit installed by linuxbrew by @menghuu in #861
- doc: mention MacOS Makefile variable for jsregexp by @fejzuli in #866
- Adding comments in installation examples by @Curs3W4ll in #863
- Generate source for loaded snippets. by @L3MON4D3 in #826
- fix: vim.pretty_print is deprecated (^neovim-0.9.0) by @ssayin in #880
- fix(docs): type annotation can by nil by @kunzaatko in #889
- Keyed nodes by @L3MON4D3 in #838
- Improve rgrav-adjustments by @L3MON4D3 in #852
- feat: add default condition for postfix by @MunifTanjim in #898
- Several improvements. by @L3MON4D3 in #906
- fix: use relative url for submodule definition (#911) by @gongfarmer in #912
- Merge multi-snippet common field, fix #921 by @Bekaboo in #924
- refactor: don't load modules in lazy_load until they are needed by @stasjok in #926
- fix: remove debug print by @stasjok in #930
- Implement more trigger-types by @L3MON4D3 in #923
- Subtraction for condition objects by @bhataktaBhai in #945
- fix: install jsregexp by @henryhchchc in #960
Big Thank You! to all new contributors :)
- @runiq made their first contribution in #755
- @evesdropper made their first contribution in #763
- @max397574 made their first contribution in #777
- @dwainm made their first contribution in #820
- @giang-nghg made their first contribution in #824
- @chuwy made their first contribution in #842
- @loichyan made their first contribution in #860
- @JxJxxJxJ made their first contribution in #849
- @menghuu made their first contribution in #861
- @fejzuli made their first contribution in #866
- @Curs3W4ll made their first contribution in #863
- @ssayin made their first contribution in #880
- @MunifTanjim made their first contribution in #898
- @gongfarmer made their first contribution in #912
- @Bekaboo made their first contribution in #924
- @stasjok made their first contribution in #926
- @bhataktaBhai made their first contribution in #945
- @henryhchchc made their first contribution in #960
Full Changelog: v1.2.1...v1.3
1.2.1
Very minor release:
The difference to 1.2.0 is only a fix for an off-by-one-error in the lsp-snippets, which causes a large amount of possible transformations to fail (but hasn't come up until now, so not-so-common?? 🤷)
Full Changelog: v1.2.0...v1.2.1
1.2.0
Deprecations & Breaking Changes
None :)
New Features
ls_file_snippets and ls_file_autosnippets
Up until now the snippets loaded by the lua-loader had to be returned in a big list at the end of the files. This prevents defining functions used in those snippets near them (at least if they are defined naively), and generally makes these files less readable.
Now, the tables ls_file_snippets and ls_file_autosnippets exposed (additionally!), and snippets can be added to them and don't have to be returned at the end of the files.
To really make use of this, adding something like
ls.setup({ snip_env = { s = function(...) local snip = ls.s(...) -- we can't just access the global `ls_file_snippets`, since it will be -- resolved in the environment of the scope in which it was defined. table.insert(getfenv(2).ls_file_snippets, snip) end, parse = function(...) local snip = ls.parser.parse_snippet(...) table.insert(getfenv(2).ls_file_snippets, snip) end, -- remaining definitions. ... }, ... })makes s and parse automatically add the snippets defined with them.
edit_snippet_files: extend-option, by @pianocomposer321
edit_snippet_files can be used to quickly jump to any file contributing snippets to the current file.
Before 61238b9, it was only possible to select an already-existing file, after it, it's possible to add some custom logic to extend the list of found files arbritarily.
A great application of this is the possibility of adding a new file in known snippet-collections:
-- loaded collections. local snippet_collections = { -- lua-snippets { dir = "/home/simon/.config/nvim/luasnippets", extension = "lua" }, -- snipmate-snippets -- this would edit snippets provided by vim-snippets. { dir = "/home/simon/.local/share/nvim/site/pack/packer/start/vim-snippets/snippets/", extension = "snippets" } -- vscode would be much more involved, if you figure something out, showcase -- it in a discussion :D } require("luasnip.loaders").edit_snippet_files({ extend = function(ft, files) local extend_items = {} for _, collection in ipairs(snippet_collections) do -- check if a file from the collection is present in the items -- already. for _, file in ipairs(files) do if file:match(collection.dir) then -- a file is in personal_dir, no need to create a new file there. goto continue end end -- not present, create item to add this file. table.insert(extend_items, { -- label of the new file. "New file in " .. collection.dir, -- location of the new file. ("%s/%s.%s"):format(collection.dir, ft, collection.extension)}) -- luajit only!! :: continue :: end return extend_items end })(The doc-entry contains a simpler example, and a proper definition of the option).
Repeat nodes automatically in fmt, by @uyha
This can be used to make snippets created with fmt more readable, by repeating nodes belonging to duplicated keys.
s("fmt", fmt([[ This {iNode} will be repeated here {iNode} ]], { iNode = i(1) }, {repeat_duplicates = true}))repeat_duplicates is false by defaults, use extend_decorator to override this default if you prefer this behaviour to failing.
pascalcase and camelcase for lsp-snippets
Up until now, we had not implemented these transformations. As long as jsregexp is installed, these will behave exactly like they do in vscode.
Logging
Luasnip now has some logging in place! This is especially useful to quickly find misconfigurations with the loaders, so definitely give it a shot. Some more details in the doc.
Pretty display of available snippets, by @lyonelz96
Opens a buffer with a pretty display of all available snippets. Very configurable!
The doc contains an extensive overview of what is possible with this. So far, there is only one pretty static way to show the available snippets in a buffer, enhancing this to create a tree-like view of all snippets would be a nice extension.
New Contributors
- @pianocomposer321 made their first contribution in #502
- @Samasaur1 made their first contribution in #645
- @tomtomjhj made their first contribution in #658
- @mrzzy made their first contribution in #666
- @Andrew15-5 made their first contribution in #679
- @uyha made their first contribution in #665
- @dheimgartner made their first contribution in #683
- @lyonelz96 made their first contribution in #652
- @bootleq made their first contribution in #727
- @Prince213 made their first contribution in #734
Thanks, all of you :)
Full Changelog: v1.1.0...v1.2.0
1.1.0
Deprecations
extras.expand_conditions
See here
Necessitated by the subsequently introduced condition-objects.
Notable additions
Autotrigger-option for individual snippets (by @atticus-sullivan)
Previously the autotriggered-feature for a snippet could only (somewhat implicitly) be specified when adding snippets (add_snippets(..., {type = "autosnippets"}) or put the snippet into the second table returned by lua-loader-loaded files). This was originally due to a limitation (snippets had to be assigned to different tables ls.snippets or ls.autosnippets, as the OGs will remember :P) which has not existed for a while, and now we finally make use of its removal.
Basically:
ls.add_snippets("all", { s({trig = "trig", snippetType = "autosnippet"}, { t"autotriggerd" }) })Will add the autotriggered snippet, without passing additional parameters to s.
For extra style, one may
local autosnippet = ls.extend_decorator.apply(s, {snippetType = "autosnippet"})so autotriggered snippets can be easily created with autosnippet.
The old ways of creating autosnippets are still present, and not deprecated, so for adding bigger collections of snippets as autosnippets, they can be used as well.
Condition-objects (by @atticus-sullivan)
Condition-objects!! They are useful for combining multiple conditions into logical expressions:
-- two show-conditions local function even_line() -- omitted end local function line_end() -- omitted end -- without condition-objects: s( -- omitted { show_condition = function(...) return even_line(...) and line_end(...) end -- show-conditions can also be passed to `condition`! condition = function(...) return even_line(...) and line_end(...) end, }) -- with condition-objects: local make_condition = require("luasnip.extras.conditions").make_condition local even_line_obj = make_condition(even_line) local end_line_obj = make_condition(end_line) s( -- omitted { -- "*" for `and` show_condition = even_line_obj * line_end_obj condition = even_line_obj * line_end_obj })Much more readable!
There are more details in the doc
Big Documentation overhaul (by me!)
The doc is now much more coherent and detailed, and concepts like jump-index
(i(1) <- that number) and node-reference (f(somefunction, {1,2}) <- those
numbers) are properly explained (and consistenly named!)
Readme (by @ejmastnak)
This is a smaller addition, but important nonetheless: The readme now
contains an improved Getting Started-section, and a section for external
resources (Videos, blogs, articles, anything really) on luasnip. Feel free to extend it!
Smaller additions
- feat: Add new locally_jumpable(direction) function by @mike325 in #587
- feat: add new built-in condition for line ending by @weilbith in #597
- fix typo emtpy to empty by @ecerulm in #601
- fix(snipmate): correctly escape backtick by @danilshvalov in #604
- doc: fix tiny typo its' -> its by @ejmastnak in #609
- Return a better error when from_lua loader fails by @robertgzr in #610
- Give a valid exmple for loaders.from_lua by @YuanYuYuan in #620
Full Changelog: v1.0.0...v1.1.0