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:
@@ -101,6 +101,27 @@ Neogen provides those defaults, and you can change them to suit your needs
|
|||||||
|
|
||||||
-- Use a snippet engine to generate annotations.
|
-- Use a snippet engine to generate annotations.
|
||||||
snippet_engine = nil,
|
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",
|
||||||
}
|
}
|
||||||
<
|
<
|
||||||
# Notes~
|
# Notes~
|
||||||
@@ -159,12 +180,23 @@ Feel free to submit a PR, I will be happy to help you !
|
|||||||
We use semantic versioning ! (https://semver.org)
|
We use semantic versioning ! (https://semver.org)
|
||||||
Here is the current Neogen version:
|
Here is the current Neogen version:
|
||||||
>
|
>
|
||||||
neogen.version = "2.5.0"
|
neogen.version = "2.6.0"
|
||||||
<
|
<
|
||||||
# Changelog~
|
# Changelog~
|
||||||
|
|
||||||
Note: We will only document `major` and `minor` versions, not `patch` ones.
|
Note: We will only document `major` and `minor` versions, not `patch` ones.
|
||||||
|
|
||||||
|
## 2.6.0~
|
||||||
|
- Add support for placeholders in snippet insertion !
|
||||||
|
- 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~
|
## 2.5.0~
|
||||||
- Ruby: Add support for `tomdoc` (http://tomdoc.org)
|
- Ruby: Add support for `tomdoc` (http://tomdoc.org)
|
||||||
## 2.4.0~
|
## 2.4.0~
|
||||||
@@ -202,6 +234,15 @@ To use a snippet engine, pass the option into neogen setup:
|
|||||||
Some snippet engines come out of the box bundled with neogen:
|
Some snippet engines come out of the box bundled with neogen:
|
||||||
- `"luasnip"` (https://github.com/L3MON4D3/LuaSnip)
|
- `"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~
|
# Add support for snippet engines~
|
||||||
|
|
||||||
To add support to a snippet engine, go to `lua/neogen/snippet.lua`.
|
To add support to a snippet engine, go to `lua/neogen/snippet.lua`.
|
||||||
|
|||||||
@@ -16,6 +16,27 @@ local default_locator = require("neogen.locators.default")
|
|||||||
local snippet = require("neogen.snippet")
|
local snippet = require("neogen.snippet")
|
||||||
local JUMP_TEXT = "$1"
|
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 function get_parent_node(filetype, typ, language)
|
||||||
local parser = vim.treesitter.get_parser(0, filetype)
|
local parser = vim.treesitter.get_parser(0, filetype)
|
||||||
local tstree = parser:parse()[1]
|
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 generated_template = template[template.annotation_convention]
|
||||||
|
|
||||||
local result = {}
|
local result = {}
|
||||||
|
local default_text = {}
|
||||||
local prefix = prefix_generator(template, commentstring, col)
|
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)
|
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
|
end
|
||||||
|
|
||||||
for _, values in ipairs(generated_template) do
|
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
|
elseif ins_type == "string" and type(data[inserted_type]) == "table" then
|
||||||
-- Format the output with the corresponding data
|
-- Format the output with the corresponding data
|
||||||
for _, s in ipairs(data[inserted_type]) do
|
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
|
if opts.after_each then
|
||||||
append_str(opts.after_each:format(s))
|
append_str(opts.after_each:format(s))
|
||||||
end
|
end
|
||||||
@@ -152,7 +182,7 @@ local function generate_content(parent, data, template, required_type)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return row, result
|
return row, result, default_text
|
||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable({}, {
|
return setmetatable({}, {
|
||||||
@@ -181,7 +211,7 @@ return setmetatable({}, {
|
|||||||
local data = granulator(parent_node, language.data[typ])
|
local data = granulator(parent_node, language.data[typ])
|
||||||
|
|
||||||
-- Will try to generate the documentation from a template and the data found from the granulator
|
-- 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 content = {}
|
||||||
local marks_pos = {}
|
local marks_pos = {}
|
||||||
@@ -205,7 +235,9 @@ return setmetatable({}, {
|
|||||||
end
|
end
|
||||||
if input_after_comment then
|
if input_after_comment then
|
||||||
len = len + s - last_col - 1
|
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
|
end
|
||||||
last_col = e
|
last_col = e
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -115,6 +115,27 @@ neogen.configuration = {
|
|||||||
|
|
||||||
-- Use a snippet engine to generate annotations.
|
-- Use a snippet engine to generate annotations.
|
||||||
snippet_engine = nil,
|
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
|
--minidoc_afterlines_end
|
||||||
|
|
||||||
@@ -216,6 +237,18 @@ end
|
|||||||
---
|
---
|
||||||
--- Note: We will only document `major` and `minor` versions, not `patch` ones.
|
--- 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~
|
--- ## 2.5.0~
|
||||||
--- - Ruby: Add support for `tomdoc` (http://tomdoc.org)
|
--- - Ruby: Add support for `tomdoc` (http://tomdoc.org)
|
||||||
--- ## 2.4.0~
|
--- ## 2.4.0~
|
||||||
@@ -238,7 +271,7 @@ end
|
|||||||
--- with multiple annotation conventions.
|
--- with multiple annotation conventions.
|
||||||
---@tag neogen-changelog
|
---@tag neogen-changelog
|
||||||
---@toc_entry Changes in neogen plugin
|
---@toc_entry Changes in neogen plugin
|
||||||
neogen.version = "2.5.0"
|
neogen.version = "2.6.0"
|
||||||
--minidoc_afterlines_end
|
--minidoc_afterlines_end
|
||||||
|
|
||||||
return neogen
|
return neogen
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ end
|
|||||||
---@return number the id of the inserted mark
|
---@return number the id of the inserted mark
|
||||||
---@private
|
---@private
|
||||||
mark.add_mark = function(self, pos)
|
mark.add_mark = function(self, pos)
|
||||||
local line, col = unpack(pos)
|
local id = api.nvim_buf_set_extmark(self.bufnr, ns, pos.row, pos.col, {})
|
||||||
local id = api.nvim_buf_set_extmark(self.bufnr, ns, line, col, {})
|
|
||||||
table.insert(mark.ids, id)
|
table.insert(mark.ids, id)
|
||||||
return id
|
return id
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
local notify = require("neogen.utilities.helpers").notify
|
local notify = require("neogen.utilities.helpers").notify
|
||||||
|
local conf = require("neogen.config").get()
|
||||||
|
|
||||||
---
|
---
|
||||||
--- To use a snippet engine, pass the option into neogen setup:
|
--- 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:
|
--- Some snippet engines come out of the box bundled with neogen:
|
||||||
--- - `"luasnip"` (https://github.com/L3MON4D3/LuaSnip)
|
--- - `"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~
|
--- # Add support for snippet engines~
|
||||||
---
|
---
|
||||||
--- To add support to a snippet engine, go to `lua/neogen/snippet.lua`.
|
--- To add support to a snippet engine, go to `lua/neogen/snippet.lua`.
|
||||||
@@ -33,16 +43,17 @@ snippet.engines = {}
|
|||||||
---@return table resulting snippet lines
|
---@return table resulting snippet lines
|
||||||
---@private
|
---@private
|
||||||
snippet.to_snippet = function(template, marks, pos)
|
snippet.to_snippet = function(template, marks, pos)
|
||||||
local offset = {}
|
local offset, ph = {}, {}
|
||||||
for i, m in ipairs(marks) do
|
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
|
if offset[r] then
|
||||||
offset[r] = offset[r] + tostring(i - 1):len() + 1
|
offset[r] = offset[r] + ph[i - 1]:len() + 1
|
||||||
else
|
else
|
||||||
offset[r] = 0
|
offset[r] = 0
|
||||||
end
|
end
|
||||||
local pre = template[r]:sub(1, col + offset[r])
|
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
|
end
|
||||||
return template
|
return template
|
||||||
end
|
end
|
||||||
@@ -52,13 +63,35 @@ end
|
|||||||
---@param pos table a tuple of row, col
|
---@param pos table a tuple of row, col
|
||||||
---@private
|
---@private
|
||||||
snippet.engines.luasnip = function(snip, pos)
|
snippet.engines.luasnip = function(snip, pos)
|
||||||
local ok, luasnip = pcall(require, "luasnip")
|
local ok, ls = pcall(require, "luasnip")
|
||||||
if not ok then
|
if not ok then
|
||||||
notify("Luasnip not found, aborting...", vim.log.levels.ERROR)
|
notify("Luasnip not found, aborting...", vim.log.levels.ERROR)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local types = require("luasnip.util.types")
|
||||||
|
|
||||||
|
-- Append a new line to create the snippet
|
||||||
vim.fn.append(pos[1], "")
|
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
|
end
|
||||||
|
|
||||||
return snippet
|
return snippet
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
return {
|
return {
|
||||||
{ nil, " $1", { no_results = true } },
|
{ nil, " $1", { no_results = true } },
|
||||||
{ "func_name", " %s $1", { type = { "func" }}},
|
{ "func_name", " %s $1", { type = { "func" } } },
|
||||||
{ "type_name", " %s $1", { type = { "type" }}},
|
{ "type_name", " %s $1", { type = { "type" } } },
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user