BufferSnapshot::chunks re-ran the tree-sitter highlight query over the
requested range on every call, so scrolling and cursor movement paid the full
query cost per frame.
Highlight captures are now computed once per 50-row chunk (the same RowChunks
that back bracket colorization), flattened into runs of capture-id stacks, and
kept in a cost-budgeted per-buffer LRU (10MB). Runs resolve through the
current HighlightMap at read time, so theme changes need no invalidation;
edits and reparses drop the cache through the existing TreeSitterData swap.
Chunks spanning more than 64KB bypass the cache and fall back to direct
querying, so files with giant lines behave as before.
New editor_render_highlighted and editor_render_highlighted_minimap benches
move the cursor through a generated 10K-line Rust file with real highlighting,
with and without the minimap; ZED_DISABLE_HIGHLIGHT_CACHE=1 routes rendering
through the pre-existing direct-query path for comparison.
MarkdownElement used to call Language::highlight_text (a full tree-sitter
parse) for every code block on every render, which made agent panel streaming
with code blocks noticeably janky.
Highlights are now computed once in the background parse task and stored on
ParsedMarkdown as capture-id stacks, which survive theme changes (resolved
through the current HighlightMap at render).
Language::highlight_text_captures memoizes its results in a per-grammar,
cost-budgeted (4MB, verified by full text comparison on hash hits) LRU cache,
so streaming appends reuse the captures of unchanged code blocks instead of
re-parsing them; texts over 512KB bypass the cache and are highlighted
directly.
The capture flattening moves into syntax_map as flatten_capture_regions,
fixing region splitting for overlapping (non-nested) captures on the way, and
capture ids get a CaptureId newtype.
The fallback_code_block_language parameter of Markdown::new has been inert
since the parser stopped recording untagged fenced code blocks in its language
name set (#28217): the lookup loop's empty-name branch became unreachable, so
hover popovers lost syntax highlighting for code blocks without a language tag.
Resolve the fallback language during the background parse (only when an
untagged fenced block is present) and store it on ParsedMarkdown, consuming it
when rendering code blocks. Also drop the now-unused futures dependency.
Closes#55345.
Wayland is the only platform whose frame ticks are conditional: a
wl_surface frame callback only arrives after a commit the compositor
goes on to repaint.
GPUI assumed unconditional ticks (any previously our Wayland backend
faked them), so an idle fullscreen window
stopped receiving callbacks and froze until external damage arrived.
This PR makes the Wayland render loop demand-driven, instead parking
when there's nothing to draw, and stops Zed committing empty frames on
every tick as the artificial heartbeat from the compositor.
---
Release Notes:
- Fixed the UI freezing in fullscreen on some Wayland compositors
- Fixed idle windows waking at the display's refresh rate on Wayland
---------
Co-authored-by: Philipp Schaffrath <philipp.schaffrath@gmail.com>
Co-authored-by: Daan De Meyer <daan@amutable.com>
Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
- Notify the author when their PR has been in draft state with no new
commits for three weeks
- Close the draft PRs that didn't get updated after one more week
- Re-try the cla-bot check on PRs that are still unsigned after a week
- Close the PRs that are still unsigned after the re-try
## Testing
It works on my machine™
```
python script/github-pr-cleanup.py --dry-run
Checking 713 open pull requests
Dry-run mode: no comments or closures will be made
PR #60885: asking the CLA bot to check again
Would comment on PR #60885:
@cla-bot check
PR #61625: asking the CLA bot to check again
Would comment on PR #61625:
@cla-bot check
PR #57239: warning about a stale draft
Would comment on PR #57239:
<!-- zed-community-automation:stale-draft-warning -->
This pull request has remained in draft without new commits for three weeks.
If it remains a draft without new commits for another week, it will be closed
automatically.
PR #57241: warning about a stale draft
Would comment on PR #57241:
<!-- zed-community-automation:stale-draft-warning -->
This pull request has remained in draft without new commits for three weeks.
If it remains a draft without new commits for another week, it will be closed
automatically.
PR #61461: warning about a stale draft
Would comment on PR #61461:
<!-- zed-community-automation:stale-draft-warning -->
This pull request has remained in draft without new commits for three weeks.
If it remains a draft without new commits for another week, it will be closed
automatically.
PR #61722: warning about a stale draft
Would comment on PR #61722:
<!-- zed-community-automation:stale-draft-warning -->
This pull request has remained in draft without new commits for three weeks.
If it remains a draft without new commits for another week, it will be closed
automatically.
PR #61808: warning about a stale draft
Would comment on PR #61808:
<!-- zed-community-automation:stale-draft-warning -->
This pull request has remained in draft without new commits for three weeks.
If it remains a draft without new commits for another week, it will be closed
automatically.
PR #61809: warning about a stale draft
Would comment on PR #61809:
<!-- zed-community-automation:stale-draft-warning -->
This pull request has remained in draft without new commits for three weeks.
If it remains a draft without new commits for another week, it will be closed
automatically.
Cleanup complete: 0 unsigned PR closures, 6 draft warnings, 0 draft closures
```
Release Notes:
- N/A
# 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 ...
Anthropic now returns distinct error types for billing failures, request
conflicts, and gateway timeouts. Because the Anthropic client did not
recognize these values, they fell through to
`LanguageModelCompletionError::Other`, losing their structured status
and causing callers to apply generic handling.
Recognize the documented `billing_error`, `conflict_error`, and
`timeout_error` codes. Billing failures now become `PaymentRequired`,
conflicts preserve their HTTP 409 status and provider message, and
timeouts become typed upstream HTTP 504 failures. End-to-end tests
exercise each mapping through the HTTP response parsing path.
Testing:
- `cargo fmt --check`
- `cargo nextest run -p anthropic`
- `./script/clippy -p anthropic`
- `git diff --check`
Release Notes:
- Fixed handling of Anthropic billing, conflict, and timeout errors.
# Objective
Make it easy to conditionally enable the gpui inspector, with a goal of
eventually turning it on in nightly.
## Solution
The new `zed/inspector` flag (and supporting flags in other crates)
enables the relevant inspector features in `gpui`, `ui`, and
`inspector_ui` to be able to display the gpui inspector.
## Testing
- Enabling the inspector adds about 5mb to the binary, and for context
the zed binary is > 400mb at this time.
- Observationally, the inspector doesn't affect performance in a
meaningful way, but I did not run profiling.
```
# release with inspector (inspector on)
cargo run --release --features inspector
# release without inspector (inspector off)
cargo run --release
# dev build with debug assertions (inspector on)
cargo run
```
then trigger `dev::ToggleInspector`.
- linux: `ctrl-alt-i`
- windows: `shift-alt-i`
- macos: `cmd-alt-i`
## 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: Kirill Bulatov <mail4score@gmail.com>
This PR adds a 'clear' button to the search field in the Settings
window. The button becomes visible only when the field contains text.
Clicking the button clears the search field, which also resets the
navigation list.
Empty:
<img width="213" height="41" alt="image"
src="https://github.com/user-attachments/assets/03f97367-1036-453f-816a-5cbad219951c"
/>
With a search term:
<img width="213" height="38" alt="image"
src="https://github.com/user-attachments/assets/518047f4-c397-4a34-bb2f-147fcf37dc69"
/>
There are similar UIs, like the macOS and Windows System Settings
windows, and even Zed's 'Help' menu filter (on macOS), where the field
acts as a 'live filter', updating results on each keystroke, and the
'clear' action is more convenient than backspacing.
The first commit adds the button and the 'on click' functionality. If
the Zed team approves this change, I would also like to use the `escape`
key to clear the field. I have done some work on this, but there are
several issues and I would like some feedback before committing the
appropriate changes:
1. The `escape` binding to clear the field could arguably be built-in
(not user-configurable) since it's the standard key for this type of
action, and it may not make sense to allow other key combinations since
this field accepts keyboard input. Would the team approve a built-in key
binding, or must it be bound to a user-configurable `Action`?
2. For the Settings Window, `escape` is currently bound to the
`CloseWindow` Action by default. If the search field is focused,
pressing the `escape` key should clear the field, but not close the
window.
- If a new `Action` is used to clear the field (containing text), the
binding to that `Action` can have a more specific context
(`SettingsWindow > NavigationMenu && search`) than the `Action` on the
window (`SettingsWindow > NavigationMenu`), so the window won't close …
but if the field is *already empty*, should `escape` close the window
(and is there a way to re-enable the `CloseWindow` action in that case)?
- If a `KeyDownEvent` listener for `escape` is used to clear the field,
the `CloseWindow` Action still closes the window – is there a way to
cancel the `CloseWindow` Action in this case?
3. There is at least one other location with a similar 'live filter'
field, namely the Filter field in the Keymap Editor, where this same
functionality could be implemented. (I could update that too if this PR
is approved). Are there other similar instances in Zed? This 'clear
filter' UX should be consistent in all those locations.
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 is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
(I could not find an existing issue or discussion about this feature.)
Release Notes:
- Added a 'clear' button to the search field in the Settings window,
which clears the field and resets the navigation list.
---------
Co-authored-by: MrSubidubi <finn@zed.dev>
Makes `ztracing` spans work on the web, by mapping them to browser
`performance` APIs.
Since calling into JS from wasm has fairly high overhead, we instead
have a dedicated reporter task that threads send timing information to.
This approach significantly decreases the performance overhead of the
span-capturing thread (which is usually the performance sensitive one),
at the expense of:
- erasing thread information for spans in the browser devtools
- potentially dropping events if the bounded queue becomes full
The first issue can be mitigated by some slightly more sophisticated
capturing, along with a fixup script, which will come in a later PR
---
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>
Closes https://github.com/zed-industries/zed/issues/62801
# Objective
Fix issue https://github.com/flathub/dev.zed.Zed/issues/395 (reported
against the flathub package, but as described in it, it was introduced
by https://github.com/zed-industries/zed/pull/57440 ).
The symptom was that when running `flatpak run dev.zed.Zed <project
path>` (or some alias), then you'd get two "files" opened `--zed` and
`zed-editor`, with `zed-editor` also being added to the Zed project list
in the open window, which was quite annoying.
## Solution
- The flatpak CLI launcher, which self-launches with potential extra
arguments, now puts those arguments first rather than last.
## Testing
- A simple unit test targets the helper function that adds the arguments
- It also verifies that the parsed args come out as expected
## 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
Note: I believe that other bullets than self-review and tests are not
relevant, as there is no unsafe, no expected performance impact, and no
UI changes.
---
Release Notes:
- Fixed an issue where Flatpak CLI launches would open
unrelated/nonexistent files due to a bug in argument construction
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
# Objective
Closes#52429Closes#56735Closes#62495Closes#62878
Reverts #13071
This PR fixes Zed windows sometimes remaining blank when first opened on
X11.
The issue remained very inconsistent across WMs and conditions to
reproduce and was finally consistently reproducable on my dwm build with
no compositor and on i3 with no compositor after removing the workaround
earlier added, which made it occur in i3 but not on my dwm build because
it was more aggressive with it's EWMH policy. It happened only on
opening a newer repo not opened the last time.
While running foreground work, a synchronous X11 request can read events
from the socket and place them in x11rb's internal event queue, calloop
monitors the underlying socket rather than this internal queue, so if
the socket is empty when the foreground work finishes, these events may
remain unprocessed until unrelated X11 activity occurs.
window is mapped -> events are buffered by x11rb
-> X11 socket is no longer readable
-> calloop does not wake
-> MapNotify is not processed
-> refresh loop does not start
-> window remains blank
This explains why the problem was inconsistent and differed between
window managers. Later focus, scrolling (on any window), exposure, or
other X11 activity could make the connection readable again and
incidentally process the older events.
My earlier PR #61162 fixed the related case where an already processed
`Expose` event could wait indefinitely for a stopped refresh loop. It
did not fix this initial-window case because the relevant events had not
reached Zed's event handler yet, which was again not perfectly
reproducable and lead me to assume was fixed.
## Solution
Process any X11 events buffered by x11rb after each foreground runnable
completes:
foreground work completes
-> buffered X11 events are processed
-> MapNotify starts the refresh loop
-> initial window contents are displayed
This also removes the unconditional
[`SetInputFocus`](https://tronche.com/gui/x/xlib/input/XSetInputFocus.html)
added in #13071. That call frequently masked the issue by generating
additional X11 activity, but also bypassed the window manager's focus
policy despite Zed already sending the standard `_NET_ACTIVE_WINDOW`
request.
With the event queue handled correctly, Zed no longer needs to force
focus to make the initial frame appear.
## Testing
Repeatedly opened fresh and existing workspaces under dwm while another
application retained focus with a new-project being opened everytime (at
least not the previous one).
Before this change, fresh windows could remain blank until later X11
activity occurred. After this change, they render immediately without
focusing, scrolling, resizing, or switching workspaces.
Also verified that window activation is left to the window manager
through `_NET_ACTIVE_WINDOW`.
## 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 Zed windows sometimes remaining blank when first opened on X11
* Fixed Zed overriding window-manager focus policies when activating
windows
# Objective
Closes#52822
When hovering over the LSP status tooltip for a running language server,
the binary path is displayed. Currently, this tooltip shows
`LanguageServerBinary.path`. However, many language servers are executed
through runtimes such as Node or Python. For example, Zed-managed
`Basedpyright` produces a `LanguageServerBinary` like:
```Rust
LanguageServerBinary {
path: "/usr/bin/node",
arguments: [
"/home/xin/.local/share/zed/languages/basedpyright/node_modules/basedpyright/langserver.index.js",
"--stdio",
],
env: ...
}
```
In this case, only `"/usr/bin/node"` is displayed, which doesn't convey
useful information about the actual language server script being
executed.
## Solution
There was a PR #53076 in which I was involved, and the solution there
was to populate every language server adapter with a special marker for
the path to be shown in the tooltip. That solution is accurate, but in
order to make this solution work for extension-provided servers, the
final diff became huge for a simple fix.
So here, as commented in
https://github.com/zed-industries/zed/pull/53076#pullrequestreview-4204849892,
a guess is performed by a newly introduced function
`tooltip_for_server_binary()` to get the real path to be shown. It may
have some edge cases, but works for current cases and is simple to
implement.
## Testing
Added new unit tests, built and tested locally, with the comparision
attached in the Showcase section.
## 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
For the mentioned `Basedpyright` language server case, the comparision
is shown below:
| Before | After |
|:--:|:--:|
| <img width="431" height="187" alt="before"
src="https://github.com/user-attachments/assets/0611f2fe-687b-4d67-ba78-380d89ed0212"
/> | <img width="582" height="185" alt="after"
src="https://github.com/user-attachments/assets/6ad08720-ac53-4b2d-a72c-3febb441e2f1"
/> |
---
Release Notes:
- Improved the LSP status tooltip to display the target script path for
runtime-managed language servers
# Objective
When a worktree has no enclosing git repository, the `global-gitignore`
check falls back to matching the raw, unbounded absolute path. This lets
an ancestor directory outside the worktree, or the worktree's own root
name, incorrectly match a bare global-ignore pattern (e.g. a global
entry like `tmp` or `*.com`) and mark the entire worktree as ignored,
which silently breaks project search and greys out every file in the
project panel.
Fixes#62126Fixes#48887
## Solution
- In `Snapshot::ignore_stack_for_abs_path`, when no containing
repository is found, fall back to the worktree's own root as the
boundary for `IgnoreStack.repo_root`, instead of leaving it `None`.
- This reuses the existing repo-root-relative matching logic in
`IgnoreStack::is_abs_path_ignored` (already correct for the
git-repository case since #61689) without needing any changes to
`ignore.rs` itself: ancestors outside the worktree now correctly fail
the prefix check and are treated as not ignored, while the global
gitignore still applies to files and directories within the worktree.
## Testing
- Added `test_global_gitignore_without_repository` in
`crates/worktree/tests/integration/worktree_tests.rs`, covering both
variants in one worktree: an ancestor directory outside a non-git
worktree matching a global pattern, and the worktree's own root name
matching one, while also confirming a file that matches the pattern from
within the worktree is still ignored.
- Verified the new test fails without the fix (reproducing both #62126
and #48887) and passes with it.
- Ran the full `worktree` integration test suite (`cargo test -p
worktree --test integration`); all tests pass.
- Not tested on Windows or macOS, only Linux.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] Tests cover the changed behavior
---
Release Notes:
- Fixed global gitignore entries incorrectly matching directories
outside the opened project and marking the entire project as ignored
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
Fixes https://github.com/zed-industries/zed/issues/62780
When formatting changed-only regions, we have received formatting
changes that are larger than the regions submitted.
Previous code merged only adjacent hunks in a single response, without
merging anything else, e.g. multiple responses' ranges that overlapped.
Release Notes:
- Fixed overlapping range format results duplicating the text
The inline assistant's streaming-tool path waited for the first
`rewrite_section` output, but treated any other completion event as
terminal. Responses API providers can emit `ReasoningDetails`,
`Thinking`, and other metadata before the tool call. This stopped the
stream early and marked generation as done without applying a
replacement.
EOF was not handled explicitly. Parse errors, provider errors,
incomplete tool calls, and truncated responses could also be reported as
successful completions.
Continue consuming informational events until a supported tool call
arrives. Track the rewrite tool call's streaming state, reject a second
`rewrite_section` call instead of concatenating unrelated outputs,
accept `failure_message` only after its input is complete, and reject a
`rewrite_section` arriving after a failure message (and vice versa).
Stop, EOF, malformed tool input, and stream errors now surface as
`CodegenStatus::Error` instead of silently completing. A completed tool
call followed by `Stop(MaxTokens)` or `Stop(Refusal)` is also an error:
the OpenAI Responses mapper flushes truncated tool calls as complete
before emitting the stop reason, so the stop reason must be checked even
when the tool input parsed. Completed failure messages are stored before
`Finished` is emitted, and a failure message left over from a previous
generation is now cleared when a new one starts.
Add regression coverage for metadata around streamed rewrites, Stop and
EOF without a tool call, incomplete rewrites, interrupted responses,
multiple rewrite calls, failure messages, malformed input, mixed tool
calls, and stream errors before and after rewrite output begins.
---
Closes#52714
Release Notes:
- Fixed the inline assistant doing nothing when the model emits
reasoning before its tool call.
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
Saves the recent navigation history (up to 20 entries) to the workspace
DB so it survives restarts. When reopening a workspace, persisted paths
that resolve to the current project are merged into the file finder's
history, deduplicated against files already opened in the session.
https://github.com/user-attachments/assets/3d8934e1-0da6-4445-8f3d-acc5597d7ac8
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 is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes: https://github.com/zed-industries/zed/issues/56271
Release Notes:
- Improved file finder history to include recently opened files from
previous sessions.
# Objective
When an user uses the Project Panel to rename a file, it is possible to
change its path too. For example, renaming `README.md` to
`documents/README.md` will create the `documents/` directory, in case it
doesn't yet exist.
Unfortunately, even though undoing a rename operation is already
supported, we were not yet considering this scenario where directories
had been created specifically to support the rename. As such, when undo
was used, for the scenario above, we'd end up moving `README.md` back to
its original location but would leave the empty `documents/` directory
behind.
## Solution
Introduce two new operations and changes specifically for this use-case,
`Operation::CreateDir`, `Operation::RemoveDir`, `Change::DirCreated` and
`Change::DirRemoved`, which we can then batch together with the
`Operation::Rename` in case directories need to be created or removed.
An initial approach of just keeping the list of created directories in
the `Operation::Rename` and `Change::Renamed` variants was considered
but it would require all users of `Operation::Rename` to now set it,
even if they don't actually need it, like the drag and paste operations.
Having separate operations and change variants also makes it clearer
what these are meant to be used for.
Something else worth noting is that, for `Operation::CreateDir`, the
directory will only be created if it doesn't yet exist, otherwise we'll
ignore. Same happens for `Operation::RemoveDir`, where if the directory
is not empty, we don't delete it, as it's possible for new files to have
been added to the directory outside of Zed and we don't want to delete
those.
## Testing
Tested both manually as well as introduced a new test case
– `project_panel::tests::undo::rename_with_dir_undo_redo` .
## Self-Review Checklist:
- [x] 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)
- [x] Tests cover the new/changed behavior
- [x] 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>Before</summary>
https://github.com/user-attachments/assets/15384fa8-9b94-495c-8992-19eee7a8f038
</details>
<details>
<summary>After</summary>
https://github.com/user-attachments/assets/c5be9f38-a2b4-4acc-8a1e-178161e326bb
</details>
---
Release Notes:
- Fixed undoing a file rename leaving behind directories created by the
rename.
# Objective
On case-insensitive volumes (the macOS default), language servers may
return `Location` URIs whose path casing differs from the worktree's
stored casing - e.g. `Utils/helpers.py` when the on-disk (and worktree)
path is `utils/helpers.py`. `LspStore::open_local_buffer_via_lsp` used
the LSP path verbatim, and worktree selection
(`WorktreeStore::find_worktree`) does a case-sensitive prefix match, so
the existing worktree was either missed (creating a duplicate invisible
worktree) or matched but with a relative path that retained the LSP's
intermediate-component casing. That relative path was then used to
`load_file`, which inserted a brand-new `Entry` keyed by the
differently-cased path alongside the existing one - producing duplicate
file entries in the project panel. This was most visible when navigating
Python imports (Go to Definition) where the LSP returned
differently-cased paths.
https://github.com/user-attachments/assets/e36930b5-8dfd-4b43-8fe4-5317d401e198
## Solution
Canonicalize the LSP-provided absolute path via `fs.canonicalize` before
the worktree lookup in `LspStore::open_local_buffer_via_lsp`, so the
path casing matches the filesystem and the existing worktree/entry is
reused. Canonicalization failures (e.g. a path that doesn't exist on
disk yet) fall back to the original path to preserve prior behavior.
To enable testing this on a fake filesystem, `FakeFs` now supports
`set_case_sensitive(false)` and its `canonicalize` resolves names
case-insensitively, returning the stored (canonical) casing.
## Testing
Added `test_open_buffer_via_lsp_case_variant_no_duplicate` in
`crates/project/tests/integration/lsp_store.rs`. It opens a buffer via
an LSP URI with differently-cased intermediate component
(`/root/SRC/main.rs` vs `/root/src/main.rs`) on a case-insensitive
FakeFs and asserts that no differently-cased entry is created and the
canonical entry is preserved. Verified the test fails without the fix
(`SRC/main.rs` duplicate appears) and passes with it. Existing worktree,
fs, and project_panel test suites remain green.
## 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/f052cf10-8b45-4547-8425-00ce4050ee7c
---
Release Notes:
- Fixed duplicate file entries in the project panel on macOS when
navigating to definitions via the language server returned paths with
different casing than the worktree root.
---------
Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
# Objective
use pickers for all kinds of lsp definitions
## Solution
add handlers for `GoToDeclaration` and `GoToTypeDefinition` in
`lsp_locations.rs`
## 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:
- [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
## Showcase
this rust code can be used to test for multiple type definitions on `a`
```rs
macro_rules! foo {
($e:ident) => {
let $e: Vec<()>;
let $e: String;
};
}
fn main() {
foo!(a);
}
```
<img width="735" height="288" alt="image"
src="https://github.com/user-attachments/assets/578e6dc2-b201-4194-bd8b-e8d17b4d3d50"
/>
---
Release Notes:
- Respect `"lsp_results_location": "picker"` for go to declaration and
type definition
Bundled GLib shadowed the system libraries for host plugins dlopen'd
into the process, like PipeWire's videoconvert on 1.6+, which would
break Wayland screen sharing on newer distros. This PR makes Zed rely on
system GLib instead, since the bundled version pulls from whatever is in
CI (presently Ubuntu 20.04).
Release Notes:
- Removed GLib libraries from Linux release bundle, which could conflict
with system plugins
# Objective
On X11, GPUI raises the ICCCM `WM_HINTS` urgency flag to ask for
attention, but
it never clears it. The window stays urgent for the rest of its life.
`request_attention` was the only thing touching the bit. There was no
code
anywhere to clear it.
Docks and taskbars latch on the rising edge, so they show the attention
state
once and then sit there with a permanent urgent indicator, no further
notifications.
## Solution
Clear the flag when the window becomes active.
The read/modify/write moves out of `request_attention` into a helper,
`set_wm_hints_urgency(xcb, x_window, urgent)`. The raise and clear sites
are on
different self types (`X11Window` vs `X11WindowStatePtr`), so it takes
the
connection and window id.
The clear goes in `set_wm_properties`, where `state.active` gets set
from
`_NET_WM_STATE_FOCUSED`. That's the same field `request_attention`
already checks
in its `if self.is_active() { return; }` guard.
Two implementation notes:
* The clear is edge triggered (`state.active && !was_active`).
`set_wm_properties` recomputes everything on every `_NET_WM_STATE`
change, so a
level triggered check would do a blocking `WmHints::get` round trip on
every
maximize, fullscreen, hide and workspace switch while focused. Edge
triggering
is safe here because `request_attention` early returns when active, so
urgency
only ever gets raised while inactive, and the false to true transition
always
follows a raise.
* Clearing reads the hints first and skips the write if the bit isn't
set.
Otherwise focusing a window that never asked for attention would create
a
`WM_HINTS` property just to say "not urgent".
The raise path behaves exactly as before. The skip can't fire when
`urgent` is
true, so repeat raises still write every time.
Focusing clears the flag even if a second thread is still waiting.
That's already
how it works, since `request_attention` early returns when the window is
active.
## Testing
Tested on X11, Cinnamon with Muffin.
On an unpatched build the window had `_NET_WM_STATE_FOCUSED` and the
urgency bit
set at the same time.
W=$(xdotool search --class "dev.zed.Zed" | head -1)
xprop -id $W WM_HINTS
xprop -spy -id $W WM_HINTS
1. Fresh window says `WM_HINTS: not found`, and still does after
focusing it.
2. With focus on another window, the urgency bit shows up when attention
is
requested. `request_attention` early returns when active, so the window
has to
be unfocused for this to fire.
3. Focusing Zed clears the bit.
4. Repeating 2 and 3 re-arms it every cycle, not just once.
5. No `WM_HINTS` writes during normal use (resize, maximize, workspace
switch).
No automated test. It's an X11 round trip on a real window and there's
no X11
test harness in the tree.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments (none added)
- [x] The content adheres to Zed's UI standards (no UI change)
- [x] Tests cover the new/changed behavior (see Testing)
- [x] Performance impact has been considered and is acceptable
Note this was manually tested, there wasn't a good way to test it
through the current harness.
---
Release Notes:
- Fixed the X11 urgency hint never being cleared, which left Zed showing
a permanent attention indicator in taskbars and docks after the first
notification
# Objective
Closing a project while a large local text file is loading can be
delayed
because file-reading and UTF-8 streaming loops have no await points.
Partially addresses #27283.
## Solution
Yield between 1 MiB blocks while:
- streaming UTF-8 files into a Rope
- reading files handled by the fallback decoder, including BOM, UTF-16,
and other non-UTF-8 encodings
Release Notes:
- Improved responsiveness when closing projects that are loading large
text files.
# Objective
- Support opening remote paths from SCP-style SSH URLs that use
bracketed IPv6 hosts, such as `ssh://[2600::]:~/foo`.
## Solution
- Validate SSH hosts with `url::Host::parse`, which supports bracketed
IPv6 addresses while continuing to reject malformed or ambiguous hosts.
- Add test coverage for IPv6 URLs with usernames, home-relative paths,
absolute paths, and explicit ports.
- Add rejection tests for unbracketed IPv6 addresses and ambiguous
port-plus-SCP-path syntax.
## Testing
- Ran `cargo fmt --all -- --check`.
- Ran `cargo test -p zed test_parse_ssh_urls -- --nocapture`.
- Ran `cargo test -p zed test_reject_ssh_urls -- --nocapture`.
- All targeted tests passed on macOS. No additional platform-specific
testing is expected to be necessary because the change only affects URL
parsing.
Release Notes:
- Fixed opening remote paths from SCP-style SSH URLs with IPv6 hosts.
Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
I was trying out zed after VS Code and I've stumbled upon inconsistency
with debugging hotkeys.
In VS Code it's f10/f11, in zed it was much more awkward f7/ctrl-f11.
Investigating, I've found that I can't just override f11, because it's
used by `zed::ToggleFullScreen` global hotkey and global hotkey always
beats `Workspace && debugger_stopped`.
Furthermore, I've found f11 hotkey is available, but only on Mac. And on
Windows there was no `StepInto` hotkey at all. So configs were unsynced
in that regard.
Code changes:
- To make f11 overridable, I've moved it to `Workspace` context - it's
still pretty global, but now it's overridable. Though `Workspace &&
debugger_stopped` have the same depth as `Workspace`, it will take
priority, because it's registered later in .json.
- StepInto - added f11 hotkey for all platforms (was missing on linux
and windows), kept older ctrl-f11 too as some users might be used to it.
A note that on Mac F11 was added previously as `Workspace &&
debugger_running` - which practically means the hotkey wasn't available.
`debugger_running` means debugger is running in background, user needs
step commands when `debugger_stopped`- when they're actually stepping
through the code.
- StepOver - added f10 hotkey for all platforms (was missing on linux
and mac). Kept old f7 hotkey on linux and mac, didn't added it on
windows as it wasn't present before.
- StepOut - it was consistently shift-f11 on all platforms already, just
moved it from global context for consistency.
- Removed StepOver, StepInto, StepOut from debugger_session context and
kept it only in `debugger_stopped`, as this is when they're actually
useful, similar to how we have `debugger::Continue"` there which also
makes sense only when debugger is stopped.
I've separated changes by commits, so it would be easier to review them.
PS Global hotkeys overriding specific ones seems a bit odd by itself -
it seems global more specific hotkeys should always have a priority, so
maybe it's something to look into too.
Another thing that `default-xxx.json` share a lot of hotkeys, so
maintaining them separately may have other things going out of sync too.
Closes#58899.
----
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 is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior - keymaps are not tested
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Improved debugger step keybindings across platforms to match VS Code
defaults while preserving fullscreen outside paused sessions
---------
Co-authored-by: Kunall Banerjee <hey@kimchiii.space>
# Objective
- Fix support for alt-f5 in terminal and add support for ctrl-alt-key
## Solution
- Fix `crates/terminal/src/mappings/keys.rs`.
## Testing
- Did you test these changes? If so, how? Added a unit test, and test
the built zed with fish_key_reader to check that the keys are indeed
recognized.
- Are there any parts that need more testing? No
- How can other people (reviewers) test your changes? Is there anything
specific they need to know? Fish has fish_key_reader which can check the
keys that it recognizes. Not sure about other shells. `cat | xxd` can be
used to confirm the exact received key codes.
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test? Tested on Linux only.
## 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:
- In terminal, "alt-f5" keystroke support is fixed and "ctrl-alt-key"
support is added for letter keys.
---------
Signed-off-by: Gary Guo <gary@garyguo.net>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
The gutter run button for Python's main guard only appears for `if
__name__ == "__main__":` but not for the alternative membership test
pattern `if __name__ in ("__main__", "__builtin__", "builtins"):`.
This adds a second Tree-sitter query in `runnables.scm` that matches the
`in` variant. It emits the same `python-module-main-method` tag, so both
patterns get the same gutter icon and task behavior.
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 (No dedicated tests for the
Python runnables queries exist. The build passes cleanly)
- [x] Performance impact has been considered and is acceptable
Closes#58909
Release Notes:
- Fixed Python run button not appearing in the gutter for `if __name__
in ("__main__", ...)` style main guards.
Co-authored-by: Finn Evers <finn@zed.dev>
# Objective
- Add an `in_preview` context that is available when the current editor
is in preview mode (opened from project panel or go to definition).
- closes https://github.com/zed-industries/zed/discussions/61765
## Solution
- In `editor.rs`, added a check in `key_context()` that detects if the
editor is the active preview item in its pane, and if so, adds
`"in_preview"` to the key context.
- Uses existing `workspace.pane_for_item_id()` and
`pane.is_active_preview_item()` methods — no new APIs introduced.
## Testing
- Added two tests in `editor_tests.rs`:
- `test_in_preview_context_added_when_in_preview_mode` — verifies
`in_preview` is present when editor is set as preview item.
- `test_in_preview_context_not_added_when_not_in_preview_mode` —
verifies `in_preview` is absent for regular (non-preview) tabs.
- Tested on Linux.
## 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:
- Added `in_preview` keybinding context for when an editor is in preview
mode.
# Objective
Fixes#62664
File names may contain control characters (`\n`, `\r`, `\t`, …) on most
platforms. Zed rendered them verbatim, so a file named `notes\ndraft.md`
broke the layout of its tab and of its project panel entry instead of
showing a readable name. The same held anywhere else a name reached the
screen without going through `Label::single_line`.
## Solution
The substitution lives in one shared place,
`ui::utils::replace_control_characters`, reached through
`Label::single_line`. `\n` keeps rendering as the `⏎` Zed already used,
so nothing that renders correctly today changes; every other C0 control
character maps onto the Unicode "Control Pictures" block by a single
rule (`U+2400 + code point`), giving `␉` for tab and `␍` for carriage
return. `DEL` maps to `␡`. C1 controls are left alone, having no
equivalent there.
Where that is wired in:
- **`Label::single_line`** — replaces its previous `\n`-only
substitution. The project panel already used it everywhere, including
folded directory components, so the panel is fixed by this alone.
- **Editor tabs** and the **default `Item::tab_content`**, neither of
which called `single_line`.
- **Terminal tab titles**, which render through their own `tab_content`.
Those titles come from OSC escape sequences, so the control characters
in them are attacker-controlled.
- **`HighlightedLabel::single_line`**, which never substituted anything
— not even `\n`. See below.
- **The file finder**, for both the file name and the path.
- **Nine `tab_content` overrides in git_ui**, by deleting them.
- **`HighlightedMatchWithPaths`**, for both the match label and its
paths — it backs the tab switcher and the outline panel, among others.
### `HighlightedLabel` needs its offsets moved, not just its text
Its highlight indices are byte offsets, and every stand-in is wider in
bytes than the character it replaces, so the offsets have to move with
the text. Left alone they index into the middle of a character, and
`highlight_ranges` slices the string at exactly those offsets — which
panics in release builds too. The constructor's `debug_panic!` does not
cover this, since `single_line` runs after construction.
So `replace_control_characters_remapping_offsets` substitutes and remaps
in one pass, over an old-to-new byte offset table built the way
`ensure_uniform_list_compatible_label` does it in `lsp_store`. This also
fixes the call sites that already asked for a single line, including the
branch picker and the tabular column filter values.
### Deleting the git_ui overrides
Nine files replicated the default `Item::tab_content` verbatim except
for the colour, hardcoding `selected ? Default : Muted` instead of
`params.text_color()`. Deleting them lets those tabs inherit the fixed
default, and fixes a second bug along the way: none of them dimmed when
the pane lost focus. Titles and icons are unaffected — they come from
`tab_content_text` and `tab_icon`, which the default calls.
`git_graph.rs` already did it this way.
### Tabular column headers
These never went through a `Label` at all: the raw `SharedString` was a
child of a `div`. They now display stand-ins, while right-click-copy
still yields the real column name.
Two notes for reviewers:
- Both helpers avoid allocating when there is nothing to replace, so the
common path is untouched. The previous `self.label.replace('\n', "⏎")`
allocated a `String` on every render for every label — including every
visible project panel entry, every frame.
- Every stand-in is exactly one character, so character offsets are
preserved and the existing `truncate_and_trailoff` math on tab titles
stays correct.
## Testing
- Unit tests cover both helpers: each control character's substitution,
repeated occurrences, multi-byte characters (accents, emoji), the
borrow-vs-own behaviour, the preserved character count, C1 passthrough,
and — for the remapping — offsets before, at and after a replacement,
offsets at and past the end, and the invariant that every remapped
offset lands on a character boundary.
- Unit tests cover `Label::single_line` and
`HighlightedLabel::single_line`, the entry points every call site uses.
`highlighted_label.rs` had no tests before.
- `cargo test -p ui -p file_finder -p workspace -p project_panel -p
git_ui -p git_ui_core -p terminal_view -p tabular_data_preview` passes
(774 tests), as do `cargo clippy` and `cargo fmt --check`.
- No existing test changes behaviour: tests assert on
`tab_content_text`, which is untouched; only rendering paths changed.
- Verified manually on macOS (aarch64) — see Showcase.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments — none added
- [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
A directory holding `report<TAB>table.csv`, `notes<LF>draft.md`,
`carriage<CR>return.txt` and a normally named `normal.txt`, all four
open as tabs.
**Before**

**After**

Three things change:
1. **The `notes<LF>draft.md` tab** is the clearest one. Before, the
literal newline splits the tab across two lines — `notes` above
`draft.md` — distorting the whole tab bar. After, it stays on one line.
2. **`carriage<CR>return.txt` in the project panel** renders as
`carriagereturn.txt` before: the `\r` is completely invisible, so the
name reads as one word and there is no way to tell a character is there.
After, it renders as `carriage␍return.txt`.
3. **`report<TAB>table.csv`** shows a bare gap before, indistinguishable
from a space. After, it renders as `report␉table.csv`.
Note that `notes<LF>draft.md` looks the same in the project panel in
both shots: that entry already called `single_line`, which already
handled `\n`. That is precisely the asymmetry this PR removes.
### File finder
Before, the newline also breaks the list itself — the
`notes<LF>draft.md` row grows to two lines and overlaps the row beneath
it.
**Before**

**After**

Searching for `table` exercises the offset remapping, the match falling
after the control character:
**Before**

**After**

One thing this PR does **not** cover: the breadcrumb below the tab bar
still renders the raw tab character, as it goes through a different
path.
## Release Notes:
- Fixed file names containing control characters, such as tabs and
newlines, rendering unreadably in tabs, the project panel, the file
finder, the tab switcher and terminal tab titles.
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Closes#46522
Release Notes:
- Added inline values support for C and C++ when debugging with CodeLLDB
or GDB
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Zed's hang telemetry could say a hang happened, but not what the app was
doing. This PR adds a foreground journal to gpui (behind the `profiler`
feature): the main thread records task polls, action handlers, input
dispatches, window draws, and frame presentations into a fixed-size
ring, and boundary entries — a newly drawn frame's presentation, or the
foreground going idle — partition that stream into activity intervals.
Recording is designed to be cheap enough to ship enabled: sub-threshold
task polls fold into a counter instead of individual entries, and the
ring is drained in bounded chunks off the main thread.
A `HangDetector` drains the journal and reports an incident for any
interval containing a single event at or above the hang threshold (100ms
in release), or whose cumulative foreground spend reaches a frame budget
(8ms in release) — catching both one long stall and many small pieces of
work that together drop a frame. Incidents serialize with phase
(startup/steady), stall and active durations, busy fraction,
dirty-to-present time, and up to 8 contributors in start order with
nesting depth: task polls carry their spawn location, actions their
names, inputs their kind. Zed batches the top 10 incidents by stall per
30 minutes plus a total incident count into a "Hang Incidents" telemetry
event, flushes the remainder on quit, and drops the old per-location
"Hang Report" histograms this replaces.
Release Notes:
- N/A
`ShapedLine` is nearly 3KB by value because it inlines a
`SmallVec<[DecorationRun; 32]>`. A consumer that builds wrapped lines
out of many small uniformly styled fragments only needs the shaped
glyphs plus a single decoration run it can track itself, but it ends up
moving and reallocating that mostly dead capacity constantly because
splitting and painting are only reachable through `ShapedLine`.
This moves the glyph-partitioning half of `ShapedLine::split_at` down to
a new `LineLayout::split_at`, and adds
`LineLayout::paint`/`paint_background` methods that take explicit
decoration runs. Together with the already-public `layout_line`, callers
can now hold a bare `Arc<LineLayout>` and their own decorations.
`ShapedLine::split_at` delegates to the new method and behaves the same.
## 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:
- N/A
Allows configuring the Bash LSP.
Tested with the following config:
```json
"bash-language-server": {
"binary": {
"path": "bash-language-server",
"arguments": ["start"]
},
"settings": {
"bashIde": {
"shfmt": {
"binaryNextLine": true,
"caseIndent": true,
"spaceRedirects": true,
"simplifyCode": true
}
}
}
}
```
Config options [defined
here](https://github.com/bash-lsp/bash-language-server/blob/main/server/src/config.ts),
all prefixed with `bashIde`.
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 is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Added support for configuring the Bash LSP adapter.
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Closes#55728
## Summary
The Windows installer writes the localized Windows 11 Explorer context
menu title to `HKCU\Software\Classes\{RegValueName}ContextMenu`, where
the release channels use `Zed`, `ZedPreview`, and `ZedNightly` as the
registry value names.
`explorer_command_injector.dll` was reading from `ZedEditor*ContextMenu`
instead, so the registry lookup failed and Explorer always received the
hardcoded `Open with Zed` fallback. This aligns the DLL registry paths
with the installer-written keys for stable, preview, and nightly.
## Tests
- `cargo check --package explorer_command_injector --no-default-features
--features stable`
- `cargo check --package explorer_command_injector --no-default-features
--features preview`
- `cargo check --package explorer_command_injector`
- `cargo check --package explorer_command_injector --all-features`
- `cargo fmt --check --package explorer_command_injector`
- `git diff --check`
Release Notes:
- Fixed localized Windows Explorer context menu titles falling back to
English.
---------
Co-authored-by: MrSubidubi <finn@zed.dev>
Refactors our query loading to instead have an enum of supported queries
and load the query files themselves in parallel, where possible.
We will use this to warn extension authors when unsupported queries are
present, as we no longer want to ship those as part of the extension.
It also now enforces one file per supported query - only one extension
currently utilizes this feature and was undocumented previously, so I
decided in favor of removing it here, since this will help with
enforcing extensions to just ship query files we actually support in the
future. The extension has also been migrated so that it does not break
with this effort
Side-effect of this change is that we now load both embedded and
external languages up to at least 10%/5% faster, since the files are now
read in parallel as opposed to sequentially one by one.
Release Notes:
- N/A
# Objective
Fixes#60922
The remote development documentation references action names as
hardcoded strings (`projects: open in wsl`, `projects: open wsl`). These
can drift out of sync with the actual action definitions in code and
don't benefit from the docs preprocessor's auto-rendering.
## Solution
Replaced hardcoded action name strings with the `{#action ...}`
preprocessor template syntax in `docs/src/remote-development.md`:
- `{#action projects::OpenFolderInWsl}` for "Opening a local folder in
WSL"
- `{#action projects::OpenWsl}` for "Opening a folder already in WSL"
This ensures the docs auto-resolve the human-readable action name from
the code definition, preventing future drift.
## Testing
- Verified the `{#action ...}` syntax is documented in
`docs/README.md:78-82` and implemented in
`crates/docs_preprocessor/src/main.rs`.
- Reviewed the action definitions in `crates/zed_actions/src/lib.rs:843`
(`OpenFolderInWsl`) and `lib.rs:852` (`OpenWsl`) to confirm correct
namespace and struct names.
- No code changes, docs only — no build or test required.
## 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
N/A — documentation-only change.
---
Release Notes:
- N/A
---------
Co-authored-by: MrSubidubi <finn@zed.dev>
Co-authored-by: Finn Evers <finn.evers@outlook.de>
# Objective
Closes#62624
Recently, Pyright and BasedPyright changed how they retrieve analysis
settings through `workspace/configuration` in microsoft/pyright#11480
and DetachHead/basedpyright#1847, respectively. Older versions requested
the dotted `python.analysis` and `basedpyright.analysis` sections
directly. Recent versions instead request the parent `python` or
`basedpyright` section and read its nested `analysis` object. Because
Zed stores many existing configurations under the dotted top-level keys,
those settings are not included in its responses to the new
parent-section requests and are therefore silently ignored.
Zed's documentation and many users' settings still use configurations
like this:
9bde578ef5/docs/src/languages/python.md (L131-L148)
all the configrations in `basedpyright.analysis` won't work now.
## Solution
To maintain compatibility with both old and new servers, we need to
support both configuration formats. This PR introduces
`normalize_pyright_analysis_configuration`, which copies the analysis
settings into both the dotted and nested formats. This ensures that the
settings are available regardless of which format the language server
requests.
The documentation, however, has been updated to use the nested
structure.
## Testing
New unit tests have been added, and the changes have also been built and
tested locally.
## 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 some Pyright and BasedPyright settings not being applied
properly.
# Objective
- Fixes#25905
- Regex search-and-replace silently does nothing when a same-line
pattern contains a lookahead or lookbehind. Searching highlights the
correct hits, but Replace All or `:s` in Vim mode leaves the buffer
untouched.
Reproduce with `316227766016837933199`, search `(\d)(?=(\d{4})+$)` in
regex mode, and replace with `$1,`. Expected:
`3,1622,7766,0168,3793,3199`. Actual before this change: nothing
changes. The same problem affects `(?<=foo: )bar` replaced with `BAZ`.
`SearchQuery::replacement_for` expanded the replacement by re-running
the whole pattern against the matched text alone. Lookaround assertions
inspect text outside the match, so the isolated hit no longer matched
and the edit replaced the hit with itself.
## Solution
- `replacement_for` now expands from captures located at the exact hit
range within its source context.
- Single-line regex hits use the complete source line, so lookahead,
lookbehind, and line anchors see the same surrounding text used by
search.
- Literal and escaped-regex searches bypass context reconstruction
because their replacements do not use captures.
- Multi-line hits retain the exact matched text, preserving the prior
cross-line behavior.
- If selection boundaries prevent the pattern from matching the
reconstructed line, replacement falls back to the isolated hit,
preserving prior behavior.
- Replace All caches the source line across hits on the same line.
Cross-line lookaround remains unchanged: assertions that need text
outside a multi-line hit still produce a no-op replacement.
Search-within-selection can also retain the prior no-op behavior when
the selection boundary changes assertion context.
## Testing
- `cargo test -p search test_replace_with_lookaround` (2 passed)
- `cargo fmt --all -- --check`
- `./script/clippy -p editor -p project -p search`
- Tested on Linux arm64. The change is platform independent.
## Self-Review Checklist:
- [x] I have reviewed the diff for quality, security, and reliability
- [x] Unsafe blocks, if any, have justifying comments
- [x] The content adheres to Zed UI standards
- [x] Tests cover the changed behavior
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- Fixed same-line regex replacements that use lookahead or lookbehind
# Objective
- Fixes#54158
## Solution
- The root cause is in `FileFinderDelegate::set_selected_index`: it
always sets `has_changed_selected_index = true`, regardless of whether
the selection change was triggered by keyboard navigation or mouse
hover.
- Fix: Added a separate `set_hovered_index` hook to the `PickerDelegate`
trait with a default implementation that delegates to
`set_selected_index`. The hover handler in Picker now calls
`set_hovered_index` instead of `set_selected_index`. FileFinderDelegate
overrides `set_hovered_index` to update `selected_index` without setting
`has_changed_selected_index`, so hover-triggered selection changes no
longer interfere with the `Cmd+P` auto-confirm logic.
## Testing
- Added `test_hover_does_not_set_has_changed_selected_index` in
`file_finder_tests.rs`
## 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 file finder auto-jumping to the wrong file when the mouse
hovered over a different entry after pressing `Cmd+P`