# Neogen - Your Annotation Toolkit [![Neovim](https://img.shields.io/badge/Neovim%200.5+-green.svg?style=for-the-badge&logo=neovim)](https://neovim.io) [![Lua](https://img.shields.io/badge/Lua-blue.svg?style=for-the-badge&logo=lua)](http://www.lua.org)
# Table Of Contents - [Features](#features) - [Requirements](#requirements) - [Installation](#installation) - [Usage](#usage) - [Configuration](#configuration) - [Supported Languages](#supported-languages) - [Adding Languages](#adding-languages) - [GIFS](#gifs) - [Credits](#credits) - [Support](#support) ## Features - Create annotations with one keybind, and jump your cursor in the inserted annotation - Defaults for multiple languages and annotation conventions - Extremely customizable and extensible - Written in lua (and uses Tree-sitter) ![screen2](https://user-images.githubusercontent.com/5306901/135055065-08def797-e5af-49c9-b530-dd5973045c4e.gif) ## Requirements - Install [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) ## Installation Use your favorite package manager to install Neogen, e.g: ```lua use { "danymat/neogen", config = function() require('neogen').setup {} end, requires = "nvim-treesitter/nvim-treesitter", -- Uncomment next line if you want to follow only stable versions -- tag = "*" } ``` ## Usage - If you want to keep it simple, you can use the `:Neogen` command: ```vim " will generate annotation for the function you're inside :Neogen " or you can force a certain type of annotation. " It'll find the next upper node that matches the type " E.g if you're on a method of a class and do `:Neogen class`, it'll find the class declaration and generate the annotation. :Neogen func|class|type|... ``` - If you like to use the lua API, I exposed a function to generate the annotations. ```lua require('neogen').generate() ``` You can bind it to your keybind of choice, like so: ```lua local opts = { noremap = true, silent = true } vim.api.nvim_set_keymap("n", "nf", ":lua require('neogen').generate()", opts) ``` Calling the `generate` function without any parameters will try to generate annotations for the current function. You can provide some options for the generate, like so: ```lua require('neogen').generate({ type = "func" -- the annotation type to generate. Currently supported: func, class, type, file }) ``` For example, I can add an other keybind to generate class annotations: ```lua local opts = { noremap = true, silent = true } vim.api.nvim_set_keymap("n", "nc", ":lua require('neogen').generate({ type = 'class' })", opts) ``` ### Snippet support 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: - `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 } vim.api.nvim_set_keymap("i", "", ":lua require('neogen').jump_next", opts) vim.api.nvim_set_keymap("i", "", ":lua require('neogen').jump_prev", opts) ``` Or, if you want to use a key that's already used for completion purposes, take a look at the code snippet here:
nvim-cmp ```lua local cmp = require('cmp') local neogen = require('neogen') cmp.setup { ... -- You must set mapping if you want. mapping = { [""] = cmp.mapping(function(fallback) if require('neogen').jumpable() then require('neogen').jump_next() else fallback() end end, { "i", "s", }), [""] = cmp.mapping(function(fallback) if require('neogen').jumpable(true) then require('neogen').jump_prev() else fallback() end end, { "i", "s", }), }, ... } ```
## Configuration ```lua require('neogen').setup { enabled = true, --if you want to disable Neogen input_after_comment = true, -- (default: true) automatic jump (with insert mode) on inserted annotation -- jump_map = "" -- (DROPPED SUPPORT, see [here](#cycle-between-annotations) !) The keymap in order to jump in the annotation fields (in insert mode) } } ``` If you're not satisfied with the default configuration for a language, you can change the defaults like this: ```lua require('neogen').setup { enabled = true, languages = { lua = { template = { annotation_convention = "emmylua" -- for a full list of annotation_conventions, see supported-languages below, ... -- for more template configurations, see the language's configuration file in configurations/{lang}.lua } }, ... } } ``` ## Supported Languages There is a list of supported languages and fields, with their annotation style | Languages | Annotation Conventions | Supported annotation types | | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | | sh | [Google Style Guide](https://google.github.io/styleguide/shellguide.html) (`"google_bash"`) | `func`, `file` | | c | [Doxygen](https://www.doxygen.nl/manual/commands.html) (`"doxygen"`) | `func`, `file` | | csharp | [Xmldoc](https://docs.microsoft.com/fr-fr/dotnet/csharp/language-reference/xmldoc/) (`"xmldoc"`)
[Doxygen](https://www.doxygen.nl/manual/commands.html) (`"doxygen"`) | `func`, `file`, `class` | | cpp | [Doxygen](https://www.doxygen.nl/manual/commands.html) (`"doxygen"`) | `func`, `file`, `class` | | go | [GoDoc](https://go.dev/blog/godoc) (`"godoc"`) | `func`, `type` | | java | [Javadoc](https://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javadoc.html#documentationcomments) (`"javadoc`) | `func`, `class` | | javascript | [JSDoc](https://jsdoc.app) (`"jsdoc"`) | `func`, `class`, `type`, `file` | | jsx | [JSDoc](https://jsdoc.app) (`"jsdoc"`) | `func`, `class`, `type`, `file` | | lua | [Emmylua](https://emmylua.github.io/) (`"emmylua"`)
[Ldoc](https://stevedonovan.github.io/ldoc/manual/doc.md.html) (`"ldoc"`) | `func`, `class`, `type`, `file` | | php | [Php-doc](https://docs.phpdoc.org/3.0/guide/references/phpdoc/index.html) (`"phpdoc"`) | `func`, `type`, `class` | | python | [Google docstrings](https://google.github.io/styleguide/pyguide.html) (`"google_docstrings"`)
[Numpydoc](https://numpydoc.readthedocs.io/en/latest/format.html) (`"numpydoc"`)
[reST](https://sphinx-rtd-tutorial.readthedocs.io/en/latest/docstrings.html) (`"reST"`) | `func`, `class`, `type`, `file` | | ruby | [YARD](https://yardoc.org/index.html) (`"yard"`)
[Rdoc](https://github.com/ruby/rdoc) (`"rdoc"`) | `func`, `type`, `class` | | rust | [RustDoc](https://doc.rust-lang.org/rustdoc/what-is-rustdoc.html) (`"rustdoc"`)
[Alternative](https://stackoverflow.com/questions/30009650/how-do-you-document-function-arguments) (`"alternative"`) | `func`, `file`, `class` | | typescript | [JSDoc](https://jsdoc.app) (`"jsdoc"`) | `func`, `class`, `type`, `file` | | tsx | [JSDoc](https://jsdoc.app) (`"jsdoc"`) | `func`, `class`, `type`, `file` | | vue | [JSDoc](https://jsdoc.app) (`"jsdoc"`) | `func`, `class`, `type`, `file` | ## Adding Languages 1. Using the defaults to generate a new language support: [Adding Languages](./docs/adding-languages.md) 2. (advanced) Only if the defaults aren't enough, please see here: [Advanced Integration](./docs/advanced-integration.md) ## GIFS ![screen1](https://user-images.githubusercontent.com/5306901/135055052-6ee6a5e8-3f30-4c41-872e-e624e21a1e98.gif) ![screen3](https://user-images.githubusercontent.com/5306901/135055174-2a9d8b88-7b23-4513-af91-135d885783ec.gif) ![screen4](https://user-images.githubusercontent.com/5306901/135056308-9808c231-b1fd-4c41-80bd-85a08d7286dd.gif) ## Credits - Binx, for making that gorgeous logo for free! - [Github](https://github.com/Binx-Codes/) - [Reddit](https://www.reddit.com/u/binxatmachine) ## Support You like my plugin and want to express your gratitude 👼 ? You can suppport me by donating the equivalent of my morning coffee (no minimum required). I would really appreciate your support as it can motivate me to continue this journey 💝 - [Donate here](https://github.com/sponsors/danymat)