Closes https://github.com/zed-industries/zed/issues/64118https://github.com/user-attachments/assets/f2152411-6011-4d87-8c8e-d83bed0afbbc
`ty` returns completion text without a `textEdit` or a completion-list
default edit range:
```json
{"label":"value2=","insertText":"value2="}
```
The [LSP
specification](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionItem)
explicitly states:
> The `insertText` is subject to interpretation by the client side.
For the reported example, `ˇ` marks the cursor:
```py
test(value1, ˇvalue2)
```
Previously, Zed inferred only a range covering the existing `value2`.
Without an insert range, completion acceptance bypassed
`completions.lsp_insert_mode` and replaced that argument with `value2=`,
producing:
```py
test(value1, value2=)
```
The patch also infers an insert range, ending at the cursor rather than
the end of the word.
This lets the existing setting choose between inserting before `value2`
and replacing it.
When a prefix has already been typed, insertion replaces that prefix
while preserving the text after the cursor.
With the unchanged default, `"replace_suffix"`, Zed replaces text after
the cursor only when it is a suffix of the completion’s label.
Here, `value2` is not a suffix of `value2=`, so Zed inserts and
produces:
```py
test(value1, value2=value2)
```
The suffix and subsequence checks now use the raw LSP `label`, not
decorated menu text or `filterText`.
These checks select the edit range; `insertText` still supplies the
inserted text in this example.
Release Notes:
- Fixed insertion modes for completions without edit ranges
# Objective
Fixes#58821. Follow-up to #58880: keep the modifier-click hint accurate
when the tooltip switches from breakpoint to bookmark.
## Solution
Build the hint from the configured secondary gutter action instead of
the currently active action.
## Self-Review Checklist
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
https://github.com/user-attachments/assets/c514d30e-9747-40a1-b359-54bc10086366
---
Release Notes:
- Fixed the gutter tooltip's modifier-click hint after holding Command.
CodeLens text currently hardcodes `text.muted`, so changing its color
also changes unrelated muted UI text such as the sidebar.
This adds a dedicated `editor.code_lens.foreground` theme color. When
omitted, it falls back to `text.muted`, preserving the existing
appearance of themes while allowing CodeLens text to be customized
independently.
Release Notes:
- Added `editor.code_lens.foreground` for customizing CodeLens text
independently.
---------
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
Zed did not advertise document highlight dynamic registration support or
handle `textDocument/documentHighlight` registrations. Dynamically
registered providers therefore fell through to the unhandled-capability
path, while servers with a fallback had to advertise a static provider
for every attached document.
Advertise dynamic registration support and track document highlight
registrations and unregistrations alongside the other selector-aware
dynamic text document capabilities. Refresh editors whenever the
effective document highlight registration state changes, including
selector-only changes that leave the merged provider unchanged, so
runtime registrations take effect immediately and unregistrations clear
stale or in-flight highlights.
Add coverage for the client capability, registration lifecycle with
multiple selectors sharing identical provider options, and editor
refresh behavior when an applicable selector is added or removed.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- N/A
---------
Co-authored-by: GPT-5.6 Sol <noreply@openai.com>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Closes https://github.com/zed-industries/zed/discussions/51582
During testing, spotted that if I toggle off the hints with the modifier
keys, they are resurrected on scrolling — fixed that in a small commit
on top.
Release Notes:
- Supported commands in inlay hints
Resubmit of #59731, which got auto-closed when I accidentally deleted
its branch. It wasn't rejected, it had already been reviewed. This is
rebased onto latest `main`, and osiewicz's review feedback (using `_`
for the unused param in the trait default) is already in.
Follow-up to #58510. Profiling multi-cursor typing on current main
showed the per-keystroke `set_active_selections` broadcast does an
O(selections) multi-buffer anchor remap and runs even with zero
collaborators (about 0.9ms/call at 1k cursors, 8.4ms at 10k, fired ~3x
per edited iteration).
This skips the broadcast when the buffer has no audience, and
re-publishes on share so there's no regression:
- Add `CollaborationHub::should_broadcast_selections`, defaulting to
`true`. `Entity<Project>` overrides it to `Project::is_shared()`, which
is true for a host that shared the project and for a collab guest, and
stays correct before peer-join notifications have propagated locally
(unlike a live collaborator count). A purely local project has no
audience.
- Gate `set_active_selections` in `selections_did_change` on it.
Follow-mode is unaffected since it uses the separate
UpdateFollowers/UpdateView channel, and the focused user's own cursors
render from `editor.selections`, not `remote_selections`.
- When the project becomes (re)shared (`RemoteIdChanged(Some)`,
`Reshared`, `HostReshared`), the focused editor re-publishes its current
selections, so a peer joining after a share still sees the host's cursor
without waiting for the next selection change.
- Reuse the post-edit display snapshot in the `hard_wrap` branch instead
of taking a redundant fresh buffer snapshot.
Multi-cursor type+delete benchmark: about 5% faster at both 1k and 10k
cursors (615 to 583 ms at 10k, significant). All 773 editor tests pass
locally. Collab and channel-buffer integration tests need the test DB,
so they run on CI.
Discussion and profiling:
https://github.com/zed-industries/zed/issues/32051
Release Notes:
- Improved multi cursor editing performance
Crash repro:
```
A
1234567890
B
C
```
1. place cursors before `A`, `B`, and `C`
2. run `editor: rotate selections forward`
Caused by the current `Editor::rotate_selections` logic assuming that
the text between the end of one of the lines being rotated and the start
of the next one is just the newline:
```rs
let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
```
which fails when those lines aren't consecutive in the editor.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- Fixed crash in `editor: rotate selections forward` and `editor: rotate
selections backward` using cursors on nonconsecutive lines.
# Objective
Case conversion commands deleted the newline at the end of the
selection,
merging the selected line into the line below it.
To reproduce:
1. A buffer with two lines:
```
hello world
goodbye
```
2. Put the cursor on line 1 and run `editor: select line` — this selects
`hello world\n`, newline included.
3. Run `editor: convert to upper camel case`.
Before: `HelloWorldgoodbye`, one line. After: `HelloWorld` / `goodbye`.
## Testing
Added a regression test to `test_manipulate_text`.
Release Notes:
- Fixed the case conversion commands deleting the line break when the
selection
ended at the start of the next line.
# Objective
Add an optional smooth cursor movement animation to make cursor position
changes easier to follow, especially during larger jumps and
multi-cursor editing.
Related to #4991.
## Solution
- Add a new `cursor_animation.enabled` editor setting, disabled by
default.
- Animate local bar and block cursors using a damped spring while
preserving momentum during rapid cursor movement.
- Support multiple local cursors independently.
- Continue using the cursor color provided by the active theme.
- Snap immediately when scrolling, resizing, or other viewport changes
would make interpolation misleading.
- Respect the `reduce_motion` setting.
- Request animation frames only while an enabled cursor animation is
active.
Enabling the feature causes additional editor redraws while the cursor
is moving, so it is opt-in and the performance cost is mentioned in the
setting documentation.
### Attribution
The cursor spring physics and four-corner deformation algorithm are
adapted from
[vscode-neovide-cursor](https://github.com/LengineerC/vscode-neovide-cursor),
which is available under the MIT License and inspired by Neovide.
The implementation adapts the algorithm to Zed's editor and GPUI
architecture, including viewport handling, selection state
reconciliation, multi-cursor support, theme integration, and
reduced-motion behavior. The attribution and license information are
also retained in the source file.
## Testing
Automated checks run on Windows:
- `cargo fmt --all --check`
- `cargo test -p editor cursor_animation --lib`
- 15 cursor animation tests passed.
The tests cover:
- Spring convergence.
- Short and long cursor movements.
- Mid-animation retargeting and momentum preservation.
- Multiple independent cursors.
- Selection replacement and state cleanup.
- Viewport and scroll changes.
- Invalid or unusually large timing values.
- Supported cursor shapes.
To test manually:
1. Add the following to the settings file:
```json
"cursor_animation": {
"enabled": true
}
```
2. Move the cursor using typing, arrow keys, mouse clicks, and
multi-cursor actions.
3. Toggle the setting off and confirm that cursor rendering immediately
returns to its normal behavior.
Manual testing was performed on Windows and Linux using a release build
from this exact PR branch.
Verified that:
- Cursor animation is disabled by default.
- Enabling `cursor_animation.enabled` is hot-reloaded without restarting
Zed.
- Disabling the setting immediately restores the original cursor
behavior.
- Cursor movement remains responsive during typing, keyboard navigation,
and mouse navigation.
This exact PR branch has not yet been manually tested on macOS.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
https://github.com/user-attachments/assets/17450529-491e-4982-b539-c46e3d5df467
---
Release Notes:
- Added an optional cursor movement animation setting.
---------
Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
# Objective
- Fixes#62923.
- When `gutter.git_gutter_width` is set to a small `Custom` value (e.g.
`{"custom": 6.0}`), the deleted-line marker becomes disproportionately
small. It is nearly invisible in the reporter's screenshots, while
added/modified markers scale acceptably.
## Solution
- The deleted marker's `Default` arm uses a `0.35 * line_height` base;
the strip's `Default` arm uses `0.275 * line_height`. That 27% larger
base is what keeps the pill-shaped deleted marker visible next to the
rectangular added/modified strips.
- The `Custom(N)` arm previously used `N` for both branches, dropping
the boost. This PR routes the deleted-empty case through a new
`deleted_marker_base_width(setting, line_height)` helper that applies a
single `DELETED_MARKER_WIDTH_RATIO = 0.35 / 0.275` constant to both
arms.
- Default-mode pixels are byte-identical because `floor(0.275 * lh *
0.35/0.275)` reduces to `floor(0.35 * lh)`. Custom-mode gains the same
1.273× multiplier the default has always had.
## Testing
- Added a pure `#[test] fn test_deleted_marker_base_width` covering
three invariants:
- `Default` at `line_height = 22.0` returns `7px`, identical to the
previous default arm.
- `Custom(6.0)` at `line_height = 22.0` returns a width greater than 6.0
(visibility preserved).
- `Custom(0.0)` returns `0.0`, so the width-0 render path is unchanged.
- Verified locally on Windows: `cargo fmt --all -- --check`, `cargo
check -p editor`, and `cargo clippy -p editor --all-targets -- -D
warnings` all exit 0.
- I have not visually verified the rendered marker on macOS or Linux. A
reviewer with the reporter's setup (`git_gutter_width: {"custom": 6.0}`
on macOS) can confirm the pill stays visible.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- Fixed the deleted git-gutter marker becoming nearly invisible when
`git_gutter_width` is set to a small custom pixel value.
Zed previously discarded the documentSelector from dynamically
registered textDocument capabilities and treated those capabilities as
applicable to every buffer attached to the server. This could route
requests for documents outside a registration selector.
Track dynamic textDocument registrations by method and registration ID,
and use their selectors when routing local requests, checking
capabilities, and deriving completion triggers. Static capabilities
continue to apply to every attached buffer. Language and URI scheme
matching are supported, while unsupported pattern matching remains
fail-open.
Keep document color, symbol, link, code lens, and folding range caches
aligned with the selector-aware server set so incapable or non-matching
servers do not leave caches perpetually incomplete.
Require an advertised diagnostic provider before sending pull diagnostic
requests, and add integration coverage for selector-aware dynamic
completion registration and trigger updates.
---
Release Notes:
- Improved language server request routing to respect dynamically
registered document selectors.
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
# Objective
Diagnostics published by a language server survive the buffer being
detached from that server, so a file keeps showing errors from a server
that is no longer reading it.
To reproduce:
1. Install the [GitHub Actions
extension](https://zed.dev/extensions/github-actions).
2. Open a composite action definition,
`.github/actions/<name>/action.yml`.
3. Select the GitHub Actions language for it in the language selector.
That server validates the file as a workflow, so it reports `on` and
`jobs` as missing and `inputs`, `outputs` and `runs` as unexpected.
4. Select YAML again, since GitHub Actions was not what you wanted here.
5. The errors are still there. `editor: restart language servers` does
not clear them either. They go away only once the buffer is dropped, in
practice by switching to another project and back.
Two things keep them alive:
- `LocalLspStore::unregister_buffer_from_language_servers` drops the
snapshot bookkeeping and sends `didClose`, but never clears what that
server already published. `LspStore::set_language_for_buffer` calls it,
so a language change detaches the buffer while leaving the old verdict
on it.
- Restarting does not reach the server either.
`stop_local_language_servers_for_buffers` collects servers through
`language_server_ids_for_buffer`, evaluated against the language the
buffer has *now*. The old server no longer matches, so it is never
stopped, and it is typically still running legitimately for other files
in the project. Only `stop_local_language_server` clears diagnostics,
and it is never reached for that server.
## Solution
The first commit cleared the detached server's diagnostics inside
`unregister_buffer_from_language_servers`, on `didClose`. Review pointed
out that publishes are applied by path regardless of registration, so a
running server can legitimately describe a file that is no longer open
in it, and that this clearing also left `diagnostic_summaries` and the
worktree's per-path diagnostics stale.
The second commit reworks this. Detaching a buffer now only drops the
buffer's entry in `buffers_opened_in_servers` and the path's
pull-diagnostics result ids for the servers it left, two pieces of
per-server state that previously leaked. After the buffer is registered
with the servers of its new language, the server tree is rebuilt through
`refresh_server_tree`, the same pruning that runs on settings changes:
every server no registered buffer maps to any more is stopped through
`stop_local_language_server`, whose path already clears buffer
diagnostic sets, `diagnostic_summaries` and worktree diagnostics. A
detached server that other buffers still map to keeps running and keeps
everything it published. An earlier revision judged orphanhood by
`buffers_opened_in_servers`, which is only filled in once a server runs,
so it stopped servers that were still starting;
`test_context_completion_provider_mentions` caught that.
## Testing
Added `test_selecting_a_language_clears_the_old_servers_diagnostics`: a
Rust buffer gets a diagnostic from a fake server, the buffer is switched
to JavaScript, and afterwards both the buffer's diagnostics and the
project-level `diagnostic_summary` must be empty. It fails on `main`,
where the message survives the switch:
```text
< ["unused constant"]
> []
```
The test passes with the rework and fails without it. The `project` test
suite, `script/clippy` and style checks ran green on the reworked change
in CI. Tested on Linux; the change is platform independent.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
The buffer is back on YAML, as the status bar shows, while the workflow
schema's complaints from the GitHub Actions server are still on screen:
`on` and `jobs` reported missing, and `inputs`, `outputs` and `runs`
reported as unexpected values.
<img width="2514" height="2008" alt="Screenshot From 2026-08-30
21-52-12"
src="https://github.com/user-attachments/assets/040898a6-cc61-41b6-88c6-f346666e8e13"
/>
---
Release Notes:
- Fixed diagnostics from the previous language server staying on a file
after changing its language.
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Closes#63301
The completion label row set `min_w_0()`, which removes a flex item's
automatic minimum size and lets it shrink below its own content width.
The label inside is `flex_none` and never shrinks, so for long
completion labels the text overflowed the row and, with GPUI's default
`Overflow::Visible`, painted directly on top of the right-aligned
documentation text.
Removing `min_w_0()` restores the row's automatic minimum so it no
longer shrinks past the label. The documentation label already has
`flex_shrink(1.0)`, `min_w_0()` and `truncate()`, so it is now the only
element that gives way, shrinking and ellipsizing as intended.
The resulting layout is `[full label] [documentation, ellipsized when it
overflows]`.
### Before
<img width="687" height="426" alt="Screenshot From 2026-09-02 00-48-03"
src="https://github.com/user-attachments/assets/b734b632-fd05-4afc-8b02-b231922646ef"
/>
### After
<img width="853" height="526" alt="Screenshot From 2026-09-02 02-23-41"
src="https://github.com/user-attachments/assets/60281115-5a8d-4f4e-bfe0-c037ff7244e3"
/>
Release Notes:
- Fixed completion menu labels overlapping the documentation text for
long completion items
# Objective
Keep Git-specific diff-base knowledge in `GitStore`, where Git
operations are defined.
Related to FR-135.
## Solution
Give each `BufferDiff` its supported hunk operations. Keep editor hooks
limited to rendering custom controls.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- N/A
## Summary
- Limit row-highlight expansion during editor rendering to ranges that
intersect the visible viewport.
- Use the stable multibuffer anchor ordering established by #62636 to
binary-prune every highlight group, including ranges with diff-base
anchors.
- Preserve exact-boundary highlights for custom blocks and add
regression coverage comparing viewport results with the full-editor
result.
This is stacked on #63394 so the benchmark fixture and batched conflict
anchor conversion are available independently.
## Performance
The severe synthetic workload contains 128 conflicted files, 256
conflict regions per file, and 163,840 accumulated row-highlight ranges.
In the initial paired measurement, viewport filtering reduced:
- project-diff refresh from 67.6–87.8 seconds to 13.47–13.53 seconds;
- cumulative row-highlight expansion from 53–74 seconds to about 7.7
milliseconds;
- the longest individual expansion from 817–875 milliseconds to
0.063–0.071 milliseconds;
- examined highlight ranges from 10.7–15.6 million to about 2,500.
After isolating this commit from the separate block-insertion experiment
and hardening the anchor-boundary behavior, two severe-workload runs
completed in 17.75 and 20.51 seconds. Those isolated runs are not a
direct A/B comparison with the initial numbers because they
intentionally omit the block-insertion fast path.
## Validation
- `cargo test -p editor test_highlighted_display_rows_in_range`
- `./script/clippy -p editor`
- `git diff --check`
- Two independent code reviews focused on viewport boundaries and anchor
ordering
Release Notes:
- Improved project diff performance for repositories with many merge
conflicts.
Closes https://github.com/zed-industries/zed/issues/59689
Symbolicating the reporter's profile (21s of typing, Windows) showed
`Window::draw` taking 63% of the main thread at ~62 redraws/s (p95 draw
= 40ms), and 30.9% of the *entire* main thread inside
`EditorconfigStore::properties()`:
every `LanguageSettings` lookup — several per frame via
`DisplayMap::tab_size`, `MultiBuffer::language_settings`, indent guides,
and `LspStore::supports_range_formatting` — re-ran the full editorconfig
resolution (ancestor walk plus `ec4rs::Section::apply_to` over every key
of every section) and then cloned the whole `LanguageSettings` struct.
Real-world `.editorconfig` files carry hundreds of irrelevant keys
(`dotnet_*`, `ij_*`, ...), so the per-call map assembly dominated:
`RtlAllocateHeap` 7.3%, `memcmp` 7.0%, `memcpy` 6.6%,
`Properties::find_idx` 5.9% self time.
## Commit 1: resolve only the editorconfig properties Zed reads
- `EditorconfigStore::properties()` now applies only the 7 keys Zed
consumes (`indent_style`, `indent_size`, `tab_width`, `end_of_line`,
`max_line_length`, `insert_final_newline`, `trim_trailing_whitespace`)
instead of materializing every key of every matching section.
- Worktrees with no editorconfig at all now return `None` early instead
of allocating an empty `Properties` and forcing a `LanguageSettings`
clone on every lookup.
- Adds an `editor_render_with_editorconfig` benchmark: maximized window,
file-backed buffer at `src/app/components/editor_pane.ts`, a root
`.editorconfig` shaped after [the second
report](https://github.com/zed-industries/zed/issues/59689#issuecomment-5475124891)
(no `root = true`, a `[*]` section with ~3200 keys, 25 sections with
large `{...}` alternation lists) plus a 4-level nested chain, and a
typing workload (insert/delete + cursor moves).
```
main (f034409b6a): time: [37.905 ms 38.005 ms 38.107 ms]
time: [38.069 ms 38.157 ms 38.248 ms]
this commit: time: [2.8547 ms 2.8618 ms 2.8702 ms]
time: [2.8372 ms 2.8435 ms 2.8510 ms]
```
The candidate is ~13x faster.
GPUI frame report over the same workload: window draw p50 12.71 ms →
0.76 ms, p99 23.38 ms → 1.22 ms; frame budget overruns 556 → 0.
## Commit 2: cache resolved `LanguageSettings` per buffer
- `Buffer` and `BufferSnapshot` now hold `resolved_settings:
Arc<LanguageSettings>`, recomputed by a `SettingsStore` global observer.
- Global methods for retrieving the settings are still there, but buffer
only uses them for multi buffer's `language_settings_at` with an
injected language different from the buffer's primary; cold scopes such
as extension API, LSP workspace configuration, server startup still use
the global resolution
Same benchmark, same method, on top of commit 1 (alternated runs, quiet
machine):
```
commit 1: time: [2.8547 ms 2.8618 ms 2.8702 ms]
time: [2.8372 ms 2.8435 ms 2.8510 ms]
this commit: time: [1.6256 ms 1.6325 ms 1.6403 ms]
change: [-42.685% -42.270% -41.854%] (p = 0.00 < 0.05)
time: [1.6221 ms 1.6284 ms 1.6352 ms]
```
Window draw p50 0.76 ms → 0.47 ms, p99 1.22 ms → 0.69 ms, max 1.02 ms;
zero frame-budget overruns on both sides.
Combined, the benchmark's per-keystroke cost drops ~23x vs `main`
(37.9–38.2 ms → 1.62–1.64 ms).
Release Notes:
- Improved typing and rendering performance in projects that use
`.editorconfig` files.
Follow-up to https://github.com/zed-industries/zed/pull/63232
Cuts closure monomorphization in settings and editor: settings file
updates now share one boxed write-pipeline instantiation instead of
inlining the `SettingsContent` clone, both `serde_json::to_value` calls,
and the JSON diff at every call site; `Editor::register_action` and the
settings enum dropdown get the same treatment. Behavior and public
signatures are unchanged; thin generic shims remain.
Symbol table of the release binary:
Before: `update_settings_file_inner` 229 instantiations, inlined
`serde_json` `SerializeMap` machinery 6547 copies
After: 3 instantiations, 673 copies (-89.7%); `render_dropdown` is no
longer instantiated at all
With sccache disabled, `cargo clean` and `cargo build --release -p zed`:
Before: zed binary 420677880 bytes
After: zed binary 396999464 bytes (-5.6%, -23.7MB)
Release Notes:
- N/A
Previously, we'd panic when constructing multibuffer excerpts in
response to "find all references" if a language server returned a
reversed range. This PR makes it so we normalize those ranges using the
existing `range_from_lsp` helper before passing them to
`set_excerpts_for_path`. It also replaces several other places where we
were calling `point_from_lsp` on each endpoint of a range separately
with `range_from_lsp`.
Closes ZED-79W
Co-authored-by: Mikayla <mikayla@zed.dev>
Release Notes:
- Fixed a crash with some languages servers when handling
`editor::FindAllReferences`.
Digging into ZED-7G6 ("buffer snapshot not found for excerpt boundary",
171 events) revealed some bugs in the implementation of multibuffer
anchors that landed in #52364. Specifically:
- In the presence of multibuffer excerpt changes, it was possible for
two anchors to satisfy `a1 < a2` but `a1.to_offset() > a2.to_offset()`.
This happened in particular when a `PathKey` was reused for two
different buffers at different times, and could cause crashes in code
that sorted anchors by `cmp` and expected the resulting offsets to be
sorted.
- Changes of diff base and normal buffer edits could cause two anchors
to sort `a1 < a2` against one snapshot and `a2 < a1` against a later
snapshot. This could also cause crashes in downstream code that
(reasonably) expected anchors to have a stable ordering.
This PR adds a property test asserting that multibuffer anchor ordering
is stable over time and consistent at every moment in time with the
ordering obtained from resolving the anchors, and fixes the bugs in
anchor resolution and comparison that are revealed by that test. It also
includes tests downstream for specific cases that previously crashed.
Closes ZED-7G6
Release Notes:
- Fixed a crash that could occur when inlay hints were present while a
multibuffer replaced the contents of a file, such as a diff view whose
base changed.
- Fixed crashes that could occur when a file's contents were replaced in
a multibuffer (such as a diff view refreshing) while highlights, inlay
hints, or other positions still referenced the old contents.
---------
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
# Objective
Closes#4868.
Reintroduce automatic language detection for user-created untitled
buffers without allowing it to override language choices made by users
or owning surfaces.
More details:
+ https://github.com/zed-industries/zed/pull/61201
+ https://github.com/zed-industries/zed/pull/61351
## Solution
VS Code distinguishes between inferred and explicitly selected
languages, and only continues automatic detection in the former state.
This change introduces a buffer-local opt-in flag with the same purpose.
It defaults to disabled and is enabled only for user-created untitled
buffers and restored untitled buffers that did not persist a language.
Choosing a language through the language picker disables detection,
while automatically detected languages remain eligible for later
redetection. Buffers whose language is assigned by their owning surface,
such as Channel Notes, never opt in.
Rather than adding persisted state or changing the database schema,
restoration reuses the existing optional serialized language. An
opted-in buffer that remains Plain Text is serialized without a language
and resumes detection after restoration. Once automatic detection has
selected a language, that language is serialized normally and
restoration leaves detection disabled, effectively treating it as an
explicit selection. This also matches VS Code's effective default after
restoration.
Candidate selection adopts VS Code's confidence-group filtering. Results
below the minimum confidence are discarded, and candidate groups are
accepted only after a clear confidence gap. The detector then selects
the first available Zed language without eagerly loading every
candidate. I then added a separate switching rule: Zed keeps the current
language unless another candidate has a clear confidence advantage,
reducing language changes as model scores fluctuate during editing.
Model inference runs off-thread on a bounded sample, and stale results
are discarded.
I also evaluated penalizing YAML and using stricter global switching
thresholds, but neither reliably resolves the ambiguity between Markdown
and YAML. In the reproduction from #61351, Betlang assigns YAML more
than 80% confidence during editing and peaks around 90%. This is
reasonable from the content alone: `#` denotes a YAML comment, while `-`
denotes a sequence item. Adding ordinary prose or a fenced code block
shifts the model strongly toward Markdown. A fixed penalty would overfit
this example and risk suppressing legitimate YAML detection. Since
known-language buffers do not opt in and manual language selection takes
precedence, I consider this level of ambiguity acceptable and prefer not
to introduce language-specific score tuning.
Model inference itself is fast. As noted in #61201:
> In release builds on Linux with an Intel Core i5-13600KF, the
`betlang::detect` call alone typically completes within 3 ms when
processing the maximum sampled input.
The main concern is the work surrounding inference. Without debouncing,
rapid typing creates a snapshot and launches a background detection task
on every keystroke, while the detected language may change before the
user has finished typing. This change therefore adds a 200 ms debounce
delay, allowing detection to run and update the language only after the
user pauses.
## Testing
Automated coverage verifies that short inputs remain Plain Text,
sufficient Rust content is detected as Rust, replacing it with Go
content triggers redetection, and manually selecting Plain Text prevents
subsequent automatic changes. Restoration coverage verifies that a
stored language keeps detection disabled, while an empty language-less
untitled buffer resumes detection.
Beyond the automated tests, I manually tested automatic language
detection while editing untitled buffers.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
https://github.com/user-attachments/assets/103fc731-e12e-48d6-ae89-03978f1c9d74
---
Release Notes:
- Added automatic language detection for untitled buffers.
---------
Co-authored-by: Max Stevens <maxstevens2708@gmail.com>
Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
# Objective
Fixes#12572
## Solution
- Adds an opt-in `reveal_if_open` setting which enables searching and
revealing an already open buffer
- Ensures this only happens if there is no pane target for the open
intent
## Testing
- Built for and tested on my Mac
- Tests added covering the scope of the feature
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
https://github.com/user-attachments/assets/cdcc78cd-85fd-4b56-b562-feba375ecd03
---
Release Notes:
- Added configuration to reveal buffers already open in a different pane
instead of the active pane, via `reveal_if_open`
---------
Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
[## Context
Fixes a bug where the Bookmarks tab, opened via `editor: view
bookmarks`, showed a stale snapshot and had to be reopened to display
bookmarks added or removed while it was open.
Closes#56268
`view_bookmarks` built a one-time multibuffer and never subscribed to
`BookmarkStore`. The store also calls `cx.notify()` while resolving
serialized bookmarks into anchors, even though that bookkeeping does not
represent a user-visible bookmark change. Observing all notifications
would therefore feed resolution notifications back into the refresh
mechanism and cause redundant cancellation and requeue work. The store
now emits a dedicated `BookmarkStoreEvent::BookmarksChanged` from
bookmark mutation paths, while `resolve_all` deliberately does not emit
it.
Refresh state lives on a `BookmarksView` entity that holds the tab's
multibuffer. Split editors already share that multibuffer, so they share
the view as well. Each store event drives one reconciliation regardless
of how many split editors display it. The view remains alive as long as
any split retains it, so closing the original tab does not stop the
remaining split from refreshing.
Each refresh reconciles excerpts per path instead of rebuilding the
multibuffer: `set_excerpts_for_path` updates files that still contain
bookmarks, while `remove_excerpts` removes files whose final bookmark
was deleted. This follows the per-path reconciliation pattern used by
project diff views.
`view_bookmarks` creates the tab synchronously and populates it
asynchronously, following the existing patterns in
`ProjectDiagnosticsEditor::deploy` and
`ProjectSearchView::existing_or_new_search`. Repeated invocations focus
the existing Bookmarks tab instead of opening duplicates.
Video of the manual test:
[Screencast from 2026-05-11
02-03-38.webm](https://github.com/user-attachments/assets/8ac97245-09ff-4a79-9634-20cb8dfbb7eb)
## How to Review
**`crates/project/src/bookmark_store.rs`**
Adds `BookmarkStoreEvent::BookmarksChanged`, emitted from bookmark
mutation paths such as toggle, label edit, file rename or deletion,
clear, and deserialization, but not from anchor resolution. It also adds
`BookmarkStore::is_empty`.
**`crates/editor/src/bookmarks.rs`**
Adds `BookmarksView`, which holds the multibuffer, store subscription,
and in-flight refresh task. It reconciles excerpts and emits
`BookmarksViewEvent::Populated(ranges)` for per-editor highlights and
cursor placement. It also caches the latest populated ranges and replays
them when an editor attaches, allowing a split created after population
to display bookmark highlights immediately.
**`crates/editor/src/editor.rs`**
Adds the shared `bookmark_view`, a per-editor subscription to its
population events, and `bookmark_initial_selection_pending` for initial
cursor placement. `Editor::clone` attaches the split to the shared view
instead of creating another store subscription and refresh task.
**`crates/editor/src/editor_tests.rs`**
Adds five tests covering automatic addition and removal across multiple
files, removal of a file's path after its final bookmark is deleted,
initial cursor placement, a bookmark change racing initial population,
splitting while population is pending, cached highlights in a
late-attaching split, and continued refreshing after the original tab
releases its view handle.
## Self-Review Checklist
- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Fixed Bookmarks tab not updating when bookmarks are added or removed
while the tab is open](https://github.com/zed-industries/zed/pull/56363)
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
LSP 3.18 allows servers to send [`MarkupContent` diagnostic
messages](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#diagnostic),
guarded by the client capability
`textDocument.diagnostic.markupMessageSupport`.
- Advertise `markup_message_support` only while pull diagnostics are
enabled because `textDocument.diagnostic` is the pull-model capability.
LSP 3.18 currently has no equivalent capability for push diagnostics:
https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#diagnosticClientCapabilitieshttps://github.com/microsoft/language-server-protocol/issues/2246
- Handle `string | MarkupContent` messages in both push and pull
diagnostic paths: markdown-kind messages populate the existing
`Diagnostic::markdown` field (rendered in hover popovers and the
diagnostics panel), plaintext-kind markup remains plain text, and plain
string messages keep going through the adapter's
`diagnostic_message_to_markdown`.
- Preserve server-provided markup for code actions sent back to the
originating server, avoid forwarding markup diagnostics to other
servers, and render diagnostic metadata without altering the
server-provided markdown.
- Carry the markup kind over RPC via a new optional
`LspDiagnostic.markup_message_kind` proto field so remote/collab
projects round-trip `MarkupContent` messages.
Depends on the lsp-types change that turns `Diagnostic.message` into a
`DiagnosticMessage` enum (`string | MarkupContent`):
https://github.com/zed-industries/lsp-types/pull/15
Once merged, Cargo.toml can point to the upstream commit.
Note that Zed already rendered some plain-string diagnostics as Markdown
through language-specific adapter hooks, including `rust-analyzer`. This
adds protocol-level support for diagnostics explicitly sent as LSP 3.18
`MarkupContent`, while preserving the existing adapter fallbacks.
As a result, this does not introduce a new diagnostics rendering
pipeline.
Server-provided Markdown is routed through the existing
`Diagnostic::markdown` path, with small fixes to handle Markdown-only
updates and block content correctly.
## Showcase
Example from [JETLS.jl](github.com/aviatesk/JETLS.jl) (a Julia language
server):
> Before
<img width="924" height="160" alt="Screenshot 2026-07-15 at 16 05 40"
src="https://github.com/user-attachments/assets/b19fe9e3-50e3-44e4-9b4d-ac8bd438d3d6"
/>
> After
<img width="924" height="160" alt="Screenshot 2026-07-15 at 14 13 05"
src="https://github.com/user-attachments/assets/359c3382-118d-4fa6-aa91-6bd3661d3d28"
/>
---
Release Notes:
- Added support for rendering LSP 3.18 Markdown diagnostic messages from
language servers.
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
# Objective
Remove avoidable clones of loop-invariant values that pay a copy on
every loop iteration. These were found by running a prototype
`deep_clone_in_loop` dylint (modeled on the accidentally quadratic
project-search fix in #62658) across the workspace. None of these sites
are quadratic in practice — the loops are bounded — but each one does
strictly wasted work that a one-line change removes.
## Solution
- `collab/src/api/extensions.rs`: use `next_marker.take()` instead of
`next_marker.clone()` for the S3 pagination marker. The marker is either
overwritten via `clone_from` at the end of the iteration or the loop
breaks, so it is never read after the `take`.
- `project/src/manifest_tree/path_trie.rs`: build the trie key with
`Arc::from(path_so_far.as_rel_path())` instead of
`path_so_far.clone().into()`. The `From<RelPathBuf> for Arc<RelPath>`
impl copies the bytes into the `Arc` anyway, so the intermediate
`RelPathBuf` clone was a second, redundant copy.
- `context_server/src/client.rs`: in `notify`, split off the last
handler and move the `serde_json::Value` payload into it, cloning only
for the preceding handlers. Previously every handler received a clone
and the final one was always wasted.
- `editor/src/rewrap.rs`: use `std::mem::replace` to move the
comment-delimiter and rewrap-prefix accumulators into the pushed range
instead of cloning them and immediately reassigning.
## Testing
- `cargo check -p collab -p project -p context_server -p editor` —
clean.
- `cargo test -p editor rewrap` — 7/7 pass, including the
boundary-sensitive `test_rewrap*` editor tests.
- `cargo test -p context_server` — 97/97 pass.
- `cargo test -p project path_trie` — 2/2 pass.
- Re-ran the `deep_clone_in_loop` lint on the four crates: the
`extensions.rs`, `path_trie.rs`, and `rewrap.rs` hits are gone;
`client.rs` still (correctly) reports the remaining required per-handler
clone.
- Not tested platform-specifically; the changes are
platform-independent.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- N/A
This prepares for the keybinding hints PR.
To reproduce, press `ctrl-b` in a GPUI app with `ctrl-b h` and `ctrl-b
j` bindings, then call `window.blur()`. The live pending state clears,
but observers still report `ctrl-b`.
`Window::blur` now clears pending input and notifies observers after the
current effect cycle. I don't think we currently exercise this path in
Zed, and I was only able to reproduce it with an example GPUI app.
Release Notes:
- N/A
# Objective
- Add file-level hyperlink support for opening and copying hyperlinks
for Git remote source control to project panel and tabs
- Unify the language for Git remote hyperlinks across blame, project
panels, and tabs to be similar to GitLens' definitions (which are
commonly used in VS Code)
## Solution
- Updated the Git crate to expose relevant metadata to surface new
options within the editor
- Added new options for `Open File on Remote` and `Copy Remote File URL`
to project panel/file explorer and file tabs
- Altered the blame UI options to be consistent with new labels / more
clear
## Testing
- Ran `cargo run` to boot app and manually smoke test (see proof below)
- Added unit tests for this change
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
https://github.com/user-attachments/assets/d600ca4f-47e7-438c-90e1-f40124a606b4
---
Release Notes:
- Added options to open or copy whole-file permalinks from file tabs and
the Project Panel.
---------
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
## Objective
Fix incorrect indentation after multiline comments and when pasting
multiline code immediately after a comment.
Fixes#61668Fixes#55597
## Solution
- Calculate logical indentation from the opening line of block comments,
documentation comments, and multiline strings.
- Reuse the logical indentation for both newline handling and multiline
paste auto-indent.
- Preserve the relative indentation of pasted multiline content while
using the logical indentation of the surrounding code as its basis.
## Testing
- `cargo test -p editor --lib test_newline -- --nocapture`
- `cargo test -p editor --lib test_paste -- --nocapture`
- `cargo test -p language --lib test_autoindent -- --nocapture`
- `./script/clippy -p language`
- `./script/clippy -p editor`
- Regression coverage includes Go, TypeScript, and Python comment/string
indentation, plus Go multiline paste after a documentation comment.
- No platform-specific behavior is involved; the fix is implemented in
shared editor and language auto-indent logic.
The demonstration video is as follows:
https://github.com/user-attachments/assets/2a2ee494-d4ea-4b16-8644-f868b9f31272https://github.com/user-attachments/assets/9487f893-e584-448d-a1c7-a94c76c03f5b
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- Fixed incorrect indentation after multiline comments and multiline
paste.
Follow-up to https://github.com/zed-industries/zed/pull/60477Closes#25022
We have more places that need a similar synchronization before quitting
the app: restarts on update, reloading the workspace.
On top of it, two more findings:
* `on_app_will_quit` was redundant: the global `on_app_quit` hook
flushes a strict superset of the same tasks and runs before windows are
cleared, while the entity hook held only a weak handle and could never
flush the `Window`-dependent workspace state anyway.
* previously, shutdown was run as `cx.spawn`, yet main threads got
parked on app shutdown: now using `cx.background_spawn` instead
Release Notes:
- Improved data persistence during various app shutdown cases
---------
Co-authored-by: Kostia R <k-bx@k-bx.com>
Closes https://github.com/zed-industries/zed/issues/9318
Most of the diff is tests.
Notable behavior changes during this mode, compared to current mode:
* unsaved changes in multi buffer won't spawn any "save or not" pop-ups
during typing — submitting the query still does it, as before.
Unsaved files will stay so after being sorted out on typing: we cannot
save them by default as file-less buffers need a save modal; Zed should
already be able to persist and restore such changes on restart.
* gutter may jump during search, if new excerpts with large line numbers
appear during query input — yet it would not shrink back to avoid
excessive flickering and rewraps
Release Notes:
- Enabled project search on type by default (use `{ "search": {
"search_on_type": false } }` to restore the previous behavior)
# Objective
Get some speedups by using unstable sortts.
Supersedes #58761 after rebasing onto current `main`.
## Solution
replace `.sort()` by `.unstable_sort()`.
## Testing
All tests pass in affected crates:
```
cargo test -p edit_prediction_context -p editor -p git -p language -p language_tools -p migrator
```
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- N/A
Closes#61005
The bookmark store notified on every change, but nothing was listening.
Editors only repainted their bookmark icons because the toggle actions
happened to notify the editor directly - so workspace::ClearBookmarks,
which never touches an editor, left stale icons in the gutter until
something else caused a repaint.
Now editors observe the bookmark store, so any change repaints them.
This also fixes toggling a bookmark in one split not updating another
split showing the same file.
Release Notes:
- Fixed bookmarks not disappearing from the gutter immediately when
running `workspace::ClearBookmarks`.
# Objective
Fixes#58104.
When using the `fold_at_level` action (default keybind: Ctrl-K
Ctrl-(1-9) on Windows) on a function with its arguments split across
multiple lines (see the example in #58104), only the arguments would be
folded, while the function body remained expanded and only blocks at the
next level inside the function were folded.
To reproduce:
1. Open a `.rs` file (or any language with similar folding behavior).
2. Add a function with multiline arguments:
```rust
fn test(
a: i32,
) {
let b = a;
}
```
3. Run `fold_at_level` with level `1`.
4. Observe that the argument list is folded, but the function body
remains expanded.
## Solution
When iterating through foldable ranges, `fold_at_level` advanced the
search position to the line after the folded crease. This caused it to
skip any crease starting on the same line as the end of the previous
one. The fix keeps the search position on the last line of the folded
crease instead, allowing consecutive creases to be processed.
## Testing
Automated: Added 1 test covering chained foldable blocks, including
functions with multiline arguments and if/else blocks.
Manual: Verified that invoking `fold_at_level(1)` on a function with
multiline arguments folds both the argument list and the function body.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
**Before:**
<img width="211" height="107" alt="image"
src="https://github.com/user-attachments/assets/dbfbbdfa-faee-42f3-ac25-0581a796e124"
/>
**After:**
<img width="221" height="41" alt="image"
src="https://github.com/user-attachments/assets/6746b341-0587-48a4-908a-e743c974cae9"
/>
## Release Notes:
- Fixed: `fold_at_level` not folding function bodies when arguments span
multiple lines
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
# Objective
Read-only marked files in zed could still be affected by format on save
feature. This PR fixes that.
FIXES#62899
## Solution
These changes add an early return on Editor's `Item::save`
implementation so neither formatting nor the write to disk occurs.
## Testing
I've tested by reproducing the issue in the original ticket.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- Fixed read-only files being formatted and saved when `format_on_save`
is enabled
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
# Objective
- Prefer using `Duration` instead of integers when dealing with spans of
time. This prevents confusing different units of time and comparing
arbitrary integers with durations.
- Remove `_ms`/`_secs` suffixes from variables which are `Duration`,
since their unit is inside of the type.
- Initialize large integer constants using `Duration`, which has more
descriptive constructors, while maintaining the resulting integer type.
Release Notes:
- N/A or Added/Fixed/Improved ...
# Objective
Add configurable inline completion debounce timeout
Fixes/implements #23159
## Solution
I initially wanted to make a global setting for this, but it would
conflict with hardcoded debounces in codestral (150ms) and copilot
(75ms) which I assume are there for a reason.
So I ended up using the same mechanism used for the hardcoded debounce
in Codestral (`DEBOUNCE_TIMEOUT`) and Copilot
(`COPILOT_DEBOUNCE_TIMEOUT`)
and made it accessible and configurable for all providers.
Also fixed a bug with `DelayMs` `Display` trait adding "ms" into the
input field which then fails to parse something like "150ms" as a `u64`
by implementing `FromStr` which strips the "ms" suffix if present.
So now both "1000" and "1000ms" are parsed correctly and apply.
If the parsing fix is not relevant enough I can open a separate issue +
PR for that (and the inconsistent use and therefore display of
`Option<u64>` vs `Option<DelayMs>` in other ms input fields).
## Testing
#### Did you test these changes? If so, how?
Added a separate test which passes
`test_refresh_prediction_from_buffer_honors_debounce_duration`
Manually tested with openapi compatible prediction
All other tests in affected crates pass (`cargo test -p settings_content
-p settings_ui -p editor -p edit_prediction -p language
`)
#### How can other people (reviewers) test your changes? Is there
anything specific they need to know?
Open provider settings and adjust debounce, then see how long it takes
for a prediction to render.
#### If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
Tested on Fedora 43 KDE, but it shouldn't matter as none of the affected
code is platform specific.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
https://github.com/user-attachments/assets/14efa628-765e-4c2a-ac44-01aaa3657097
---
Release Notes:
- Added configurable inline completion debounce timeout, fixes#23159
---------
Co-authored-by: Ben Kunkle <ben@zed.dev>