Open-source project
JoosepAlviste/nvim-ts-context-commentstring avatar
JoosepAlviste/nvim-ts-context-commentstring

nvim-ts-context-commentstring: picking the right comment style by cursor position

Neovim treesitter plugin for setting the commentstring based on the cursor location in a file.

1,301 stars47 forksLuaMIT

At a glance

What is it?
nvim-ts-context-commentstring is a small Neovim plugin that sets the commentstring option from a tree-sitter query on the cursor's location, so a Vue file's script block and its style block can each get their own comment syntax. It changes the option and nothing else.
Who is it for?
nvim-ts-context-commentstring fits a Neovim user who works in single-file frameworks where several languages share one buffer, such as Vue, Svelte or HTML with scripts, and who already has a commenting plugin. It does not fit a user who only needs a fixed comment style, and it does not comment anything on its own.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Activity is slowing. The repository last received commits 6 months ago.
What is it written in?
Mainly Lua, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One option, and only one option

nvim-ts-context-commentstring sets the `commentstring` option based on the cursor location in a file, and the location is checked via tree-sitter queries.

The scope is worth stating precisely because the plugin name can suggest more. The README is explicit: this plugin only changes the `commentstring` setting, it does not add any mappings for commenting. It is recommended to use a commenting plugin such as Comment.nvim alongside it.

So the division of labour is: the commenting plugin decides when to comment and what to do with the result, and this plugin decides which comment syntax is appropriate at the cursor. A user who installs it expecting a comment keybinding will find nothing happens, and the reason is by design rather than by omission.

The problem it solves is narrow and real. In files that embed several languages, each section can have a different style for comments. A Vue file is the example given: it can have many different sections, each of which can have a different comment style. Without this plugin, the comment syntax is a single value for the whole buffer, so commenting a script block might use the style that belongs to the template block.

The code is Lua, as a Neovim plugin should be, and the licence is MIT.

Installation with lazy.nvim and the setup call

The plugin needs Neovim 0.9.4, and tree-sitter parsers, for example installed with nvim-treesitter. Those are the two requirements stated in the README, and the parser requirement is the one people miss, since a plugin that depends on tree-sitter queries cannot do anything useful without the parsers for the languages you edit.

Installation uses whatever plugin manager you already have. With lazy.nvim the README shows a single spec:

lua
require('lazy').setup {
  'JoosepAlviste/nvim-ts-context-commentstring',
}

For most commenting plugins that is the whole setup, and the defaults should work out of the box. Some commenting plugins need a little more, which is why the configuration section exists.

To change the configuration, call the setup function of the plugin:

lua
require('ts_context_commentstring').setup {
  enable_autocmd = false,
}

Two notes come with this. A minimal configuration file is available at `utils/minimal_init.lua` in the repository, which is the fastest way to see a working configuration from scratch. And if you are using `init.vim`, the README reminds you to use `:h lua-heredoc`, since Lua blocks in a Vimscript file are not the same thing as Lua code in `init.lua`.

For anything beyond the basics, the documentation is in Neovim's own help system under `:h ts-context-commentstring`, which is a better place to look than the README for the option list.

Integrations versus the CursorHold fallback

This is where the plugin's real design shows, and it is a design decision rather than an implementation detail.

The recommendation is to use a commenting plugin that has an integration available with this plugin, so the commentstring calculation is triggered only when commenting rather than continuously. The available integrations are listed in the project wiki, and the README names the plugins that have one: native Neovim commenting, b3nj5m1n/kommentary, terrortylor/nvim-comment, numToStr/Comment.nvim, echasnovski/mini.nvim mini-comment, and tpope/vim-commentary.

That is a broad spread. Native Neovim commenting means the plugin works with the editor's built-in commenting without a third-party plugin at all, and the rest cover the common commenting plugins in both the Lua and Vim script worlds.

Without an integration, the default behaviour is to calculate the commentstring on the `CursorHold` autocmd. That means the plugin has to run its tree-sitter queries whenever the cursor sits still long enough, which has a cost, and the README handles it with a specific instruction: `:h updatetime` should be set to a smaller value than the default of 4s.

lua
vim.opt.updatetime = 100

Setting that to 100 milliseconds means the cursor has to be idle for a tenth of a second before the recalculation happens. The trade is between responsiveness and idle work, and if you find the commentstring lagging behind the cursor in a file with many embedded languages, this is the knob.

Turning `enable_autocmd` off in the setup call is the other half of the same decision, and it is the option to reach for if you have an integration and do not want the fallback running at all.

Nesting works without extra configuration

The demo gifs in the README cover React, Svelte and HTML, and the interesting one is the nesting case.

The author describes injecting HTML into JavaScript strings and creating multiple levels of nesting with a language tree, and states that this sort of nesting of languages works without any extra configuration in the plugin.

That is a stronger claim than it first appears. A file where HTML sits inside a JavaScript string which itself sits inside a Vue template has three possible comment syntaxes, and the naive implementation would need to know how to unwind back to the outermost language. The tree-sitter query approach means the plugin asks the parser what is under the cursor rather than tracking a nesting stack itself, so the parser does the unwinding.

The practical consequence for a user is that the configuration does not need to enumerate every embedding case for every framework you use. Whether the file is React, Svelte, or Vue with an inline script, the mechanism is the same one, driven by whichever tree-sitter grammar is installed.

What this does not cover is anything the parser cannot see. A language region that the tree-sitter grammar does not model as a distinct node falls back to whatever the outer query gives, and that is the boundary of the approach.

Repository shape and maintenance state

The tree is what you would expect for a Lua Neovim plugin: a `lua/` directory for the module code, a `plugin/` directory for the files Neovim sources at startup, a `doc/` directory for the help file, a `utils/` directory holding the minimal init file referenced in the README, and a `stylua.toml` for formatting the Lua source. There is a LICENSE file, a `.gitignore` and a `.github/` directory.

The `stylua.toml` is worth a second look for a different reason. It tells you the project formats its Lua with StyLua rather than relying on whatever the author has installed, which is the kind of small consistency decision that keeps a plugin's source readable when several people contribute.

The `doc/` directory is the more important one for a user, since the README points at `:h ts-context-commentstring` for advanced configuration, and that help file is what the `:h` command resolves to. Having the documentation inside the plugin means it is available offline, which matters for a plugin whose main audience is people who read help files.

On maintenance, the repository is not archived and the last push was on 2026-04-04, and there are no GitHub releases, which is normal for a Neovim plugin distributed through a plugin manager rather than as a versioned package. The absence of releases means the plugin is versioned by commit, and a plugin manager pulling the main branch can pick up a change you did not expect.

Editorial conclusion

nvim-ts-context-commentstring fits a Neovim user who works in single-file frameworks where several languages share one buffer, such as Vue, Svelte or HTML with scripts, and who already has a commenting plugin. It does not fit a user who only needs a fixed comment style, and it does not comment anything on its own. Before adopting it, confirm your Neovim version is 0.9.4 or newer and that tree-sitter parsers are installed, then wire it into a commenting plugin that has an integration listed in the project wiki, and only fall back to the CursorHold autocmd if no integration exists.

Frequently asked questions

What does nvim-ts-context-commentstring do?

It is a Neovim plugin that sets the commentstring option based on the cursor location in a file, using tree-sitter queries. It is useful when a file embeds several languages, since each section can have a different comment style.

Does nvim-ts-context-commentstring add commenting keybindings?

No. The plugin only changes the commentstring setting and does not add any mappings for commenting. The README recommends using a commenting plugin such as Comment.nvim alongside it.

How do I install nvim-ts-context-commentstring?

You need Neovim 0.9.4 and tree-sitter parsers, for example via nvim-treesitter. With lazy.nvim, add `require('lazy').setup { 'JoosepAlviste/nvim-ts-context-commentstring' }` to your config.

Which commenting plugins have an integration?

Native Neovim commenting, kommentary, nvim-comment, Comment.nvim, mini-comment and vim-commentary are listed in the README, with the full list of integrations in the project wiki.

Why is my commentstring not updating fast enough?

Without a commenting plugin integration, the plugin recalculates on the CursorHold autocmd, and the README says updatetime should be set below the default of 4s, for example `vim.opt.updatetime = 100`. Alternatively, call setup with enable_autocmd = false.

Official sources

  1. Issues
  2. JoosepAlviste/nvim-ts-context-commentstring on GitHub
  3. License: MIT
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/joosepalviste-nvim-ts-context-commentstring.svg)](https://hysenlabs.com/projects/joosepalviste-nvim-ts-context-commentstring)

Was this useful?