Nvim plugin to enable multi cursor editing
Find a file
Adam Martin 3d0620b615
Merge pull request #1 from amartincodes/visual-select
first pass at visual select and keymap fixes
2026-05-28 23:43:30 +01:00
doc fixed replace motion support 2026-05-28 22:21:39 +00:00
lua/multilinea markdown tweaks 2026-05-28 22:40:30 +00:00
plugin init 2026-01-28 22:59:54 +00:00
.gitignore init 2026-01-28 22:59:54 +00:00
CLAUDE.md markdown tweaks 2026-05-28 22:40:30 +00:00
LICENSE init 2026-01-28 22:59:54 +00:00
QUICKSTART.md markdown tweaks 2026-05-28 22:40:30 +00:00
README.md markdown tweaks 2026-05-28 22:40:30 +00:00
test_example.txt fixed replace motion support 2026-05-28 22:21:39 +00:00

Multilinea.nvim

A powerful multi-cursor editing plugin for Neovim, inspired by VSCode's multi-cursor functionality. Built with LazyVim compatibility in mind.

Features

  • 🎯 VSCode-style cursor addition - Press <C-n> to add cursors at matches
  • ⬆️⬇️ Directional cursors - Add cursors above/below current position
  • 🔍 Literal matching - Match char, visual selection, or linewise visual blocks (V)
  • ✏️ Simultaneous editing - Type once, edit everywhere
  • 🎨 Visual feedback - Clear cursor indicators using Neovim's extmarks
  • Lightweight - Pure Lua implementation with minimal dependencies
  • 🔧 Fully customizable - Configure keybindings, highlights, and behavior

Installation

-- In ~/.config/nvim/lua/plugins/multilinea.lua
return {
  "amartincodes/multilinea.nvim",
  event = "BufReadPost",
  opts = {
    -- Your configuration here (optional)
  },
}

Using packer.nvim

use {
  "amartincodes/multilinea.nvim",
  config = function()
    require("multilinea").setup()
  end
}

Using vim-plug

Plug 'amartincodes/multilinea.nvim'

" In your init.vim
lua << EOF
  require("multilinea").setup()
EOF

Usage

Basic Operations

  1. Add cursor at next match (VSCode-style)

    • Place cursor on a character, visually select text, or use linewise visual mode (V)
    • Press <C-n> to add cursor at the next occurrence
    • Keep pressing <C-n> to add more cursors
    • Press <Esc> to clear all cursors
  2. Add cursors vertically

    • Press <C-j> to add cursor below
    • Press <C-k> to add cursor above
    • Great for editing aligned columns
  3. Add all matches

    • Place cursor on a character, visually select text, or use linewise visual mode (V)
    • Press <leader>ma to add cursors at all occurrences
  4. Manual cursor placement

    • Press <leader>mc to add a cursor at current position
    • Move around and add more cursors where needed

Editing with Multiple Cursors

Once you have multiple cursors:

  • Insert mode: Press i, a, I, A, o, or O to start editing at all cursors
  • Normal mode: Most motions and operators work at all cursors:
    • w, b, e - word motions
    • 0, ^, $ - line motions
    • dd, D, x - delete operations
    • r{char} - replace character at all cursors
    • y, p - yank and paste
  • Clear cursors: Press <Esc> to exit multi-cursor mode

Example Workflow

-- Rename all occurrences of a variable
1. Place cursor on variable name
2. Press <C-n> multiple times (or <leader>ma for all)
3. Press 'ciw' to change inner word
4. Type the new name
5. Press <Esc> to apply to all cursors

Configuration

Default Configuration

require("multilinea").setup({
  -- Keybindings (all customizable)
  keymaps = {
    add_cursor_next = "<C-n>",      -- Add cursor at next match
    add_cursor_below = "<C-j>",      -- Add cursor below
    add_cursor_above = "<C-k>",      -- Add cursor above
    add_all_matches = "<leader>ma",  -- Add all matches
    remove_cursor = "<M-x>",         -- Remove current cursor
    clear_cursors = "<Esc>",         -- Clear all cursors
    skip_match = "<leader>ms",       -- Skip current match
    add_cursor_here = "<leader>mc",  -- Add cursor at position
  },

  -- Visual appearance
  highlights = {
    primary = "CursorLine",
    secondary = "Visual",
  },

  -- Behavior
  show_cursor_numbers = false,     -- Show cursor index numbers
  case_sensitive_search = false,   -- Case sensitivity for matching
})

Custom Keybindings

require("multilinea").setup({
  keymaps = {
    add_cursor_next = "<C-d>",      -- Use Ctrl-d like Sublime Text
    add_all_matches = "<C-M-l>",    -- Custom binding
    clear_cursors = "<leader>mc",   -- Use leader instead of Esc
  },
})

Custom Highlights

require("multilinea").setup({
  highlights = {
    primary = "Search",             -- Use Search highlight for primary cursor
    secondary = "IncSearch",        -- Use IncSearch for secondary cursors
  },
})

Commands

Multilinea provides the following user commands:

  • :MultilineaAddCursor - Add cursor at current position
  • :MultilineaAddNext - Add cursor at next match
  • :MultilineaAddAll - Add cursors at all matches
  • :MultilineaClear - Clear all cursors
  • :MultilineaAddBelow - Add cursor below
  • :MultilineaAddAbove - Add cursor above

API

Multilinea exposes a public API for integration with other plugins:

local multilinea = require("multilinea")

-- Add cursor programmatically
multilinea.api.add_cursor(row, col, is_primary)

-- Remove cursor
multilinea.api.remove_cursor(row, col)

-- Clear all cursors
multilinea.api.clear_all()

-- Get cursor positions
local cursors = multilinea.api.get_cursors()

-- Check if active
if multilinea.api.is_active() then
  print("Multi-cursor mode active")
end

-- Get cursor count
local count = multilinea.api.get_count()

Health Check

Run :checkhealth multilinea to verify your installation.

Comparison with Other Plugins

Feature Multilinea vim-visual-multi multiple-cursors.nvim
Pure Lua
Extmarks API
VSCode-style <C-n>
LazyVim ready ⚠️ ⚠️
Lightweight
Visual mode (charwise + linewise)

Roadmap

  • Basic multi-cursor operations
  • VSCode-style literal matching
  • Directional cursor addition
  • Insert mode editing
  • Normal mode operations
  • Blockwise visual mode support (<C-v>)
  • Macro recording per cursor
  • Advanced selection refinement
  • Pattern-based cursor placement
  • Split/join cursor operations

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

# Clone the repository
git clone https://github.com/amartincodes/multilinea.nvim.git
cd multilinea.nvim

# Test in Neovim
nvim --cmd "set rtp+=."

License

MIT License - see LICENSE file for details.

Acknowledgments

Inspired by:

Support

If you encounter issues or have questions:

  1. Check the documentation
  2. Search existing issues
  3. Create a new issue with:
    • Neovim version (:version)
    • Configuration
    • Steps to reproduce
    • Expected vs actual behavior

Made with ❤️ for the Neovim community