1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
|
<h1 align="center">// Comment.nvim </h1>
<p align="center"><sup>⚡ Smart and Powerful commenting plugin for neovim ⚡</sup></p>
![Comment.nvim](https://user-images.githubusercontent.com/42532967/136532939-926a8350-84b7-4e78-b045-fe21b5947388.gif "Commenting go brrrr")
### ✨ Features
- Supports treesitter. [Read more](#treesitter)
- 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`
- Left-right (`gcw` `gc$`) and Up-Down (`gc2j` `gc4k`) motions
- Use with text-objects (`gci{` `gbat`)
- Supports pre and post hooks
- Ignore certain lines, powered by Lua regex
### 🚀 Installation
- With [packer.nvim](https://github.com/wbthomason/packer.nvim)
```lua
use {
'numToStr/Comment.nvim',
config = function()
require('Comment').setup()
end
}
```
- With [vim-plug](https://github.com/junegunn/vim-plug)
```vim
Plug 'numToStr/Comment.nvim'
" Somewhere after plug#end()
lua require('Comment').setup()
```
### 📖 Getting Help
`Comment.nvim` provides help docs which can be accessed by running `:help comment-nvim`
<a id="setup"></a>
### ⚒️ Setup
First you need to call the `setup()` method to create the default mappings.
> **Note** - If you are facing **Keybindings are mapped but they are not working** issue then please try [this](https://github.com/numToStr/Comment.nvim/issues/115#issuecomment-1032290098)
- Lua
```lua
require('Comment').setup()
```
- VimL
```vim
lua << EOF
require('Comment').setup()
EOF
```
<a id="config"></a>
#### 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. Read `:h comment.config` for more info.
```lua
{
---Add a space b/w comment and the line
padding = true,
---Whether the cursor should stay at its position
sticky = true,
---Lines to be ignored while (un)comment
ignore = nil,
---LHS of toggle mappings in NORMAL mode
toggler = {
---Line-comment toggle keymap
line = 'gcc',
---Block-comment toggle keymap
block = 'gbc',
},
---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
extra = {
---Add comment on the line above
above = 'gcO',
---Add comment on the line below
below = 'gco',
---Add comment at the end of line
eol = 'gcA',
},
---Enable keybindings
---NOTE: If given `false` then the plugin won't create any mappings
mappings = {
---Operator-pending mapping; `gcc` `gbc` `gc[count]{motion}` `gb[count]{motion}`
basic = true,
---Extra mapping; `gco`, `gcO`, `gcA`
extra = true,
},
---Function to call before (un)comment
pre_hook = nil,
---Function to call after (un)comment
post_hook = nil,
}
```
### 🔥 Usage
When you call [`setup()`](#setup) method, `Comment.nvim` sets up some basic mapping which can be used in NORMAL and VISUAL mode to get you started with the pleasure of commenting stuff out.
<a id="basic-mappings"></a>
#### Basic mappings
These mappings are enabled by default. (config: `mappings.basic`)
- NORMAL mode
```help
`gcc` - Toggles the current line using linewise comment
`gbc` - Toggles the current line using blockwise comment
`[count]gcc` - Toggles the number of line given as a prefix-count using linewise
`[count]gbc` - Toggles the number of line given as a prefix-count using blockwise
`gc[count]{motion}` - (Op-pending) Toggles the region using linewise comment
`gb[count]{motion}` - (Op-pending) Toggles the region using blockwise comment
```
- VISUAL mode
```help
`gc` - Toggles the region using linewise comment
`gb` - Toggles the region using blockwise comment
```
<a id="extra-mappings"></a>
#### Extra mappings
These mappings are enabled by default. (config: `mappings.extra`)
- NORMAL mode
```help
`gco` - Insert comment to the next line and enters INSERT mode
`gcO` - Insert comment to the previous line and enters INSERT mode
`gcA` - Insert comment to end of the current line and enters INSERT mode
```
##### Examples
```help
# 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
`gc5j` - Toggle 5 lines after the current cursor position
`gc8k` - Toggle 8 lines before the current cursor position
`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)
```
<a id="treesitter"></a>
### 🌳 Treesitter
This plugin has native **treesitter** support for calculating `commentstring` which works for multiple (injected/embedded) languages like Vue or Markdown. But due to the nature of the parsed tree, this implementation has some known limitations.
1. No `jsx/tsx` support. Its implementation was quite complicated.
2. Invalid comment on the region where one language ends and the other starts. [Read more](https://github.com/numToStr/Comment.nvim/pull/62#issuecomment-972790418)
3. Unexpected comment on a line with multiple languages. [#144](https://github.com/numToStr/Comment.nvim/issues/144)
For advance use cases, use [nvim-ts-context-commentstring](https://github.com/JoosepAlviste/nvim-ts-context-commentstring). See [`pre_hook`](#pre-hook) section for the integration.
> **Note** - This plugin does not depend on [nvim-treesitter](https://github.com/nvim-treesitter/nvim-treesitter) however it is recommended in order to easily install tree-sitter parsers.
<a id="hooks"></a>
### 🎣 Hooks
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()`](#setup).
<a id="pre-hook"></a>
- `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.
```lua
{
pre_hook = function(ctx)
if ctx.range.srow == ctx.range.erow then
-- do something with the current line
else
-- do something with lines range
end
end,
}
```
You can also integrate [nvim-ts-context-commentstring](https://github.com/JoosepAlviste/nvim-ts-context-commentstring#commentnvim) using `pre_hook` to easily comment `tsx/jsx` files.
> **Note** - `Comment.nvim` already supports [`treesitter`](#treesitter) out-of-the-box for all the languages except `tsx/jsx`.
```lua
{
pre_hook = require('ts_context_commentstring.integrations.comment_nvim').create_pre_hook(),
}
```
<a id="post-hook"></a>
- `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
{
post_hook = function(ctx)
if ctx.range.srow == ctx.range.erow then
-- do something with the current line
else
-- do something with lines range
end
end,
}
```
The `post_hook` can be implemented to cover some niche use cases like the following:
- Using newlines instead of padding e.g. for commenting out code in C with `#if 0`. See an example [here](https://github.com/numToStr/Comment.nvim/issues/38#issuecomment-945082507).
- Duplicating the commented block (using `pre_hook`) and moving the cursor to the next block (using `post_hook`). See [this](https://github.com/numToStr/Comment.nvim/issues/70).
> NOTE: When pressing `gc`, `gb` and friends, `cmode` (Comment mode) inside `pre_hook` will always be toggle because when pre-hook is called, in that moment we don't know whether `gc` or `gb` will comment or uncomment the lines. But luckily, we do know this before `post_hook` and this will always receive either comment or uncomment status
### 🚫 Ignoring lines
You can use `ignore` to ignore certain lines during comment/uncomment. It can takes lua regex string or a function that returns a regex string and should be provided during [`setup()`](#setup).
> NOTE: Ignore only works when with linewise comment. This is by design. As ignoring lines in block comments doesn't make that much sense.
- With `string`
```lua
-- 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?)=>'
```
- With `function`
```lua
{
ignore = function()
-- Only ignore empty lines for lua files
if vim.bo.filetype == 'lua' then
return '^$'
end
end,
}
```
<a id="languages"></a>
### 🗨️ Filetypes + Languages
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. Read `:h commentstring` for more info.
```lua
vim.bo.commentstring = '//%s'
-- or
vim.api.nvim_command('set commentstring=//%s')
```
<a id="ft-lua"></a>
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
ft
-- Set only line comment
.set('yaml', '#%s')
-- Or set both line and block commentstring
.set('javascript', {'//%s', '/*%s*/'})
-- 2. Metatable magic
ft.javascript = {'//%s', '/*%s*/'}
ft.yaml = '#%s'
-- Multiple filetypes
ft({'go', 'rust'}, ft.get('c'))
ft({'toml', 'graphql'}, '#%s')
```
> PR(s) are welcome to add more commentstring inside the plugin
### 🤝 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.
### 📺 Videos
- [TakeTuesday E02: Comment.nvim](https://www.youtube.com/watch?v=-InmtHhk2qM) by [TJ DeVries](https://github.com/tjdevries)
### 💐 Credits
- [tcomment](https://github.com/tomtom/tcomment_vim) - To be with me forever and motivated me to write this.
- [nvim-comment](https://github.com/terrortylor/nvim-comment) - Little and less powerful cousin. Also I took some code from it.
- [kommentary](https://github.com/b3nj5m1n/kommentary) - Nicely done plugin but lacks some features. But it helped me to design this plugin.
### 🚗 Roadmap
- Doc comment i.e `/**%s*/` (js), `///%s` (rust)
- Header comment
```lua
----------------------
-- This is a header --
----------------------
```
|