Replies: 2 comments 5 replies
-
Oh, no, the only way to do that is storing stuff in the snippet (but I don't know what you mean with callbacks. FunctionNode?) |
Beta Was this translation helpful? Give feedback.
-
I mean snippet callbacks. I should have included my code. I'm just beginning to learn both lua and luasnips so any suggestions will be gladly accepted. This snippet started with your javadoc demo and evolved to include specifying the types inline as in typescript. For example typing:
/**
* A short Description
*
* @param {string} a
* @param {number} b
* @returns {string}
*/
function test(a, b) {
} My goal is making it easy to create the jsdoc first rather than as an afterthought. This way I get the benefits of type checking from tsserver in my javascript code. All that said, here is my code with the actual snippet down at the end. local ls = require("luasnip")
local s = ls.snippet
local sn = ls.snippet_node
local t = ls.text_node
local i = ls.insert_node
local d = ls.dynamic_node
local r = ls.restore_node
local c = ls.choice_node
local l = require("luasnip.extras").lambda
local events = require("luasnip.util.events")
-- from https://github.com/L3MON4D3/LuaSnip/blob/master/Examples/snippets.lua#L81-L166
-- hacked up for javascript and jsdoc
local function jsdoc(_, parent)
-- communication between functions uses the jsdoc key in the parent node
-- if the jsdoc key isn't present add it
if parent.jsdoc == nil then
parent.jsdoc = { types = {}, parameters = {} }
end
-- these are filled in by the callbacks in the snippet
local types = parent.jsdoc.types
local parameters = parent.jsdoc.parameters
-- build up the resulting snippet here
local nodes = {
t({ "/**", " * " }),
r(1, "desc", i(1, "A short Description")),
t({ "", "" }),
}
-- At least one param.
if #parameters > 0 then
vim.list_extend(nodes, { t({ " * ", "" }) })
end
local insert = 2
for pindex = 1, #parameters do
local parameter = parameters[pindex]
local type = types[parameter]
local inode
if #type > 0 then
inode = t(type)
else
inode = i(insert, "any")
insert = insert + 1
end
vim.list_extend(nodes, {
t({ " * @param {" }),
inode,
t({ "} " .. parameter .. " ", "" }),
})
end
local returns = types["returns"] or ""
if #returns > 0 then
vim.list_extend(nodes, {
t({ " * @returns {" }),
t({ returns }),
t({ "} ", "" }),
})
end
vim.list_extend(nodes, { t({ " */" }) })
local snip = sn(nil, nodes)
return snip
end
-- parse a type declaration
-- a:number
-- a:number[]
-- complicated types can be written like ::type here:: and the whole thing will be used
-- a::Map<string,string>::
local function parseType(string, start)
local patterns = {
"^::(.-)::", -- everything complicated goes here
"^:(%w+%[%])", -- arrays of simple types are here
"^:(%w+)", -- simple types
}
for index = 1, #patterns do
local _, tend, type = string.find(string, patterns[index], start)
if type ~= nil then
return type, tend + 1
end
end
return "", start -- didn't find a type
end
local function parseParameters(node)
local types = node.parent.jsdoc.types
local parameterstring = table.concat(node:get_text(), "\n")
local index = 1
local parameters = {}
while index < #parameterstring do
local _, aend, parameter =
string.find(parameterstring, "%s*(%w+)%s*", index)
if parameter ~= nil then
index = aend + 1
local type, nextindex = parseType(parameterstring, index)
if type ~= "" or types[parameter] == nil then
types[parameter] = type
end
table.insert(parameters, parameter)
index = nextindex
end
if string.match(parameterstring, ",", index) ~= nil then
index = index + 1
end
end
-- pass the parameters to jsdoc through our parent
node.parent.jsdoc.parameters = parameters
-- rewrite the parameters
local from_pos, to_pos = node.mark:pos_begin_end_raw()
vim.api.nvim_buf_set_text(
0,
from_pos[1],
from_pos[2],
to_pos[1],
to_pos[2],
{ table.concat(parameters, ", ") }
)
end
local function parseReturns(node)
local rstring = table.concat(node:get_text(), "\n")
local type = parseType(rstring, 1)
local types = node.parent.jsdoc.types
types["returns"] = type
-- rewrite the returns
local from_pos, to_pos = node.mark:pos_begin_end_raw()
vim.api.nvim_buf_set_text(
0,
from_pos[1],
from_pos[2],
to_pos[1],
to_pos[2],
{ "" }
)
end
return {
-- function with jsdoc
s("jfunction", {
d(5, jsdoc, { 3, 4 }), -- generate the jsdoc
t({ "", "" }),
c(1, { -- choose function or method
t({ "function " }),
t({ "" }),
}),
i(2, "myfunc"), -- give it a name
t("("),
i(3), -- parameters
t(")"),
i(4, " "), -- return type
t({ " {", "\t" }),
i(0), -- body
t({ "", "}" }),
}, {
callbacks = {
[3] = { -- parameters
[events.leave] = parseParameters,
},
[4] = { -- return type
[events.leave] = parseReturns,
},
},
}),
) |
Beta Was this translation helpful? Give feedback.
-
I've got a snippet that uses a couple of callbacks and a dynamic node to create jsdoc with types specified using typescript like syntax.
I need to pass state derived in the callbacks to the dynamic node. As a hack I simply added a key to the parent node table where I stored the shared state.
I'm wondering if there is some better way to pass state among different elements of a snip?
Beta Was this translation helpful? Give feedback.
All reactions