← Back to DevBytes

Emacs Multi-Cursor Editing: Complete Guide

What is Multi-Cursor Editing in Emacs?

Multi-cursor editing allows you to create multiple simultaneous cursors (also called "multiple cursors" or "mc") at different locations in a buffer. Any text you type appears at all cursor positions at once. This is similar to the multi-selection editing found in modern editors like Sublime Text, VS Code, or IntelliJ IDEA, but Emacs implements it with its own unique flavor and extensibility.

In Emacs, multi-cursor support comes primarily through the multiple-cursors package. The package transforms Emacs's single-cursor paradigm into a multi-cursor powerhouse, letting you edit many locations simultaneously without resorting to macros or repetitive commands.

Core Concepts

When you activate multiple cursors, Emacs maintains:

The package works by intercepting your input, running the commands at each cursor location in sequence, and updating all positions accordingly. It handles complex scenarios like overlapping edits, undo behavior, and region-specific operations remarkably well.

Why Multi-Cursor Editing Matters

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

Multi-cursor editing dramatically accelerates repetitive editing tasks. Consider these common scenarios:

Without multi-cursors, you'd typically reach for:

Multi-cursors give you visual, interactive, simultaneous editing — you see exactly what changes are happening and can adjust on the fly. This immediacy reduces cognitive overhead and catches errors before they propagate.

Installation and Setup

Installing the Multiple-Cursors Package

The canonical package is multiple-cursors by Magnar Sveen, available on MELPA. Add this to your Emacs configuration:

;; Add MELPA if you haven't already
(require 'package)
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)

;; Install multiple-cursors
(unless (package-installed-p 'multiple-cursors)
  (package-refresh-contents)
  (package-install 'multiple-cursors))

;; Enable the package
(require 'multiple-cursors)

Basic Keybindings

The package provides sensible default bindings. Here's a recommended setup that doesn't conflict with common Emacs workflows:

(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
(global-set-key (kbd "C->")         'mc/mark-next-like-this)
(global-set-key (kbd "C-<")         'mc/mark-previous-like-this)
(global-set-key (kbd "C-c C-<")     'mc/mark-all-like-this)
(global-set-key (kbd "C-S-d")       'mc/mark-all-like-this-dwim)
(global-set-key (kbd "C-S-m")       'mc/mark-more-like-this-extended)

;; For Emacs 28+ with repeat-mode, consider:
(global-set-key (kbd "C-.")         'mc/mark-next-like-this)
(global-set-key (kbd "C-,")         'mc/mark-previous-like-this)

If you use use-package, here's a clean configuration block:

(use-package multiple-cursors
  :ensure t
  :bind (("C-S-c C-S-c" . mc/edit-lines)
         ("C->"         . mc/mark-next-like-this)
         ("C-<"         . mc/mark-previous-like-this)
         ("C-c C-<"     . mc/mark-all-like-this)
         ("C-S-d"       . mc/mark-all-like-this-dwim))
  :config
  (setq mc/always-run-for-all-cursors t
        mc/always-focus-minibuffer t))

How to Use Multiple Cursors

Adding Cursors One by One

The most common workflow: place your cursor on a symbol, then press C-> to mark the next occurrence and create a new cursor there. Repeat to add more cursors. Use C-< to skip back and remove the most recent cursor.

Example — given this code:

function updateUser(userId, userName) {
  console.log(userId);
  return fetchUser(userId, userName);
}

Place the cursor on userId, press C-> twice to mark the other two occurrences. Now type accountId — all three instances change simultaneously.

Marking All Occurrences at Once

To select every occurrence of the symbol at point, use C-c C-< (mc/mark-all-like-this). This is faster than stepping through occurrences when you want to edit them all.

;; Before — cursor on 'status'
status = computeStatus(data);
if (status == 0) {
  logStatus(status);
}

;; Press C-c C-< then type 'result'
result = computeResult(data);
if (result == 0) {
  logResult(result);
}

DWIM (Do What I Mean) Marking

The mc/mark-all-like-this-dwim command (bound to C-S-d) intelligently decides whether to mark all occurrences in the whole buffer or just within the current defun/scope. If a region is active, it limits searching to that region. This is the most versatile marking command for programming.

Editing Multiple Lines

The mc/edit-lines command (C-S-c C-S-c) places a cursor at the beginning of each line in the active region. This is perfect for columnar editing:

;; Select these three lines with a region, then C-S-c C-S-c:
apple
banana
cherry

;; Type: " - fruit" at each cursor
apple - fruit
banana - fruit
cherry - fruit

You can also use mc/edit-lines without a region — it operates on consecutive lines starting from the current line, placing cursors at the beginning of each. Use a numeric prefix argument (e.g., C-u 10 C-S-c C-S-c) to specify how many lines to cover.

Matching Complex Patterns

The command mc/mark-more-like-this-extended (bound to C-S-m) prompts you for a regular expression and marks all matches with cursors. This is invaluable for pattern-based edits:

;; Buffer contains:
;; error: connection refused on port 8080
;; error: timeout on port 3000
;; error: invalid token on port 5432

;; Press C-S-m, enter regex: port \d+
;; All port numbers are now selected with cursors
;; Type: 9090 — all ports change at once

Using Rectangle Mark Mode with Multi-Cursors

You can combine rectangle selections with multi-cursors. Use C-x SPC to enter rectangle-mark-mode, select a rectangle, then use mc/edit-lines — cursors appear at each line within the rectangle, at the column of the rectangle's edge.

Practical Code Examples

Example 1: Converting a List of Constants to Enums

Given a plain list of constants that need enum wrapping:

STATUS_ACTIVE = 1
STATUS_PENDING = 2
STATUS_CLOSED = 3

Workflow:

  1. Place cursor on STATUS_ACTIVE
  2. Press C-S-m, enter regex: STATUS_\w+ to mark all three lines
  3. Type: case (appears before each constant)
  4. Press C-e to move each cursor to end of its line
  5. Type: : return ", then C-e again, then type: "; break;

Result:

case STATUS_ACTIVE: return "STATUS_ACTIVE"; break;
case STATUS_PENDING: return "STATUS_PENDING"; break;
case STATUS_CLOSED: return "STATUS_CLOSED"; break;

Example 2: Adding Type Annotations to Function Parameters

Starting with untyped Python parameters:

def process_data(name, age, location, status):
    pass

Workflow:

  1. Place cursor on name
  2. Press C-> three times to mark age, location, status
  3. Press C-s , to search forward for comma, then RET to exit search — now each cursor is after its parameter
  4. Type: : str (or appropriate types)

Result:

def process_data(name: str, age: str, location: str, status: str):
    pass

Note: For different types, you'd manually adjust individual cursors or use a macro instead.

Example 3: HTML List Transformation

Transform a bullet list into HTML list items:

* Introduction
* Getting Started
* Advanced Topics
* Conclusion

Workflow:

  1. Select all four lines as a region
  2. Press C-S-c C-S-c (mc/edit-lines)
  3. Type: <li> at the start of each line
  4. Press C-e to move to end of each line
  5. Type: </li>

Result:

<li>Introduction</li>
<li>Getting Started</li>
<li>Advanced Topics</li>
<li>Conclusion</li>

Example 4: Inserting Commas at Line Ends

Given a JSON-like list missing commas:

{"name": "Alice"}
{"name": "Bob"}
{"name": "Carol"}
{"name": "Dave"}

Workflow:

  1. Select the region covering all lines
  2. C-S-c C-S-c to place cursors at line starts
  3. C-e to move all cursors to line ends
  4. Type: ,

Result:

{"name": "Alice"},
{"name": "Bob"},
{"name": "Carol"},
{"name": "Dave"},

Advanced Techniques

Navigating with Multiple Cursors

When you have multiple cursors active, standard motion commands work but behave slightly differently. Here are key navigation patterns:

Be careful with line-based movement when cursors are on different lines — each cursor maintains its own column position independently.

Undo Behavior with Multiple Cursors

Undo (C-/ or C-x u) with multiple cursors undoes the entire batch of simultaneous edits as a single undo step. This is a major advantage over macros, where undo replays the entire macro in reverse. With multi-cursors, one undo reverts all changes from the last multi-cursor edit atomically.

Exiting Multi-Cursor Mode

Press C-g (keyboard-quit) to exit multi-cursor mode and return to a single cursor. Alternatively, RET or SPC in the special mc/keymap context also exits gracefully. If you accidentally enter multi-cursor mode, C-g is your escape hatch.

Using Marks and Regions

With multiple cursors, each cursor has its own mark. You can set marks with C-SPC and then perform region-based operations. The primary cursor's region determines the behavior for commands that aren't cursor-aware. For predictable results, stick to simple insertions and deletions when using regions across multiple cursors.

Customizing Cursor Appearance

You can customize how fake cursors look:

(setq mc/cursor-color "red")           ;; Color of fake cursors
(setq mc/cursor-bar-color "orange")    ;; Bar cursor color (if using bar cursor)
(setq mc/use-blink-cursor t)           ;; Blink fake cursors
(setq mc/use-falling-bomb-cursor t)    ;; Fun animation (try it!)

Built-in Emacs Alternatives

While multiple-cursors is the most popular package, Emacs has several built-in approaches worth knowing:

Iedit Mode

Built into Emacs (since 24.x), iedit lets you edit all occurrences of a symbol in a buffer or region. It's more limited than multiple-cursors but requires no external package:

;; Place cursor on a symbol, then:
;; M-x iedit-mode   (or bind to a key)
;; All occurrences are highlighted and editable
;; Type your changes — they appear everywhere
;; Press C-g to exit iedit mode

Iedit shines for quick symbol renaming without the visual overhead of multiple cursors. It's essentially "edit all occurrences inline."

Query-Replace with Zero-Length Replacements

A creative built-in approach: use query-replace-regexp with capture groups and zero-length assertions to simulate multi-cursor insertion:

;; To insert "DEBUG: " before every line starting with "log"
;; M-x query-replace-regexp
;; Search: ^\(log.*\)
;; Replace: DEBUG: \1

This is powerful but lacks the interactive visual feedback of multi-cursors.

Keyboard Macros

For truly complex, non-uniform edits across multiple locations, keyboard macros remain the gold standard:

;; Record a macro (F3)
;; Perform the edit on one occurrence
;; Stop recording (F4)
;; Execute macro with prefix: C-u 0 F4 (runs until error)
;; Or: C-x e e e e ... for manual step-through

Macros complement multi-cursors — use macros for sequential, pattern-based edits and multi-cursors for simultaneous, uniform edits.

Best Practices

1. Start Simple, Add Cursors Incrementally

Don't immediately mark all occurrences. Start with C-> to add cursors one at a time. This builds spatial awareness of where each cursor is and prevents accidentally editing locations you didn't intend to touch.

2. Use DWIM for Scoped Edits

Prefer mc/mark-all-like-this-dwim over mc/mark-all-like-this. The DWIM variant respects function boundaries and active regions, reducing the chance of editing code outside your current context.

3. Combine with Isearch for Precision

After activating multiple cursors, use C-s (isearch) to navigate all cursors to specific positions. For example, if you want to insert text after the first comma on each line, place cursors at line starts, then C-s , to jump all cursors to their respective commas.

4. Limit Cursor Count on Large Files

With hundreds of cursors, Emacs can slow down noticeably. If you're marking all occurrences of a common symbol (like i or tmp) in a large file, consider narrowing the buffer first with C-x n n (narrow-to-region) to limit the scope.

5. Use Rectangle Mode for Columnar Data

For CSV files, log files, or tabular data, combine rectangle-mark-mode with mc/edit-lines. Select a rectangle over the column you want to edit, then activate multi-cursors within that rectangle.

6. Master the Escape Hatch

Train yourself to hit C-g immediately if multi-cursor behavior goes wrong. It's fast, non-destructive, and gets you back to a single cursor instantly. Don't try to "fix" a bad multi-cursor state — escape and start fresh.

7. Pair with Multiple-Cursors for Symmetrical Edits

When editing HTML/JSX with matching tags, or parentheses-balanced expressions, use multi-cursors together with smartparens or paredit for structural editing across multiple locations simultaneously.

8. Customize the mc/keymap for Efficiency

During multi-cursor editing, a special keymap (mc/keymap) is active. You can bind keys specifically for use during multi-cursor sessions:

(define-key mc/keymap (kbd "C-j") 'mc/insert-newline)
(define-key mc/keymap (kbd "C-d") 'mc/delete-forward)
;; This ensures predictable behavior across all cursors

9. Use Prefix Arguments for edit-lines

Instead of selecting a region for mc/edit-lines, use a prefix argument: C-u 20 C-S-c C-S-c places cursors on the next 20 lines. This is often faster than mouse-selecting a region.

10. Combine Macros and Multi-Cursors

For edits that require different types of changes at each cursor, record a keyboard macro that handles the variation, then apply it with multi-cursors. The macro executes at each cursor position sequentially, giving you the best of both worlds.

Troubleshooting Common Issues

Cursors Disappear or Flicker

If fake cursors flicker or disappear, check your theme. Some themes don't handle the cursor overlay well. Try setting mc/cursor-color explicitly to a contrasting color. Also, disable mc/use-falling-bomb-cursor if it causes visual glitches.

Commands Don't Work with Multiple Cursors

Not all Emacs commands are multi-cursor-aware. Commands that rely on buffer-wide state (like undo, complex query-replace, or commands that manipulate windows) may behave unpredictably. Stick to insertion, deletion, and simple motion commands for reliable results.

Performance Degradation

With more than ~50 cursors on a large buffer, you may notice lag. Solutions:

Accidental Activation

If you find yourself accidentally triggering multi-cursors (especially with easy-to-reach bindings like C->), consider using a less sensitive binding or enabling a confirmation prompt:

(setq mc/always-confirm t)  ;; Prompt before activating multiple cursors

Comparison with Other Editors

Emacs multi-cursor editing differs from implementations in other editors in notable ways:

The key advantage in Emacs: multi-cursors compose with every other Emacs feature — registers, macros, rectangle commands, isearch, and custom functions. This composability is uniquely Emacs.

Conclusion

Multi-cursor editing transforms Emacs from a single-point editor into a parallel editing machine. The multiple-cursors package provides an intuitive, visual way to apply simultaneous edits across many locations, filling the gap between simple query-replace and complex keyboard macros. By mastering the incremental marking commands, the DWIM variant, and the line-editing mode, you can handle the vast majority of repetitive editing tasks with fluid, interactive precision.

Start with C-> to mark occurrences one by one, graduate to C-S-d for scoped DWIM marking, and combine with C-S-c C-S-c for line-based edits. Keep C-g ready as your escape, and remember that multi-cursors complement rather than replace macros and query-replace — each tool has its sweet spot. With practice, multi-cursor editing becomes an indispensable part of your Emacs muscle memory, turning tedious repetition into a satisfying, instantaneous transformation.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles