Make it easy to create functions that override the defaults of functions.
Sounds a bit cryptic, the general idea is to allow stuff like
-- this somewhere above: local override_fn = require("luasnip.extras.override_fn")
local fmts = override_fn.fmt({delimiters = "[]"})
This makes it easy to create functions with different defaults, like above for fmt, or maybe a ls.snippet-function that always sets regTrig or some combination of parameters.
This needs some more work:
- [ ] snippet does not really work yet, if the first arg is a string, we're in trouble.
- [ ] add more functions beside
fmt - [ ] think about exposing and documenting the generic function (
override_any, currently) so it can be used to craft yet more of these override-functions (although that is really quick) - [ ] think of a better name,
override_fnisn't very self-explanatory
WTYT if instead of the override_fn.func api you just expose override_with(func, opt_overrides) in luasnip.utils or in luasnip.extras?
The same function could be used for creating auto-expand snippets by wrapping add_snippets with the auto_expand (is that the name?).
The issue with that is that we don't know which position the opts are in, or how many there are (think ls.s, one might like to override both the first or third parameter).
So we'd best provide presets for common functions (like fmt, s, add_snippets), that's why I put that mechanism into its own module for now.
The same function could be used for creating auto-expand snippets by wrapping
add_snippetswith the auto_expand (is that the name?).
Yeah right, via type = "autosnippets"
Did a small rewrite, now it's possible to override the snippet-parameters. Also, extend instead of override would make more sense I think. Example:
ls.setup_snip_env()
local override_fn = require("luasnip.extras.override_fn")
local expand_conditions = require("luasnip.extras.expand_conditions")
local fmts = override_fn.fmt({delimiters = "[]"})
-- equivalent to ultisnips br (well, bp for pattern :D)
local br_snip = override_fn.snippet(
{regTrig = true},
{condition = expand_conditions.line_begin} )
ls.add_snippets("all", {
br_snip("%d", {
i(1, "asdf")
}),
s("trig", fmts("[]", {i(1, "asdf")} ) )
}, {
key = "asd"
})
I think this is really sick, great idea @leiserfg!!
I was riding my :bike: and an idea came to my mind. What if we add a fun._opt_pos to every function that can be overridden, so you don't have to import everything inside of luasnip.extras.override_fn? That way you only expose override_fn and it uses ._opt_pos to know where to override. The decorated function should get the same `_opt_pos as the original one, that way a function can be wrapped more than once. The default value should be 2, maybe it can be also a 3rd parameter of the function, in case someone wanna override a function that is not shipped by luasnip.
Mhmmm interesting idea :+1:
I definitely like defining properties of the function (position of the opts-arg, how can it be overridden) close to the function, as opposed to in a completely different file.
To implement this, we'd have to turn all outward-facing functions into tables with __call, right? (Don't like this very much, although we could hide this behind a nice constructor, so at least the code doesn't look completely weird)
(Can you think of a better approach for the implementation?)
Communicating which functions are overridable would be a bit harder this way, by putting all of the overridable functions into one module it's very clearly defined. (We don't have this problem if we make all functions overridable though xD) (OTOH, we can just return a readable error in the function that's responsible for overriding, yeeah that works)
Yeah, I think this is even better :+1::+1:
To implement this, we'd have to turn all outward-facing functions into tables with __call, right?
Crap, I forgot functions are not indexable in lua :face_exhaling:
But also, it does not need to make every function a table, you can just expose a function to annotate where the opt goes, like so:
local opt_pos = setmetatable({}, {__mode = "kv"})
function M.overridable(fn, pos)
opt_pos[fn] = pos
return fn
end
local function M.override(fn, opt, maybe_pos)
-- if maybe_pos use it other way check the table, if none is there, consider it's 2 or fail, the one you prefer
-- HERE THE MAGIC happens
-- call `overridable` on the decorated function to set the same position as the used
end
To implement this, we'd have to turn all outward-facing functions into tables with __call, right?
Crap, I forgot functions are not indexable in lua :face_exhaling:
xD What language is that possible in?
But also, it does not need to make every function a table, you can just expose a function to annotate where the opt goes, like so:
Oh, yeah I like that approach :+1:
Sidenote: Making the keys weak is a nice touch, but I don't get why the values are weak too, aren't they only stored in this table?
xD What language is that possible in?
I use python 90% of the time :smile:, there you can.
Oho, I use Python sometimes but have never seen that, cool
Making the keys weak is a nice touch, but I don't get why the values are weak too, aren't they only stored in this table?
Yes, kv is not needed, k is good enough.
Okay, works pretty well, I've renamed everything to reflect that we're extending, not overriding the passed args (not sure what's easier to understand, overriding defaults or extending passed arguments...) Here's what usage looks like now:
ls.setup_snip_env()
local ed = require("luasnip.util.extend_decorator")
local expand_conditions = require("luasnip.extras.expand_conditions")
local fmts = ed.apply(fmt, {delimiters = "[]"})
-- can also apply to already-decorated functions.
local fmtd = ed.apply(require("luasnip.extras.fmt").fmta, {dedent = false})
-- equivalent to ultisnips br (well, bp for pattern :D)
local br_snip = ed.apply(s,
{regTrig = true},
{condition = expand_conditions.line_begin} )
ls.add_snippets("all", {
br_snip("%d", {
i(1, "asdf")
}),
s("trig", fmts("\t\t\t[]", {i(1, "asdf")} ) ),
s("triga", fmtd("\t\t\t<>", {i(1, "asdf")} ) )
}, {
key = "asd"
})
Also moved it to util, since we now rely on it internally.
It's also pretty straightforward to register personal functions, I think we should properly expose this.
I've decided not to set default-values for the opts-parameter, too easy to introduce subtle errors imo. Maybe I'll also remove the defaulting for the extend-function and just export the default-extend from the module, I think that's okay. Maybe export it from util, under a fitting name.
Yes, it makes sense to re-export it (as we did for the function to add environments) and only document that exposed part.
Ahh, yeah, that file is so small it's fine to re-export :+1: Can you think of useful functions to extend? I guess
- node-constructors (not thaaaaaaat useful, but one can more easily create highlighted nodes that way, like
red_insertNodexD) -
parse: once the parser-update is merged, it'll also havededentandtrim_emptylikefmt, but default false to not mess up snippets from lsp. So overriding that is an easy target. - ???
will come in handy, but those are the only ones that come to mind directly.
@leiserfg Would you take a look?
@leiserfg Would you take a look?
Sure, tonight I will review it.
Looks awesome :tada:
Hell yeah, that's what I wanna hear :D Thank you!