Placeholder support for snippet engines (#76)
- Add support for placeholders in snippet insertion ! None: placeholders are automatically set when using a bundled snippet engine. - Add `enable_placeholders` option (see |neogen-configuration|) - Add `placeholders_text` option (see |neogen-configuration|) Co-authored-by: danymat <d.danymat@gmail.com>
This commit is contained in:
@@ -16,6 +16,27 @@ local default_locator = require("neogen.locators.default")
|
||||
local snippet = require("neogen.snippet")
|
||||
local JUMP_TEXT = "$1"
|
||||
|
||||
local function todo_text(type)
|
||||
local i = require("neogen.types.template").item
|
||||
local todo = conf.placeholders_text
|
||||
return ({
|
||||
[i.Tparam] = todo["tparam"],
|
||||
[i.Parameter] = todo["parameter"],
|
||||
[i.Return] = todo["return"],
|
||||
[i.ReturnTypeHint] = todo["return"],
|
||||
[i.ReturnAnonym] = todo["return"],
|
||||
[i.ClassName] = todo["class"],
|
||||
[i.Throw] = todo["throw"],
|
||||
[i.Vararg] = todo["varargs"],
|
||||
[i.Type] = todo["type"],
|
||||
[i.ClassAttribute] = todo["attribute"],
|
||||
[i.HasParameter] = todo["parameter"],
|
||||
[i.HasReturn] = todo["return"],
|
||||
[i.ArbitraryArgs] = todo["args"],
|
||||
[i.Kwargs] = todo["kwargs"],
|
||||
})[type] or todo["description"]
|
||||
end
|
||||
|
||||
local function get_parent_node(filetype, typ, language)
|
||||
local parser = vim.treesitter.get_parser(0, filetype)
|
||||
local tstree = parser:parse()[1]
|
||||
@@ -91,10 +112,19 @@ local function generate_content(parent, data, template, required_type)
|
||||
local generated_template = template[template.annotation_convention]
|
||||
|
||||
local result = {}
|
||||
local default_text = {}
|
||||
local prefix = prefix_generator(template, commentstring, col)
|
||||
|
||||
local function append_str(str)
|
||||
local n = 0
|
||||
|
||||
local function append_str(str, inserted_type)
|
||||
table.insert(result, str == "" and str or prefix .. str)
|
||||
local x -- placeholders in the same line after the first are 'descriptions'
|
||||
for _ in string.gmatch(str, "%$1") do
|
||||
n = n + 1
|
||||
default_text[n] = not x and todo_text(inserted_type) or todo_text()
|
||||
x = true
|
||||
end
|
||||
end
|
||||
|
||||
for _, values in ipairs(generated_template) do
|
||||
@@ -121,7 +151,7 @@ local function generate_content(parent, data, template, required_type)
|
||||
elseif ins_type == "string" and type(data[inserted_type]) == "table" then
|
||||
-- Format the output with the corresponding data
|
||||
for _, s in ipairs(data[inserted_type]) do
|
||||
append_str(formatted_str:format(s))
|
||||
append_str(formatted_str:format(s), inserted_type)
|
||||
if opts.after_each then
|
||||
append_str(opts.after_each:format(s))
|
||||
end
|
||||
@@ -152,7 +182,7 @@ local function generate_content(parent, data, template, required_type)
|
||||
end
|
||||
end
|
||||
|
||||
return row, result
|
||||
return row, result, default_text
|
||||
end
|
||||
|
||||
return setmetatable({}, {
|
||||
@@ -181,7 +211,7 @@ return setmetatable({}, {
|
||||
local data = granulator(parent_node, language.data[typ])
|
||||
|
||||
-- Will try to generate the documentation from a template and the data found from the granulator
|
||||
local row, template_content = generate_content(parent_node, data, template, typ)
|
||||
local row, template_content, default_text = generate_content(parent_node, data, template, typ)
|
||||
|
||||
local content = {}
|
||||
local marks_pos = {}
|
||||
@@ -205,7 +235,9 @@ return setmetatable({}, {
|
||||
end
|
||||
if input_after_comment then
|
||||
len = len + s - last_col - 1
|
||||
table.insert(marks_pos, { row + r - 1, len - 1 })
|
||||
local m = { row = row + r - 1, col = len - 1 }
|
||||
table.insert(marks_pos, m)
|
||||
m.text = default_text[#marks_pos]
|
||||
end
|
||||
last_col = e
|
||||
end
|
||||
|
||||
@@ -115,6 +115,27 @@ neogen.configuration = {
|
||||
|
||||
-- Use a snippet engine to generate annotations.
|
||||
snippet_engine = nil,
|
||||
|
||||
-- Enables placeholders when inserting annotation
|
||||
enable_placeholders = true,
|
||||
|
||||
-- Placeholders used during annotation expansion
|
||||
placeholders_text = {
|
||||
["description"] = "[TODO:description]",
|
||||
["tparam"] = "[TODO:tparam]",
|
||||
["parameter"] = "[TODO:parameter]",
|
||||
["return"] = "[TODO:return]",
|
||||
["class"] = "[TODO:class]",
|
||||
["throw"] = "[TODO:throw]",
|
||||
["varargs"] = "[TODO:varargs]",
|
||||
["type"] = "[TODO:type]",
|
||||
["attribute"] = "[TODO:attribute]",
|
||||
["args"] = "[TODO:args]",
|
||||
["kwargs"] = "[TODO:kwargs]",
|
||||
},
|
||||
|
||||
-- Placeholders highlights to use. If you don't want custom highlight, pass "None"
|
||||
placeholders_hl = "DiagnosticHint",
|
||||
}
|
||||
--minidoc_afterlines_end
|
||||
|
||||
@@ -216,6 +237,18 @@ end
|
||||
---
|
||||
--- Note: We will only document `major` and `minor` versions, not `patch` ones.
|
||||
---
|
||||
--- ## 2.6.0~
|
||||
--- - Add support for placeholders in snippet insertion !
|
||||
--- None: placeholders are automatically set when using a bundled snippet engine.
|
||||
--- - Add `enable_placeholders` option (see |neogen-configuration|)
|
||||
--- - Add `placeholders_text` option (see |neogen-configuration|)
|
||||
---
|
||||
--- Example placeholders:
|
||||
--- >
|
||||
--- --- [TODO:description]
|
||||
--- ---@param param1 [TODO:parameter] [TODO:description]
|
||||
--- function test(param1) end
|
||||
--- <
|
||||
--- ## 2.5.0~
|
||||
--- - Ruby: Add support for `tomdoc` (http://tomdoc.org)
|
||||
--- ## 2.4.0~
|
||||
@@ -238,7 +271,7 @@ end
|
||||
--- with multiple annotation conventions.
|
||||
---@tag neogen-changelog
|
||||
---@toc_entry Changes in neogen plugin
|
||||
neogen.version = "2.5.0"
|
||||
neogen.version = "2.6.0"
|
||||
--minidoc_afterlines_end
|
||||
|
||||
return neogen
|
||||
|
||||
@@ -49,8 +49,7 @@ end
|
||||
---@return number the id of the inserted mark
|
||||
---@private
|
||||
mark.add_mark = function(self, pos)
|
||||
local line, col = unpack(pos)
|
||||
local id = api.nvim_buf_set_extmark(self.bufnr, ns, line, col, {})
|
||||
local id = api.nvim_buf_set_extmark(self.bufnr, ns, pos.row, pos.col, {})
|
||||
table.insert(mark.ids, id)
|
||||
return id
|
||||
end
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
local notify = require("neogen.utilities.helpers").notify
|
||||
local conf = require("neogen.config").get()
|
||||
|
||||
---
|
||||
--- To use a snippet engine, pass the option into neogen setup:
|
||||
@@ -11,6 +12,15 @@ local notify = require("neogen.utilities.helpers").notify
|
||||
--- Some snippet engines come out of the box bundled with neogen:
|
||||
--- - `"luasnip"` (https://github.com/L3MON4D3/LuaSnip)
|
||||
---
|
||||
--- If you want to customize the placeholders, you can use `placeholders_text` option:
|
||||
--- >
|
||||
--- require('neogen').setup({
|
||||
--- placeholders_text = {
|
||||
--- ['description'] = "[description]",
|
||||
--- }
|
||||
--- })
|
||||
--- <
|
||||
---
|
||||
--- # Add support for snippet engines~
|
||||
---
|
||||
--- To add support to a snippet engine, go to `lua/neogen/snippet.lua`.
|
||||
@@ -33,16 +43,17 @@ snippet.engines = {}
|
||||
---@return table resulting snippet lines
|
||||
---@private
|
||||
snippet.to_snippet = function(template, marks, pos)
|
||||
local offset = {}
|
||||
local offset, ph = {}, {}
|
||||
for i, m in ipairs(marks) do
|
||||
local r, col = m[1] - pos[1] + 1, m[2]
|
||||
local r, col = m.row - pos[1] + 1, m.col
|
||||
ph[i] = (m.text and conf.enable_placeholders) and string.format("${%d:%s}", i, m.text) or "$" .. i
|
||||
if offset[r] then
|
||||
offset[r] = offset[r] + tostring(i - 1):len() + 1
|
||||
offset[r] = offset[r] + ph[i - 1]:len() + 1
|
||||
else
|
||||
offset[r] = 0
|
||||
end
|
||||
local pre = template[r]:sub(1, col + offset[r])
|
||||
template[r] = pre .. "$" .. i .. template[r]:sub(col + 1 + offset[r])
|
||||
template[r] = pre .. ph[i] .. template[r]:sub(col + 1 + offset[r])
|
||||
end
|
||||
return template
|
||||
end
|
||||
@@ -52,13 +63,35 @@ end
|
||||
---@param pos table a tuple of row, col
|
||||
---@private
|
||||
snippet.engines.luasnip = function(snip, pos)
|
||||
local ok, luasnip = pcall(require, "luasnip")
|
||||
local ok, ls = pcall(require, "luasnip")
|
||||
if not ok then
|
||||
notify("Luasnip not found, aborting...", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
local types = require("luasnip.util.types")
|
||||
|
||||
-- Append a new line to create the snippet
|
||||
vim.fn.append(pos[1], "")
|
||||
luasnip.lsp_expand(table.concat(snip, "\n"), { pos = { pos[1], pos[2] } })
|
||||
|
||||
-- Convert the snippet to string
|
||||
local _snip = table.concat(snip, "\n")
|
||||
|
||||
ls.snip_expand(
|
||||
ls.s("", ls.parser.parse_snippet(nil, _snip), {
|
||||
|
||||
child_ext_opts = {
|
||||
-- for highlighting the placeholders
|
||||
[types.insertNode] = {
|
||||
-- when outside placeholder, but in snippet
|
||||
passive = { hl_group = conf.placeholders_hl },
|
||||
},
|
||||
},
|
||||
-- prevent mixing styles
|
||||
merge_child_ext_opts = true,
|
||||
}),
|
||||
{ pos = pos }
|
||||
)
|
||||
end
|
||||
|
||||
return snippet
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
return {
|
||||
{ nil, " $1", { no_results = true } },
|
||||
{ "func_name", " %s $1", { type = { "func" }}},
|
||||
{ "type_name", " %s $1", { type = { "type" }}},
|
||||
{ "func_name", " %s $1", { type = { "func" } } },
|
||||
{ "type_name", " %s $1", { type = { "type" } } },
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user