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:
33
README.md
33
README.md
@@ -93,11 +93,38 @@ local opts = { noremap = true, silent = true }
|
|||||||
vim.api.nvim_set_keymap("n", "<Leader>nc", ":lua require('neogen').generate({ type = 'class' })<CR>", opts)
|
vim.api.nvim_set_keymap("n", "<Leader>nc", ":lua require('neogen').generate({ type = 'class' })<CR>", opts)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cycle between annotations
|
### Snippet support
|
||||||
|
|
||||||
I added support passing cursor positionings in templates. That means you can now cycle your cursor between different parts of the annotation.
|
We added snippet support, and we provide defaults for some snippet engines.
|
||||||
|
And this is done via the `snippet_engine` option in neogen's setup:
|
||||||
|
|
||||||
If you want to map some keys to the cycling feature, you can do like so:
|
- `snippet_engine` option will use provided engine to place the annotations:
|
||||||
|
|
||||||
|
Currently supported: `luasnip`.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
require('neogen').setup({ snippet_engine = "luasnip" })
|
||||||
|
```
|
||||||
|
|
||||||
|
That's all ! You can now use your favorite snippet engine to control the annotation, like jumping between placeholders.
|
||||||
|
|
||||||
|
Or, if you want to return the snippet as a string (to integrate with other snippet engines, for example),
|
||||||
|
you can do it by using the `return_snippet` option in the `generate` function:
|
||||||
|
|
||||||
|
- `return_snippet` option will return the annotations as lsp snippets.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local snippet, row, col = require('neogen').generate({ snippet_engine = "luasnip" })
|
||||||
|
```
|
||||||
|
|
||||||
|
And then pass the snippet to the plugin's snippet expansion function.
|
||||||
|
|
||||||
|
### Default cycling support
|
||||||
|
|
||||||
|
_Note that this part is only useful if you don't use the snippets integration._
|
||||||
|
|
||||||
|
If you don't want to use a snippet engine with Neogen, you can leverage Neogen's native jumps between placeholders.
|
||||||
|
To map some keys to the cycling feature, you can do like so:
|
||||||
|
|
||||||
```lua
|
```lua
|
||||||
local opts = { noremap = true, silent = true }
|
local opts = { noremap = true, silent = true }
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ Table of contents:
|
|||||||
Generate annotations.....................................|neogen.generate()|
|
Generate annotations.....................................|neogen.generate()|
|
||||||
Contributing................................................|neogen-develop|
|
Contributing................................................|neogen-develop|
|
||||||
Changes in neogen plugin..................................|neogen-changelog|
|
Changes in neogen plugin..................................|neogen-changelog|
|
||||||
|
Use popular snippet engines............................|snippet-integration|
|
||||||
Configurations for the template table........|neogen-template-configuration|
|
Configurations for the template table........|neogen-template-configuration|
|
||||||
How to create/customize an annotation....................|neogen-annotation|
|
How to create/customize an annotation....................|neogen-annotation|
|
||||||
|
|
||||||
@@ -97,18 +98,24 @@ Neogen provides those defaults, and you can change them to suit your needs
|
|||||||
|
|
||||||
-- Configuration for default languages
|
-- Configuration for default languages
|
||||||
languages = {},
|
languages = {},
|
||||||
|
|
||||||
|
-- Use a snippet engine to generate annotations.
|
||||||
|
snippet_engine = nil,
|
||||||
}
|
}
|
||||||
<
|
<
|
||||||
# Notes~
|
# Notes~
|
||||||
|
|
||||||
- to configure a language, just add your configurations in the `languages` table.
|
- to configure a language, just add your configurations in the `languages` table.
|
||||||
For example, for the `lua` lang:
|
For example, for the `lua` lang:
|
||||||
>
|
>
|
||||||
languages = {
|
languages = {
|
||||||
lua = { -- Configuration here }
|
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"`
|
||||||
|
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
@@ -121,9 +128,15 @@ 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.
|
Neogen will go until the start of the function and start annotating for you.
|
||||||
|
|
||||||
Parameters~
|
Parameters~
|
||||||
{opts} `(table)` Options to change default behaviour of generation.
|
{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.
|
- {opts.type} `(string, default: "func")` Which type we are trying to use for generating annotations.
|
||||||
Currently supported: `func`, `class`, `type`, `file`
|
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
|
||||||
|
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
*neogen-develop*
|
*neogen-develop*
|
||||||
@@ -152,6 +165,10 @@ Here is the current Neogen version:
|
|||||||
|
|
||||||
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.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~
|
## 2.2.0~
|
||||||
### Python~
|
### Python~
|
||||||
- Add support for `*args` and `**kwargs`
|
- Add support for `*args` and `**kwargs`
|
||||||
@@ -167,6 +184,22 @@ Note: We will only document `major` and `minor` versions, not `patch` ones.
|
|||||||
with multiple annotation conventions.
|
with multiple annotation conventions.
|
||||||
|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
*snippet-integration*
|
||||||
|
`snippet`
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
*neogen-template-configuration*
|
*neogen-template-configuration*
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ local granulator = require("neogen.granulator")
|
|||||||
local mark = require("neogen.mark")
|
local mark = require("neogen.mark")
|
||||||
local nodes = require("neogen.utilities.nodes")
|
local nodes = require("neogen.utilities.nodes")
|
||||||
local default_locator = require("neogen.locators.default")
|
local default_locator = require("neogen.locators.default")
|
||||||
|
local snippet = require("neogen.snippet")
|
||||||
local JUMP_TEXT = "$1"
|
local JUMP_TEXT = "$1"
|
||||||
|
|
||||||
local function get_parent_node(filetype, typ, language)
|
local function get_parent_node(filetype, typ, language)
|
||||||
@@ -33,7 +34,7 @@ end
|
|||||||
---@param n integer
|
---@param n integer
|
||||||
---@return string
|
---@return string
|
||||||
local function prefix_generator(template, commentstring, n)
|
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
|
-- Do not append the comment string if not wanted
|
||||||
if template.use_default_comment ~= false then
|
if template.use_default_comment ~= false then
|
||||||
@@ -155,7 +156,7 @@ local function generate_content(parent, data, template, required_type)
|
|||||||
end
|
end
|
||||||
|
|
||||||
return setmetatable({}, {
|
return setmetatable({}, {
|
||||||
__call = function(_, filetype, typ)
|
__call = function(_, filetype, typ, return_snippet)
|
||||||
if filetype == "" then
|
if filetype == "" then
|
||||||
notify("No filetype detected", vim.log.levels.WARN)
|
notify("No filetype detected", vim.log.levels.WARN)
|
||||||
return
|
return
|
||||||
@@ -210,6 +211,28 @@ return setmetatable({}, {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
-- Append content to row
|
||||||
vim.api.nvim_buf_set_lines(0, row, row, true, content)
|
vim.api.nvim_buf_set_lines(0, row, row, true, content)
|
||||||
|
|
||||||
@@ -224,5 +247,6 @@ return setmetatable({}, {
|
|||||||
-- Add range mark after first jump
|
-- Add range mark after first jump
|
||||||
mark:add_range_mark({ row, 0, row + #template_content, 1 })
|
mark:add_range_mark({ row, 0, row + #template_content, 1 })
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -96,7 +96,10 @@ end
|
|||||||
--- lua = { -- Configuration here }
|
--- 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
|
---@toc_entry Configure the setup
|
||||||
---@tag neogen-configuration
|
---@tag neogen-configuration
|
||||||
@@ -109,6 +112,9 @@ neogen.configuration = {
|
|||||||
|
|
||||||
-- Configuration for default languages
|
-- Configuration for default languages
|
||||||
languages = {},
|
languages = {},
|
||||||
|
|
||||||
|
-- Use a snippet engine to generate annotations.
|
||||||
|
snippet_engine = nil,
|
||||||
}
|
}
|
||||||
--minidoc_afterlines_end
|
--minidoc_afterlines_end
|
||||||
|
|
||||||
@@ -120,9 +126,15 @@ neogen.configuration = {
|
|||||||
--- For example, if you are inside a function, and called `generate({ type = "func" })`,
|
--- 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.
|
--- Neogen will go until the start of the function and start annotating for you.
|
||||||
---
|
---
|
||||||
---@param opts table Options to change default behaviour of generation.
|
---@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.
|
--- - {opts.type} `(string, default: "func")` Which type we are trying to use for generating annotations.
|
||||||
--- Currently supported: `func`, `class`, `type`, `file`
|
--- 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
|
---@toc_entry Generate annotations
|
||||||
neogen.generate = function(opts)
|
neogen.generate = function(opts)
|
||||||
if not conf or not conf.enabled then
|
if not conf or not conf.enabled then
|
||||||
@@ -130,7 +142,7 @@ neogen.generate = function(opts)
|
|||||||
return
|
return
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
-- Expose more API ============================================================
|
-- Expose more API ============================================================
|
||||||
@@ -204,6 +216,10 @@ 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.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~
|
--- ## 2.2.0~
|
||||||
--- ### Python~
|
--- ### Python~
|
||||||
--- - Add support for `*args` and `**kwargs`
|
--- - 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
|
||||||
@@ -4,4 +4,4 @@ if _G.MiniDoc == nil then
|
|||||||
minidoc.setup()
|
minidoc.setup()
|
||||||
end
|
end
|
||||||
|
|
||||||
minidoc.generate({ "lua/neogen/init.lua", "lua/neogen/template.lua" }, nil, nil)
|
minidoc.generate({ "lua/neogen/init.lua", "lua/neogen/snippet.lua", "lua/neogen/template.lua" }, nil, nil)
|
||||||
|
|||||||
Reference in New Issue
Block a user