From 089b972acca731ac943dfbc454c39003468d7e11 Mon Sep 17 00:00:00 2001 From: numToStr <24727447+numToStr@users.noreply.github.com> Date: Fri, 19 Aug 2022 16:10:35 +0530 Subject: [PATCH] feat: help docs `:h comment-nvim` (#205) Finally! We now have proper help docs for everything from keybindings to Lua API. It's auto generated from emmylua annotation so it would always be up to date. Credits to https://github.com/phaazon/hop.nvim for excellent docs and reference. --- .github/workflows/ci.yaml | 1 - .gitignore | 3 + README.md | 136 ++---- doc/API.md | 228 +--------- doc/Comment.txt | 874 ++++++++++++++++++++++++++++++++++++++ doc/plugs.md | 35 +- dump.lua | 56 --- lua/Comment/api.lua | 207 ++++++--- lua/Comment/config.lua | 123 ++++-- lua/Comment/extra.lua | 9 +- lua/Comment/ft.lua | 78 +++- lua/Comment/init.lua | 87 +++- lua/Comment/opfunc.lua | 113 ++--- lua/Comment/utils.lua | 10 +- plugin/Comment.lua | 85 ++++ 15 files changed, 1449 insertions(+), 596 deletions(-) create mode 100644 doc/Comment.txt delete mode 100644 dump.lua diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 31900b2..0870cfc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -6,7 +6,6 @@ on: - "**.lua" branches: - master - - docs env: PLUGIN_NAME: Comment diff --git a/.gitignore b/.gitignore index 2deeee7..8aa6b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,6 @@ luac.out tmp scratch + +# ignore generated doc tags +doc/tags diff --git a/README.md b/README.md index 7e47fb9..3f2d052 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ### โœจ Features - Supports treesitter. [Read more](#treesitter) -- Supports `commentstring`. [Read more](#commentstring) +- Supports `commentstring`. Read `:h comment.commentstring` - Supports line (`//`) and block (`/* */`) comments - Dot (`.`) repeat support for `gcc`, `gbc` and friends - Count support for `[count]gcc` and `[count]gbc` @@ -37,6 +37,10 @@ Plug 'numToStr/Comment.nvim' lua require('Comment').setup() ``` +### ๐Ÿ“– Getting Help + +`Comment.nvim` provides help docs which can be accessed by running `:help comment-nvim` + ### โš’๏ธ Setup @@ -63,46 +67,31 @@ EOF #### Configuration (optional) -Following are the **default** config for the [`setup()`](#setup). If you want to override, just modify the option that you want then it will be merged with the default config. +Following are the **default** config for the [`setup()`](#setup). If you want to override, just modify the option that you want then it will be merged with the default config. Read `:h comment.config` for more info. ```lua { ---Add a space b/w comment and the line - ---@type boolean|fun():boolean padding = true, - ---Whether the cursor should stay at its position - ---NOTE: This only affects NORMAL mode mappings and doesn't work with dot-repeat - ---@type boolean sticky = true, - - ---Lines to be ignored while comment/uncomment. - ---Could be a regex string or a function that returns a regex string. - ---Example: Use '^$' to ignore empty lines - ---@type string|fun():string + ---Lines to be ignored while (un)comment ignore = nil, - ---LHS of toggle mappings in NORMAL mode - ---@type table toggler = { ---Line-comment toggle keymap line = 'gcc', ---Block-comment toggle keymap block = 'gbc', }, - - ---LHS of operator-pending mappings in NORMAL mode - ---LHS of mapping in VISUAL mode - ---@type table + ---LHS of operator-pending mappings in NORMAL and VISUAL mode opleader = { ---Line-comment keymap line = 'gc', ---Block-comment keymap block = 'gb', }, - ---LHS of extra mappings - ---@type table extra = { ---Add comment on the line above above = 'gcO', @@ -111,29 +100,19 @@ Following are the **default** config for the [`setup()`](#setup). If you want to ---Add comment at the end of line eol = 'gcA', }, - - ---Create basic (operator-pending) and extended mappings for NORMAL + VISUAL mode - ---NOTE: If `mappings = false` then the plugin won't create any mappings - ---@type boolean|table + ---Enable keybindings + ---NOTE: If given `false` then the plugin won't create any mappings mappings = { - ---Operator-pending mapping - ---Includes `gcc`, `gbc`, `gc[count]{motion}` and `gb[count]{motion}` - ---NOTE: These mappings can be changed individually by `opleader` and `toggler` config + ---Operator-pending mapping; `gcc` `gbc` `gc[count]{motion}` `gb[count]{motion}` basic = true, - ---Extra mapping - ---Includes `gco`, `gcO`, `gcA` + ---Extra mapping; `gco`, `gcO`, `gcA` extra = true, - ---Extended mapping - ---Includes `g>`, `g<`, `g>[count]{motion}` and `g<[count]{motion}` + ---Extended mapping; `g>` `g<` `g>[count]{motion}` `g<[count]{motion}` extended = false, }, - - ---Pre-hook, called before commenting the line - ---@type fun(ctx: CommentCtx):string + ---Function to call before (un)comment pre_hook = nil, - - ---Post-hook, called after commenting is done - ---@type fun(ctx: CommentCtx) + ---Function to call after (un)comment post_hook = nil, } ``` @@ -224,14 +203,6 @@ These mappings are disabled by default. (config: `mappings.extended`) `gbac` - Toggle comment around a class (w/ LSP/treesitter support) ``` - - -### โš™๏ธ API - -- [Plug Mappings](./doc/plugs.md) - Excellent for creating custom keybindings - -- [Lua API](./doc/API.md) - Details the Lua API. Great for making custom comment function. - ### ๐ŸŒณ Treesitter @@ -254,12 +225,10 @@ There are two hook methods i.e `pre_hook` and `post_hook` which are called befor -- `pre_hook` - This method is called with a [`ctx`](#comment-context) argument before comment/uncomment is started. It can be used to return a custom `commentstring` which will be used for comment/uncomment the lines. You can use something like [nvim-ts-context-commentstring](https://github.com/JoosepAlviste/nvim-ts-context-commentstring) to compute the commentstring using treesitter. +- `pre_hook` - Called with a `ctx` argument (Read `:h comment.utils.CommentCtx`) before (un)comment. Can optionally return a `commentstring` to be used for (un)commenting. You can use [nvim-ts-context-commentstring](https://github.com/JoosepAlviste/nvim-ts-context-commentstring) to easily comment `tsx/jsx` files. ```lua --- NOTE: The example below is a proper integration and it is RECOMMENDED. { - ---@param ctx CommentCtx pre_hook = function(ctx) -- Only calculate commentstring for tsx filetypes if vim.bo.filetype == 'typescriptreact' then @@ -285,13 +254,14 @@ There are two hook methods i.e `pre_hook` and `post_hook` which are called befor } ``` +> **Note** - `Comment.nvim` already supports [`treesitter`](#treesitter) out-of-the-box except for `tsx/jsx`. + -- `post_hook` - This method is called after commenting is done. It receives the same [`ctx`](#comment-context) argument as [`pre_hook`](#pre_hook). +- `post_hook` - This method is called after (un)commenting. It receives the same `ctx` (Read `:h comment.utils.CommentCtx`) argument as [`pre_hook`](#pre_hook). ```lua { - ---@param ctx CommentCtx post_hook = function(ctx) if ctx.range.srow == ctx.range.erow then -- do something with the current line @@ -347,7 +317,7 @@ ignore = '^const(.*)=(%s?)%((.*)%)(%s?)=>' Most languages/filetypes have native support for comments via `commentstring` but there might be a filetype that is not supported. There are two ways to enable commenting for unsupported filetypes: -1. You can set `commentstring` for that particular filetype like the following +1. You can set `commentstring` for that particular filetype like the following. Read `:h commentstring` for more info. ```lua vim.bo.commentstring = '//%s' @@ -356,27 +326,23 @@ vim.bo.commentstring = '//%s' vim.api.nvim_command('set commentstring=//%s') ``` -> Run `:h commentstring` for more help - -2. You can also use this plugin interface to store both line and block commentstring for the filetype. You can treat this as a more powerful version of the `commentstring` +2. You can also use this plugin interface to store both line and block commentstring for the filetype. You can treat this as a more powerful version of the `commentstring`. Read `:h comment.ft` for more info. ```lua local ft = require('Comment.ft') -- 1. Using set function --- Just set only line comment -ft.set('yaml', '#%s') - --- Or set both line and block commentstring --- You can also chain the set calls -ft.set('javascript', {'//%s', '/*%s*/'}).set('conf', '#%s') +ft + -- Set only line comment + .set('yaml', '#%s') + -- Or set both line and block commentstring + .set('javascript', {'//%s', '/*%s*/'}) -- 2. Metatable magic --- One filetype at a time ft.javascript = {'//%s', '/*%s*/'} ft.yaml = '#%s' @@ -391,56 +357,6 @@ ft.lang('javascript') -- { '//%s', '/*%s*/' } > PR(s) are welcome to add more commentstring inside the plugin - - -### ๐Ÿงต Comment String - -Although, `Comment.nvim` supports neovim's `commentstring` but unfortunately it has the least priority. The commentstring is taken from the following place in the respective order. - -- [`pre_hook`](#hooks) - If a string is returned from this method then it will be used for commenting. - -- [`ft.lua`](#ft-lua) - If the current filetype is found in the table, then the string there will be used. - -- `commentstring` - Neovim's native commentstring for the filetype - - - -> There is one caveat with this approach. If someone sets the `commentstring` (w/o returning a string) from the `pre_hook` method and if the current filetype also exists in the `ft_table` then the commenting will be done using the string in `ft_table` instead of using `commentstring` - - - -### ๐Ÿง  Comment Context - -The following object is provided as an argument to `pre_hook` and `post_hook` functions. - -> I am just placing it here just for documentation purpose - -```lua ----Comment context ----@class CommentCtx ----@field ctype CommentType ----@field cmode CommentMode ----@field cmotion CommentMotion ----@field range CommentRange - ----Range of the selection that needs to be commented ----@class CommentRange ----@field srow integer Starting row ----@field scol integer Starting column ----@field erow integer Ending row ----@field ecol integer Ending column -``` - -`CommentType`, `CommentMode` and `CommentMotion` all of them are exported from the plugin's utils for reuse - -```lua -require('Comment.utils').ctype.{linewise,blockwise} - -require('Comment.utils').cmode.{toggle,comment,uncomment} - -require('Comment.utils').cmotion.{line,char,v,V} -``` - ### ๐Ÿค Contributing There are multiple ways to contribute reporting/fixing bugs, feature requests. You can also submit commentstring to this plugin by updating [ft.lua](./lua/Comment/ft.lua) and sending PR. diff --git a/doc/API.md b/doc/API.md index a547063..ecc574f 100644 --- a/doc/API.md +++ b/doc/API.md @@ -1,227 +1 @@ -# โš™๏ธ API - -Following are list of APIs that are exported from the plugin. These can be used to setup [custom keybinding](#usage) or to make your own custom comment function. All API functions can take a `{motion}` (Read `:h :map-operator`) and a optional [`{cfg}`](../README.md#config) argument which can be used to override the [default configuration](../README.md#config) - -
-Deprecated API - -```lua ----@alias OpMode 'line'|'char'|'v'|'V' Vim operator-mode motions. Read `:h map-operator` -``` - -### Core - -These APIs powers the [basic-mappings](../README.md#basic-mappings). - -```lua ---######### LINEWISE #########-- - ----Toggle linewise-comment on the current line ----@param cfg? CommentConfig -require('Comment.api').toggle_current_linewise(cfg) - ----(Operator-Pending) Toggle linewise-comment on the current line ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').toggle_current_linewise_op(opmode, cfg) - ----(Operator-Pending) Toggle linewise-comment over multiple lines ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').toggle_linewise_op(opmode, cfg) - ----Toggle linewise-comment over multiple lines using `vim.v.count` ----@param cfg? CommentConfig -require('Comment.api').toggle_linewise_count(cfg) - ---######### BLOCKWISE #########-- - ----Toggle blockwise comment on the current line ----@param cfg? CommentConfig -require('Comment.api').toggle_current_blockwise(cfg) - ----(Operator-Pending) Toggle blockwise comment on the current line ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').toggle_current_blockwise_op(opmode, cfg) - ----(Operator-Pending) Toggle blockwise-comment over multiple lines ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').toggle_blockwise_op(opmode, cfg) - ----Toggle blockwise-comment over multiple lines using `vim.v.count` ----@param cfg? CommentConfig -require('Comment.api').toggle_blockwise_count(cfg) -``` - -### Extra - -These APIs powers the [extra-mappings](../README.md#extra-mappings) and also provides the blockwise version. - -```lua ---######### LINEWISE #########-- - ----Insert a linewise-comment below ----@param cfg? CommentConfig -require('Comment.api').insert_linewise_below(cfg) - ----Insert a linewise-comment above ----@param cfg? CommentConfig -require('Comment.api').insert_linewise_above(cfg) - ----Insert a linewise-comment at the end-of-line ----@param cfg? CommentConfig -require('Comment.api').insert_linewise_eol(cfg) - ---######### BLOCKWISE #########-- - ----Insert a blockwise-comment below ----@param cfg? CommentConfig -require('Comment.api').insert_blockwise_below(cfg) - ----Insert a blockwise-comment above ----@param cfg? CommentConfig -require('Comment.api').insert_blockwise_above(cfg) - ----Insert a blockwise-comment at the end-of-line ----@param cfg? CommentConfig -require('Comment.api').insert_blockwise_eol(cfg) -``` - -### Extended - -These APIs powers the [extended-mappings](../README.md#extended-mappings). - -```lua ---######### LINEWISE #########-- - ----Comment current line using linewise-comment ----@param cfg? CommentConfig -require('Comment.api').comment_current_linewise(cfg) - ----(Operator-Pending) Comment current line using linewise-comment ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').comment_current_linewise_op(opmode, cfg) - ----(Operator-Pending) Comment multiple line using linewise-comment ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').comment_linewise_op(opmode, cfg) - ----Uncomment current line using linewise-comment ----@param cfg? CommentConfig -require('Comment.api').uncomment_current_linewise(cfg) - ----(Operator-Pending) Uncomment current line using linewise-comment ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').uncomment_current_linewise_op(opmode, cfg) - ----(Operator-Pending) Uncomment multiple line using linewise-comment ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').uncomment_linewise_op(opmode, cfg) - ---######### BLOCKWISE #########-- - ----Comment current line using linewise-comment ----@param cfg? CommentConfig -require('Comment.api').comment_current_blockwise(cfg) - ----(Operator-Pending) Comment current line using blockwise-comment ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').comment_current_blockwise_op(opmode, cfg) - ----Uncomment current line using blockwise-comment ----@param cfg? CommentConfig -require('Comment.api').uncomment_current_blockwise(cfg) - ----(Operator-Pending) Uncomment current line using blockwise-comment ----@param opmode OpMode ----@param cfg? CommentConfig -require('Comment.api').uncomment_current_blockwise_op(opmode, cfg) -``` - -
- -### Core - -> **NOTE**: -> -> 1. All API functions are dot-repeatable except `*.count()` -> 2. For the `*.current()` functions, `{motion}` argument is optional -> 3. `{cfg}` is optional for all the API functions - -```lua -require('Comment.api').toggle.linewise(motion, cfg) -require('Comment.api').toggle.linewise.current(motion, cfg) -require('Comment.api').toggle.linewise.count(count, cfg) - -require('Comment.api').toggle.blockwise(motion, cfg) -require('Comment.api').toggle.blockwise.current(motion, cfg) -require('Comment.api').toggle.blockwise.count(count, cfg) - -require('Comment.api').comment.linewise(motion, cfg) -require('Comment.api').comment.linewise.current(motion, cfg) -require('Comment.api').comment.linewise.count(count, cfg) - -require('Comment.api').comment.blockwise(motion, cfg) -require('Comment.api').comment.blockwise.current(motion, cfg) -require('Comment.api').comment.blockwise.count(count, cfg) - -require('Comment.api').uncomment.linewise(motion, cfg) -require('Comment.api').uncomment.linewise.current(motion, cfg) -require('Comment.api').uncomment.linewise.count(count, cfg) - -require('Comment.api').uncomment.blockwise(motion, cfg) -require('Comment.api').uncomment.blockwise.current(motion, cfg) -require('Comment.api').uncomment.blockwise.count(count, cfg) -``` - -### Additional - -```lua ----Callback function to provide dot-repeat support ----NOTE: VISUAL mode mapping doesn't support dot-repeat ----@param cb string Name of the API function to call -require('Comment.api').call(cb) -``` - - - -# โš™๏ธ Usage - -Following are some example keybindings using the APIs. - -```lua --- # NORMAL mode - --- Linewise toggle current line using C-/ -vim.keymap.set('n', '', 'lua require("Comment.api").toggle.linewise.current()') --- or with dot-repeat support --- vim.keymap.set('n', '', 'lua require("Comment.api").call("toggle.linewise.current")g@$') - --- Blockwise toggle current line using C-\ -vim.keymap.set('n', '', 'lua require("Comment.api").toggle.blockwise.current()') --- or with dot-repeat support --- vim.keymap.set('n', '', 'lua require("Comment.api").call("toggle.blockwise.current")g@$') - --- Linewise toggle multiple line using gc with dot-repeat support --- Example: gc3j will comment 4 lines -vim.keymap.set('n', 'gc', 'lua require("Comment.api").call("toggle.linewise")g@') - --- Blockwise toggle multiple line using gc with dot-repeat support --- Example: gb3j will comment 4 lines -vim.keymap.set('n', 'gb', 'lua require("Comment.api").call("toggle.blockwise")g@') - --- # VISUAL mode - --- Linewise toggle using C-/ -vim.keymap.set('x', '', 'lua require("Comment.api").toggle.linewise(vim.fn.visualmode())') - --- Blockwise toggle using gb -vim.keymap.set('x', 'gb', 'lua require("Comment.api").toggle.blockwise(vim.fn.visualmode())') -``` +`Comment.nvim` now has `:help` docs ๐ŸŽ‰. Read `:h comment.api` for the Lua API documentation and usage. diff --git a/doc/Comment.txt b/doc/Comment.txt new file mode 100644 index 0000000..8d303af --- /dev/null +++ b/doc/Comment.txt @@ -0,0 +1,874 @@ +*comment-nvim.txt* For Neovim version 0.7 Last change: 2021 July 11 + + _____ _ _ + / ____/ / / (_) + / / ___ _ __ ___ _ __ ___ ___ _ __ / /_ _ ____ ___ _ __ ___ + / / / _ \/ '_ ` _ \/ '_ ` _ \ / _ \ '_ \/ __/ / '_ \ \ / / / '_ ` _ \ + / /___/ (_) / / / / / / / / / / / __/ / / / /_ _/ / / \ V // / / / / / / + \_____\___//_/ /_/ /_/_/ /_/ /_/\___/_/ /_/\__(_)_/ /_/\_/ /_/_/ /_/ /_/ + + ยท Smart and Powerful comment plugin ยท + + +================================================================================ +Table of Contents *comment.contents* + +Introductionยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment-nvim| +Usageยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment.usage| +Configurationยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment.config| +Keybindingsยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment.keybindings| +Plug Mappingsยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment.plugmap| +Core Lua APIยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment.api| +Language/Filetype detectionยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment.ft| +Utilitiesยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment.utils| +Operator-mode APIยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment.opfunc| +Insert APIยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยทยท|comment.extra| + +================================================================================ +Introduction *comment-nvim* + +Comment.nvim is a smart and powerful comment plugin for neovim. It supports +dot-repeat, counts, line ('//') and block ('/* */') comments, and can be used +with motion and text-objects. It has native integration with tressitter to +support embedded filetypes like html, vue, markdown with codeblocks etc. + + *comment.dotrepeat* +Comment.nvim uses |operatorfunc| combined with |g@| to support dot-repeat, and +various marks i.e., |'[| |']| |'<| |'>| to deduce the region with the {motion} +argument provided by 'operatorfunc'. See |comment.api.call| + + *comment.commentstring* +Comment.nvim picks commentstring, either linewise/blockwise, from one of the +following places + + 1. 'pre_hook' + If a string is returned from this function then it will be used for + (un)commenting. See |comment.config| + + 2. |comment.ft| + Using the commentstring table inside the plugin (using treesitter). + Fallback to |commentstring|, if not found. + + 3. |commentstring| - Neovim's native commentstring for the filetype + +Although Comment.nvim supports native 'commentstring' but unfortunately it has +the least priority. The caveat with this approach is that if someone sets the +`commentstring`, without returning it, from the 'pre_hook' and the current +filetype also exists in the |comment.ft| then the commenting will be done using +the string in |comment.ft| instead of using 'commentstring'. To override this +behavior, you have to manually return the 'commentstring' from 'pre_hook'. + +================================================================================ +Usage *comment.usage* + +Before using the plugin, you need to call the `setup()` function to create the +default mappings. If you want, you can also override the default configuration +by giving it a partial 'comment.config.Config' object, it will then be merged +with the default config. + +C.setup({config?}) *comment.usage.setup* + Configures the plugin + + Parameters: ~ + {config?} (CommentConfig) User configuration + + Returns: ~ + {CommentConfig} Returns the mutated config + + See: ~ + |comment.config| + + Usage: ~ + > + require('Comment').setup({ + ignore = '^$', + toggler = { + line = 'cc', + block = 'bc', + }, + opleader = { + line = 'c', + block = 'b', + }, + }) + < + + +================================================================================ +Configuration *comment.config* + +CommentConfig *comment.config.CommentConfig* + Plugin's configuration + + Fields: ~ + {padding} (boolean) Controls space between the comment + and the line (default: 'true') + {sticky} (boolean) Whether cursor should stay at the + same position. Only works with NORMAL + mode mappings (default: 'true') + {ignore} (string|fun():string) Lua pattern used to ignore lines + during (un)comment (default: 'nil') + {mappings} (Mappings|boolean) + {toggler} (Toggler) + {opleader} (Opleader) + {extra} (ExtraMapping) + {pre_hook} (fun(ctx):string) Function to call before (un)comment + (default: 'nil') + {post_hook} (fun(ctx)) Function to call after (un)comment + (default: 'nil') + + +Mappings *comment.config.Mappings* + Create default mappings + + Fields: ~ + {basic} (boolean) Enables operator-pending mapping; `gcc`, `gbc`, + `gc{motion}` and `gb{motion}` (default: 'true') + {extra} (boolean) Enable extra mapping; `gco`, `gcO` and `gcA` + (default: 'true') + {extended} (boolean) Enable extended mapping; `g>`, `g{motion}` and `g<{motion}` + (default: 'false') + + +Toggler *comment.config.Toggler* + LHS of toggle mappings in NORMAL + + Fields: ~ + {line} (string) Linewise comment (default: 'gcc') + {block} (string) Blockwise comment (default: 'gbc') + + +Opleader *comment.config.Opleader* + LHS of operator-mode mappings in NORMAL and VISUAL mode + + Fields: ~ + {line} (string) Linewise comment (default: 'gc') + {block} (string) Blockwise comment (default: 'gb') + + +ExtraMapping *comment.config.ExtraMapping* + LHS of extra mappings + + Fields: ~ + {below} (string) Inserts comment below (default: 'gco') + {above} (string) Inserts comment above (default: 'gcO') + {eol} (string) Inserts comment at the end of line (default: 'gcA') + + +Config:get() *comment.config:get* + Get the config + + Returns: ~ + {CommentConfig} + + Usage: ~ + > + require('Comment.config'):get() + < + + +================================================================================ +Keybindings *comment.keybindings* + +Comment.nvim provides default keybinds which is used for (un)comment your code. +These keybinds are enabled upon calling |commen.usage.setup| and can be +configured or disabled, if desired. + +Basic: ~ + + *gc* + *gb* + *gc[count]{motion}* + *gb[count]{motion}* + + Toggle comment on a region using linewise/blockwise comment. In 'NORMAL' + mode, it uses 'Operator-Pending' mode to listen for an operator/motion. + In 'VISUAL' mode it simply comment the selected region. + + *gcc* + *gbc* + *[count]gcc* + *[count]gbc* + + Toggle comment on the current line using linewise/blockwise comment. If + prefixed with a 'v:count' then it will comment over the number of lines + corresponding to the {count}. These are only available in 'NORMAL' mode. + + +Extra: ~ + + *gco* - Inserts comment below and enters INSERT mode + *gcO* - Inserts comment above and enters INSERT mode + *gcA* - Inserts comment at the end of line and enters INSERT mode + +================================================================================ +Plug Mappings *comment.plugmap* + +Comment.nvim provides mappings for most commonly used actions. These +can be used to make custom keybindings and are enabled by default. All plug +mappings has support for dot-repeat except VISUAL mode keybindings. To create +custom comment function, check out 'comment.api' section. + + *(comment_toggle_linewise)* + *(comment_toggle_blockwise)* + + Toggle comment on a region with linewise/blockwise comment in NORMAL mode. + using |Operator-Pending| mode (or |g@|) to get the region to comment. + These powers the |gc| and |gb| keybindings. + + *(comment_toggle_linewise_current)* + *(comment_toggle_blockwise_current)* + + Toggle comment on the current line with linewise/blockwise comment in + NORMAL mode. These powers the |gcc| and 'gbc' keybindings. + + *(comment_toggle_linewise_count)* + *(comment_toggle_blockwise_count)* + + Toggle comment on a region using 'v:count' with linewise/blockwise comment + in NORMAL mode. These powers the |[count]gcc| and |[count]gbc| keybindings. + + *(comment_toggle_linewise_visual)* + *(comment_toggle_blockwise_visual)* + + Toggle comment on the selected region with linewise/blockwise comment in + NORMAL mode. These powers the |{visual}gc| and |{visual}gb| keybindings. + +Usage: ~ + +> + -- Toggle current line or with count + vim.keymap.set('n', 'gcc', function() + return vim.v.count == 0 + and '(comment_toggle_linewise_current)' + or '(comment_toggle_linewise_count)' + end, { expr = true }) + + -- Toggle in Op-pending mode + vim.keymap.set('n', 'gc', '(comment_toggle_linewise)') + + -- Toggle in VISUAL mode + vim.keymap.set('x', 'gc', '(comment_toggle_linewise_visual)') +< + +================================================================================ +Core Lua API *comment.api* + +This module provides the core lua APIs which is used by the default keybindings +and (Read |comment.plugmap|) mappings. These API can be used to setup your +own custom keybindings or to even make your (un)comment function. + + *comment.api.toggle.linewise* + *comment.api.toggle.blockwise* +api.toggle *comment.api.toggle* + Provides API to toggle comments over a region, on current-line, or with a + count using line or block comment string. + + All functions takes a {motion} argument, except '*.count()' function which + takes an {count} argument, and an optional {config} parameter. + + Type: ~ + (table) A metatable containing API functions + + See: ~ + |comment.opfunc.OpMotion| + |comment.config| + + Usage: ~ + > + local api = require('Comment.api') + + api.toggle.linewise(motion, config) + api.toggle.linewise.current(motion?, config?) + api.toggle.linewise.count(count, config?) + + api.toggle.blockwise(motion, config?) + api.toggle.blockwise.current(motion?, config?) + api.toggle.blockwise.count(count, config?) + + -- NORMAL mode + + -- Toggle current line (linewise) using C-/ + vim.keymap.set('n', '', api.toggle.linewise.current) + + -- Toggle current line (blockwise) using C-\ + vim.keymap.set('n', '', api.toggle.blockwise.current) + + -- Toggle lines (linewise) with dot-repeat support + -- Example: gc3j will comment 4 lines + vim.keymap.set( + 'n', 'gc', api.call('toggle.linewise', 'g@'), + { expr = true } + ) + + -- Toggle lines (blockwise) with dot-repeat support + -- Example: gb3j will comment 4 lines + vim.keymap.set( + 'n', 'gb', api.call('toggle.blockwise', 'g@'), + { expr = true } + ) + + -- VISUAL mode + + local esc = vim.api.nvim_replace_termcodes( + '', true, false, true + ) + + -- Linewise toggle (linewise) + vim.keymap.set('x', 'c', function() + vim.api.nvim_feedkeys(esc, 'nx', false) + api.toggle.linewise(vim.fn.visualmode()) + end) + + -- Blockwise toggle (blockwise) + vim.keymap.set('x', 'b', function() + vim.api.nvim_feedkeys(esc, 'nx', false) + api.toggle.blockwise(vim.fn.visualmode()) + end) + < + + + *comment.api.comment.linewise* + *comment.api.comment.blockwise* +api.comment *comment.api.comment* + Provides API to (only) comment a region, on current-line, or with a + count using line or block comment string. + + All functions takes a {motion} argument, except '*.count()' function which + takes an {count} argument, and an optional {config} parameter. + + Type: ~ + (table) A metatable containing API functions + + See: ~ + |comment.opfunc.OpMotion| + |comment.config| + + Usage: ~ + > + local api = require('Comment.api') + + api.comment.linewise(motion, config) + api.comment.linewise.current(motion?, config?) + api.comment.linewise.count(count, config?) + + api.comment.blockwise(motion, config?) + api.comment.blockwise.current(motion?, config?) + api.comment.blockwise.count(count, config?) + < + + + *comment.api.uncomment.linewise* + *comment.api.uncomment.blockwise* +api.uncomment *comment.api.uncomment* + Provides API to (only) uncomment a region, on current-line, or with a + count using line or block comment string. + + All functions takes a {motion} argument, except '*.count()' function which + takes an {count} argument, and an optional {config} parameter. + + Type: ~ + (table) A metatable containing API functions + + See: ~ + |comment.opfunc.OpMotion| + |comment.config| + + Usage: ~ + > + local api = require('Comment.api') + + api.uncomment.linewise(motion, config) + api.uncomment.linewise.current(motion?, config?) + api.uncomment.linewise.count(count, config?) + + api.uncomment.blockwise(motion, config?) + api.uncomment.blockwise.current(motion?, config?) + api.uncomment.blockwise.count(count, config?) + < + + +api.insert *comment.api.insert* + Provides API to to insert comment on previous, next or at the end-of-line. + All functions takes an optional {config} parameter. + + Type: ~ + (table) A metatable containing API functions + + See: ~ + |comment.config| + + Usage: ~ + > + local api = require('Comment.api') + + api.insert.linewise.above(cfg?) + api.insert.linewise.below(cfg?) + api.insert.linewise.eol(cfg?) + + api.insert.blockwise.above(cfg?) + api.insert.blockwise.below(cfg?) + api.insert.blockwise.eol(cfg?) + < + + +api.locked *comment.api.locked* + Wraps the given API function with 'lockmarks' to preserve marks/jumps + + Type: ~ + (fun(cb:string):fun(motion:OpMotion)) + + See: ~ + |lockmarks| + |comment.opfunc.OpMotion| + + Usage: ~ + > + local api = require('Comment.api') + + vim.keymap.set( + 'n', 'c', api.locked('toggle.linewise.current') + ) + + local esc = vim.api.nvim_replace_termcodes( + '', true, false, true + ) + vim.keymap.set('x', 'c', function() + vim.api.nvim_feedkeys(esc, 'nx', false) + api.locked('toggle.linewise')(vim.fn.visualmode()) + end) + + -- NOTE: `locked` method is just a wrapper around `lockmarks` + vim.api.nvim_command([[ + lockmarks lua require('Comment.api').toggle.linewise.current() + ]]) + < + + +api.call({cb}, {op}) *comment.api.call* + Callback function which does the following + 1. Sets 'operatorfunc' for dot-repeat + 2. Preserves jumps and marks + 3. Stores last cursor position + + Parameters: ~ + {cb} (string) Name of the API function to call + {op} ('g@'|'g@$') Operator string to execute + + Returns: ~ + {fun():string} Keymap RHS callback + + See: ~ + |g@| + |operatorfunc| + + Usage: ~ + > + local api = require('Comment.api') + vim.keymap.set( + 'n', 'gc', api.call('toggle.linewise', 'g@'), + { expr = true } + ) + vim.keymap.set( + 'n', 'gcc', api.call('toggle.linewise.current', 'g@$'), + { expr = true } + ) + < + + +================================================================================ +Language/Filetype detection *comment.ft* + +ft.set({lang}, {val}) *comment.ft.set* + Sets a commentstring(s) for a filetype/language + + Parameters: ~ + {lang} (string) Filetype/Language of the buffer + {val} (string|string[]) + + Returns: ~ + {table} Returns itself + + Usage: ~ + > + local ft = require('Comment.ft') + + --1. Using method signature + -- Set only line comment or both + -- You can also chain the set calls + ft.set('yaml', '#%s').set('javascript', {'//%s', '/*%s*/'}) + + -- 2. Metatable magic + ft.javascript = {'//%s', '/*%s*/'} + ft.yaml = '#%s' + + -- 3. Multiple filetypes + ft({'go', 'rust'}, {'//%s', '/*%s*/'}) + ft({'toml', 'graphql'}, '#%s') + < + + +ft.get({lang}, {ctype}) *comment.ft.get* + Get line/block commentstring for a given filetype + + Parameters: ~ + {lang} (string) Filetype/Language of the buffer + {ctype} (integer) See |comment.utils.ctype| + + Returns: ~ + {string} Commentstring + + Usage: ~ + > + local ft = require('Comment.ft') + local U = require('Comment.utils') + print(ft.get(vim.bo.filetype, U.ctype.linewise)) + < + + +ft.lang({lang}) *comment.ft.lang* + Get a copy of commentstring(s) for a given filetype + + Parameters: ~ + {lang} (string) Filetype/Language of the buffer + + Returns: ~ + {string[]} Tuple of { line, block } commentstring + + Usage: ~ + > + require('Comment.ft').lang(vim.bo.filetype) + < + + +ft.contains({tree}, {range}) *comment.ft.contains* + Get a language tree for a given range by walking the parse tree recursively. + This uses 'lua-treesitter' API under the hood. This can be used to calculate + language of a particular region which embedded multiple filetypes like html, + vue, markdown etc. + + NOTE: This ignores `tree-sitter-comment` parser, if installed. + + Parameters: ~ + {tree} (userdata) Parse tree to be walked + {range} (integer[]) Range to check for + {start_row, start_col, end_row, end_col} + + Returns: ~ + {userdata} Returns a |treesitter-languagetree| + + See: ~ + |treesitter-languagetree| + |lua-treesitter-core| + + Usage: ~ + > + local ok, parser = pcall(vim.treesitter.get_parser, 0) + assert(ok, "No parser found!") + local tree = require('Comment.ft').contains(parser, {0, 0, -1, 0}) + print('Lang:', tree:lang()) + < + + +ft.calculate({ctx}) *comment.ft.calculate* + Calculate commentstring with the power of treesitter + + Parameters: ~ + {ctx} (CommentCtx) + + Returns: ~ + {string} Commentstring + + See: ~ + |comment.utils.CommentCtx| + + +================================================================================ +Utilities *comment.utils* + +CommentCtx *comment.utils.CommentCtx* + Comment context + + Fields: ~ + {ctype} (integer) See |comment.utils.ctype| + {cmode} (integer) See |comment.utils.cmode| + {cmotion} (integer) See |comment.utils.cmotion| + {range} (CommentRange) + + +CommentRange *comment.utils.CommentRange* + Range of the selection that needs to be commented + + Fields: ~ + {srow} (integer) Starting row + {scol} (integer) Starting column + {erow} (integer) Ending row + {ecol} (integer) Ending column + + +CommentMode *comment.utils.CommentMode* + Comment modes - Can be manual or computed via operator-mode + + Fields: ~ + {toggle} (integer) Toggle action + {comment} (integer) Comment action + {uncomment} (integer) Uncomment action + + +U.cmode *comment.utils.cmode* + An object containing comment modes + + Type: ~ + (CommentMode) + + +CommentType *comment.utils.CommentType* + Comment types + + Fields: ~ + {linewise} (integer) Use linewise commentstring + {blockwise} (integer) Use blockwise commentstring + + +U.ctype *comment.utils.ctype* + An object containing comment types + + Type: ~ + (CommentType) + + +CommentMotion *comment.utils.CommentMotion* + Comment motion types + + Fields: ~ + {line} (integer) Line motion (ie. 'gc2j') + {char} (integer) Character/left-right motion (ie. 'gc2w') + {block} (integer) Visual operator-pending motion + {v} (integer) Visual motion (ie. 'v3jgc') + {V} (integer) Visual-line motion (ie. 'V10kgc') + + +U.cmotion *comment.utils.cmotion* + An object containing comment motions + + Type: ~ + (CommentMotion) + + +U.get_region({opmode?}) *comment.utils.get_region* + Get region for line movement or visual selection + NOTE: Returns the current line region, if `opmode` is not given. + + Parameters: ~ + {opmode?} (OpMotion) + + Returns: ~ + {CommentRange} + + +U.get_count_lines({count}) *comment.utils.get_count_lines* + Get lines from the current position to the given count + + Parameters: ~ + {count} (integer) Probably 'vim.v.count' + + Returns: ~ + {string[]} of lines + {CommentRange} + + +U.get_lines({range}) *comment.utils.get_lines* + Get lines from a NORMAL/VISUAL mode + + Parameters: ~ + {range} (CommentRange) + + Returns: ~ + {string[]} of lines + + +U.unwrap_cstr({cstr}) *comment.utils.unwrap_cstr* + Validates and unwraps the given commentstring + + Parameters: ~ + {cstr} (string) See 'commentstring' + + Returns: ~ + {string} Left side of the commentstring + {string} Right side of the commentstring + + +U.parse_cstr({cfg}, {ctx}) *comment.utils.parse_cstr* + Parses commentstring from the following places in the respective order + 1. pre_hook - commentstring returned from the function + 2. ft.lua - commentstring table bundled with the plugin + 3. commentstring - Neovim's native. See 'commentstring' + + Parameters: ~ + {cfg} (CommentConfig) + {ctx} (CommentCtx) + + Returns: ~ + {string} Left side of the commentstring + {string} Right side of the commentstring + + + *comment.utils.commenter* +U.commenter({left}, {right}, {padding}, {scol?}, {ecol?}) + Returns a closure which is used to do comments + + If given {string[]} to the closure then it will do blockwise comment + else linewise comment will be done with the given {string} + + Parameters: ~ + {left} (string) Left side of the commentstring + {right} (string) Right side of the commentstring + {padding} (boolean) Is padding enabled? + {scol?} (integer) Starting column + {ecol?} (integer) Ending column + + Returns: ~ + {fun(line:string|string[]):string} + + + *comment.utils.uncommenter* +U.uncommenter({left}, {right}, {padding}, {scol?}, {ecol?}) + Returns a closure which is used to uncomment a line + + If given {string[]} to the closure then it will block uncomment + else linewise uncomment will be done with the given {string} + + Parameters: ~ + {left} (string) Left side of the commentstring + {right} (string) Right side of the commentstring + {padding} (boolean) Is padding enabled? + {scol?} (integer) Starting column + {ecol?} (integer) Ending column + + Returns: ~ + {fun(line:string|string[]):string} + + + *comment.utils.is_commented* +U.is_commented({left}, {right}, {padding}, {scol?}, {ecol?}) + Check if the given string is commented or not + + If given {string[]} to the closure, it will check the first and last line + with LHS and RHS of commentstring respectively else it will check the given + line with LHS and RHS (if given) of the commenstring + + Parameters: ~ + {left} (string) Left side of the commentstring + {right} (string) Right side of the commentstring + {padding} (boolean) Is padding enabled? + {scol?} (integer) Starting column + {ecol?} (integer) Ending column + + Returns: ~ + {fun(line:string|string[]):boolean} + + +================================================================================ +Operator-mode API *comment.opfunc* + +Underlying functions that powers the |comment.api.toggle|, |comment.api.comment|, +and |comment.api.uncomment| lua API. + +OpMotion *comment.opfunc.OpMotion* + Vim operator-mode motion enum. Read |:map-operator| + + Variants: ~ + ('line') Vertical motion + ('char') Horizontal motion + ('v') Visual Block motion + ('V') Visual Line motion + + + *comment.opfunc.opfunc* +Op.opfunc({motion?}, {cfg}, {cmode}, {ctype}) + Common operatorfunc callback + This function contains the core logic for comment/uncomment + + Parameters: ~ + {motion?} (OpMotion) If given 'nil', it'll only (un)comment + the current line + {cfg} (CommentConfig) + {cmode} (integer) See |comment.utils.cmode| + {ctype} (integer) See |comment.utils.ctype| + + + *comment.opfunc.count* +Op.count({count}, {cfg}, {cmode}, {ctype}) + Line commenting with count + + Parameters: ~ + {count} (integer) Value of |v:count| + {cfg} (CommentConfig) + {cmode} (integer) See |comment.utils.cmode| + {ctype} (integer) See |comment.utils.ctype| + + +OpFnParams *comment.opfunc.OpFnParams* + Operator-mode function parameters + + Fields: ~ + {cfg} (CommentConfig) + {cmode} (integer) See |comment.utils.cmode| + {lines} (string[]) List of lines + {rcs} (string) RHS of commentstring + {lcs} (string) LHS of commentstring + {range} (CommentRange) + + +Op.linewise({param}) *comment.opfunc.linewise* + Line commenting + + Parameters: ~ + {param} (OpFnParams) + + Returns: ~ + {integer} Returns a calculated comment mode + + +Op.blockwise({param}, {partial?}) *comment.opfunc.blockwise* + Full/Partial/Current-Line Block commenting + + Parameters: ~ + {param} (OpFnParams) + {partial?} (boolean) Comment the partial region (visual mode) + + Returns: ~ + {integer} Returns a calculated comment mode + + +================================================================================ +Insert API *comment.extra* + +Underlying functions that powers the |comment.api.insert| lua API. + +extra.insert_below({ctype}, {cfg}) *comment.extra.insert_below* + Add a comment below the current line and goes to INSERT mode + + Parameters: ~ + {ctype} (integer) See |comment.utils.ctype| + {cfg} (CommentConfig) + + +extra.insert_above({ctype}, {cfg}) *comment.extra.insert_above* + Add a comment above the current line and goes to INSERT mode + + Parameters: ~ + {ctype} (integer) See |comment.utils.ctype| + {cfg} (CommentConfig) + + +extra.insert_eol({ctype}, {cfg}) *comment.extra.insert_eol* + Add a comment at the end of current line and goes to INSERT mode + + Parameters: ~ + {ctype} (integer) See |comment.utils.ctype| + {cfg} (CommentConfig) + + +vim:tw=78:ts=8:noet:ft=help:norl: diff --git a/doc/plugs.md b/doc/plugs.md index 11622d7..b1fdf31 100644 --- a/doc/plugs.md +++ b/doc/plugs.md @@ -1,34 +1 @@ -## ๐Ÿ”Œ Plug Mappings - -Following are the `` mappings which you can use to quickly setup your custom keybindings - -- `(comment_toggle_linewise)` - Toggles line comment via Operator pending mode -- `(comment_toggle_blockwise)` - Toggles block comment via Operator pending mode -- `(comment_toggle_linewise_current)` - Toggles line comment on the current line -- `(comment_toggle_blockwise_current)` - Toggles block comment on the current line -- `(comment_toggle_linewise_count)` - Toggles line comment with count -- `(comment_toggle_blockwise_count)` - Toggles block comment with count -- `(comment_toggle_linewise_visual)` - Toggles line comment in VISUAL mode -- `(comment_toggle_blockwise_visual)` - Toggles block comment in VISUAL mode - -> NOTE: There are only meant for custom keybindings but If you want to create a custom comment function then be sure to check out all the [API](./API.md). - -#### Usage - -Following snippets is same as the default mappings set by the plugin. - -```lua -local opt = { expr = true, remap = true, replace_keycodes = false } - --- Toggle using count -vim.keymap.set('n', 'gcc', "v:count == 0 ? '(comment_toggle_linewise_current)' : '(comment_toggle_linewise_count)'", opt) -vim.keymap.set('n', 'gbc', "v:count == 0 ? '(comment_toggle_blockwise_current)' : '(comment_toggle_blockwise_count)'", opt) - --- Toggle in Op-pending mode -vim.keymap.set('n', 'gc', '(comment_toggle_linewise)') -vim.keymap.set('n', 'gb', '(comment_toggle_blockwise)') - --- Toggle in VISUAL mode -vim.keymap.set('x', 'gc', '(comment_toggle_linewise_visual)') -vim.keymap.set('x', 'gb', '(comment_toggle_blockwise_visual)') -``` +`Comment.nvim` now has `:help` docs ๐ŸŽ‰. Read `:h comment.plugmap` for the `` mappings documentation and usage. diff --git a/dump.lua b/dump.lua deleted file mode 100644 index 832c703..0000000 --- a/dump.lua +++ /dev/null @@ -1,56 +0,0 @@ --- TODO --- [x] Handle Tabs --- [x] Dot repeat --- [x] Comment multiple line. --- [x] Hook support --- [x] pre --- [x] post --- [x] Custom (language) commentstring support --- [x] Block comment basic ie. /* */ (for js) --- [-] Block comment extended --- [x] left-right-motions --- [x] Partial blocks ie. gba{ gbaf --- [ ] V-BLOCK (IDK, maybe) --- [ ] Char motion covering mutliple lines ie. gc300w (level: HARD) --- [-] Treesitter Integration --- [ ] Better comment detection --- [x] Context commentstring --- [x] Port `commentstring` from tcomment --- [x] Ignore line --- [x] Disable `extra` mapping by default --- [x] Provide more arguments to pre and post hooks --- [x] `ignore` as a function --- [x] Return the operator's starting and ending position in pre and post hook --- [x] Restore cursor position in some motion operator (try `gcip`) --- [ ] Doc comment ie. /** */ (for js) --- [ ] Header comment - --- FIXME --- [x] visual mode not working correctly --- [x] space after and before of commentstring --- [x] multiple line behavior to tcomment --- [x] preserve indent --- [x] determine comment status (to comment or not) --- [x] prevent uncomment on uncommented line --- [x] `comment` and `toggle` misbehaving when there is leading space --- [x] messed up indentation, if the first line has greater indentation than next line (calc min indendation) --- [x] `gcc` empty line not toggling comment --- [x] Optimize blockwise mode (just modifiy the start and end line) --- [x] Weird commenting when the first line is empty and the whole is indented --- [x] no padding support in block-x - --- THINK: --- [ ] Dot support for `[count]gcc` and `[count]gbc` --- [ ] Parse `comments` if block comment is missing in the plugin - --- ITS_OK: --- 1. Weird comments, if you do comments on already commented lines incl. an extra empty line --- 2. Conflict when uncommenting interchangebly with line/block wise comment --- 3. `ignore` doesn't work in blockwise and blockwise_x --- 4. When a empty line is b/w two commented blocks then it should uncomment instead of commenting again in toggle. - --- DROPPED: --- 1. Insert mode mapping (also move the cursor after commentstring) --- 2. Use `nvim_buf_get_text` instead of `nvim_buf_get_lines`. Blocked by https://github.com/neovim/neovim/pull/15181 --- 3. Use `nvim_buf_set_text` instead of `nvim_buf_set_lines` --- 4. Dot repeat support for visual mode mappings (Doesn't make sense) diff --git a/lua/Comment/api.lua b/lua/Comment/api.lua index 7b9cdfe..d9b75c9 100644 --- a/lua/Comment/api.lua +++ b/lua/Comment/api.lua @@ -1,4 +1,9 @@ ----@mod comment.api API functions +---@mod comment.api Core Lua API +---@brief [[ +---This module provides the core lua APIs which is used by the default keybindings +---and (Read |comment.plugmap|) mappings. These API can be used to setup your +---own custom keybindings or to even make your (un)comment function. +---@brief ]] local Config = require('Comment.config') local U = require('Comment.utils') @@ -281,7 +286,7 @@ function core.__index(that, ctype) ---To comment lines with a count function idxd.count(count, cfg) - Op.count(Config.count or count, cfg or Config:get(), U.ctype[ctype]) + Op.count(Config.count or count, cfg or Config:get(), that.cmode, U.ctype[ctype]) end ---@private @@ -299,60 +304,126 @@ function core.__index(that, ctype) }) end ----API to toggle comments using line or block comment string +---@tag comment.api.toggle.linewise +---@tag comment.api.toggle.blockwise +---Provides API to toggle comments over a region, on current-line, or with a +---count using line or block comment string. --- ----Following are the API functions that are available: ---- ----require('Comment.api').toggle.linewise({motion}, {cfg?}) ----require('Comment.api').toggle.linewise.current({motion?}, {cfg?}) ----require('Comment.api').toggle.linewise.count({count}, {cfg?}) ---- ----require('Comment.api').toggle.blockwise({motion}, {cfg?}) ----require('Comment.api').toggle.blockwise.current({motion?}, {cfg?}) ----require('Comment.api').toggle.blockwise.count({count}, {cfg?}) +---All functions takes a {motion} argument, except '*.count()' function which +---takes an {count} argument, and an optional {config} parameter. ---@type table A metatable containing API functions +---@see comment.opfunc.OpMotion +---@see comment.config +---@usage [[ +---local api = require('Comment.api') +--- +---api.toggle.linewise(motion, config) +---api.toggle.linewise.current(motion?, config?) +---api.toggle.linewise.count(count, config?) +--- +---api.toggle.blockwise(motion, config?) +---api.toggle.blockwise.current(motion?, config?) +---api.toggle.blockwise.count(count, config?) +--- +----- Toggle current line (linewise) using C-/ +---vim.keymap.set('n', '', api.toggle.linewise.current) +--- +----- Toggle current line (blockwise) using C-\ +---vim.keymap.set('n', '', api.toggle.blockwise.current) +--- +----- Toggle lines (linewise) with dot-repeat support +----- Example: gc3j will comment 4 lines +---vim.keymap.set( +--- 'n', 'gc', api.call('toggle.linewise', 'g@'), +--- { expr = true } +---) +--- +----- Toggle lines (blockwise) with dot-repeat support +----- Example: gb3j will comment 4 lines +---vim.keymap.set( +--- 'n', 'gb', api.call('toggle.blockwise', 'g@'), +--- { expr = true } +---) +--- +---local esc = vim.api.nvim_replace_termcodes( +--- '', true, false, true +---) +--- +----- Toggle selection (linewise) +---vim.keymap.set('x', 'c', function() +--- vim.api.nvim_feedkeys(esc, 'nx', false) +--- api.toggle.linewise(vim.fn.visualmode()) +---end) +--- +----- Toggle selection (blockwise) +---vim.keymap.set('x', 'b', function() +--- vim.api.nvim_feedkeys(esc, 'nx', false) +--- api.toggle.blockwise(vim.fn.visualmode()) +---end) +---@usage ]] api.toggle = setmetatable({ cmode = U.cmode.toggle }, core) ----API to (only) comment using line or block comment string +---@tag comment.api.comment.linewise +---@tag comment.api.comment.blockwise +---Provides API to (only) comment a region, on current-line, or with a +---count using line or block comment string. --- ----Following are the API functions that are available: ---- ----require('Comment.api').comment.linewise({motion}, {cfg?}) ----require('Comment.api').comment.linewise.current({motion?}, {cfg?}) ----require('Comment.api').comment.linewise.count({count}, {cfg?}) ---- ----require('Comment.api').comment.blockwise({motion}, {cfg?}) ----require('Comment.api').comment.blockwise.current({motion?}, {cfg?}) ----require('Comment.api').comment.blockwise.count({count}, {cfg?}) +---All functions takes a {motion} argument, except '*.count()' function which +---takes an {count} argument, and an optional {config} parameter. ---@type table A metatable containing API functions +---@see comment.opfunc.OpMotion +---@see comment.config +---@usage [[ +---local api = require('Comment.api') +--- +---api.comment.linewise(motion, config) +---api.comment.linewise.current(motion?, config?) +---api.comment.linewise.count(count, config?) +--- +---api.comment.blockwise(motion, config?) +---api.comment.blockwise.current(motion?, config?) +---api.comment.blockwise.count(count, config?) +---@usage ]] api.comment = setmetatable({ cmode = U.cmode.comment }, core) ----API to (only) uncomment using line or block comment string +---@tag comment.api.uncomment.linewise +---@tag comment.api.uncomment.blockwise +---Provides API to (only) uncomment a region, on current-line, or with a +---count using line or block comment string. --- ----Following are the API functions that are available: ---- ----require('Comment.api').uncomment.linewise({motion}, {cfg?}) ----require('Comment.api').uncomment.linewise.current({motion?}, {cfg?}) ----require('Comment.api').uncomment.linewise.count({count}, {cfg?}) ---- ----require('Comment.api').uncomment.blockwise({motion}, {cfg?}) ----require('Comment.api').uncomment.blockwise.current({motion?}, {cfg?}) ----require('Comment.api').uncomment.blockwise.count({count}, {cfg?}) +---All functions takes a {motion} argument, except '*.count()' function which +---takes an {count} argument, and an optional {config} parameter. ---@type table A metatable containing API functions -api.uncomment = setmetatable({ cmode = U.cmode.comment }, core) +---@see comment.opfunc.OpMotion +---@see comment.config +---@usage [[ +---local api = require('Comment.api') +--- +---api.uncomment.linewise(motion, config) +---api.uncomment.linewise.current(motion?, config?) +---api.uncomment.linewise.count(count, config?) +--- +---api.uncomment.blockwise(motion, config?) +---api.uncomment.blockwise.current(motion?, config?) +---api.uncomment.blockwise.count(count, config?) +---@usage ]] +api.uncomment = setmetatable({ cmode = U.cmode.uncomment }, core) ----API to insert comment on previous, next or at the end-of-line ---- ----Following are the API functions that are available: ---- ----require('Comment.api').insert.linewise.above({cfg?}) ----require('Comment.api').insert.linewise.below({cfg?}) ----require('Comment.api').insert.linewise.eol({cfg?}) ---- ----require('Comment.api').insert.blockwise.above({cfg?}) ----require('Comment.api').insert.blockwise.below({cfg?}) ----require('Comment.api').insert.blockwise.eol({cfg?}) +---Provides API to to insert comment on previous, next or at the end-of-line. +---All functions takes an optional {config} parameter. ---@type table A metatable containing API functions +---@see comment.config +---@usage [[ +---local api = require('Comment.api') +--- +---api.insert.linewise.above(cfg?) +---api.insert.linewise.below(cfg?) +---api.insert.linewise.eol(cfg?) +--- +---api.insert.blockwise.above(cfg?) +---api.insert.blockwise.below(cfg?) +---api.insert.blockwise.eol(cfg?) +---@usage ]] api.insert = setmetatable({}, { __index = function(_, ctype) return { @@ -369,17 +440,41 @@ api.insert = setmetatable({}, { end, }) ----Wraps a given function with `lockmarks` to preserve marks/jumps when commenting +-- TODO: After removing old API +-- 1. make `api.locked` a simple function call +-- 2. fix emmylua doc + +---Wraps the given API function with 'lockmarks' to preserve marks/jumps ---@type fun(cb:string):fun(motion:OpMotion) ----@usage `require('Comment.api').locked('toggle.linewise.current')()` +---@see lockmarks +---@see comment.opfunc.OpMotion +---@usage [[ +---local api = require('Comment.api') +--- +---vim.keymap.set( +--- 'n', 'c', api.locked('toggle.linewise.current') +---) +--- +---local esc = vim.api.nvim_replace_termcodes( +--- '', true, false, true +---) +---vim.keymap.set('x', 'c', function() +--- vim.api.nvim_feedkeys(esc, 'nx', false) +--- api.locked('toggle.linewise')(vim.fn.visualmode()) +---end) +--- +----- NOTE: `locked` method is just a wrapper around `lockmarks` +---vim.api.nvim_command([[ +--- lockmarks lua require('Comment.api').toggle.linewise.current() +---]]) +---@usage ]] api.locked = setmetatable({}, { __index = function(this, cb) D(string.format('locker.%s(args...)', cb), string.format('locked(%q)(args...)', cb)) return this(cb) end, - -- TODO: After removal of the old api functions, make `api.locked` a simple function call __call = function(_, cb) - ---Actual function which will be attached to operatorfunc + ---operatorfunc callback ---@param motion OpMotion return function(motion) return A.nvim_command( @@ -390,13 +485,25 @@ api.locked = setmetatable({}, { }) ---Callback function which does the following ---- 1. Sets operatorfunc for dot-repeat +--- 1. Sets 'operatorfunc' for dot-repeat --- 2. Preserves jumps and marks --- 3. Stores last cursor position ---@param cb string Name of the API function to call ---@param op 'g@'|'g@$' Operator string to execute ---@return fun():string _ Keymap RHS callback ----@usage `vim.keymap.set('n', 'gc', api.call('toggle.linewise', 'g@'), { expr = true })` +---@see g@ +---@see operatorfunc +---@usage [[ +---local api = require('Comment.api') +---vim.keymap.set( +--- 'n', 'gc', api.call('toggle.linewise', 'g@'), +--- { expr = true } +---) +---vim.keymap.set( +--- 'n', 'gcc', api.call('toggle.linewise.current', 'g@$'), +--- { expr = true } +---) +---@usage ]] function api.call(cb, op) return function() A.nvim_set_option('operatorfunc', ("v:lua.require'Comment.api'.locked'%s'"):format(cb)) diff --git a/lua/Comment/config.lua b/lua/Comment/config.lua index fae4a16..775c894 100644 --- a/lua/Comment/config.lua +++ b/lua/Comment/config.lua @@ -1,45 +1,92 @@ ---@mod comment.config Configuration - ----@class Toggler LHS of toggle mappings in NORMAL + VISUAL mode ----@field line string Linewise comment keymap ----@field block string Blockwise comment keymap - ----@class Opleader LHS of operator-mode mappings in NORMAL + VISUAL mode ----@field line string Linewise comment keymap ----@field block string Blockwise comment keymap - ----@class ExtraMapping LHS of extra mappings ----@field above string Mapping to add comment on the line above ----@field below string Mapping to add comment on the line below ----@field eol string Mapping to add comment at the end of line - ----@class Mappings Create default mappings ----Enable operator-pending mapping ----Includes `gcc`, `gbc`, `gc[count]{motion}` and `gb[count]{motion}` ----NOTE: These mappings can be changed individually by `opleader` and `toggler` config ----@field basic boolean ----Enable extra mapping ----Includes `gco`, `gcO`, `gcA` ----@field extra boolean ----Enable extended mapping ----Includes `g>`, `g<`, `g>[count]{motion}` and `g<[count]{motion}` ----@field extended boolean +---@tag comment.config.defaults +---@brief [[ +---Following is the default config for the |comment.usage.setup|. If you want to +---override, just modify the option that you want, then it will be merged with the +---default config. +--- +---> +--- { +--- padding = true, +--- sticky = true, +--- ignore = nil, +--- toggler = { +--- line = 'gcc', +--- block = 'gbc', +--- }, +--- opleader = { +--- line = 'gc', +--- block = 'gb', +--- }, +--- extra = { +--- above = 'gcO', +--- below = 'gco', +--- eol = 'gcA', +--- }, +--- mappings = { +--- basic = true, +--- extra = true, +--- extended = false, +--- }, +--- pre_hook = nil, +--- post_hook = nil, +--- } +---< +---@brief ]] ---@class CommentConfig Plugin's configuration ----@field padding boolean Add a space b/w comment and the line ----Whether the cursor should stay at its position ----NOTE: This only affects NORMAL mode mappings and doesn't work with dot-repeat +---Controls space between the comment +---and the line (default: 'true') +---@field padding boolean|fun():boolean +---Whether cursor should stay at the +---same position. Only works in NORMAL +---mode mappings (default: 'true') ---@field sticky boolean ----Lines to be ignored while comment/uncomment. ----Could be a regex string or a function that returns a regex string. ----Example: Use '^$' to ignore empty lines +---Lua pattern used to ignore lines +---during (un)comment (default: 'nil') ---@field ignore string|fun():string ----@field mappings boolean|Mappings +---Enables |comment.keybindings| +---NOTE: If given 'false', then the +---plugin won't create any mappings +---@field mappings Mappings|false ---@field toggler Toggler ---@field opleader Opleader ---@field extra ExtraMapping ----@field pre_hook fun(ctx:CommentCtx):string Function to be called before comment/uncomment ----@field post_hook fun(ctx:CommentCtx) Function to be called after comment/uncomment +---Function to call before (un)comment. +---It is called with a {ctx} argument +---of type |comment.utils.CommentCtx| +---(default: 'nil') +---@field pre_hook fun(ctx):string +---Function to call after (un)comment. +---It is called with a {ctx} argument +---of type |comment.utils.CommentCtx| +---(default: 'nil') +---@field post_hook fun(ctx) + +---@class Mappings Create default mappings +---Enables operator-pending mapping; `gcc`, `gbc`, +---`gc{motion}` and `gb{motion}` (default: 'true') +---@field basic boolean +---Enable extra mapping; `gco`, `gcO` and `gcA` +---(default: 'true') +---@field extra boolean +---Enable extended mapping; `g>`, `g{motion}` and `g<{motion}` +---(default: 'false') +---@field extended boolean + +---@class Toggler LHS of toggle mappings in NORMAL +---@field line string Linewise comment (default: 'gcc') +---@field block string Blockwise comment (default: 'gbc') + +---@class Opleader LHS of operator-mode mappings in NORMAL and VISUAL mode +---@field line string Linewise comment (default: 'gc') +---@field block string Blockwise comment (default: 'gb') + +---@class ExtraMapping LHS of extra mappings +---@field below string Inserts comment below (default: 'gco') +---@field above string Inserts comment above (default: 'gcO') +---@field eol string Inserts comment at the end of line (default: 'gcA') ---@private ---@class RootConfig @@ -72,9 +119,12 @@ local Config = { }, } ----Update the config +---@private +---Updates the default config ---@param cfg? CommentConfig ---@return RootConfig +---@see comment.usage.setup +---@usage `require('Comment.config'):set({config})` function Config:set(cfg) if cfg then self.config = vim.tbl_deep_extend('force', self.config, cfg) @@ -84,11 +134,12 @@ end ---Get the config ---@return CommentConfig +---@usage `require('Comment.config'):get()` function Config:get() return self.config end ----@export ft +---@export Config return setmetatable(Config, { __index = function(this, k) return this.state[k] diff --git a/lua/Comment/extra.lua b/lua/Comment/extra.lua index 495394f..6c3dcc4 100644 --- a/lua/Comment/extra.lua +++ b/lua/Comment/extra.lua @@ -1,4 +1,7 @@ ----@mod comment.extra Extra functions +---@mod comment.extra Extra API +---@brief [[ +---Underlying functions that powers the |comment.api.insert| lua API. +---@brief ]] local U = require('Comment.utils') local A = vim.api @@ -30,7 +33,7 @@ local function ins_on_line(lnum, ctype, cfg) local srow = row + lnum local lcs, rcs = U.parse_cstr(cfg, ctx) - local padding = U.get_pad(cfg.padding) + local padding = U.get_pad(U.is_fn(cfg.padding)) -- We need RHS of cstr, if we are doing block comments or if RHS exists -- because even in line comment RHS do exists for some filetypes like jsx_element, ocaml @@ -73,7 +76,7 @@ function extra.insert_eol(ctype, cfg) local lcs, rcs = U.parse_cstr(cfg, ctx) local line = A.nvim_get_current_line() - local padding = U.get_pad(cfg.padding) + local padding = U.get_pad(U.is_fn(cfg.padding)) -- We need RHS of cstr, if we are doing block comments or if RHS exists -- because even in line comment RHS do exists for some filetypes like jsx_element, ocaml diff --git a/lua/Comment/ft.lua b/lua/Comment/ft.lua index 7d61da8..a2dd3cb 100644 --- a/lua/Comment/ft.lua +++ b/lua/Comment/ft.lua @@ -1,4 +1,9 @@ ----@mod comment.ft Language or Filetype detection +---@mod comment.ft Language/Filetype detection +---@brief [[ +---This module is the core of filetype and commentstring detection and uses the +---|lua-treesitter| APIs to accurately detect filetype and gives the corresponding +---commentstring, stored inside the plugin, for the filetype/langauge. +---@brief ]] local A = vim.api @@ -108,37 +113,71 @@ local L = { local ft = {} ----@alias CommentLang string Filetype/Language of the buffer - ---Sets a commentstring(s) for a filetype/language ----@param lang CommentLang +---@param lang string Filetype/Language of the buffer ---@param val string|string[] +---@return table self Returns itself +---@usage [[ +---local ft = require('Comment.ft') +--- +-----1. Using method signature +----- Set only line comment or both +----- You can also chain the set calls +---ft.set('yaml', '#%s').set('javascript', {'//%s', '/*%s*/'}) +--- +----- 2. Metatable magic +---ft.javascript = {'//%s', '/*%s*/'} +---ft.yaml = '#%s' +--- +----- 3. Multiple filetypes +---ft({'go', 'rust'}, {'//%s', '/*%s*/'}) +---ft({'toml', 'graphql'}, '#%s') +---@usage ]] function ft.set(lang, val) L[lang] = type(val) == 'string' and { val } or val --[[ @as string[] ]] return ft end ----Get a commentstring from the filtype list ----@param lang CommentLang +---Get line/block commentstring for a given filetype +---@param lang string Filetype/Language of the buffer ---@param ctype integer See |comment.utils.ctype| ----@return string +---@return string _ Commentstring +---@usage [[ +---local ft = require('Comment.ft') +---local U = require('Comment.utils') +---print(ft.get(vim.bo.filetype, U.ctype.linewise)) +---@usage ]] function ft.get(lang, ctype) - local l = ft.lang(lang) + local l = L[lang] return l and l[ctype] end ----Get the commentstring(s) from the filtype list ----@param lang CommentLang ----@return string[] +---Get a copy of commentstring(s) for a given filetype +---@param lang string Filetype/Language of the buffer +---@return string[] _ Tuple of { line, block } commentstring +---@usage `require('Comment.ft').lang(vim.bo.filetype)` function ft.lang(lang) - return L[lang] + return vim.deepcopy(L[lang]) end ----Get the tree in range by walking the whole tree recursively ----NOTE: This ignores `comment` parser as this is not needed ----@param tree userdata Tree to be walked ----@param range integer[] Range to check - {start_line, s_col, end_line, end_col} ----@return userdata _ Returns a 'treesitter-languagetree' +---Get a language tree for a given range by walking the parse tree recursively. +---This uses 'lua-treesitter' API under the hood. This can be used to calculate +---language of a particular region which embedded multiple filetypes like html, +---vue, markdown etc. +--- +---NOTE: This ignores `tree-sitter-comment` parser, if installed. +---@param tree userdata Parse tree to be walked +---@param range integer[] Range to check for +---{start_row, start_col, end_row, end_col} +---@return userdata _ Returns a |treesitter-languagetree| +---@see treesitter-languagetree +---@see lua-treesitter-core +---@usage [[ +---local ok, parser = pcall(vim.treesitter.get_parser, 0) +---assert(ok, "No parser found!") +---local tree = require('Comment.ft').contains(parser, {0, 0, -1, 0}) +---print('Lang:', tree:lang()) +---@usage ]] function ft.contains(tree, range) for lang, child in pairs(tree:children()) do if lang ~= 'comment' and child:contains(range) then @@ -149,9 +188,10 @@ function ft.contains(tree, range) return tree end ----Calculate commentstring w/ the power of treesitter +---Calculate commentstring with the power of treesitter ---@param ctx CommentCtx ----@return string +---@return string _ Commentstring +---@see comment.utils.CommentCtx function ft.calculate(ctx) local buf = A.nvim_get_current_buf() local ok, parser = pcall(vim.treesitter.get_parser, buf) diff --git a/lua/Comment/init.lua b/lua/Comment/init.lua index 21987f0..54a1146 100644 --- a/lua/Comment/init.lua +++ b/lua/Comment/init.lua @@ -1,10 +1,91 @@ ----@mod comment.nvim Welcome to Comment.nvim +---@brief [[ +---*comment-nvim.txt* For Neovim version 0.7 Last change: 2021 July 11 +--- +--- _____ _ _ +--- / ____/ / / (_) +--- / / ___ _ __ ___ _ __ ___ ___ _ __ / /_ _ ____ ___ _ __ ___ +--- / / / _ \/ '_ ` _ \/ '_ ` _ \ / _ \ '_ \/ __/ / '_ \ \ / / / '_ ` _ \ +--- / /___/ (_) / / / / / / / / / / / __/ / / / /_ _/ / / \ V // / / / / / / +--- \_____\___//_/ /_/ /_/_/ /_/ /_/\___/_/ /_/\__(_)_/ /_/\_/ /_/_/ /_/ /_/ +--- +--- ยท Smart and Powerful comment plugin ยท +--- +---@brief ]] + +---@toc comment.contents + +---@mod comment-nvim Introduction +---@brief [[ +---Comment.nvim is a smart and powerful comment plugin for neovim. It supports +---dot-repeat, counts, line ('//') and block ('/* */') comments, and can be used +---with motion and text-objects. It has native integration with |tressitter| to +---support embedded filetypes like html, vue, markdown with codeblocks etc. +---@brief ]] +---@tag comment.dotrepeat +---@brief [[ +---Comment.nvim uses |operatorfunc| combined with |g@| to support dot-repeat, and +---various marks i.e., |'[| |']| |'<| |'>| to deduce the region with the {motion} +---argument provided by 'operatorfunc'. See |comment.api.call| +---@brief ]] +---@tag comment.commentstring +---@brief [[ +---Comment.nvim picks commentstring, either linewise/blockwise, from one of the +---following places +--- +--- 1. 'pre_hook' +--- If a string is returned from this function then it will be used for +--- (un)commenting. See |comment.config| +--- +--- 2. |comment.ft| +--- Using the commentstring table inside the plugin (using treesitter). +--- Fallback to |commentstring|, if not found. +--- +--- 3. |commentstring| - Neovim's native commentstring for the filetype +--- +---Although Comment.nvim supports native 'commentstring' but unfortunately it has +---the least priority. The caveat with this approach is that if someone sets the +---`commentstring`, without returning it, from the 'pre_hook' and the current +---filetype also exists in the |comment.ft| then the commenting will be done using +---the string in |comment.ft| instead of using 'commentstring'. To override this +---behavior, you have to manually return the 'commentstring' from 'pre_hook'. +---@brief ]] +---@tag comment.sourcecode +---@brief [[ +---Comment.nvim is FOSS provided under MIT license. All the source code is avaiable +---at https://github.com/numToStr/Comment.nvim +---@brief ]] + +---@mod comment.usage Usage +---@brief [[ +---Before using the plugin, you need to call the `setup()` function to create the +---default mappings. If you want, you can also override the default configuration +---by giving it a partial 'comment.config.Config' object, it will then be merged +---with the default config. +---@brief ]] local C = {} ---Configures the plugin ----@param config? CommentConfig ----@return CommentConfig +---@param config? CommentConfig User configuration +---@return CommentConfig _ Returns the mutated config +---@see comment.config +---@usage [[ +----- Use default configuration +---require('Comment').setup() +--- +----- or with custom configuration +---require('Comment').setup({ +--- ignore = '^$', +--- toggler = { +--- line = 'cc', +--- block = 'bc', +--- }, +--- opleader = { +--- line = 'c', +--- block = 'b', +--- }, +---}) +---@usage ]] function C.setup(config) return require('Comment.api').setup(config) end diff --git a/lua/Comment/opfunc.lua b/lua/Comment/opfunc.lua index 02d90f7..df94a71 100644 --- a/lua/Comment/opfunc.lua +++ b/lua/Comment/opfunc.lua @@ -1,4 +1,8 @@ ----@mod comment.opfunc Operator-mode +---@mod comment.opfunc Operator-mode API +---@brief [[ +---Underlying functions that powers the |comment.api.toggle|, |comment.api.comment|, +---and |comment.api.uncomment| lua API. +---@brief ]] local U = require('Comment.utils') local Config = require('Comment.config') @@ -6,31 +10,18 @@ local A = vim.api local Op = {} ----Vim operator-mode motions. ----Read `:h :map-operator` +---Vim operator-mode motion enum. Read |:map-operator| ---@alias OpMotion ---| 'line' # Vertical motion ---| 'char' # Horizontal motion ---| 'v' # Visual Block motion ---| 'V' # Visual Line motion ----@class CommentCtx Comment context ----@field ctype integer See |comment.utils.ctype| ----@field cmode integer See |comment.utils.cmode| ----@field cmotion integer See |comment.utils.cmotion| ----@field range CommentRange - ----@class OpFnParams Operator-mode function parameters ----@field cfg CommentConfig ----@field cmode integer See |comment.utils.cmode| ----@field lines string[] List of lines ----@field rcs string RHS of commentstring ----@field lcs string LHS of commentstring ----@field range CommentRange - ---Common operatorfunc callback ---This function contains the core logic for comment/uncomment ----@param motion? OpMotion If nil is given, it'll work on the current line +---@param motion? OpMotion +---If given 'nil', it'll only (un)comment +---the current line ---@param cfg CommentConfig ---@param cmode integer See |comment.utils.cmode| ---@param ctype integer See |comment.utils.ctype| @@ -90,6 +81,50 @@ function Op.opfunc(motion, cfg, cmode, ctype) U.is_fn(cfg.post_hook, ctx) end +---Line commenting with count +---@param count integer Value of |v:count| +---@param cfg CommentConfig +---@param cmode integer See |comment.utils.cmode| +---@param ctype integer See |comment.utils.ctype| +function Op.count(count, cfg, cmode, ctype) + local lines, range = U.get_count_lines(count) + + ---@type CommentCtx + local ctx = { + cmode = cmode, + cmotion = U.cmotion.line, + ctype = ctype, + range = range, + } + local lcs, rcs = U.parse_cstr(cfg, ctx) + + ---@type OpFnParams + local params = { + cfg = cfg, + cmode = ctx.cmode, + lines = lines, + lcs = lcs, + rcs = rcs, + range = range, + } + + if ctype == U.ctype.blockwise then + ctx.cmode = Op.blockwise(params) + else + ctx.cmode = Op.linewise(params) + end + + U.is_fn(cfg.post_hook, ctx) +end + +---@class OpFnParams Operator-mode function parameters +---@field cfg CommentConfig +---@field cmode integer See |comment.utils.cmode| +---@field lines string[] List of lines +---@field rcs string RHS of commentstring +---@field lcs string LHS of commentstring +---@field range CommentRange + ---Line commenting ---@param param OpFnParams ---@return integer _ Returns a calculated comment mode @@ -113,7 +148,7 @@ function Op.linewise(param) for _, line in ipairs(param.lines) do -- I wish lua had `continue` statement [sad noises] if not U.ignore(line, pattern) then - if cmode == U.cmode.uncomment and (not check_comment(line)) then + if cmode == U.cmode.uncomment and param.cmode == U.cmode.toggle and (not check_comment(line)) then cmode = U.cmode.comment end @@ -129,6 +164,11 @@ function Op.linewise(param) end end + -- If the comment mode given is not toggle than force that mode + if param.cmode ~= U.cmode.toggle then + cmode = param.cmode + end + if cmode == U.cmode.uncomment then local uncomment = U.uncommenter(param.lcs, param.rcs, padding) for i, line in ipairs(param.lines) do @@ -187,39 +227,4 @@ function Op.blockwise(param, partial) return cmode end ----Line commenting with count i.e vim.v.count ----@param count integer Number of lines ----@param cfg CommentConfig ----@param ctype integer See |comment.utils.ctype| -function Op.count(count, cfg, ctype) - local lines, range = U.get_count_lines(count) - - ---@type CommentCtx - local ctx = { - cmode = U.cmode.toggle, - cmotion = U.cmotion.line, - ctype = ctype, - range = range, - } - local lcs, rcs = U.parse_cstr(cfg, ctx) - - ---@type OpFnParams - local params = { - cfg = cfg, - cmode = ctx.cmode, - lines = lines, - lcs = lcs, - rcs = rcs, - range = range, - } - - if ctype == U.ctype.blockwise then - ctx.cmode = Op.blockwise(params) - else - ctx.cmode = Op.linewise(params) - end - - U.is_fn(cfg.post_hook, ctx) -end - return Op diff --git a/lua/Comment/utils.lua b/lua/Comment/utils.lua index 3f513d0..3988836 100644 --- a/lua/Comment/utils.lua +++ b/lua/Comment/utils.lua @@ -4,7 +4,11 @@ local A = vim.api local U = {} ----@alias CommentLines string[] List of lines inside the start and end index +---@class CommentCtx Comment context +---@field ctype integer See |comment.utils.ctype| +---@field cmode integer See |comment.utils.cmode| +---@field cmotion integer See |comment.utils.cmotion| +---@field range CommentRange ---@class CommentRange Range of the selection that needs to be commented ---@field srow integer Starting row @@ -124,7 +128,7 @@ end ---Get lines from the current position to the given count ---@param count integer Probably 'vim.v.count' ----@return CommentLines +---@return string[] _ List of lines ---@return CommentRange function U.get_count_lines(count) local srow = unpack(A.nvim_win_get_cursor(0)) @@ -136,7 +140,7 @@ end ---Get lines from a NORMAL/VISUAL mode ---@param range CommentRange ----@return CommentLines +---@return string[] _ List of lines function U.get_lines(range) -- If start and end is same, then just return the current line if range.srow == range.erow then diff --git a/plugin/Comment.lua b/plugin/Comment.lua index d3d8605..9681d9d 100644 --- a/plugin/Comment.lua +++ b/plugin/Comment.lua @@ -1,6 +1,91 @@ local K = vim.keymap.set local call = require('Comment.api').call +---@mod comment.keybindings Keybindings +---@brief [[ +---Comment.nvim provides default keybinds which is used for (un)comment your code. +---These keybinds are enabled upon calling |commen.usage.setup| and can be +---configured or disabled, if desired. +--- +---Basic: ~ +--- +--- *gc* +--- *gb* +--- *gc[count]{motion}* +--- *gb[count]{motion}* +--- +--- Toggle comment on a region using linewise/blockwise comment. In 'NORMAL' +--- mode, it uses 'Operator-Pending' mode to listen for an operator/motion. +--- In 'VISUAL' mode it simply comment the selected region. +--- +--- *gcc* +--- *gbc* +--- *[count]gcc* +--- *[count]gbc* +--- +--- Toggle comment on the current line using linewise/blockwise comment. If +--- prefixed with a 'v:count' then it will comment over the number of lines +--- corresponding to the {count}. These are only available in 'NORMAL' mode. +--- +--- +---Extra: ~ +--- +--- *gco* - Inserts comment below and enters INSERT mode +--- *gcO* - Inserts comment above and enters INSERT mode +--- *gcA* - Inserts comment at the end of line and enters INSERT mode +---@brief ]] + +---@mod comment.plugmap Plug Mappings +---@brief [[ +---Comment.nvim provides mappings for most commonly used actions. These +---can be used to make custom keybindings and are enabled by default. All plug +---mappings has support for dot-repeat except VISUAL mode keybindings. To create +---custom comment function, check out 'comment.api' section. +--- +--- *(comment_toggle_linewise)* +--- *(comment_toggle_blockwise)* +--- +--- Toggle comment on a region with linewise/blockwise comment in NORMAL mode. +--- using |Operator-Pending| mode (or |g@|) to get the region to comment. +--- These powers the |gc| and |gb| keybindings. +--- +--- *(comment_toggle_linewise_current)* +--- *(comment_toggle_blockwise_current)* +--- +--- Toggle comment on the current line with linewise/blockwise comment in +--- NORMAL mode. These powers the |gcc| and 'gbc' keybindings. +--- +--- *(comment_toggle_linewise_count)* +--- *(comment_toggle_blockwise_count)* +--- +--- Toggle comment on a region using 'v:count' with linewise/blockwise comment +--- in NORMAL mode. These powers the |[count]gcc| and |[count]gbc| keybindings. +--- +--- *(comment_toggle_linewise_visual)* +--- *(comment_toggle_blockwise_visual)* +--- +--- Toggle comment on the selected region with linewise/blockwise comment in +--- NORMAL mode. These powers the |{visual}gc| and |{visual}gb| keybindings. +--- +---Usage: ~ +--- +---> +--- -- Toggle current line or with count +--- vim.keymap.set('n', 'gcc', function() +--- return vim.v.count == 0 +--- and '(comment_toggle_linewise_current)' +--- or '(comment_toggle_linewise_count)' +--- end, { expr = true }) +--- +--- -- Toggle in Op-pending mode +--- vim.keymap.set('n', 'gc', '(comment_toggle_linewise)') +--- +--- -- Toggle in VISUAL mode +--- vim.keymap.set('x', 'gc', '(comment_toggle_linewise_visual)') +---< +---@brief ]] +---@export plugs + -- Operator-Pending mappings K( 'n',