main
5299
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fe62a99bf5 |
gwen: Purge remaining Zed branding from user-facing surfaces
Sweep every user-visible product string to Gwen: app menus (Quit, Hide, Gwen Repository), feedback links (repo/issues now point at github.com/kk376/zed, email to yenru@yrkaierx.com), move-to-Applications and update dialogs, provider and settings copy, CLI help, installer and desktop/flatpak/snap/plist metadata. Rename user-facing settings values with back-compat aliases: base_keymap "Gwen" (accepts "Zed"), fonts ".GwenMono"/".GwenSans" (accept ".ZedMono"/".ZedSans"), icon theme "Gwen (Default)". Fix F10 app-menu keymap arguments to "Gwen" and align the Windows installer AppMutex with release_channel::app_identifier(). Internal identifiers, wire protocol names, upstream service URLs and legal attribution are intentionally kept. |
||
|
|
8e29ede557 |
editor: Paint block cursor text upon arrival during animation (#64521)
Follow-up to #63195. # Objective When `cursor_animation` is enabled, moving a block cursor (e.g. in Vim mode) leaves the character underneath hidden until the spring animation fully finishes, after which the letter pops in. This happens because `CursorLayout::paint` returned early while animating, skipping `block_text`. ## Solution Paint `block_text` upon the animated cursor's arrival at the target cell, rather than waiting for the entire spring settling phase to complete: - Check if any animated corner has reached the target bounds (`bounds.dilate(...)`). - If the cursor is still in mid-air, return early so we don't draw the destination letter prematurely. - Once it touches the target cell, fall through and paint `block_text` over the cursor polygon. ## 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 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 Left: before, Right: after https://github.com/user-attachments/assets/7057f40a-64a7-4035-b8e2-7c0b7dc40069 --- Release Notes: - Fixed an issue where the block cursor hid the character underneath until cursor animation completed. --------- Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com> |
||
|
|
a596e1b294 |
Speedup completions test (#64464)
Follow-up to https://github.com/zed-industries/zed/pull/64139 Fixes CI flacks like https://github.com/zed-industries/zed/actions/runs/35351932842/job/105623037967?pr=64405#step:15:7107 Halve the test runtime by avoiding the entire `MultiWorkspace` creation and redraws. Release Notes: - N/A |
||
|
|
108fd3ac11 |
editor: Fix vertical scroll margin calculation (#63944)
# Objective - Fixes an issue where setting an arbitrarily high `Vertical Scroll Margin` fails to perfectly lock the cursor in the center of the viewport (Typewriter Mode?). In certain cases one could go up/down a line before auto-scroll gets triggered, deviating from user intent. - Fixes #63862 ## Solution - **The Issue:** When `Vertical Scroll Margin` is very high, the effective margin applied above and below the cursor is derived from the viewport's free space: ```rust ((visible_lines - (target_bottom - target_top)) / 2.0).floor() ``` - **The Fix:** Instead of using the same rounded number for both the top and bottom margins, calculate them separately: 1. The top margin stays the same as before. 2. The bottom margin is calculated by subtracting the top margin from the total free screen space. - This ensures the bottom margin automatically catches whatever fraction the floor operation on the top margin drops, so the two margins always sum to the full available space. ## Testing - Did you test these changes? If so, how? Ran `cargo test -p editor`, all passed. I've also attached the results of manual testing in the Showcase section below. ## 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)](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)](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 and after screen recording <details> <summary>Click to view showcase</summary> **Before:** https://private-user-images.githubusercontent.com/63847494/646999418-4dd388b8-4aba-4004-ac4f-6f1e0dad0f70.mp4?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3ODg5MTE3MTUsIm5iZiI6MTc4ODkxMTQxNSwicGF0aCI6Ii82Mzg0NzQ5NC82NDY5OTk0MTgtNGRkMzg4YjgtNGFiYS00MDA0LWFjNGYtNmYxZTBkYWQwZjcwLm1wND9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjA5MDglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwOTA4VDIzNTAxNVomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWRhZGM5MWExMDkyMDIzZjVlYjcxYmQ4YTRmOTM3MDliNDcyOTUzZjFhYmY1ZTgwMDY0YzhlYmQ1NzllYWYyN2EmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JnJlc3BvbnNlLWNvbnRlbnQtdHlwZT12aWRlbyUyRm1wNCJ9.DG6RpiEM-781ZctlvtQeWhw3kAYJ4KS6rNsAmMU38fg **After:** https://github.com/user-attachments/assets/4bf870e0-84ba-449a-bf2a-925c4a90d5ed </details> Release Notes: - Fixed the cursor not staying perfectly centered when using a high Vertical Scroll Margin (Typewriter Mode). --------- Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com> |
||
|
|
5428eb8399 |
editor: Fix cursor animation across width and scroll changes (#64184)
Follow-up to #63195. This PR fixes the cursor animation problems reported in [this comment](https://github.com/zed-industries/zed/pull/63195#issuecomment-5662566417): - Block cursors snapped instead of animating when moving between characters with different display widths, such as an ASCII character and an emoji or CJK character. - Cursor animation disappeared near the top and bottom scroll margins when keyboard navigation triggered vertical autoscrolling. The first issue happened because any cursor geometry size change was treated as a reason to snap. Cursor movement now retargets the animation when either the rectangle position or size changes, while geometry changes without a logical cursor move still snap immediately. The second issue happened because every viewport change cleared the active animation. Scroll-only viewport changes now translate the current and target corner positions, as well as the previous target geometry, by the scroll pixel delta before retargeting. This preserves the spring's motion and velocity across autoscroll. Actual layout changes, including text-area size, line height, and font advance changes, continue to snap. Regression coverage includes: - Both narrow-to-wide and wide-to-narrow cursor transitions, including convergence to the new rectangle. - Cursor movement in both directions while the viewport scrolls. - Scrolling during an active animation without clearing its position or velocity. - Layout changes that must still snap. - An editor-level keyboard autoscroll test using a vertical scroll margin of 3. Validation: - `cargo test -p editor cursor_animation --lib` - `cargo fmt --all --check` - `cargo build -p zed --bin zed --profile release-fast` - Manual verification with the release-fast binary Release Notes: - Fixed cursor animations when moving between characters of different widths and during keyboard-triggered autoscrolling. --------- Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com> |
||
|
|
9f1587c697 |
editor: Fix columnar selection coordinates (#63723)
Closes #63712 ## Summary - Use tab-expanded grapheme columns for Add Selection Above/Below when `skip_soft_wrap` is enabled, rather than UTF-8 byte offsets or Unicode scalar counts. - Keep mouse rectangles pixel-based and preserve logical selection goals across short rows, direction changes, and selection/text undo and redo. - Reconcile columnar groups when selections change, while preserving committed groups during cancellable mouse previews. - Batch source and destination queries by row and skip fully replaced input rows without a persistent row cache. - Handle folds, inlays, and replacement blocks with small map-query additions, and fix the tab bitmap boundary at a tab size of 128. ## Validation - Full editor library suite: 1,109 passed, one ignored. - Editor Clippy and scoped formatting passed. - Regression checks failed without the corresponding lifecycle and batching fixes, then passed with them restored. - The three related sync/history tests were rerun and passed after the final callback-variable renames. Release Notes: - Fixed columnar selections landing in the wrong column around non-ASCII text, tabs, soft wraps, and collapsed content. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> Co-authored-by: Kirill Bulatov <mail4score@gmail.com> |
||
|
|
9a606bc84c |
editor: Render point diagnostics without glyphs (#63933)
Closes #63084. Zed already normalizes most empty and line-terminator-only diagnostic ranges onto an adjacent character. A diagnostic can still remain a true point when its position has no glyph, such as column zero of an empty line or an empty file. The shaped-text path has no `TextRun` at that position, so the diagnostic appears in diagnostic UI but has no editor squiggle. Render only diagnostics that remain zero-width after ingress as a one-em wavy underline at their `DisplayPoint`. This keeps the stored LSP range unchanged, uses the existing diagnostic underline policy and font metrics, and also paints the decoration in a pinned sticky-header copy when an anchored point survives an edit. ## Evidence ### Empty Go file with gopls Before: <img width="471" height="430" alt="Empty Go file before the fix: diagnostic message without a squiggle" src="https://github.com/user-attachments/assets/a7f29dd3-a16c-43ea-a53f-d0264efb4ce0" /> After: <img width="471" height="430" alt="Empty Go file after the fix: diagnostic message with a point squiggle" src="https://github.com/user-attachments/assets/0546970a-e24e-4e15-a764-d548291eb623" /> `gopls` reports `expected ';', found 'EOF'` at `(0,0)..(0,0)` for the empty file. The diagnostic message is present in both builds; only the patched build paints the point squiggle. Sticky-header behavior was also verified with a deterministic stdio LSP. Before/after recordings are included in the review response below. ## Validation - `cargo test -p editor point_diagnostic` - `cargo test -p editor test_point_diagnostic_stays_in_edited_excerpt` - `cargo test -p editor test_point_diagnostics_follow_expanded_deletions` - `cargo test -p project test_empty_diagnostic_ranges` - `cargo test -p project test_diagnostic_range_spanning_line_terminator` - `cargo fmt --all -- --check` - `CCACHE_TEMPDIR=/tmp/zed-ccache-tmp ./script/clippy -p editor -p gpui -p multi_buffer -p project` - `git diff --check` - Manual before/after verification with gopls on an empty Go file - Manual before/after verification of a retained point diagnostic in a sticky header - Manual Fedora verification of physical overlap handling with `.ZedMono` and proportional Jomolhari text Regression coverage also includes retained point diagnostics across edited excerpt boundaries and expanded deleted diff hunks at the beginning, middle, and EOF, including an empty live buffer, plus painted-span severity arbitration for point-vs-range and point-vs-point overlaps. Release Notes: - Fixed missing editor underlines for language server diagnostics at positions without underlying text. - [GPUI] N/A --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> Co-authored-by: Kirill Bulatov <mail4score@gmail.com> |
||
|
|
69a09e1c5e |
editor: Expand excerpts from deleted diff hunks (#63946)
# Objective Fixes #62278. Allow `editor: expand excerpts` from deleted text in unified diffs. ## Solution - Resolve cursor and selection ranges against the current snapshot, including deleted hunks. - Preserve half-open selection boundaries and include trailing empty excerpts at EOF. - Skip removed paths during expansion. ## Testing Regression coverage includes deleted-hunk cursors and selections, stale paths, selections ending at excerpt boundaries, and trailing empty excerpts. The boundary and EOF cases cover all three expansion directions. The Bookmarks action case uses `excerpt_context_lines: 0`. The new boundary and EOF regressions failed before the fix and passed afterward. - `cargo test --locked -p editor -p multi_buffer --lib`: 1026 editor tests and 67 multibuffer tests passed; 1 ignored. - `./script/clippy -p editor -p multi_buffer`: passed. - `cargo fmt --all -- --check`: passed. - `git diff --check origin/main..HEAD`: passed. Automated testing ran on Linux. The first full run hit a SQLite table lock in `persistence::tests::test_save_and_get_serialized_editor`. The isolated test and full rerun passed. ## Self-Review Checklist: - [x] I have reviewed my own 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 new behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Fixed excerpt expansion when the selection is on deleted text in unified diffs --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
2f10cba7c6 |
editor: Honor lsp_results_location on cmd-click (#64039)
# Objective Fixes #62916. With `"lsp_results_location": "picker"`, `cmd-b` opens the LSP locations picker but cmd-clicking the same symbol still opens a `Definitions for …` multibuffer. #61187 fixed this for the go-to-definition *fallback*; the definition path itself was left behind. The setting is only consulted by `handle_nav_action` in `lsp_locations`, which runs when one of the navigation *actions* is dispatched. Cmd-click never dispatches them: `cmd_click_reveal_task` either navigates the cached hover links itself, or calls `go_to_definition_of_kind` / `go_to_type_definition` directly. ## Solution Both cmd-click paths now dispatch the matching action (`GoToDefinition`, `GoToTypeDefinition`, …) when `lsp_results_location` is `picker` and the click is not a split one, so the picker gets its chance; everything else is untouched: - with the default `multi_buffer` setting `picker_action` returns `None` and the old code runs unchanged; - alt (split) clicks keep their current behavior, since the split actions have no picker handler; - URL and file links keep opening directly — the action is only dispatched when every resolved link is a `HoverLink::Text`. The dispatch is deferred to after the current editor update via `cx.spawn_in`: `LspLocationsPicker::open_for_editor` reads the editor, so dispatching inline panics with `cannot read editor::Editor while it is already being updated` (this is also why the existing fallback dispatch happens from a spawn). ## Testing `cargo test -p lsp_locations` — two new tests, one per cmd-click path: a cold cmd-click, and a cmd-click on a link already resolved by hovering with the modifier held (the path users actually hit). Both fail on `main` with the fix reverted and pass with it. Also ran `cargo test -p editor --lib hover` (68 passed) and `cargo clippy -p editor -p lsp_locations --all-targets`. Not yet verified by hand in a running Zed build — the automated tests above are what backs this. ## 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 cmd-click on a symbol ignoring the `lsp_results_location` setting: with `"picker"` it opened a definitions multibuffer instead of the picker that `cmd-b` opens ([#62916](https://github.com/zed-industries/zed/issues/62916)). --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
b84803f56f |
Fix insertion modes for completions without edit ranges (#64139)
Closes https://github.com/zed-industries/zed/issues/64118 https://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 |
||
|
|
8b9a2df705 |
Share application adapter implementations (reduce LLVM IR bloat again) (#64262)
Move settings-update routing, fallible deserialization recovery,
selection effects, context-menu initialization, picker resize handles,
and ACP client setup into shared implementations. Inline the small
button callback adapters.
`cargo llvm-lines --locked -p settings_ui`:
Before (
|
||
|
|
82a076e3ab |
editor: Fix gutter tooltip modifier hint (#64124)
# 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. |
||
|
|
fde3e42be8 |
editor: Allow customizing CodeLens text color (#64084)
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> |
||
|
|
aac4829c4d |
Add action parameter comment_empty_lines for editor::ToggleComments (#63961)
# Objective - Fixes: https://github.com/zed-industries/zed/issues/60738 - Re-iteration of https://github.com/zed-industries/zed/pull/63918 with suggested changes ## Solution - Added the parameter `comment_empty_lines` to `editor::ToggleComments` set to `false` by default. ## Testing - Tested manually. See showcase below. - Added two automated tests for the added feature. - 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 ## References The action's behavior was observed across Emacs, VSCode, and Intellij, and the corresponding keymaps were set accordingly. https://github.com/user-attachments/assets/36c1a27a-357c-468a-b56b-59ef31265329 https://github.com/user-attachments/assets/de755753-9de1-4771-980f-177810fb85ef https://github.com/user-attachments/assets/c8ecd261-2bba-4345-89f4-c1d708d8b6d2 ## Showcase Below is the screen recording of these three tests: 1. Behavior of toggling comments when `comment_empty_lines` is `true`. 2. Switching the parameter value to true after commenting a block and un-commenting the same block does not re-comment the block due to an empty line in between. 3. Menu bar item is still present, albeit it's behavior is mapped to the default value of the parameters of the bound action, instead of what is inside the keybindings file. This (bug?) was present even before. See the attached clip below. 1. https://github.com/user-attachments/assets/a9cd2a2c-437b-41a3-bd8e-c4c3a1f350cd 2. https://github.com/user-attachments/assets/4bbfb77c-9019-410e-9d0a-952d4438d2a7 3. https://github.com/user-attachments/assets/ca300e2d-2106-4bb7-865b-5d2ab89cd0f2 https://github.com/user-attachments/assets/ec1e47b6-ff99-461e-93af-af925be4d914 --- Release Notes: - Added `comment_empty_lines` parameter to `editor::ToggleComments` for multiline selections. Use `["editor::ToggleComments", {"comment_empty_lines": true}]` to comment blank lines too (default for Zed keymap now), or `["editor::ToggleComments", {"comment_empty_lines": false}]` to skip them (default for VSCode keymap). --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
4ee80bcbbb |
lsp: Handle dynamic registration of textDocument/documentHighlight (#63029)
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> |
||
|
|
3af83d6d0b |
Support commands in inlay hints (#63605)
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 |
||
|
|
66a1d8d7cb |
Support LSP command executions and showDocument requests (#63607)
Closes https://github.com/zed-industries/zed/issues/13756 Closes https://github.com/zed-industries/zed/issues/61572 Last window client capability we were missing! <img width="1557" height="159" alt="image" src="https://github.com/user-attachments/assets/2cca5d92-a28e-4262-8f55-89f582782bbc" /> Two features are connected to each other, as most of the commands result in opening a document: https://github.com/user-attachments/assets/661aae88-7af9-4173-9f6a-2fd11dbec675 Release Notes: - Added support for LSP command executions and showDocument requests |
||
|
|
5df18ff955 |
editor: Skip multi-cursor selection broadcast when unshared (#60605)
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 |
||
|
|
bcf8c7bee7 |
Fix crash in Editor::rotate_selections using cursors on nonconsecutive lines (#63937)
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. |
||
|
|
a6b3c5b33d |
Fix block-comment prefix stripping when joining lines (#63916)
Closes https://github.com/zed-industries/zed/issues/63273#issuecomment-5580302020 https://github.com/user-attachments/assets/0945d43d-9a19-4af6-bc85-c3369d8babb3 Release Notes: - Fixed block-comment prefix stripping when joining lines |
||
|
|
153405b4cb |
editor: Preserve the trailing newline when converting case (#63463)
# 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. |
||
|
|
326a5f026a |
editor: Add optional cursor movement animation (#63195)
# 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> |
||
|
|
b536d5369d |
editor: Keep deleted git-gutter marker visible at small custom widths (#63434)
# 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. |
||
|
|
8482496a16 |
lsp: Honor dynamic LSP document selectors (#59243)
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> |
||
|
|
cdee8dd547 |
Properly clear diagnostics data for stopped servers (#63460)
# 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> |
||
|
|
74f3fa1454 |
Support Emmet's wrap with abbreviation (#63383)
Closes https://github.com/zed-industries/zed/issues/15588 https://github.com/user-attachments/assets/2813d235-6dac-4fe6-9ae0-2783e16270ac Release Notes: - Added Emmet's wrap with abbreviation support |
||
|
|
24f9172064 |
editor: Fix completion menu label overlapping documentation text (#63581)
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 |
||
|
|
aecaacdb44 |
git: Move diff hunk operations onto buffer diffs (#63556)
# 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 |
||
|
|
29a2ce8d46 |
editor: Limit row highlight expansion to viewport (#63395)
## 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. |
||
|
|
7ea8eb3f2e |
Support CSV preview in project-less set-ups (#63350)
Closes https://github.com/zed-industries/zed/issues/63265 Release Notes: - Fixed CSV preview not showing in project-less set-ups |
||
|
|
b6490c5fbd |
Stop re-resolving editorconfig sections on every language settings lookup (#63323)
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 (
|
||
|
|
77d716d5ce |
Keep first match selecting during type on search (#63375)
Follow-up to https://github.com/zed-industries/zed/pull/62506 Before: https://github.com/user-attachments/assets/19f6f0df-c5e3-417e-a351-13a09ccb726b After: https://github.com/user-attachments/assets/0b302ed7-a98d-4db4-81bc-d67f5cc7db87 * Fixes type on search not selecting the very first result as the regular search does. * Unifies the flicker freezing state better in the editor Release Notes: - N/A |
||
|
|
6dc2206180 |
Reduce LLVM IR bloat in closure funnels (#63426)
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 |
||
|
|
9cdbece495 |
Normalize ranges returned by language servers in more cases (#63372)
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`. |
||
|
|
f64d69fec6 |
Ensure that multibuffer anchor ordering is stable over time and consistent with resolution (#62636)
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>
|
||
|
|
513ad12cef |
Avoid redundant string allocations (#63377)
Remove unnecessary intermediate `String` allocations when constructing `Arc<str>` and `SharedString` values. Use static `SharedString` storage for fixed worktree picker identifiers. Validation: - `cargo fmt --all -- --check` - `tooling/lints/single-lint owned_string_into_shared -p editor -p git_ui_core -p toolchain_selector` - `cargo test -p editor -p git_ui_core -p toolchain_selector` Release Notes: - N/A |
||
|
|
951357a916 |
editor: Add language detection for untitled buffers (#61412)
# 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> |
||
|
|
a0608b889d |
feat: Add reveal buffer if already open (#63306)
# 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> |
||
|
|
8a54abc4b9 |
Improve outline fonts and colors (#63325)
Closes https://github.com/zed-industries/zed/issues/58580 * Outline modal and panel now use buffer fonts for the contents: <img width="1728" height="1117" alt="modal" src="https://github.com/user-attachments/assets/5e0ef6e3-be39-4949-bc32-7087a51a02ec" /> <img width="1728" height="1092" alt="panel" src="https://github.com/user-attachments/assets/5cf9edbf-5ff3-402d-a2ca-bc915bd10e8e" /> * Gutter colors are now fall-backed to tree-sitter better, if no semantic tokens could be retrieved due to multi buffer shenanigans: <img width="1728" height="426" alt="gutter" src="https://github.com/user-attachments/assets/a175b2c8-843e-4632-b030-3edfbd350982" /> Release Notes: - Improved outline fonts and colors |
||
|
|
bb3b7953fe |
editor: Auto-refresh Bookmarks tab when bookmarks change (#56363)
[## 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> |
||
|
|
c684a6a537 |
Add LSP call hierarchy modal (#53239)
<img width="1128" height="953" alt="image" src="https://github.com/user-attachments/assets/b2017c0a-e25a-49d7-9342-d074014d085c" /> Closes #14203 Release Notes: - Initial Call Hierarchy support in Zed --------- Co-authored-by: Alexey Olshanskiy <gh@aohoy.dev> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
09440c85cb |
lsp: Add client support for LSP 3.18 markdown diagnostic messages (#61030)
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/#diagnosticClientCapabilities https://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> |
||
|
|
22a582a86a |
Remove wasted clones of loop-invariant values (#62763)
# 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 |
||
|
|
b16d08d473 |
gpui: Fix stale pending input when a window is blurred (#63271)
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 |
||
|
|
3ba893e4ac |
editor: Add file permalink support to tabs and the Project Panel (#62177)
# 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> |
||
|
|
918e494e61 |
Improve auto indentation in situations with multiline comments present (#61669)
## Objective Fix incorrect indentation after multiline comments and when pasting multiline code immediately after a comment. Fixes #61668 Fixes #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-f868b9f31272 https://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. |
||
|
|
f36284a155 |
Bump dependencies to dedupe the crate graph (#63231)
Deduplicates crates with different versions from the graph, drops unused features. `cargo tree -d duplicate` listing: 160 -> 112 lines. <details> <summary>Deduplicated list</summary> ``` base64 (v0.22.1, v0.21.7 -> v0.22.1) convert_case (v0.11.0, v0.10.0, v0.8.0 -> v0.11.0, v0.10.0) core-foundation (v0.10.0, v0.9.4 -> v0.10.0) cssparser (v0.36.0, v0.35.0 -> v0.37.0, v0.36.0) fancy-regex (v0.18.0, v0.16.2 -> v0.19.0) fixedbitset (v0.5.7, v0.4.2 -> v0.5.7) h2 (v0.4.12, v0.3.27 -> v0.4.12) heck (v0.5.0, v0.4.1, v0.3.3 -> v0.5.0, v0.4.1) html5ever (v0.39.0, v0.35.0 -> v0.39.0) hyper (v1.7.0, v0.14.32 -> v1.7.0) hyper-rustls (v0.27.9, v0.24.2 -> v0.27.9) mach2 (v0.6.0, v0.5.0, v0.4.3 -> v0.6.0, v0.5.0) markup5ever (v0.39.0, v0.35.0 -> v0.39.0) phf (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3) phf_codegen (v0.13.1, v0.11.3 -> v0.13.1) phf_generator (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3) phf_macros (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3) phf_shared (v0.13.1, v0.12.1, v0.11.3 -> v0.13.1, v0.11.3) prost (v0.12.6, v0.9.0 -> v0.14.4) prost-build (v0.12.6, v0.9.0 -> v0.14.4) prost-derive (v0.12.6, v0.9.0 -> v0.14.4) prost-types (v0.12.6, v0.9.0 -> v0.14.4) rustix (v1.1.4, v0.38.44 -> v1.1.4) rustls (v0.23.40, v0.21.12 -> v0.23.40) rustls-native-certs (v0.8.3, v0.6.3 -> v0.8.3) rustls-pemfile (v2.2.0, v1.0.4 -> v2.2.0) rustls-webpki (v0.103.13, v0.101.7 -> v0.103.13) security-framework (v3.5.1, v2.11.1 -> v3.5.1) socket2 (v0.6.3, v0.5.10 -> v0.6.3) string_cache (v0.9.0, v0.8.9 -> v0.9.0) string_cache_codegen (v0.6.1, v0.5.4 -> v0.6.1) strum (v0.28.0, v0.27.2 -> v0.28.0) strum_macros (v0.28.0, v0.27.2 -> v0.28.0) tendril (v0.5.1, v0.4.3 -> v0.5.1) tokio-rustls (v0.26.4, v0.24.1 -> v0.26.4) tungstenite (v0.28.0, v0.27.0 -> v0.28.0) web_atoms (v0.2.6, v0.1.3 -> v0.2.6) which (v6.0.3, v4.4.2 -> v8.0.5) ``` </details> Release Notes: - N/A |
||
|
|
677e8174b5 |
Flush all persistence threads for the rest for various shutdown cases (#63213)
Follow-up to https://github.com/zed-industries/zed/pull/60477 Closes #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> |
||
|
|
6c6673e4a5 |
Fix shallow diffs causing a lot of computations (#63024)
For repositories with shallow mode enabled, before, Zed instantly loaded diff changes which could be very large and CPU-demanding: https://github.com/user-attachments/assets/5577730a-efef-424f-b749-501394a8b51f Now, we show the following state instead of loading: <img width="1728" height="1084" alt="after" src="https://github.com/user-attachments/assets/03cc47fe-7074-4e8b-ba12-2fefa101377d" /> (the button allows to move on and do the load nonetheless) Release Notes: - Fixed shallow diffs causing a lot of computations --------- Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de> |
||
|
|
28c7f0cd8e |
Enable project search on type by default (#62506)
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) |