Add wezel scenario for an incremental editor build (#62016)

# Objective

This PR codifies one of the scenarios I've used to measure build health
of a codebase via [Wezel](https://wezel.build), a tool I've built for
that purpose.
## Solution

`wezel exp run incremental-editor`

## Testing

- Did you test these changes? If so, how?
- Are there any parts that need more testing?
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?

## Self-Review Checklist:

- [ ] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable

## Showcase

> This section is optional. If this PR does not include a visual change
or does not add a new user-facing feature, you can delete this section.

- Help others understand the result of this PR by showcasing your
awesome work!
- If this PR includes a visual change, consider adding a screenshot,
GIF, or video
- A before/after comparison is very useful for changes to existing
features!

While a showcase should aim to be brief and digestible, you can use a
toggleable section to save space on longer showcases:

<details>
  <summary>Click to view showcase</summary>

My super cool demos here

</details>

---

Release Notes:

- N/A or Added/Fixed/Improved ...
This commit is contained in:
Piotr Osiewicz authored and GitHub committed 2026-08-02 18:40:37 +00:00
1 parent 66ed3027b8
commit 538a4a267b
6 files changed
+287

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
# Wezel project-local state. Add patterns here as needed.
events/
*.local.toml
+13
View File
@@ -0,0 +1,13 @@
project_id = "85f406f4-69f1-4f41-b8e2-45550cd925d7"
name = "zed"
[tools]
targets = [
"aarch64-apple-darwin",
"x86_64-apple-darwin",
"aarch64-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
]
[tools.foragers.cargo]
github = "wezel-build/forager_cargo"
@@ -0,0 +1,12 @@
diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs
index 31ddc4b5c4..cd8e8e77e2 100644
--- a/crates/editor/src/editor.rs
+++ b/crates/editor/src/editor.rs
@@ -11,6 +11,7 @@
//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
//!
//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
+//!
pub mod actions;
pub mod blink_manager;
mod bracket_colorization;
@@ -0,0 +1,23 @@
#:schema ../../schema.json
description = "Measures rebuild time after a trivial edit to the editor crate"
# `zed` rather than `workspace`: it pulls in the whole editor -> ... -> binary
# chain that a developer actually waits on, without also building collab, the
# benchmarks and the other workspace members that no editor edit can affect.
# Prime the build cache off a clean build, so the measured step below pays only
# for editor and its dependents.
[step.cargo.prime-cache]
command = "build"
build_target = ["zed"]
# The patch only appends an empty `//!` line to the crate-root doc comment, so
# nothing about editor's public surface changes. What's left is the floor cost
# of touching the crate at all: rustc's incremental reuse for editor itself,
# plus the relink of every crate downstream of it.
[step.cargo.editor-doc-comment]
apply-diff = true
command = "build"
build_target = ["zed"]
summary.incremental-editor-build = { outcome = "time_ms", aggregation = "min", samples = 5 }
+226
View File
@@ -0,0 +1,226 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"Aggregation": {
"description": "How to aggregate measurement values into a conclusion scalar.",
"enum": [
"sum",
"mean",
"median",
"max",
"min"
],
"type": "string"
},
"DiffField": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "string"
}
],
"description": "Either a boolean (uses `<step.name>.patch`) or an explicit patch filename."
},
"EmbeddedSummaryToml": {
"description": "Summary definition embedded under a step. The summary's `name` and `step` fields are recovered from the map keys (`step.<step>.summary.<name>`).",
"properties": {
"aggregation": {
"anyOf": [
{
"$ref": "#/definitions/Aggregation"
},
{
"type": "null"
}
],
"default": null,
"description": "How to combine multiple matching values. Omit when the filter is expected to select a single value."
},
"bisect": {
"default": true,
"description": "Trigger bisection when this summary regresses.",
"type": "boolean"
},
"filter": {
"additionalProperties": {
"type": "string"
},
"default": {},
"description": "Tag key=value filters applied before aggregation.",
"type": "object"
},
"outcome": {
"description": "Outcome name (as emitted by the forager) to aggregate over.",
"type": "string"
},
"samples": {
"default": 1,
"description": "Number of forager invocations of the step to take. Lint requires all summaries on the same step to agree. Default 1.",
"format": "uint",
"minimum": 0.0,
"type": "integer"
}
},
"required": [
"outcome"
],
"type": "object"
},
"Step_cargo": {
"additionalProperties": false,
"description": "Body of a `[step.<tool>.<step_name>]` table. The tool name is recovered from the outer key, not a field; flatten-collected `rest` is forwarded to the forager plugin via `FORAGER_INPUTS` as JSON.",
"properties": {
"all_targets": {
"default": false,
"description": "Build every target (lib, bins, tests, benches, examples) via `--all-targets`.",
"type": "boolean"
},
"apply-diff": {
"anyOf": [
{
"$ref": "#/definitions/DiffField"
},
{
"type": "null"
}
],
"description": "Apply a patch before running this step. `true` uses `<step name>.patch`; a string overrides the filename."
},
"benches": {
"anyOf": [
{
"$ref": "#/definitions/TargetSpecifier"
},
{
"type": "null"
}
],
"description": "Benchmarks to build, as `--benches` (all) or `--bench <name>` per name. Omit to build none."
},
"bins": {
"anyOf": [
{
"$ref": "#/definitions/TargetSpecifier"
},
{
"type": "null"
}
],
"description": "Binaries to build, as `--bins` (all) or `--bin <name>` per name. Omit to build none."
},
"build_target": {
"allOf": [
{
"$ref": "#/definitions/PackageSpecifier"
}
],
"description": "Build target — either a list of package names or the literal string \"workspace\"."
},
"command": {
"allOf": [
{
"$ref": "#/definitions/Command"
}
],
"description": "Cargo subcommand to invoke (`build`, `bench`, or `test`)."
},
"description": {
"type": [
"string",
"null"
]
},
"examples": {
"anyOf": [
{
"$ref": "#/definitions/TargetSpecifier"
},
{
"type": "null"
}
],
"description": "Examples to build, as `--examples` (all) or `--example <name>` per name. Omit to build none."
},
"lib": {
"default": false,
"description": "Build the library target via `--lib`.",
"type": "boolean"
},
"profile": {
"default": null,
"description": "Cargo profile to use, propagated as `--profile <value>`. Omit to use the default profile.",
"type": [
"string",
"null"
]
},
"summary": {
"additionalProperties": {
"allOf": [
{
"$ref": "#/definitions/EmbeddedSummaryToml"
},
{
"properties": {
"outcome": {
"description": "**`time_ms`** — cargo's own reported build duration (the `Finished … in <t>` line), in milliseconds. Excludes process startup and dependency resolution.",
"type": "string"
}
}
}
]
},
"description": "Summaries emitted by this step, keyed by summary name.",
"type": "object"
},
"tests": {
"anyOf": [
{
"$ref": "#/definitions/TargetSpecifier"
},
{
"type": "null"
}
],
"description": "Test targets to build, as `--tests` (all) or `--test <name>` per name. Omit to build none."
}
},
"required": [
"build_target",
"command"
],
"type": "object"
}
},
"description": "Top-level shape of `.wezel/experiments/<name>/experiment.toml`.\n\nSteps live under `[step.<tool>.<step_name>]`. The outer map is keyed by tool name and the inner by step name; bodies are wrapped in `toml::Spanned` so the parser can recover file-line order across reopened tables.",
"properties": {
"description": {
"description": "Human-readable description of what the experiment measures.",
"type": [
"string",
"null"
]
},
"step": {
"additionalProperties": false,
"description": "`[step.<tool>.<step_name>]`. Two-level map; step names must be unique across tools (enforced in [`parse_experiment`]).",
"properties": {
"cargo": {
"additionalProperties": {
"$ref": "#/definitions/Step_cargo"
},
"description": "Runs `cargo <command>` and records the build time cargo reports",
"type": "object"
}
},
"type": "object"
}
},
"required": [
"step"
],
"title": "Wezel experiment.toml",
"type": "object"
}
+10
View File
@@ -0,0 +1,10 @@
version = 1
[tools.foragers.cargo]
github = "wezel-build/forager_cargo"
tag = "nightly-2026-07-17-dd1c13f"
[tools.foragers.cargo.assets]
aarch64-unknown-linux-gnu = "sha256:4162756b5268d29046242a1f29d41649e07ef024c72a690914bff61af82dcee1"
x86_64-apple-darwin = "sha256:263224ed47256fabd71a02e638fccd768cda4ff7023f34cc35bd520edcee0162"
x86_64-unknown-linux-gnu = "sha256:18092f74eabef4e0774d14ac3ca967505b6d5ccf6fd2a1f1ddef79d8317b0722"