⚡ Smart and Powerful commenting plugin for neovim ⚡
- Supports
commentstring
. Read more - Prefers single-line/linewise comments
- Supports line (
//
) and block (/* */
) comments - Left-right (
gcw
gc$
) and Up-Down motions (gc2j
gc4k
) - Use with text-objects (
gci{
gcat
) - Dot (
.
) repeat support forgcc
,gbc
and friends - Supports pre and post hooks
- Custom language/commentstring support
- Ignore certain lines, powered by Lua regex
- With packer.nvim
use {
'numToStr/Comment.nvim',
config = function()
require('Comment').setup()
end
}
- With vim-plug
Plug 'numToStr/Comment.nvim'
" Somewhere after plug#end()
lua require('Comment').setup()
First you need to call the setup()
method to create the default mappings.
- Lua
require('Comment').setup()
- VimL
lua << EOF
require('Comment').setup()
EOF
Following are the default config for the setup()
. If you want to override, just modify the option that you want then it will be merged with the default config.
{
---Add a space b/w comment and the line
---@type boolean
padding = true,
---Line which should be ignored while comment/uncomment
---Example: Use '^$' to ignore empty lines
---@type string Lua regex
ignore = nil,
---Whether to create basic (operator-pending) and extra mappings for NORMAL/VISUAL mode
---@type table
mappings = {
---operator-pending mapping
---Includes `gcc`, `gcb`, `gc[count]{motion}` and `gb[count]{motion}`
basic = true,
---extended mapping
---Includes `g>`, `g<`, `g>[count]{motion}` and `g<[count]{motion}`
extra = false,
},
---LHS of line and block comment toggle mapping in NORMAL/VISUAL mode
---@type table
toggler = {
---line-comment toggle
line = 'gcc',
---block-comment toggle
block = 'gbc',
},
---LHS of line and block comment operator-mode mapping in NORMAL/VISUAL mode
---@type table
opleader = {
---line-comment opfunc mapping
line = 'gc',
---block-comment opfunc mapping
block = 'gb',
},
---Pre-hook, called before commenting the line
---@type function|nil
pre_hook = nil,
---Post-hook, called after commenting is done
---@type function|nil
post_hook = nil,
}
When you call setup()
method, Comment.nvim
sets up some basic mapping which can used in NORMAL and VISUAL mode to get you started with the pleasure of commenting stuff out.
- Basic/Toggle mappings (enabled by
config.mappings.basic
)
NORMAL mode
`gc[count]{motion}` - (Operator mode) Toggles the region using linewise comment
`gb[count]{motion}` - (Operator mode) Toggles the region using linewise comment
`gcc` - Toggles the current line using linewise comment
`gbc` - Toggles the current line using blockwise comment
VISUAL mode
`gc` - Toggles the region using linewise comment
`gb` - Toggles the region using blockwise comment
- Extra/Explicit mappings (enabled by
config.mappings.extra
)
NORMAL mode
`g>[count]{motion}` - (Operator Mode) Comments the region using linewise comment
`g>c` - Comments the current line using linewise comment
`g>b` - Comments the current line using blockwise comment
`g<[count]{motion}` - (Operator mode) Uncomments the region using linewise comment
`g<c` - Uncomments the current line using linewise comment
`g<b`- Uncomments the current line using blockwise comment
VISUAL mode
`g>` - Comments the region using single line
`g<` - Unomments the region using single line
# Linewise
`gcw` - Toggle from the current cursor position to the next word
`gc$` - Toggle from the current cursor position to the end of line
`gc}` - Toggle until the next blank line
`gc5l` - Toggle 5 lines after the current cursor
`gc8k` - Toggle 8 lines before the current cursor
`gcip` - Toggle inside of paragraph
`gca}` - Toggle around curly brackets
# Blockwise
`gb2}` - Toggle until the 2 next blank line
`gbaf` - Toggle comment around a function (w/ LSP/treesitter support)
`gbac` - Toggle comment around a class (w/ LSP/treesitter support)
Comment.nvim
also provides some methods apart from the mappings. Also note that these methods only do linewise commenting and only on the current line.
-- Comments the current line
require('Comment').comment()
-- Uncomments the current lines
require('Comment').uncomment()
-- Toggles the current lines
require('Comment').toggle()
There are two hook methods i.e pre_hook
and post_hook
which are called before comment and after comment respectively. Both should be provided during setup()
.
pre_hook
- This method is called before commenting is started. It can be used to return a customcommentstring
which will be used for commenting the lines. You can use something like nvim-ts-context-commentstring to compute the commentstring using treesitter.
{
pre_hook = function()
return require('ts_context_commentstring.internal').calculate_commentstring()
end
}
Also, you can set the commentstring
from here but i won't recommend it for now.
{
pre_hook = function()
require('ts_context_commentstring.internal').update_commentstring()
end
}
post_hook
- This method is called after commenting is done. It receives the lines range or-1
for the current line.
{
post_hook = function(start_col, end_col)
if start_col == -1 then
-- do something with the current line
else
-- do something with `start_col` and `end_col` line range
end
end
}
You can use ignore
to ignore certain lines during comment/uncomment. It takes a lua regex string and should be provided during setup()
.
-- ignores empty lines
ignore = '^$'
-- ignores line that starts with `local` (excluding any leading whitespace)
ignore = '^(%s*)local'
-- ignores any lines similar to arrow function
ignore = '^const(.*)=(%s?)%((.*)%)(%s?)=>'
Most languages have support for comments via commentstring
but there might be a language that is not supported. There are two ways to enable commenting for unsupported languages:
- You can set
commentstring
for that language like the following
vim.bo.commentstring = '//%s'
-- or
vim.api.nvim_command('set commentstring=//%s')
Run
:h commentstring
for more help
- You can also use this plugin interface to store both line and block commentstring. You can treat this as a more powerful version of the
commentstring
local lang = require('Comment.lang')
-- 1. Using set function
-- set both line and block commentstring
lang.set('javascript', {'//%s', '/*%*/'})
-- Just set only line comment
lang.set('yaml', '#%s')
-- 2. Metatable magic
-- One lang at a time
lang.javascript = {'//%s', '/*%*/'}
lang.yaml = '#%s'
-- Multiple langs
lang({'go', 'rust'}, {'//%s', '/*%*/'})
lang({'toml', 'graphql'}, '#%s')
PR(s) are welcome to add more commentstring inside the plugin
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
- If a string is returned from this method then it will be used for commenting. -
lang_table
- 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 thepre_hook
method and if the current filetype also exists in thelang_table
then the commenting will be done using the string inlang_table
instead of usingcommentstring
There are multiple ways to contribute reporting/fixing bugs, feature requests. You can also submit commentstring to this plugin by updating lang.lua and sending PR.
- tcomment - To be with me forever and motivated me to write this.
- nvim-comment - Little and less powerful cousin. Also I took some code from it.
- kommentary - Nicely done plugin but lacks some features. But it helped me to design this plugin.
-
Live upto the expectation of
tcomment
-
Basic INSERT mode mappings
-
Doc comment i.e
/**%s*/
(js),///%s
(rust) -
Inbuilt context commentstring using treesitter
{
pre_hook = function()
return require('Comment.ts').commentstring()
end
}
- Header comment
----------------------
-- This is a header --
----------------------