LuaSnip
LuaSnip copied to clipboard
modify `ls.available()` to include each snippets origin file path.
Discussed in https://github.com/L3MON4D3/LuaSnip/discussions/716
Originally posted by molleweide January 6, 2023
(I tried the "transfer" feature and assumed that the existing discussion would be removed...)
Proposed solution
After digging in the source a little bit I am thinking that the appropriate way to go about this would be
- Attach the
origin_file_pathto each snippet when loading files withload_files(ft, files)fromluasnip/loaders/from_lua.lua. - Update the
luasnip/init.luafuncget_context()so that it also grabs the path of each snip. - Modify the available function to mean "available in a broader sense".
local function available(ft:<string|table>) -- ft could be either a string or a table. -- 1. if ft == nil, then do the exact same as current `available()` and deprecate the available function. -- 2. if ft == string, retrieve snips for this specific file type. -- 3. if ft == table, then return all snippets for the containing filetypes. - optionally, also do this same procedure for
snipmate, andvscodeas well.
With these three additions it would be possible to extend the existing telescope-luasnip extension repo to become a CRUD manager. I also have some more ideas for the picker that would make life easier, eg. add snippet to new filetype and then create all of the boilerplate in your default luasnippets path for a new filetype.
If @L3MON4D3 if you agree with my proposed solution I will make a PR for this. This should NOT introduce any breaking changes.
(I tried the "transfer" feature and assumed that the existing discussion would be removed...)
No worries, I'll leave a comment to redirect here :D
I think that's a pretty cool usecase, we already have open-by-filetype, open-by-snippet is a slick addition.
But! I would propose to implement this by adding source (or metadata, for arbritary data, and add a config-option for what is put in there) as a key to add_snippets, this would make it more versatile (can also be done if a snippets is added via add_snippets).
Not sure what you are thinking of with attaching the source to the snippet, but I'd rather not include metadata inside the snippet itself. I think a table mapping snippet-id -> source/metadata+ a function to retrieve that should do it.
Creating the boilerplate could be done by passing extend in edit_snippet_files's opts, which is pretty elegant imo, but similar functionality can be added to telescope-luasnip, if that fits your workflow better :D
Thanks for appreciating my idea!!
jump-to-snip
I think that's a pretty cool usecase, we already have open-by-filetype, open-by-snippet is a slick addition.
Yeah right, feels like we could reduce the number of keystrokes for getting to any snippet by 10 - 25 keystrokes or even more in some cases with my crud idea described below.
But! I would propose to implement this by adding
source(ormetadata, for arbritary data, and add a config-option for what is put in there) as a key toadd_snippets, this would make it more versatile (can also be done if a snippets is added viaadd_snippets).
Aaah yes, I see what you mean. This was excellent advice.
Not sure what you are thinking of with attaching the source to the snippet, but I'd rather not include metadata inside the snippet itself. I think a table mapping
snippet-id -> source/metadata+ a function to retrieve that should do it.
This was a hack for my own picker because I did not understand how to get the loaders to work properly at first. I just made a custom loader and did `snippet["origin_file_path"] = ..." but using a id/source mapping is smarter.
I did not succeed in getting the builtin loader working properly for myself at first, so I never experienced the ui.select flow to edit but this was very nice now that it worked for me.
Creating the boilerplate could be done by passing
extendinedit_snippet_files'sopts, which is pretty elegant imo, but similar functionality can be added totelescope-luasnip, if that fits your workflow better :D
Ohh shit, this made me realise that my local fork was quite an old commit so I pulled latest just now...
mappings
The solution should ofc work regardless of telescope . If you have the completion menu open or even if you are within an active snippet, we could have an insert mode mapping that (rolls back the snippet and) exits to normal mode and opens up the current snippet in a split or something.
crud (brainstorming)
When the jump-to-snip feature is working, what do you think about having something like utils/crud.lua OR manage.lua where we could put all functions related to managing single snippets. Eg.:
- jump to snip
- remove snip
- update -> eg. you make a bind for updateing the trig or descr and then move cursor and enter insert with treesitter etc.
Basically make a comprehensive manager function that allows you to jump specifically to any node within a snippet instantly and then take it from there with whatever user
optsor configs in order to reduce keystrokes as much as possible.
In telescope or insert mode we could have:
<C-u><C-t>jump to trig string -<C-u><C-i>jump to first insert node etc. so that we achieve a super fine grained control of jumping to snip.
progress so far
https://github.com/molleweide/LuaSnip/commits/molleweide
updated solution / summary
- update
add_snippets()with id/source key value pair. DONE! - add new
retrieve_source_from_snippet()function DONE! - update
edit_snippets_file()to take an optional snippet argument and then handle thejump-to-snipaccordingly in this function. DONE! - find snip by
snip.nameDONE! - add
cmp / if ls.active_snipmapping that allows you to jump-to-snip without telescope. -> I realise that this might be outside of the scope of luasnip and up for each users config, right? BUT if I get this to work I could add the config to wiki or something. - extend the existing
telescope-luasniprepo with a hook to the above. - add comprehensive crud stuff with treesitter.
question
if data.name then
local feed_str = vim.api.nvim_replace_termcodes("/"..data.name.."<CR>", true, true, true)
vim.fn.feedkeys(feed_str, "n")
end
I used this rather hacky method for moving cursor to the snippet location. Do you have a better/preferred suggestion for moving the cursor? As I mentionned above my intention is to use treesitter and query the file later in order to get more details from the code but now I have to take a break.
treesitter idea / crud api
1. require ts
2. local snip_tree = query for snippet containing name or trig string
3. depending on which mapping was used filter out required subcomponent.
4. create some api funcs
- move cursor to snip
- add new snippet to same snip file as selected and expand template snip.
- remove snip
- move snip from snip file A to B (not super important lol)
- move cursor to snip node N
- if has `fmt()` move cursor to format string
Which would be the most useful ones? Do you have any additional ideas you'd like?
Considering the amount of data, should the "storing metadata" part be opt-in?
Considering the amount of data, should the "storing metadata" part be opt-in?
Good idea, and maybe one could also configure which specific dirs to add source maps for.
I guess one way to reduce amount of data would be to store snippets by source path as a subtable within each ft table, but this might introduce a breaking changes (right, or would it??) but it could be an interesting idea. EDIT. Hmm nah bc it wouldn't solve the jump to snip issue anyways I believe.
snippets -> {ft = {["path1"] = { snips... }}}
The solution should ofc work regardless of telescope . If you have the completion menu open or even if you are within an active snippet, we could have an insert mode mapping that (rolls back the snippet and) exits to normal mode and opens up the current snippet in a split or something.
Right, delete faulty snippet -> edit source of snippet sounds like a good workflow :+1:
crud (brainstorming)
When the
jump-to-snipfeature is working, what do you think about having something likeutils/crud.lua OR manage.luawhere we could put all functions related to managing single snippets. Eg.:
- jump to snip
- remove snip
- update -> eg. you make a bind for updateing the trig or descr and then move cursor and enter insert with treesitter etc. Basically make a comprehensive manager function that allows you to jump specifically to any node within a snippet instantly and then take it from there with whatever user
optsor configs in order to reduce keystrokes as much as possible.In telescope or insert mode we could have:
<C-u><C-t>jump to trig string -<C-u><C-i>jump to first insert node etc. so that we achieve a super fine grained control of jumping to snip.
I don't think it's worth it to reduce keystrokes beyond moving the cursor onto the line where the snippet is defined. Stuff like remove/updating some part of a snippet seems too specific to me.
treesitter idea / crud api
1. require ts 2. local snip_tree = query for snippet containing name or trig string 3. depending on which mapping was used filter out required subcomponent. 4. create some api funcs - move cursor to snip - add new snippet to same snip file as selected and expand template snip. - remove snip - move snip from snip file A to B (not super important lol) - move cursor to snip node N - if has `fmt()` move cursor to format stringWhich would be the most useful ones? Do you have any additional ideas you'd like?
Same as above, anything beyond finding where the snippet is defined seems too granular. But, if you want to implement this, don't let my opinion stop you :D I'm not convinced it's useful, but maybe my workflow is just different from yours
Considering the amount of data, should the "storing metadata" part be opt-in?
Right, yes, it probably should. I'm thinking of adding a config-option loader_snip_metadata (name WIP xD) which takes a table like {lua = ..., vscode = ..., snipmate = ...}, and ... are functions which get as much data as a loader can provide (only the file I think), and generate the metatdata that should be attached to its snippets. By default function() return nil end such that nothing is stored, we could, as usual :D, provide some sensible defaults in luasnip.extras. This would also cover excluding some dirs.
How to store it, yeah, that's a question.. Most straightforward would be snip_id -> metadata, but that might be a bit too wasteful. Perhaps snip_id -> metadata_id -> metadata?
I'm not convinced it's useful,
Lol, me neither. I consider this RnD. Now that I got the jump to snip functionality to work I feel pretty much satisfied because it is very fast (and fast enough..). However, I might play around with my picker and see what happens. Just like you say, it is stupid to over optimise etc. so we'll see what happens maybe some patterns arise that become useful. Also, I'm less experienced as a coder/luasnipper so I really need to consult with you before I spend time on something really stupid. Now I also need to get deeper in general with luasnip so that I don't accidentally reinvent any wheels.
Anyways, I'm thinking that now I'll
- add a config option for my solution that defaults as
false(opt-in), - add this option to the docs,
- and then I'll submit the PR so that we can have this solution working for now until we implement something smarter in the future.
Does this sound good?
Lol, me neither. I consider this RnD
Ah, alright xD Go ahead then :D
Does this sound good?
Yeup :+1: I'll wait for your PR and then take a closer look at the implementation
One more idea: make it possible to attach more metadata to the snippets. But for now, it should be enough to have one metatdata-entry per add_snippets-call, and then point all snippets to that
PR submitted.
make it possible to attach more metadata to the snippets.
I believe that my implementation makes this possible but might need minor changes. I created a table { source = path} for each add_snippets call and then point each snip to this table.
Here is a link to my custom picker: https://github.com/molleweide/doom-nvim/blob/merging-doom-neovim/lua/doom/modules/features/extra_snippets/pickers.lua
And my mappings for calling the picker fyi: https://github.com/molleweide/doom-nvim/blob/7f67e56d3517a1aa1f66f82bf81e04217f22cdf8/lua/doom/modules/features/extra_snippets/init.lua#L177
Right,
delete faulty snippet -> edit source of snippetsounds like a good workflow 👍
Next step would be to implement this now, and also maybe if the cmp menu is open make it possible to edit snip from there instead of expanding.