← Back to DevBytes

Zed Multi-Cursor Editing: Complete Guide

Introduction to Zed Multi-Cursor Editing

Zed is a high-performance code editor built in Rust by the creators of Atom. One of its standout features is the robust multi-cursor editing system, which allows developers to place multiple cursors throughout a document and edit text at all locations simultaneously. This capability dramatically accelerates repetitive editing tasks and is a cornerstone of efficient text manipulation in modern editors.

Whether you are refactoring variable names across a file, transforming data structures, or applying consistent formatting, multi-cursor editing in Zed provides a fast, keyboard-driven workflow that keeps your hands on the keys and your focus on the code.

What Is Multi-Cursor Editing?

Multi-cursor editing is the ability to have more than one active cursor in a single document at the same time. When you type, delete, or apply commands, those actions are mirrored across every cursor position. Each cursor can also have its own selection range, enabling simultaneous edits to different spans of text.

In Zed, multi-cursor support is deeply integrated into the editor's core rather than bolted on as a plugin. This means operations like find and replace, indentation, and even language-aware features work seamlessly across all active cursors.

Key Concepts

Why Multi-Cursor Editing Matters

Multi-cursor editing matters because it eliminates the need for complex regular expressions or brittle find-and-replace patterns when the changes you need are visual and contextual. Instead of crafting a regex that might match unintended text, you can simply select the exact occurrences you want and edit them directly.

This approach offers several advantages:

For developers working in large codebases, these benefits compound. Refactoring a function signature, updating API calls, or reformatting data literals can all be accomplished in seconds rather than minutes.

How to Use Multi-Cursor Editing in Zed

Zed provides a rich set of keyboard shortcuts for creating and manipulating multiple cursors. The exact bindings depend on your platform, but the following examples use the default macOS keymap. On Linux and Windows, substitute Cmd with Ctrl in most cases.

Adding Cursors Manually

The simplest way to create multiple cursors is to add them one at a time at specific locations.

Column Selection

Column selection creates a rectangular block of cursors, which is useful for editing tabular data or aligned code blocks.

Practical Example: Renaming a Variable Across a Function

Suppose you have the following JavaScript function and you want to rename the variable user to account only within this function.

function getUserInfo(user) {
  const name = user.name;
  const email = user.email;
  const role = user.role;

  return {
    name,
    email,
    role,
    id: user.id,
  };
}

Follow these steps:

The result will look like this:

function getUserInfo(account) {
  const name = account.name;
  const email = account.email;
  const role = account.role;

  return {
    name,
    email,
    role,
    id: account.id,
  };
}

Practical Example: Editing Aligned Data

Column selection shines when working with aligned data. Consider this list of configuration entries:

const config = {
  host:   "localhost",
  port:   "8080",
  user:   "admin",
  pass:   "secret",
  debug:  "true",
};

If you want to change all the string values to template literals, you can use column selection:

The result:

const config = {
  host:   `localhost`,
  port:   `8080`,
  user:   `admin`,
  pass:   `secret`,
  debug:  `true`,
};

Using Select All Occurrences

When you need to change every instance of a word in the entire file, Cmd + Shift + L is your fastest option. For example, given this Python code:

def calculate_total(items):
    total = 0
    for item in items:
        total += item.price
    return total

def print_total(items):
    total = calculate_total(items)
    print(f"Total: {total}")

If you place your cursor on total and press Cmd + Shift + L, every occurrence of total in the file will be selected. You can then type a new name, such as sum_value, and all instances update simultaneously.

Combining Multi-Cursor with Find and Replace

Zed's find and replace panel integrates with multi-cursor editing. After performing a search, you can select all matches and convert them into cursors for direct editing.

This is particularly powerful when combined with regular expressions. For example, to wrap all numbers in a file with a function call, you could search for the regex \d+ and then use Alt + Enter to place a cursor at each match.

// Before
const values = [10, 20, 30, 40];
const more   = [100, 200, 300];

// After wrapping each number with Number()
const values = [Number(10), Number(20), Number(30), Number(40)];
const more   = [Number(100), Number(200), Number(300)];

To achieve this, after selecting all matches with Alt + Enter, you can use the End key to move all cursors to the end of each number, type ), then jump back to the start of each number with Home or Cmd + Left, and type Number(.

Managing and Navigating Selections

Once you have multiple cursors, Zed provides tools to manage them efficiently.

Practical Example: Adding a Prefix to Multiple Lines

Imagine you have a list of imports and want to comment out several of them:

import fs from 'fs';
import path from 'path';
import os from 'os';
import http from 'http';
import url from 'url';

To comment out the middle three lines:

import fs from 'fs';
// import path from 'path';
// import os from 'os';
// import http from 'http';
import url from 'url';

Best Practices for Multi-Cursor Editing

Start Small and Build Up

When learning multi-cursor editing, begin with two or three cursors and gradually work up to more complex selections. This helps you understand how edits propagate and reduces the chance of accidentally modifying unintended locations.

Use Cmd + U to Undo Selections

If you accidentally select one too many occurrences with Cmd + D, do not reach for Escape and start over. Instead, press Cmd + U to undo just the last selection addition. This keeps your workflow smooth and preserves the selections you already built.

Leverage Skip When Selecting Occurrences

When using Cmd + D to select occurrences one by one, you may encounter a match you do not want to change. Use the skip command (Cmd + K, Cmd + U) to move past that occurrence without selecting it, then continue selecting with Cmd + D.

Combine with Snippets

Zed supports snippets, and they work with multi-cursor editing. You can place multiple cursors and then expand a snippet at each location. This is useful for generating repetitive boilerplate code such as test cases or interface definitions.

// Place a cursor on each empty line, then type a snippet trigger
test("should ", () => {
  
});

test("should ", () => {
  
});

test("should ", () => {
  
});

Know When to Use Find and Replace Instead

Multi-cursor editing is excellent for visual, contextual changes, but it is not always the right tool. For truly global replacements across many files, Zed's project-wide find and replace is more appropriate. Reserve multi-cursor editing for changes within a single file where you need fine-grained control over which occurrences to modify.

Save Before Complex Edits

Before performing a large multi-cursor edit, save your file or commit your current changes. If the edit goes wrong, you can quickly revert without losing work. Zed's undo history will also help, but having a clean save point provides peace of mind.

Practice Common Patterns

Certain multi-cursor patterns appear frequently in real-world editing. Practicing these will make you faster over time:

Advanced Techniques

Selection Stack

Zed maintains a selection stack that lets you push and pop selections. This is useful when you want to temporarily work on a different part of the document without losing your current multi-cursor selection. You can push your current selection, make edits elsewhere, and then pop back to your previous selection state.

Multi-Cursor with Language-Aware Features

Because Zed's multi-cursor system is integrated with its language servers, features like autocomplete and code actions work at each cursor independently. This means you can type a partial identifier at multiple cursors and accept autocomplete suggestions at each location, potentially with different completions.

// Cursors placed before each property name
const user = {
  na: "",    // autocomplete suggests "name"
  em: "",    // autocomplete suggests "email"
  ag: "",    // autocomplete suggests "age"
};

Transforming Data with Multi-Cursor and Regex

One of the most powerful workflows combines regex search with multi-cursor selection. For example, converting a list of key-value pairs from one format to another:

// Original format
name: John
email: john@example.com
role: admin
active: true

Using a regex search for (\w+): (.+) with capture groups, you can select all matches and then use multi-cursor editing to reformat them into JSON syntax:

{
  "name": "John",
  "email": "john@example.com",
  "role": "admin",
  "active": "true"
}

The key insight is that after selecting all matches with Alt + Enter, you can navigate each cursor independently within its match to insert quotes, commas, and braces as needed.

Conclusion

Multi-cursor editing in Zed is a transformative feature that turns tedious, repetitive text manipulation into a fast and intuitive process. By mastering the core commands for adding cursors, selecting occurrences, and managing selections, you can dramatically reduce the time spent on refactoring and formatting tasks. The key to proficiency is practice: start with simple two-cursor edits, gradually incorporate column selection and regex integration, and soon multi-cursor editing will become a natural extension of your thinking. Combined with Zed's speed and language-aware features, it makes the editor a powerful tool for developers who value efficiency and precision in their daily workflow.

— Ad —

Google AdSense will appear here after approval

← Back to all articles