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)
|
||||
```
|
||||
|
||||
### 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
|
||||
local opts = { noremap = true, silent = true }
|
||||
|
||||
@@ -8,6 +8,7 @@ Table of contents:
|
||||
Generate annotations.....................................|neogen.generate()|
|
||||
Contributing................................................|neogen-develop|
|
||||
Changes in neogen plugin..................................|neogen-changelog|
|
||||
Use popular snippet engines............................|snippet-integration|
|
||||
Configurations for the template table........|neogen-template-configuration|
|
||||
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
|
||||
languages = {},
|
||||
|
||||
-- Use a snippet engine to generate annotations.
|
||||
snippet_engine = nil,
|
||||
}
|
||||
<
|
||||
# Notes~
|
||||
|
||||
- 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"`
|
||||
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
@@ -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.
|
||||
|
||||
Parameters~
|
||||
{opts} `(table)` Options to change default behaviour of generation.
|
||||
- {opts.type} `(string?, default: "func")` Which type we are trying to use for generating annotations.
|
||||
{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
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
*neogen-develop*
|
||||
@@ -152,6 +165,10 @@ Here is the current Neogen version:
|
||||
|
||||
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`
|
||||
@@ -167,6 +184,22 @@ Note: We will only document `major` and `minor` versions, not `patch` ones.
|
||||
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*
|
||||
|
||||
@@ -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,6 +211,28 @@ return setmetatable({}, {
|
||||
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
|
||||
vim.api.nvim_buf_set_lines(0, row, row, true, content)
|
||||
|
||||
@@ -224,5 +247,6 @@ return setmetatable({}, {
|
||||
-- Add range mark after first jump
|
||||
mark:add_range_mark({ row, 0, row + #template_content, 1 })
|
||||
end
|
||||
end
|
||||
end,
|
||||
})
|
||||
|
||||
@@ -96,7 +96,10 @@ end
|
||||
--- 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
|
||||
@@ -4,4 +4,4 @@ if _G.MiniDoc == nil then
|
||||
minidoc.setup()
|
||||
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