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:
mg979
2022-03-13 16:05:04 +01:00
committed by GitHub
parent 4e3dca63c6
commit c9ac5a6fd8
6 changed files with 155 additions and 17 deletions

View File

@@ -101,6 +101,27 @@ Neogen provides those defaults, and you can change them to suit your needs
-- 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",
}
<
# 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)
Here is the current Neogen version:
>
neogen.version = "2.5.0"
neogen.version = "2.6.0"
<
# Changelog~
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~
- Ruby: Add support for `tomdoc` (http://tomdoc.org)
## 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:
- `"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`.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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" } } },
}