Releases: L3MON4D3/LuaSnip
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_dofile
or a package vials_tracked_dopackage
to 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
desc
to 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_env
by 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_filter
toedit_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
1.0.0
We're doing versioning now!! :D
The current plan is adhering closely to semver, although just vMajor.Minor.Patch
This means that there's now an easy way to prevent surprise-breaking changes: configure your package manager to stick to some version (or version matching a pattern), and manually update this version once you're comfortable:
For packer
, this means
use({"L3MON4D3/LuaSnip", tag = "v<CurrentMajor>.*"})
and for vim-plug
Plug 'L3MON4D3/LuaSnip', {'tag': 'v<CurrentMajor>.*'}
The above examples will update when a new minor or patch version becomes available, but not when the major changes (this is my recommendation, it will prevent breaking changes from suddenly messing up your config).
Of course, following the minor, or even the patch is also an option.
I recommend watching releases so you're aware of new stuff (all the way at the top watch -> custom -> releases
)
That's all, until the next release 👋 (hopefully not 2.0.0 :D)