Snippet support (#72)
To know more about snippet integration, please visit `:h snippet-integration`, or https://github.com/danymat/neogen#snippet-support ! Co-authored-by: danymat <d.danymat@gmail.com>
This commit is contained in:
@@ -13,6 +13,7 @@ local granulator = require("neogen.granulator")
|
||||
local mark = require("neogen.mark")
|
||||
local nodes = require("neogen.utilities.nodes")
|
||||
local default_locator = require("neogen.locators.default")
|
||||
local snippet = require("neogen.snippet")
|
||||
local JUMP_TEXT = "$1"
|
||||
|
||||
local function get_parent_node(filetype, typ, language)
|
||||
@@ -33,7 +34,7 @@ end
|
||||
---@param n integer
|
||||
---@return string
|
||||
local function prefix_generator(template, commentstring, n)
|
||||
local prefix = (" "):rep(n)
|
||||
local prefix = (vim.bo.expandtab and " " or "\t"):rep(n)
|
||||
|
||||
-- Do not append the comment string if not wanted
|
||||
if template.use_default_comment ~= false then
|
||||
@@ -155,7 +156,7 @@ local function generate_content(parent, data, template, required_type)
|
||||
end
|
||||
|
||||
return setmetatable({}, {
|
||||
__call = function(_, filetype, typ)
|
||||
__call = function(_, filetype, typ, return_snippet)
|
||||
if filetype == "" then
|
||||
notify("No filetype detected", vim.log.levels.WARN)
|
||||
return
|
||||
@@ -210,19 +211,42 @@ return setmetatable({}, {
|
||||
end
|
||||
end
|
||||
|
||||
-- Append content to row
|
||||
vim.api.nvim_buf_set_lines(0, row, row, true, content)
|
||||
if return_snippet then
|
||||
-- User just wants the snippet, so we give him the snippet plus placement informations
|
||||
local generated_snippet = snippet.to_snippet(content, marks_pos, { row, 0 })
|
||||
return generated_snippet, row
|
||||
end
|
||||
|
||||
if #marks_pos > 0 then
|
||||
-- Start session of marks
|
||||
mark:start()
|
||||
for _, pos in ipairs(marks_pos) do
|
||||
mark:add_mark(pos)
|
||||
local snippet_engine = conf.snippet_engine
|
||||
if snippet_engine then
|
||||
-- User want to use a snippet engine instead of native handling
|
||||
local engines = snippet.engines
|
||||
if not vim.tbl_contains(vim.tbl_keys(engines), snippet_engine) then
|
||||
notify(string.format("Snippet engine '%s' not supported", snippet_engine), vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
|
||||
-- Converts the content to a lsp compatible snippet
|
||||
local generated_snippet = snippet.to_snippet(content, marks_pos, { row, 0 })
|
||||
-- Calls the snippet expand function for required snippet engine
|
||||
engines[snippet_engine](generated_snippet, { row, 0 })
|
||||
return
|
||||
else
|
||||
-- We use default marks for jumping between annotations
|
||||
-- Append content to row
|
||||
vim.api.nvim_buf_set_lines(0, row, row, true, content)
|
||||
|
||||
if #marks_pos > 0 then
|
||||
-- Start session of marks
|
||||
mark:start()
|
||||
for _, pos in ipairs(marks_pos) do
|
||||
mark:add_mark(pos)
|
||||
end
|
||||
vim.cmd("startinsert")
|
||||
mark:jump()
|
||||
-- Add range mark after first jump
|
||||
mark:add_range_mark({ row, 0, row + #template_content, 1 })
|
||||
end
|
||||
vim.cmd("startinsert")
|
||||
mark:jump()
|
||||
-- Add range mark after first jump
|
||||
mark:add_range_mark({ row, 0, row + #template_content, 1 })
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -91,12 +91,15 @@ end
|
||||
---
|
||||
--- - to configure a language, just add your configurations in the `languages` table.
|
||||
--- For example, for the `lua` lang:
|
||||
--- >
|
||||
--- >
|
||||
--- languages = {
|
||||
--- lua = { -- Configuration here }
|
||||
--- }
|
||||
--- <
|
||||
--- Default configurations for a languages can be found in `lua/neogen/configurations/<you_language>.lua`
|
||||
--- <
|
||||
--- Default configurations for a languages can be found in `lua/neogen/configurations/<your_language>.lua`
|
||||
---
|
||||
--- - To know which snippet engines are supported, take a look at |snippet-integration|.
|
||||
--- Example: `snippet_engine = "luasnip"`
|
||||
---
|
||||
---@toc_entry Configure the setup
|
||||
---@tag neogen-configuration
|
||||
@@ -109,6 +112,9 @@ neogen.configuration = {
|
||||
|
||||
-- Configuration for default languages
|
||||
languages = {},
|
||||
|
||||
-- Use a snippet engine to generate annotations.
|
||||
snippet_engine = nil,
|
||||
}
|
||||
--minidoc_afterlines_end
|
||||
|
||||
@@ -120,9 +126,15 @@ neogen.configuration = {
|
||||
--- For example, if you are inside a function, and called `generate({ type = "func" })`,
|
||||
--- Neogen will go until the start of the function and start annotating for you.
|
||||
---
|
||||
---@param opts table Options to change default behaviour of generation.
|
||||
--- - {opts.type} `(string?, default: "func")` Which type we are trying to use for generating annotations.
|
||||
---@param opts table Optional configs to change default behaviour of generation.
|
||||
--- - {opts.type} `(string, default: "func")` Which type we are trying to use for generating annotations.
|
||||
--- Currently supported: `func`, `class`, `type`, `file`
|
||||
--- - {opts.return_snippet} `boolean` if true, will return 3 values from the function call.
|
||||
--- This option is useful if you want to get the snippet to use with a unsupported snippet engine
|
||||
--- Below are the returned values:
|
||||
--- - 1: (type: `string[]`) the resulting lsp snippet
|
||||
--- - 2: (type: `number`) the `row` to insert the annotations
|
||||
--- - 3: (type: `number`) the `col` to insert the annotations
|
||||
---@toc_entry Generate annotations
|
||||
neogen.generate = function(opts)
|
||||
if not conf or not conf.enabled then
|
||||
@@ -130,7 +142,7 @@ neogen.generate = function(opts)
|
||||
return
|
||||
end
|
||||
|
||||
require("neogen.generator")(vim.bo.filetype, opts and opts.type)
|
||||
return require("neogen.generator")(vim.bo.filetype, opts and opts.type, opts and opts.return_snippet)
|
||||
end
|
||||
|
||||
-- Expose more API ============================================================
|
||||
@@ -204,6 +216,10 @@ end
|
||||
---
|
||||
--- Note: We will only document `major` and `minor` versions, not `patch` ones.
|
||||
---
|
||||
--- ## 2.3.0~
|
||||
--- - Added bundled support with snippet engines !
|
||||
--- Check out |snippet-integration| for basic setup
|
||||
--- For more information of possible options, check out |neogen.generate()|
|
||||
--- ## 2.2.0~
|
||||
--- ### Python~
|
||||
--- - Add support for `*args` and `**kwargs`
|
||||
|
||||
53
lua/neogen/snippet.lua
Normal file
53
lua/neogen/snippet.lua
Normal file
@@ -0,0 +1,53 @@
|
||||
local notify = require("neogen.utilities.helpers").notify
|
||||
|
||||
---
|
||||
--- To use a snippet engine, pass the option into neogen setup:
|
||||
--- >
|
||||
--- require('neogen').setup({
|
||||
--- snippet_engine = "luasnip",
|
||||
--- ...
|
||||
--- })
|
||||
--- <
|
||||
--- Some snippet engines come out of the box bundled with neogen:
|
||||
--- - `"luasnip"` (https://github.com/L3MON4D3/LuaSnip)
|
||||
---@tag snippet-integration
|
||||
---@toc_entry Use popular snippet engines
|
||||
local snippet = {}
|
||||
snippet.engines = {}
|
||||
|
||||
--- Converts a template to a lsp-compatible snippet
|
||||
---@param template string[] the generated annotations to parse
|
||||
---@param marks table generated marks for the annotations
|
||||
---@param pos table a tuple of row,col
|
||||
---@return table resulting snippet lines
|
||||
---@private
|
||||
snippet.to_snippet = function(template, marks, pos)
|
||||
local offset = {}
|
||||
for i, m in ipairs(marks) do
|
||||
local r, col = m[1] - pos[1] + 1, m[2]
|
||||
if offset[r] then
|
||||
offset[r] = offset[r] + tostring(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])
|
||||
end
|
||||
return template
|
||||
end
|
||||
|
||||
--- Expand snippet for luasnip engine
|
||||
---@param snip string the snippet to expand
|
||||
---@param pos table a tuple of row, col
|
||||
---@private
|
||||
snippet.engines.luasnip = function(snip, pos)
|
||||
local ok, luasnip = pcall(require, "luasnip")
|
||||
if not ok then
|
||||
notify("Luasnip not found, aborting...", vim.log.levels.ERROR)
|
||||
return
|
||||
end
|
||||
vim.fn.append(pos[1], "")
|
||||
luasnip.lsp_expand(table.concat(snip, "\n"), { pos = { pos[1], pos[2] } })
|
||||
end
|
||||
|
||||
return snippet
|
||||
Reference in New Issue
Block a user