Bot releases are visible (Hide)
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}})})
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.
Full Changelog: https://github.com/L3MON4D3/LuaSnip/compare/v2.2.0...v2.3.0
And, as always, a big Thank You to all new and recurring contributors ❤️
Published by L3MON4D3 10 months ago
The implementation of the loaders was greatly refactored, and there are a few new features:
fs_event_providers = {libuv=true}
to the load
-call, like sorequire("luasnip.loaders.from_lua").lazy_load({paths = "./luasnippets", fs_event_providers = {libuv=true}})
lazy_paths
-key in load
: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)
ls_tracked_dofile
or a package via ls_tracked_dopackage
to make use of this.All of these features are also documented in DOC.md
, take a look for more details.
A hearty Thank You! to all contributors :)
Full Changelog: https://github.com/L3MON4D3/LuaSnip/compare/v2.1.1...v2.2.0
Published by L3MON4D3 11 months ago
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: https://github.com/L3MON4D3/LuaSnip/compare/v2.1.0...v2.1.1
Published by L3MON4D3 11 months ago
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.
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)
https://github.com/L3MON4D3/LuaSnip/assets/41961280/7dea57aa-17da-4ce4-b0cd-d214d6b30e93
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.
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.
Finally, luasnip is now available as a luarock, which means it can be added by rocks.nvim
.
desc
to set snippet description by @bew in https://github.com/L3MON4D3/LuaSnip/pull/1005
A big Thank You! to all contributors to LuaSnip ❤️ :)
Full Changelog: https://github.com/L3MON4D3/LuaSnip/compare/v2.0.0...v2.1.0
Published by L3MON4D3 over 1 year ago
Drop support for neovim < 0.7.
Since this probably affects very few users, and enables access to some better api, this decision was obvious.
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.
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, {})
https://github.com/L3MON4D3/LuaSnip/assets/41961280/8b1c3c22-76bb-4f6f-aabe-e1eb1527e3fd
To work correctly for all loaders, this needs treesitter
, and parsers for json (jsonc if there are snippet-files in that format) and lua.
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.
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.
snip_env
by default. by @L3MON4D3 in https://github.com/L3MON4D3/LuaSnip/pull/765
ft_filter
to edit_snippet_filetypes
(close #635). by @L3MON4D3 in https://github.com/L3MON4D3/LuaSnip/pull/812
expand_or_locally_jumpable()
checks the next node by @loichyan in https://github.com/L3MON4D3/LuaSnip/pull/860
Full Changelog: https://github.com/L3MON4D3/LuaSnip/compare/v1.2.1...v1.3
Published by L3MON4D3 over 1 year ago
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?? 🤷)
See #746 and d191820
Full Changelog: https://github.com/L3MON4D3/LuaSnip/compare/v1.2.0...v1.2.1
Published by L3MON4D3 over 1 year ago
None :)
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 @pianocomposer321edit_snippet_files
can be used to quickly jump to any file contributing snippets to the current file.
Before 61238b9e0ef, 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).
fmt
, by @uyhaThis 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-snippetsUp until now, we had not implemented these transformations. As long as jsregexp
is installed, these will behave exactly like they do in vscode.
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.
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.
Thanks, all of you :)
Full Changelog: https://github.com/L3MON4D3/LuaSnip/compare/v1.1.0...v1.2.0
Published by L3MON4D3 about 2 years ago
extras.expand_conditions
See here
Necessitated by the subsequently introduced condition-objects
.
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!! 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
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!)
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!
Full Changelog: https://github.com/L3MON4D3/LuaSnip/compare/v1.0.0...v1.1.0
Published by L3MON4D3 about 2 years ago
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)