Skip to main content
This configuration includes comprehensive editing enhancements for efficient code manipulation across multiple languages.

Autopairs

Intelligent bracket and quote pairing with language-specific rules:
lua/plugins/editing.lua
{
  "windwp/nvim-autopairs",
  event = "InsertEnter",
  dependencies = {
    "nvim-treesitter/nvim-treesitter",
    "saghen/blink.cmp",
  },
}

Features

Treesitter-aware

Understands context to avoid pairing in strings/comments

Language-specific

Custom rules for Go, Rust, JavaScript, TypeScript, React

JSX support

Space padding for JSX expressions

Smart deletion

Delete both pairs with single backspace

Configuration

lua/plugins/editing.lua
npairs.setup({
  check_ts = true, -- Use treesitter for smarter pairing
  ts_config = {
    lua = { "string", "source" },
    javascript = { "template_string" },
    typescript = { "template_string" },
    javascriptreact = { "template_string", "jsx_attribute" },
    typescriptreact = { "template_string", "jsx_attribute" },
  },
  disable_filetype = { "TelescopePrompt", "vim", "lazy", "mason" },
  enable_check_bracket_line = true,
  enable_bracket_in_quote = true,
  map_cr = true, -- Handle JSX Enter!
  map_bs = true, -- Map backspace for pair deletion
})
Treesitter integration prevents autopairs from triggering inside strings, comments, and template literals.

JSX space padding

Automatically adds space padding in JSX braces:
lua/plugins/editing.lua
Rule(" ", " ")
  :with_pair(function(opts)
    local pair = opts.line:sub(opts.col - 1, opts.col)
    return vim.tbl_contains({
      brackets[1][1] .. brackets[1][2],
      brackets[2][1] .. brackets[2][2],
      brackets[3][1] .. brackets[3][2],
    }, pair)
  end)
Example:
<div className={|}>
// Press space:
<div className={ | }>

Language-specific rules

npairs.add_rule(Rule("<", ">", { "rust" })
  :with_pair(cond.before_regex("%a+:?:?$", 3)))
Handles lifetime annotations and turbofish:
  • Vec<|>
  • 'a<|>
lua/plugins/editing.lua
local blink_ok, blink = pcall(require, "blink.cmp")
if blink_ok then
  -- blink.cmp doesn't need explicit autopairs integration
  -- autopairs' map_cr handles <CR> behavior automatically
end
Autopairs works seamlessly with Blink.cmp completion.

Auto-tags

Automatic HTML/JSX tag closing and renaming:
lua/plugins/editing.lua
{
  "windwp/nvim-ts-autotag",
  event = { "BufReadPost", "BufNewFile" },
  opts = {
    opts = {
      enable_close = true,      -- Auto close tags
      enable_rename = true,     -- Auto rename pairs
      enable_close_on_slash = true, -- Auto close on trailing </
    },
  },
}

Features

1

Auto close

<div>|</div>
<!-- Type content, tag closes automatically -->
2

Auto rename

<div>content</div>
<!-- Change div to span, closing tag updates automatically -->
<span>content</span>
3

Self-closing

<Component /|
<!-- Type >, automatically becomes self-closing -->
<Component />

Supported languages

  • HTML
  • XML
  • JavaScript (JSX)
  • TypeScript (TSX)
  • Vue
  • Svelte
  • PHP

Comments

Context-aware commenting with JSX support:
lua/plugins/editing.lua
{
  "numToStr/Comment.nvim",
  lazy = false,
  dependencies = { "JoosepAlviste/nvim-ts-context-commentstring" },
  config = function()
    require("Comment").setup({
      pre_hook = require("ts_context_commentstring.integrations.comment_nvim").create_pre_hook(),
    })
  end,
}

Keybindings

KeyModeActionDescription
gccNormalToggle lineComment/uncomment current line
gbcNormalToggle blockBlock comment current line
gcVisualToggle linesComment/uncomment selection
gbVisualToggle blockBlock comment selection

Context-aware comments

lua/plugins/editing.lua
{
  "JoosepAlviste/nvim-ts-context-commentstring",
  lazy = true,
  opts = {
    enable_autocmd = false, -- Handled by Comment.nvim pre_hook
  },
}
Automatically uses correct comment syntax based on context:
function App() {
  return (
    <div>
      {/* HTML comment in JSX */}
      // JavaScript comment outside JSX
    </div>
  )
}
Context-commentstring uses Treesitter to determine the correct comment syntax for the current cursor position.

Vim-sleuth

Automatic indentation detection:
lua/plugins/editing.lua
{ "tpope/vim-sleuth" }
Automatically detects and sets:
  • shiftwidth - Indentation width
  • expandtab - Tabs vs spaces
  • tabstop - Tab display width
Vim-sleuth analyzes the file and other project files to detect the indentation style automatically.

CamelCase motion

Navigate and operate on CamelCase and snake_case words:
lua/plugins/editing.lua
{
  "bkad/CamelCaseMotion",
  init = function()
    vim.g.camelcasemotion_key = "<leader>"
  end,
}

Keybindings

All motions are prefixed with <leader>:
KeyActionDescription
<leader>wNext wordJump to next CamelCase word part
<leader>bPrevious wordJump to previous CamelCase word part
<leader>eEnd of wordJump to end of CamelCase word part
<leader>geEnd backwardsJump backwards to end of word part

Example

const myVariableName = "value"
//    ^ <leader>w -> ^ <leader>w -> ^ <leader>w -> ^

Text objects

OperatorTargetDescription
i<leader>wInner wordCamelCase word part (inner)
a<leader>wAround wordCamelCase word part (outer)
Examples:
  • di<leader>w - Delete CamelCase word part
  • ci<leader>w - Change CamelCase word part
  • vi<leader>w - Select CamelCase word part

Additional editing features

From mini.nvim

Surround

Add/delete/replace surrounding brackets, quotes, etc.

Split/join

Split/join code blocks intelligently (gS)

Operators

Additional operators for replace, exchange, sort

From Treesitter

Text objects

Code-aware text objects (af, if, ac, ic, etc.)

Parameter swap

Swap function parameters with <leader>a/<leader>A

Workflow examples

<div class="container">
  Content
</div>
  1. Change div to section
  2. Closing tag updates automatically to </section>

Completions

Blink.cmp integrates with autopairs for completion

Treesitter

Powers context detection for autopairs and comments

Mini.nvim

Additional editing operators and surround

Build docs developers (and LLMs) love