Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snippet priority and visibility in nvim-cmp #267

Closed
apmyplol opened this issue Jan 18, 2022 · 7 comments
Closed

Snippet priority and visibility in nvim-cmp #267

apmyplol opened this issue Jan 18, 2022 · 7 comments

Comments

@apmyplol
Copy link

First of all thanks for the really great plugin!
Im in the middle of switching to neovim and Im loving it because there are so many awesome plugins, including this one.

I would like to know how Luasnip chooses which snippet to expand when there are multiple snippets that could be expanded. In particular I would like to know whether there is a way to prioritize snippets loaded from vscode style json files over regex snippets.
For example I have a couple of snippets for tex and markdown in vscode style like in -> \in.
I also created some regex snippets and one of them is a choice snippets which expands letters and numbers followed by d, i, k or n, like for example 5n or blak to 5^n OR 5_n / bla^k OR bla_k.
This collides with some snippets, one of them being in -> \in. Is there a way to fix this? (I tried putting the load from vscode command at the top of my config file and define the snippets at the bottom but that did not change anything)

Another thing that I would like to know is whether I can turn off regex snippets to pop up in the nvim-cmp completion menu. When selecting them, they just expand to the trigger which is not desirable in most cases I think.

Thanks in advance, I really appreciate it!

@L3MON4D3
Copy link
Owner

First of all thanks for the really great plugin!
Im in the middle of switching to neovim and Im loving it because there are so many awesome plugins, including this one.

TY! 😄

I would like to know how Luasnip chooses which snippet to expand when there are multiple snippets that could be expanded. In particular I would like to know whether there is a way to prioritize snippets loaded from vscode style json files over regex snippets.

Currently we're just returning the first matching snippet (see here), there is no concept of priority (so far).
Still, as ipairs iterates from 1 -> #table, you can get by by just inserting higher-priority-snippets at a numerically lower position (because they will be tested earlier).
In your case that would mean appending the lower priority-snippets after load (won't work with lazy_load!), by doing

-- load(....)

table.insert(ls.snippets.markdown, s(....))
-- or alternatively:
vim.list_extend(ls.snippets.markdown, {<multiple snippets>})

That will work as long as the snippets are loaded from the same filetype, different filtetypes will be searched sequentially.
You can see the order by calling

print(vim.inspect(require("luasnip.util.util").get_snippet_filetypes()))

in a given file.
It's possible to influence the order:

ls.filetype_extend("ft1", {"ft2"}) -- leads to {"ft1", "ft2", "all"}
ls.filetype_set("ft1", {"ft2", "ft1"}) -- leads to {"ft2", "ft1", "all"}

If that doesn't help, we might have to implement priority properly.

@L3MON4D3
Copy link
Owner

Another thing that I would like to know is whether I can turn off regex snippets to pop up in the nvim-cmp completion menu. When selecting them, they just expand to the trigger which is not desirable in most cases I think.

They should expand so that the trigger is editable, so [%d%w]+d (expand) -> ${1:[%d%w]+}d.

Apart from that, if hidden is set for a snippet, it won't show up in cmp.

You could define a wrapper around s() that sets both of these, to make authoring snippets more comfortable:

local function s_reg(trigger, nodes)
	return s({trig = trigger, regTrig = true, hidden = true}, nodes)
end

s_reg("[%d%w]+d", {
	t"yey, expanded"
})

@apmyplol
Copy link
Author

Thank you for the quick response!
I just tried doing what you suggested by using vim.list_extend but I get the error vim/shared.lua:360: dst: expected table, got nil.
I load my snippets at the beginning of the file with

local status_ok, vsloader = pcall(require, "luasnip.loaders.from_vscode")
if not status_ok then
  return
end
vsloader.load({paths = "~/.config/nvim/snippets/"})

Then define

local texsnippets = {
      -- Snippets for math text
      s(
          { trig = "fancy([a-z])", name = "fancy math text", dscr = "expands 'fancy a' to \\mathcal{A}", regTrig = true, hidden = true },
          f(function(_, snip)
            return "\\mathcal{ "   .. snip.captures[1]:upper() .. "}"
          end, {})
      ), 
....
}

and then finally use

vim.list_extend(ls.snippets.markdown, texsnippets)

to append the snippets.
The same error happpens, if I use table.insert.
Looks like lua does not recognize ls.snippets.markdown as a table. Maybe because the vscode style snippets are not loaded properly or are stored somewhere else?
If I insert ls.snippets = {markdown = {}, ....} at the beginning then adding the snippets like this works, however the priority does not change, i.e. in still expands to i^n instead of \in.

The hidden thing however works perfectly fine. Looks like Ive overlooked this parameter, Thanks a lot!

@L3MON4D3
Copy link
Owner

Ohhh, I thought you were loading markdown snippets, try replacing all those markdown-ocurrences with tex, that should work (I think :D)

@apmyplol
Copy link
Author

Actually im loading them both for markdown and for latex using ls.filetype_set("markdown", {"tex"}) at the end of my init file.

In my package.json I have

{
  "name": "mysnippets",
  "engines": {
    "vscode": "^1.11.0"
  },
  "contributes": {
    "snippets": [
      {
        "language": [
          "tex"
        ],
        "path": "./tex.json"
    }
    ]
  }
}

And I changed my luasnip file to

local status_ok, vsloader = pcall(require, "luasnip.loaders.from_vscode")
if not status_ok then
  return
end
vsloader.load({paths = "~/.config/nvim/snippets/"})
...


local texsnippets = {
      -- Snippets for math text
      s(
          { trig = "fancy([a-z])", name = "fancy math text", dscr = "expands 'fancy a' to \\mathcal{A}", regTrig = true, hidden = true },
          f(function(_, snip)
            return "\\mathcal{ "   .. snip.captures[1]:upper() .. "}"
          end, {})
      ), 
....
}

vim.list_extend(ls.snippets.tex, texsnippets)
ls.filetype_set("markdown", {"tex"})

which still does not work.
I tried printing print(vim.inspect(ls.snippets)) and print(vim.inspect(ls.snippets.tex)) after vsloader.load(...) but this retuns nil both times.

@L3MON4D3
Copy link
Owner

I tried printing print(vim.inspect(ls.snippets)) and print(vim.inspect(ls.snippets.tex)) after vsloader.load(...) but this retuns nil both times.

Ohhh, that's because we read the files asynchronally, so the snippets are only added after the list is extended 🤦

We do have an event in place that a loader fires when it adds new snippets, so you could listen to that and add the snippets once the loader has added all tex-snippets:

-- requires texsnippets to be global.
vim.cmd([[au User LuasnipSnippetsAdded lua if ls.session.latest_load_ft == "tex" do vim.list_extend(ls.snippets.tex, texsnippets) end]])

The above is only possible if there's just one package adding tex-snippets, if multiple packages add tex-snippets, texsnippets is appended more than once, leading to duplicates (noticable in eg. cmp).
It's possible to prevent that by preventing appending more than once (set and check some var), but then the order would, again, be unknown (maybe the higher-priority snippets from the package are appended only after the low-prio ones in texsnippets).

In short, we probably should implement some kind of priority (or make the loading synchronous, that would also make it simpler).

@L3MON4D3
Copy link
Owner

Okay I think this can now, finally, be done pretty comfortably, check the loader-docs :D
Closed 🥳

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants