Skip to content

Releases: L3MON4D3/LuaSnip

v2.4.1

03 Nov 22:56

Choose a tag to compare

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-server support for snippet-files. I highly recommend setting this up if much of your time is spent editing snippets :)
  • 10092a5 updates the jsregexp included in luasnip (via git-submodule) to 0.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 via load_standalone. This could cause missing snippets if a snippet-collection relied on this (as I understand it) non-standard behaviour.

New Contributors

A big Thank You to all old and new contributors ❤️

Full Changelog: v2.4.0...v2.5.0

v2.4.0

08 May 11:40

Choose a tag to compare

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_roots option, 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. latex and tex.
  • #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 snipmate files.
  • #1209 (by me :) ) provides API for customising the mappings that populate the TM_SELECTED_TEXT and 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_len option 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

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

16 Apr 18:34

Choose a tag to compare

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

Full Changelog: v2.2.0...v2.3.0

And, as always, a big Thank You to all new and recurring contributors ❤️

2.2.0

31 Dec 12:25

Choose a tag to compare

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 passing fs_event_providers = {libuv=true} to the load-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 the 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)

  • 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 via ls_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

A hearty Thank You! to all contributors :)

Full Changelog: v2.1.1...v2.2.0

2.1.1

01 Dec 21:09

Choose a tag to compare

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

13 Nov 12:08

Choose a tag to compare

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

New Contributors

A big Thank You! to all contributors to LuaSnip ❤️ :)

Full Changelog: v2.0.0...v2.1.0

2.0.0

18 Jul 15:33

Choose a tag to compare

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.

More details here and here

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:

Big Thank You! to all new contributors :)

Full Changelog: v1.2.1...v1.3

1.2.1

27 Jan 09:59

Choose a tag to compare

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: v1.2.0...v1.2.1

1.2.0

26 Jan 19:27

Choose a tag to compare

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

Thanks, all of you :)

Full Changelog: v1.1.0...v1.2.0

1.1.0

13 Oct 16:59
563827f

Choose a tag to compare

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

Full Changelog: v1.0.0...v1.1.0