L3MON4D3 / LuaSnip

Snippet Engine for Neovim written in Lua.
Apache License 2.0
3.44k stars 243 forks source link

[Bug] Cannot extend `ls.multi_snippet` #921

Closed Bekaboo closed 1 year ago

Bekaboo commented 1 year ago

I tried to extend ls.multi_snippet with the following code:

local ls = require('luasnip')
local ms = ls.multi_snippet
-- Multi snippets that does not expand in string or comments ('code' snippets)
local msc = ls.extend_decorator.apply(ms, {
  common = {
    condition = -- [[ some conds ]],
    show_condition = -- [[ some conds ]],
  },
})

but get this error:

Failed to run `config` for LuaSnip
...ckages/opt/LuaSnip/lua/luasnip/util/extend_decorator.lua:26: Cannot extend this function, it was not registered! Check :h luasnip-extend_decorator for more infos.
# stacktrace:
  - /LuaSnip/lua/luasnip/util/extend_decorator.lua:26 _in_ **apply**
  - ~/.config/nvim/lua/snippets/lua.lua:22
  - ~/.config/nvim/lua/configs/LuaSnip.lua:9 _in_ **load_snippets**
  - ~/.config/nvim/lua/configs/LuaSnip.lua:25 _in_ **lazy_load_snippets**
  - ~/.config/nvim/lua/configs/LuaSnip.lua:79
  - ~/.config/nvim/lua/modules/completion.lua:83 _in_ **config**

Seems that multi-snippets cannot be extended like normal snippets? Is this intended or a bug? Thanks in advance!

L3MON4D3 commented 1 year ago

Ah, it's possible we don't have that set up yet. Take a look at the extend-decorator section in DOC.md if you want to do that yourself, it's one call that can also just happen in your config

Bekaboo commented 1 year ago

Thanks for your prompt reply, will look into it later.

Bekaboo commented 1 year ago

For future reference:

To register the multi-snippet function, just call ls.extend_decorator.register:

local ls = require('luasnip')
local ms = ls.multi_snippet
ls.extend_decorator.register(ms, { arg_indx = 1 }, { arg_indx = 3 })
L3MON4D3 commented 1 year ago

(also added this in 1a42854, with slightly different behaviour: if apply gets a list for the first argument, the lists from apply and the one passed in the call to the decorated function are merged, while common is extended normally. I hope that is good behaviour, and not counterintuitive :D)

Bekaboo commented 1 year ago

@L3MON4D3 Currently the common field is replaced as a whole when the passed arg has this field set instead of merging the passed arg and the extend arg, which is not expected.

To clarify, consider the following cases:

I create some luasnip conds and define a new multi-snippet that only expand if ts is not active or ts and active and the cursor is not in a comment or string:

local msc = ls.extend_decorator.apply(ms, {
  common = {
    condition = -conds.ts_active
      + -conds.in_tsnode('comment') * -conds.in_tsnode('string'),
    show_condition = -conds.ts_active
      + -conds.in_tsnode('comment') * -conds.in_tsnode('string'),
  },
})

Then I want to create a multi-snippet with regex trigger and only expand when the cursor is not in a comment or string:

msc(
  {
    common = { regTrig = true },
    { trig = '(%S?)(%s*)%.%.%s*ck' },
    { trig = '(%S?)(%s*)%.%.%s*check' },
  },
  fmta('<spc>.. ", <v>: " .. vim.inspect(<v>)', {
    spc = f(function(_, snip, _)
      return snip.captures[1] == '' and snip.captures[2]
        or snip.captures[1] .. ' '
    end, {}, {}),
    v = i(1),
  }, { repeat_duplicates = true })
)

the original condition field is dropped because I provide the common field in the new snippet, making the original common table completely replaced by the new one i.e. { regTrig = true, condition = nil, show_condition = nil, ... }

I would suggest using vim.tbl_deep_extend to merge the common table, this fixes the issue (in function extend_multisnippet_contexts:

    -- extend ("keep") valid keyword-arguments.
    passed_arg.common = vim.tbl_deep_extend(
        "keep",
        passed_arg.common or {},
        extend_arg.common or {}
    )

EDIT: typo