1be046a007649761cdc20bf032191df8a87fddbd
5137
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a76b5fee01 |
Fix mouse multi cursor placement for wrapped lines (#61590)
Closes https://github.com/zed-industries/zed/issues/25237 https://github.com/user-attachments/assets/0f1d54a0-c8f1-4b49-8327-73375a2e1f4e Release Notes: - Fixed mouse multi cursor placement for wrapped lines --------- Co-authored-by: Finn Evers <finn@zed.dev> |
||
|
|
90483395af |
project: Fix panic when an inlay hint response outlives its buffer version (#61747)
# Objective Fix a nightly crash where Zed aborts on a bounds-check panic in the inlay hint cache. `LspStore::inlay_hints` captures a `RowChunk` before awaiting the language server, then reads the hint cache with that chunk's id afterwards. If the buffer shrank meanwhile, `latest_lsp_data` has already rebuilt the cache with fewer chunks, so the stale id indexes out of bounds. Chunks are 50 rows, so the reported crash only needed a ~150-250 line deletion, not a drastic edit. Regressed in #61523. Nightly only; the regressing commit is in no release tag, so this never reached preview or stable. Fixes ZED-AGY Fixes FR-142 ## Solution - Return an empty result when the buffer version no longer matches, so a stale chunk id can never index the rebuilt cache. The stale *writes* were already guarded by this version check; only the read sat outside it. - An empty result is already treated as "not fetched", so the chunk is simply re-requested on the next refresh. ## Testing `test_inlay_hint_response_after_buffer_shrinks` reproduces the abort deterministically and passes with the fix. Note that it drives the race through a fake language server rather than a real one. ## 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 |
||
|
|
aefad70496 |
Revert force hardmark settings for documentation hover (#61622)
Closes https://github.com/zed-industries/zed/issues/60777 # Objective - Due to #59426, forcing docString softmark to hardmark, an regression has appeared. It causes all docString on different language to load newLine (`\n`) by default, instead of soft wrap. - By checking the issue, turns out we should not setting `soft_break_as_hard_break: true`, this will make the hover docString less - Details can refer to #60777 ## Solution - Revert settings by removing the line in `hover_popover.rs:742` ## Testing - About the testing result and comparsion, you can refer to #60777 - Updated test `test_hover_markdown_preserves_soft_breaks` to `test_hover_markdown_soft_breaks_reflow_per_commonmark` ## 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 an issue where hover documentation could have too many line breaks. --------- Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com> |
||
|
|
55b2687062 |
editor: Check anchor validity for hovered links (#61686)
Closes FR-112 Otherwise, if a multibuffer snapshot changed under the hood for example one of the paths changed, without doing an explicit validity check, we would panic during comparison instead. Release Notes: - Fixed panic when hovering links during an under-the-hood multibuffer changes. |
||
|
|
0222e451f9 |
Fix: prevent completion labels and docs from being truncated (#61324)
# Objective - Fixes #60374 ## Solution - Moved the `documentation_label` from the `ListItem::end_slot` into the main `h_flex` layout alongside the `main_label`. - Added `.flex_shrink(1.0)` and `.truncate()` to the documentation container. - To allow it to shrink gracefully when space is tight. - Removed `.w_full()` from the main label's container. - To prevent it from aggressively occupying all available horizontal space, allowing the layout to balance the width between the label and the documentation. ## Testing - Visual and layout fixes tested manually by verifying the completion menu in `settings.json`. - All unit tests in the affected crate passed: `cargo test -p 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 ## Showcase ### Visual change <img width="813" height="314" alt="スクリーンショット 2026-07-20 143707" src="https://github.com/user-attachments/assets/1daa3fa4-a479-465a-b7fd-cc803242c8a2" /> --- Release Notes: - Fixed(CompletionsMenu): prevent completion labels and docs from being truncated. --------- Co-authored-by: Nathan Sobo <nathan@zed.dev> |
||
|
|
8a24015e4f |
editor: Skip untitled buffers when saving a multi-buffer (#61380)
Closes #60041. ## Summary When Project Search results contain both a saved file and an untitled buffer, running `workspace: reload` did nothing (quitting hit the same path). The log showed: ``` ERROR [.../workspace.rs] buffer doesn't have a file ``` ## Root cause The Project Search results view is an `Editor` over a multi-buffer, and its `Item::save` delegates to `Editor::save`. For a multi-buffer, `Editor::save` collects every dirty buffer and calls `Project::save_buffers`. An untitled excerpt has no file, so `BufferStore::save_buffer` returns `Err("buffer doesn't have a file")`. That error propagates through `Pane::save_item` → `save_all_internal` → `prepare_to_close`, which then reports the workspace as not ready to close, so `reload`/quit silently aborts. A singleton untitled buffer avoids this because `Editor::can_save` returns `false` for it (the workspace routes it to `save_as`); for a multi-buffer, `can_save` is always `true`. ## Fix Exclude file-less (untitled) buffers when collecting the buffers to save for a multi-buffer. Untitled buffers can only be written via `save_as`, so a bulk multi-buffer save now persists the file-backed excerpts and leaves untitled ones untouched. This also addresses the same latent issue in other multi-buffer views (diagnostics, find-all-references) that can excerpt an untitled buffer. ## Testing - Added `test_save_multi_buffer_with_untitled_buffer_skips_untitled` in `crates/editor/src/items.rs`: it builds a multi-buffer over a file-backed buffer and an untitled buffer (both dirty), then asserts `save` succeeds, the file-backed buffer is persisted, and the untitled buffer stays dirty. Fails before this change (`buffer doesn't have a file`), passes after. - `cargo test -p editor --lib save` (13 tests) and `cargo test -p search --lib project_search` (22 tests) pass. - `./script/clippy -p editor` is clean. Manual repro (before): new untitled buffer with text → Project Search for a term matching both it and a saved file → `workspace: reload` → no-op with `buffer doesn't have a file` in the log. After: reload proceeds. Release Notes: - Fixed `workspace: reload` and quitting silently doing nothing when Project Search results included an unsaved untitled buffer. |
||
|
|
76e43838aa |
editor: Fix sticky header drag cancels autoscroll (#53592)
In #52636 I seem to have introduced this bug, where mouse-down on a sticky header followed by an immediate mouse movements sometimes dropped the pending autoscroll request (to jump to the sticky header line): https://github.com/zed-industries/zed/blob/967ae5ea24376be68c41336fa0ff721f5ca5a3cf/crates/editor/src/scroll.rs#L453 Fixed by exiting early from `mouse_dragged` when `editor.has_autoscroll_request()`. What sometimes happened before this fix: https://github.com/user-attachments/assets/b6dd6650-b5f0-4ea1-ae70-9c4cf69e31a0 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 Release Notes: - Fixed bug where clicking on a sticky header would sometimes not jump to that line in the editor |
||
|
|
8d0742b017 |
Fix adding breakpoint/bookmark via gutter context menu using the wrong row (#59269)
# Objective Fixes #59265 ## Solution Use `display_point_to_anchor` to properly convert `DisplayRow` to `Anchor`, instead of manually constructing `Point` directly as done currently. ## Testing - Tested manually, see video in issue - Tested on windows ## 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 <details> <summary>Click to view showcase</summary> My super cool demos here </details> --- Release Notes: - Fixed the gutter context menu adding breakpoints/bookmarks to the wrong row in multibuffers. --------- Co-authored-by: dino <dinojoaocosta@gmail.com> |
||
|
|
0cc6d59389 |
Properly replace hints per each chunk (#61562)
Follow-up to hints part of https://github.com/zed-industries/zed/pull/61523 Instead of appending to the chunk data, we have to replace as we always get all hints for the entire chunk. Given that we order and invalidate the requests by `Version`, this can only happen when a racy requests from e.g. same file split or /refresh and edit etc. happens. Release Notes: - N/A |
||
|
|
9f1883fd4a |
editor: Fix crash when copying and pasting using multiple cursors (#61545)
Fixes a crash when copying and pasting a mixed empty/nonempty multi-cursor selection. `Editor::do_copy` is meant to insert a newline after each non-final selection that doesn't copy the entire line, but `prev_selection_was_entire_line` is currently based on the current selection instead of the previous one. `Editor::cut_common` does already correctly track this state across loop iterations. This can lead to an out of bounds crash when pasting because the indexing logic in `Editor::do_paste` relies on these newlines being added correctly, depending on `is_entire_line`. Repro: ``` foo bar ``` 1. select `foo` 2. option-click after `bar` to add an empty selection ``` «fooˇ» barˇ ``` 3. copy 4. paste ## 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 a crash when copying and pasting using multiple cursors. |
||
|
|
1db5b3ae06 |
project: Prevent empty external formatter output from clearing buffers (#61276)
## Context Zed runs external formatters as stdin/stdout filters: it writes the current buffer to stdin and replaces the buffer with the formatter's stdout. Commands such as `cargo fmt` instead rewrite files on disk and exit successfully without producing stdout, causing Zed to interpret the empty output as the formatted contents and clear a non-empty buffer. The fix treats empty stdout from a successful external formatter as no output when the original buffer is non-empty. Zed leaves the buffer unchanged and displays a notification explaining that the formatter did not return formatted contents. The formatter documentation now clarifies the stdin/stdout contract and recommends using the Rust language server or invoking `rustfmt` directly. Closes #56344 Behavior before the fix : [Screencast from 2026-07-19 02-58-29.webm](https://github.com/user-attachments/assets/61fc5bf9-4420-43f1-94a3-394bbbc4f2a0) Behavior after the fix : [Screencast from 2026-07-19 02-55-35.webm](https://github.com/user-attachments/assets/21062065-6b95-4cd4-8200-506f5681d98e) ## How to Review **crates/project/src/lsp_store.rs** Start with `format_via_external_command`, which now checks whether a successful formatter returned empty stdout while the input buffer was non-empty. In that case, it returns `None` before constructing a diff, preventing the buffer contents from being replaced with an empty string. Then review the external formatter branch in `apply_formatter`: when it receives `None`, it skips extending the formatting transaction, logs the condition, and emits an `LspStoreEvent::Notification` explaining why the buffer was left unchanged. **crates/editor/src/editor_tests.rs** Adds a GPUI regression test that configures an external command to consume stdin and return no stdout. It uses platform-specific commands for Windows and Unix, invokes manual formatting on a non-empty Rust buffer, and verifies that the buffer remains unchanged, the operation is not recorded as a formatter failure, and a notification is emitted. **docs/src/reference/all-settings.md** Extends the external formatter documentation to state that formatters must return the formatted buffer through stdout. It calls out file-rewriting tools such as `cargo fmt` as incompatible and recommends using the Rust language server or `rustfmt --emit stdout`. ## 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 external formatters that produce no output clearing non-empty buffers |
||
|
|
3c9a3d4176 |
editor: Preserve preview tabs for references multibuffers (#61021)
When `preview_tabs.enabled` and `preview_tabs.enable_preview_multibuffer_from_code_navigation` are enabled, Find All References opens its multibuffer as a preview tab. A references multibuffer is assembled from existing buffers, which may already contain edits when the preview is created. When creating the multibuffer to display the references, it ends up emitting edit events as excerpts are added, this will later cause `Pane::handle_item_edit` to run, which would see these buffer edits since `Buffer::preview_version` and unpreview the tab, as the `Buffer::preview_version` value was not being updated after edits. Refresh the multibuffer’s preview baseline before opening a newly created code-navigation multibuffer as a preview. Background diff updates then preserve the preview, while subsequent user edits still make it permanent. This leaves the existing editor event and search invalidation behavior unchanged. Release Notes: - Fixed `editor: find all references` preview tabs becoming permanent tabs if any of the buffers had been edited before --------- Co-authored-by: dino <dinojoaocosta@gmail.com> |
||
|
|
aa1fd6bff0 |
Calculate buffer chunks lazily (#61523)
<img width="1728" height="1084" alt="image" src="https://github.com/user-attachments/assets/a560b10a-6e26-43ff-b830-c528e2dc6798" /> Before, each edit in a 50 MB plaintext file would trigger a lot of anchor calculations (as chunk is 50 lines only) done on main thread + did extra work when no language grammar or brackets were available. The PR now moves all anchor calculations into `computed_chunks: Mutex<HashMap<usize, RowChunk>>,` cache miss. `TreeSitterData` is wrapped in `Arc` and shared as a part of the snapshot, hence the need for `Mutex` and internal mutability here. Trace after the changes: <img width="1728" height="1084" alt="image" src="https://github.com/user-attachments/assets/cb258980-8461-4559-b725-aef63c835e60" /> Release Notes: - Improved input performance in large files --------- Co-authored-by: Finn Evers <finn@zed.dev> |
||
|
|
336679c8e1 |
Fall back to file names in breadcumbs with LSP symbols (#61511)
Closes https://github.com/zed-industries/zed/issues/60905 Also makes the breadcrumbs to update on settings change — before, one needed to focus them. Release Notes: - Improved breadcrumbs for `"document_symbols": "on"` case when no LSP data is sent |
||
|
|
25632b979b |
language: Refactor available_languages into its own struct (#61388)
This adds a dedicated `AvailableLanguages` struct in preparation for a more cabable language matching based on a given language config. No functional changes, just shuffling some code around for this round. Also made the LanguageMatcher non-cloneable in favor of wrapping it in an Arc, since cloning is rather expensive for this and having a reference is sufficient in all cases right now. Release Notes: - N/A --------- Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com> |
||
|
|
97b51f2620 |
language: Fix JSON rainbow bracket colors across chunks (#60741)
## Context
JSON rainbow bracket colors could shift across row chunk boundaries when
large ancestor objects were omitted by the bounded tree-sitter bracket
query window. This fixes the chunk-local depth reset by caching bracket
chunk data together with the active bracket stack after each chunk, then
using that inherited stack when later chunks are computed. For JSON
object braces that are too large for the bounded query, the
implementation recovers active ancestor `{...}` pairs from the syntax
tree so sibling object braces keep the same color even when jumping
directly to a later chunk.
Closes #50185
## How to Review
`crates/language/src/buffer/row_chunk.rs` adds indexed access to row
chunks so bracket cache computation can walk from the nearest cached
chunk up to the requested chunk.
`crates/language/src/buffer.rs` changes bracket range caching from
storing only per-chunk matches to storing per-chunk matches plus the
active bracket stack after that chunk. It preserves the existing bounded
query and greedy-match repair behavior, while adding JSON-specific
ancestor recovery for large object braces omitted by
`MAX_BYTES_TO_QUERY`.
`crates/language/src/buffer_tests.rs` adds a JSON regression fixture
that exceeds `MAX_BYTES_TO_QUERY`, fetches a later chunk before earlier
chunks, and verifies all same-depth sibling object braces keep the same
`color_index` across row chunks.
Video of manual test below :
[Screencast from 2026-07-10
08-09-30.webm](https://github.com/user-attachments/assets/fca6425b-b79c-4097-b4af-148db6aa23d9)
## 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 JSON rainbow bracket colors changing across row chunk
boundaries.
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
|
||
|
|
756e764b90 |
project: Track inlay hint / code lens / document symbol registrations by ID (#55340)
extends the precedent set by #43703 (thanks @reflectronic) so that `textDocument/inlayHint`, `textDocument/codeLens`, and `textDocument/documentSymbol` correctly track multiple dynamic registrations by id. previously each register call overwrote the slot on `ServerCapabilities`, and unregister either silently did nothing (inlayHint, documentSymbol — no match arm) or wiped the entire capability (codeLens). now each method keeps its own id-keyed map on `DynamicRegistrations`; the field on `ServerCapabilities` is cleared only when the last registration is removed. textDocument-sync notifications (`didChange`/`didSave`/`willSave`) are deliberately out of scope — their fan-out semantics are ambiguous in the spec and were flagged on @smitbarmase's earlier exploration in #36876. verified with `cargo check -p project -p lsp -p editor`, `cargo test -p project --test integration -- multi_registration` (3/3 passing), and `cargo fmt -p project`. closes part of #37838. Release Notes: - Improved support for language servers that dynamically register inlay hints, code lens, or document symbols multiple times. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
81b67f4741 |
editor: Fix horizontal autoscroll only revealing part of search matches (#61487)
# Objective - While navigating between search matches with word wrap off via Select Next match and Select Previous Match, the horizontal autoscroll would sometimes fail to scroll the viewport enough to show the full searched word. This happened in both the cases of Previous match and next search till we had to come to the first appearance of the word. - Fixes #61409 ## Solution - In `/crates/editor/src/scroll/autoscroll.rs` the function `autoscroll_horizontally`, the scroll bounds were both being derived from `selection.head()`, I inferred that head is the position of the cursor at the end of the selection. But for the correct `start_column` and `end_column` it needs to depend not just on the cursor at the end. So rather than using the head for the calculation for both, I have calculated them using `selection.start` and `selection.end` directly to display pts. - Falling back to col 0 or the full line length when the start or end lies on different row than the current being processed. Now it scrolls enough to reveal the entire match. ## Testing - Did you test these changes? If so, how? 1. Ran full tests using `cargo test` on the full repository 2. Manual test present in the showcase section - How can other people (reviewers) test your changes? Is there anything specific they need to know? Disable word wrap, create a file with a short match near the start of a long unwrapped line and another match further right, search for it, and use Select Next/Previous Match to jump between them. The full match should scroll into view each time. - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? Tested on macOS Tahoe 26.5.2 ## 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 - [ ] Performance impact has been considered and is acceptable ## Showcase https://github.com/user-attachments/assets/ace25b26-560d-47f1-a905-f04879f23f15 --- Release Notes: - Fixed horizontal autoscroll not fully revealing search matches when navigating between matches with word wrap disabled. |
||
|
|
cbe92a9c1a |
snippets: Strip path separators from language snippet file names (#61421)
Closes #59620 ## Problem A language whose name contains a `/`, such as a custom `PL/X` extension (`lsp_id` → `pl/x`), broke snippets end to end: - The `snippets: configure snippets` action wrote the file to `~/.config/zed/snippets/pl/x.json`, i.e. inside a `pl/` subdirectory. - The snippet scanner reads `snippets/` non-recursively and skips directories, so that file was never loaded and the snippet could never be used. - The completion lookup keyed off the raw `lsp_id` (`pl/x`), which wouldn't have matched the file-stem key even if the file had been scanned. So Zed's own UI created a snippet file it could never read back. ## Fix Add `LanguageName::snippet_scope_id()` (the `lsp_id` with `/` and `\` removed) and use it everywhere a language maps to its snippet file name or lookup key: - the Configure Snippets writer and its "already configured" label, and - the two completion lookups in `editor`. `PL/X` now maps to a flat `plx.json`, as suggested in the issue. The `editor::InsertSnippet` action is intentionally left unchanged: its `language` field is documented to be the snippet file name stem, which is already separator-free. Note: files created under the old behavior (nested `foo/bar.json`) aren't migrated; re-running Configure Snippets writes the corrected flat file. ## Testing - Added a `language_core` unit test asserting `snippet_scope_id()` strips `/` and `\` (e.g. `PL/X` → `plx`). - `cargo test -p language_core` passes. - `./script/clippy -p language_core -p language` passes. - Docs Prettier passes. Release Notes: - Fixed snippets being unusable for languages whose name contains a `/` character |
||
|
|
7dc8071ac8 |
Add wrapper type for language servers in settings (#61398)
This is in preparation for making configuration of language servers more comfortable for users/extensions. Release Notes: - N/A |
||
|
|
cb68afbd2b |
Respect disabled trailing whitespace removal (#58776)
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 #58686 Release Notes: - Fixed `.editorconfig` re-enabling trailing whitespace removal when Zed settings disable it. --------- Co-authored-by: Martin Ye <martin@zed.dev> |
||
|
|
aa2a4211a3 |
editor: Treat single punctuation as a word boundary (#58882)
## Context `next_word_end` and `previous_word_start` have a special case that skips a punctuation character so that word movement treats the punctuation as a part of the word (`|.foo` -> `.foo|`). But the check only looked at whether the next char was punctuation, not whitespace, so it skipped single punctuation marks. foo |. bar -> foo . bar| (should be `foo .| bar`) Fix: only skip the punctuation when it's next to a word char. Closes #55601 ## How to Review In any buffer, type `foo . bar`: - Cursor before `.`, alt-right -> stops after the `.` (`foo .| bar`), not at the end of `bar`. - Cursor after `.`, alt-left -> stops before the `.` (`foo |. bar`). ## 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 word movement skipping single punctuation characters surrounded by whitespace. --------- Co-authored-by: Martin Ye <martin@zed.dev> Co-authored-by: MartinYe1234 <52641447+MartinYe1234@users.noreply.github.com> |
||
|
|
24058c8659 |
editor: Fix right-click context menus failing to appear at pixel-snapped scroll positions (#61348)
# Objective Fixes #56136. The issue was initially reported while an agent was generating code. Later reports reproduced it during manual editing and with AI disabled, ruling out the agent as the cause. At fractional display scales, the editor's right-click context menu could fail to appear at specific discrete scroll positions. Scrolling one line at a time could make the menu alternate between hidden and visible, even when its anchor remained within the viewport. ## Solution The editor-specific changes in #54728 started pixel-snapping the vertical scroll position used by `EditorElement` to derive and render visible rows. However, `Editor::display_to_pixel_point` continued using the raw scroll position for its visibility check and vertical projection. When a downward pixel snap crossed an integer display-row boundary, `EditorElement` treated the preceding row as the visible range start. `display_to_pixel_point` then rejected that row as being above the raw viewport. Mouse context menu layout returned early before inspecting the actual clicked anchor, leaving the menu state present without rendering its element. This change applies the same line-height and display-scale pixel snapping in `display_to_pixel_point`. Its visibility check and coordinate projection now use the coordinate space actually rendered by the editor. A test-support-only scale-factor setter was also added so GPUI tests can exercise fractional display scaling without depending on the host display. ## Testing Added a GPUI regression test using 100 plain-text lines so the editor can scroll. The test uses a `1.25` scale factor and a `14px` font with `1.3` relative line height. The resulting `18.2px` line height is rounded to `18px`, producing exactly `22.5` device pixels per row. At a raw scroll position of one row, midpoint-toward-zero snapping maps `22.5` device pixels to `22`, or approximately `0.978` rows. This reproduces the old boundary mismatch where the snapped visible range starts at row zero while the raw visibility check starts at row one. The test pins these values with precondition assertions. Row five and an in-bounds click keep the actual source visible, while checking the rendered bounds of the `Copy` item ensures the test does not pass merely because menu state was created. Manually verified that scrolling from the start of a document no longer makes the context menu alternate between hidden and 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 ## Showcase Before: https://github.com/user-attachments/assets/e14c030f-1587-4172-aed2-fecfbfcb65ed After: https://github.com/user-attachments/assets/3080db1e-46eb-4e20-a619-b1608f233668 --- Release Notes: - Fixed editor right-click context menus intermittently failing to appear at certain scroll positions. |
||
|
|
9cbae806f2 |
editor: Do not reserve inline blame scroll width when blame is in the status bar (#61422)
## Problem When `git.inline_blame.location` is `status_bar` (anything other than `inline`), nothing is painted inline at the end of the line — yet the horizontal scroll range still reserves the longest row's inline blame width (introduced in #23374), letting the editor scroll into blank space when a line is long enough to scroll. Reported in #24752 (e.g. @Nemesis19's comment: still reproduces with `location: status_bar`). ## Fix Skip the blame width reservation in the scroll range when the blame location isn't `Inline` — one guard in the `longest_line_blame_width` closure in `element.rs`. This is independent of the soft-wrap fix for #24752 (#61319) and can land on its own. ## Test `test_status_bar_blame_location_reserves_no_scroll_width` asserts that, with a long line and no soft wrap, moving blame from inline to the status bar shrinks the horizontal scroll range (the reservation is dropped). It uses a fixed-width test `BlameRenderer`, since the default test renderer returns `None` and never exercised the reservation. Release Notes: - Fixed inline git blame reserving horizontal scroll space even when blame is displayed in the status bar |
||
|
|
df5d437085 |
Disable LSP for files with very long lines (#61447)
Release Notes: - Fixed ui stutters when opening large single line files like minified javascript due to running LSP requests against them |
||
|
|
185c6986da |
Add gutter action to clear run status (#61375)
# Objective Add a way to manually clear completed run statuses from the gutter. Folow-up to #61095 This follows up on feedback from the previous gutter run status PR. Currently, editing a file clears run statuses automatically, but there was no direct way to clear a completed status without changing the file. ## Solution - Added a `Clear Run Status` entry to the gutter context menu. - Show the entry only when the row has a completed run status. - Clear the stored run status for that runnable when selected. - Keep running statuses unchanged, so this does not behave like task cancellation. ## Testing - Ran `cargo check -p editor`. - Manually ran a test from the gutter and waited for a completed status. - Verified right-clicking the gutter icon shows `Clear Run Status`. - Verified selecting `Clear Run Status` clears the status icon. - Verified the action is not shown for rows without a completed run status. ## 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 [after.webm](https://github.com/user-attachments/assets/1ae284e1-03b1-4842-a63e-9d66c290b325) --- Release Notes: - Improved gutter run statuses by allowing completed statuses to be cleared from the gutter context menu. |
||
|
|
b7e1f5026b |
editor: Disable gutter breakpoint and bookmark actions in unsaved buf… (#61310)
## Context Closes #58818 Breakpoints and bookmarks are keyed by a buffer's absolute file path. In an unsaved (untitled) buffer there is no worktree file, so both `BreakpointStore::toggle_breakpoint` and `BookmarkStore::toggle_bookmark` early-return and do nothing. The gutter still offered the affordances, so clicking (or cmd-clicking) the gutter hover button, or picking an entry from the gutter right-click menu, silently did nothing. Rather than support these actions on unsaved buffers, this hides them: the gutter hover button and the gutter context menu are both suppressed for buffers without a worktree file, matching the store-level eligibility check (`project::File::from_dyn(...).is_some()`). The buffer is resolved per row via `anchor_to_buffer_anchor`, so multibuffers with a mix of saved and unsaved excerpts behave correctly. Manual test after the changes : [Screencast from 2026-07-19 18-46-26.webm](https://github.com/user-attachments/assets/d1fe6704-3843-49bb-bcd6-d84ecdd4f19d) ## How to Review **`crates/editor/src/element/mouse.rs`** In the gutter hover-button computation in `mouse_moved`, the existing `anchor_to_buffer_anchor(...).is_some()` guard is tightened to also require the resolved buffer to have a worktree file. When the row belongs to an unsaved buffer the button state stays `None` and the debounce task is never armed, so the add-breakpoint/add-bookmark button no longer appears. This is the single writer of `gutter_hover_button`, and it recomputes on every mouse move, so a buffer that later gets saved picks up the button again immediately. **`crates/editor/src/editor.rs`** `set_gutter_context_menu` now binds the multibuffer snapshot once, computes the effective anchor, and returns early when that anchor's buffer is not file-backed, so no menu is opened. This is the shared choke point for all three ways the menu can open (gutter background right-click, breakpoint-marker right-click, bookmark-marker right-click), so every store-backed entry (Set/Unset Breakpoint, log/condition/hit-condition, Enable/Disable, Add/Remove Bookmark, Edit Bookmark, Run to Cursor) and the file-meaningless Git Blame entry are all suppressed together. `gutter_context_menu` itself is unchanged. **`crates/editor/src/editor_tests.rs`** Adds a shared `build_gutter_hover_test_editor(saved)` helper that builds either a saved-file editor or an untitled-buffer editor (via `Project::create_buffer`), plus small helpers that draw the window and simulate a mouse move / right-click over row 0 of the gutter hitbox. Four tests cover both surfaces on both buffer kinds: `test_gutter_hover_button_shown_for_saved_buffer` / `test_gutter_hover_button_hidden_for_unsaved_buffer` (asserting the hover button state and its activation debounce), and `test_gutter_context_menu_shown_for_saved_buffer` / `test_gutter_context_menu_hidden_for_unsaved_buffer` (asserting `mouse_context_menu` opens only for the saved buffer). The saved-buffer tests act as positive controls so the negative tests cannot pass vacuously. ## 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 the gutter offering breakpoint and bookmark actions in unsaved buffers, where they could not take effect |
||
|
|
8c1364c8ca |
Fix toggling diagnostics off not allowing to toggle them back (#60963)
# Objective This change fixes an issue where once a single file has had it diagnostics disabled, it will permenently make re-enabling diagnostics in that specific file, no longer possible by either command or keybind. This fixes issue #60958. ## Solution This solution is quite simple. The logic used for registering the action in the editor used a one way flip. The editor read the `cx` and then checked its `diagnostics_enabled()` and `inline_diagnostics_enabled()` and if they were disabled they would not register the corrosponding `Editor::toggle_diagnostics` and `Editor::toggle_inline_diagnostics` respectively. This meant once toggled off, the editor was no longer able to register the action as it was already disabled, and thus made the "toggle" part impossible. The fix simply removes the state checks for the current editor and will leave the actions registered. ## Testing This has been both manualy tested as well as had an `editor_tests.rs` test added. Simply taking in the the `EditorTestContext`, then checks the starting state, then toggles the diagnostics off and checks that it correctly shows the state change, and then proceeds to re-enable the diagnostics state, and check its again to make sure the appropriate state has been set. I manually tested this on windows_11_x64/x86(Desktop), archlinux_7.0.10_x64/x86(Laptop), and it has **not** been tested on my mac mini **yet**. However, the change 'should' be platform agnostic. If someone wants to review this, they can simply open their settings file with the JSONC lsp `on` and then disable their diagnostics and then, the option to re-enable them, toggle, will now show up and also be able to be executed by the keybinds too. ## 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) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase <details> <summary>Click to view showcase</summary> Original Behaviour: [Zed Diagnostic Toggle (Original Behaviour).webm](https://github.com/user-attachments/assets/bca860cd-f7e9-42b9-9456-56b9b1d2604f) New Behaviour: [Zed Diagnostic Toggle (New Behaviour).webm](https://github.com/user-attachments/assets/e3629491-abb5-4e29-95ab-e8f0464db726) </details> --- Release Notes: - Fixed `editor::ToggleDiagnostics` & `editor: toggle diagnostics` permanently turning off diagnostics for the current file/editor, addressing issue #60958. --------- Signed-off-by: Counterfit IQ <logicye@proton.me> Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
298b3e8d7b |
Open relative file links at line numbers (#61006)
## Summary - Open relative file links with GitHub-style line fragments at the referenced line - Support line navigation from agent responses and Markdown previews - Preserve decoded-first path resolution with literal percent-escape fallback ## Testing - cargo test -q -p util test_source_line_from_fragment -- --nocapture - cargo test -q -p acp_thread test_hyperlink_percent_escapes_are_decoded -- --nocapture - cargo test -q -p agent_ui test_open_link -- --nocapture - cargo test -q -p markdown_preview -- --nocapture - cargo fmt --all -- --check Release Notes: - Improved relative file links with line numbers to open at the referenced line. |
||
|
|
8b8c03e3fb |
Improve bogus brackets filtering (#60364)
Closes https://github.com/zed-industries/zed/issues/59298 Left — before, right — after: <img width="1604" height="1001" alt="Screenshot 2026-07-03 at 19 45 45" src="https://github.com/user-attachments/assets/cc43b639-8fbe-4951-9da8-4b1e9482ca39" /> Release Notes: - Fixed incorrect rainbow brackets highlights in certain cases |
||
|
|
32adc59cb7 |
Surround selection with backticks in Rust, C, and C++ comments (#58674)
Typing a backtick over selected text in Rust, C, and C++ comments replaced the selection instead of wrapping it. Markdown already supports this via its backtick bracket pair. Add a backtick bracket pair for these languages: - `surround = true` wraps selections in backticks - `close = false` avoids auto-closing lone backticks - `not_in = ["string"]` enables it in comments but not strings 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](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 #58538 Release Notes: - Added support for surrounding selected text with backticks in Rust, C, and C++ --------- Co-authored-by: dino <dinojoaocosta@gmail.com> |
||
|
|
78dde3c78d |
editor: Place added cursors by tab-expanded column (#61153)
with `hard_tabs: true` and `tab_size: 4`, shift-alt-down off a
tab-aligned column drops the cursor in the wrong spot:
```
current.rgb.r ˇ= p[0] >> 8; <- cursor here
residuals[run].rˇgb.r = p[0] & 0xff; <- lands here, not on the =
```
both `=` render at column 48 but sit at buffer columns 22 and 27, since
a different number of tabs pads each row. shift-alt-down is
`skip_soft_wrap: true`, which placed the cursor by utf16 column where a
tab counts as one.
so count the column with tabs expanded instead. still a column and not a
pixel position, so the buffer-column behaviour
`test_add_selection_skip_soft_wrap_option` pins doesn't change (without
tabs the expanded column *is* the buffer column). tried pixels first and
it breaks that test, since x is measured inside a wrapped segment.
heads up that the existing tests here all pass `Default::default()`,
which is `skip_soft_wrap: false` (the `default_true` only applies to
deserializing), so nothing covered the branch the keybinding actually
uses.
Closes #60752.
Release Notes:
- Fixed added cursors landing in the wrong column when using tabs to
align code
|
||
|
|
0d67b1a7ff |
search: Fix toggle soft wrap not working while the search bar is focused (#61150)
Closes #34698 The buffer search query input is itself an editor, so dispatching `editor::ToggleSoftWrap` from the command palette while the search bar had focus toggled soft wrap on the single-line query editor (with no visible effect) and never reached the searched editor. This intercepts the action on the search bar in the capture phase and applies it to the active searchable item, the same way `ToggleFoldAll` is already relayed. Focus stays in the search bar, so you can keep typing your query. `Editor::toggle_soft_wrap` and `Editor::soft_wrap_mode` become `pub` (matching `fold_all`/`has_any_buffer_folded`, which the existing `ToggleFoldAll` relay already uses). Includes a regression test that fails without the fix: it deploys the search bar, dispatches `ToggleSoftWrap` with the query editor focused, and asserts the searched editor's wrap mode changes while focus remains in the search bar. Release Notes: - Fixed `editor: toggle soft wrap` doing nothing when invoked while the buffer search bar was focused --------- Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com> |
||
|
|
5f865ffd69 |
Show runnable task results in gutter (#61095)
# Objective - Make runnable task results visible directly in the editor gutter after running a test or task. - This makes it easier to see whether the last run passed or failed without looking at the terminal output. ## Solution - Track the completion result for scheduled runnable tasks. - Show the last runnable result in the gutter: - running task: accent play icon - successful task: success check icon - failed/cancelled task: error icon - Apply the same status update path when running from the gutter play button and from inline code lens actions such as `Run Test`. ## Testing - Ran `cargo check -p editor -p workspace`. - Ran `cargo test -p workspace test_schedule_resolved_task_with_completion_reports_success`. - Manually tested running a GPUI test from the gutter play button. - Manually tested running a GPUI test from the inline `Run Test` code lens. - Verified the gutter icon updates after completion in both cases. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon] (https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase Before: <img width="1897" height="691" alt="before" src="https://github.com/user-attachments/assets/614c2811-ee0a-43c0-8619-d0301836aa62" /> After: <img width="1897" height="691" alt="after" src="https://github.com/user-attachments/assets/a3db19f2-71e6-4c9b-824d-43a4f020a6b7" /> --- Release Notes: - Improved runnable tasks by showing the last run result in the editor gutter. |
||
|
|
fcd85e1bfb |
git_ui: Show full files by default in solo diffs (#60989)
# Objective Make solo diff views show the full file by default while preserving an easy way to focus on changed hunks. This addresses a recurring request across issues and pull requests for full-file context in single-file Git diffs. ## Solution - Initialize the solo diff with a singleton multibuffer so the entire file is visible on open. - Keep the existing toolbar toggle available for switching to changes-only excerpts. - Use the singleton path key when replacing excerpts so toggling remains reliable. - Preserve Git change indicators in the scrollbar; the editor generates those markers for singleton buffers. ## Testing - Ran `cargo fmt -p git_ui`. - Ran `git diff --check`. - Ran `cargo check -p git_ui --no-default-features` successfully. - Manually reviewed the full-file and changes-only state transitions in `SoloDiffView`. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase Before, solo diffs opened with only changed hunks and surrounding context. They now open with the complete file, retain Git change indicators in the scrollbar, and can still be toggled to changes-only from the toolbar. --- Release Notes: - Improved solo diffs to show the full file by default while retaining Git change indicators in the scrollbar. |
||
|
|
2d06fded9c |
Revert "editor: Add language detection for untitled buffers (#61201)" (#61351)
This reverts commit
|
||
|
|
a98c7e2fa8 |
editor: Add language detection for untitled buffers (#61201)
# Objective Closes #4868. Untitled buffers start as Plain Text and require users to select a language manually before receiving syntax highlighting. Add lightweight automatic language detection for code entered or pasted into untitled buffers. ## Solution This builds on [Max Stevens's earlier language-detection work](https://github.com/zed-industries/zed/pull/43057), replacing Magika with [Betlang](https://github.com/DioxusLabs/betlang). While researching smaller and faster alternatives to Magika, I came across Betlang, a recently introduced language detection library developed by DioxusLabs for dioxus-code. The fact that it comes from DioxusLabs gave me more confidence in evaluating this relatively new dependency for Zed. Betlang embeds an approximately 50 KB model, is MIT-licensed, and depends only on `fearless_simd`, making it well suited to Zed's cross-platform embedding requirements. Detection runs on the background executor with bounded input sampling. It is restricted to untitled buffers, skips content shorter than 20 bytes, and requires at least 50% confidence. These limits have worked well in local testing. 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. ## Testing I added a test for language detection in untitled buffers that covers both manually entered and pasted content. The test passes successfully. I also manually tested the feature to verify that the overall experience works well. ## 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/96e28ad7-2968-4325-9aff-37fe813a2da7 --- Release Notes: - Added automatic language detection for untitled buffers. --------- Co-authored-by: Max Stevens <maxstevens2708@gmail.com> |
||
|
|
9005ced680 |
vim: Fix selection motions when trailing newline is selected (#61253)
# Objective Closes #41743 When selecting text on the last line, excluding the trailing newline, Vim and Helix modes behave differently from native Vim and Helix when the file has a trailing newline: 1. We cannot use `l` (move right) to include the final `\n` in the selection, while native Vim and Helix allow this. 2. By default, the rendered cursor should appear on the selected character. When that character is the final `\n`, however, Zed renders the cursor on the synthetic empty line after it rather than at the end of the preceding line. This differs from native Vim and Helix, as well as from Zed's behavior for newlines elsewhere in the file. 3. When the final `\n` is selected, it affects subsequent selection motions, as reported in #41743. The cause is several special-case guards for trailing newlines in Visual and Select modes. These guards exist in the cursor rendering logic: https://github.com/zed-industries/zed/blob/73523ec50bafcdab9308fa51808bef074ae898bc/crates/editor/src/element.rs#L201-L213 They also exist in the Visual motion logic for Vim mode and the Select motion logic for Helix mode (the Helix implementation was adopted directly from Vim in #43234): https://github.com/zed-industries/zed/blob/73523ec50bafcdab9308fa51808bef074ae898bc/crates/vim/src/visual.rs#L254-L259 Finally, they exist in the selection extension logic for Vim and Helix (the Helix logic was also adopted from Vim): https://github.com/zed-industries/zed/blob/73523ec50bafcdab9308fa51808bef074ae898bc/crates/vim/src/visual.rs#L273-L284 These guards cause trailing-newline selections to behave inconsistently with selections containing newlines elsewhere in the file. ## Solution Remove all the guards mentioned above, including those in cursor rendering, Visual and Select motions, and selection extension. And due to the cursor rendering logic is also changed, an exsisting test is updated. After removing these guards, I could not reproduce the unexpected behavior described in the existing comments: https://github.com/zed-industries/zed/blob/73523ec50bafcdab9308fa51808bef074ae898bc/crates/vim/src/visual.rs#L247-L253 The only remaining difference is that, when the cursor is on the last line in Visual mode, pressing `j` moves it to the final `\n` rather than to the synthetic empty line after it. In comparison, native Vim and Helix do nothing in this case. ## Testing - Built and tested locally. - Added new GPUI tests. ## 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: - Improved Vim Visual and Helix Select modes when selections include a trailing newline. |
||
|
|
0ccd4b7613 |
editor: Fix opaque multibuffer header backgrounds not rendering in transparent themes (#61268)
# Objective As part of the transparent-window artifact fixes in #58981, multibuffer header backgrounds stopped rendering whenever the window was transparent or blurred. This caused a regression for transparent themes, which commonly use an opaque multibuffer header background to prevent editor text from showing through sticky headers. ## Solution Render `editor_subheader_background` when either the window or the configured background color is opaque. This restores opaque multibuffer header backgrounds as a mask for the editor content beneath them, while preserving the #58981 behavior for translucent backgrounds that would otherwise create a darker layered region. ## Testing Manually verified locally with a transparent theme that an opaque multibuffer header background is rendered and prevents editor text from showing through sticky headers. ## 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 **Nightfox - opaque / blurred** Before: <img width="2566" height="1771" alt="图片" src="https://github.com/user-attachments/assets/55b333bc-b029-4079-9bbc-86462a3f41a7" /> After: <img width="2444" height="1687" alt="图片" src="https://github.com/user-attachments/assets/217e1ee7-717c-4961-8db0-5eac8104e5bb" /> --- Release Notes: - Fixed editor text showing through multibuffer headers and overlapping header text in transparent themes. |
||
|
|
f839ff93ed |
editor: Reduce allocations during editor prepaint (#61290)
Found some unnecessary allocations and an `.unwrap()` while working on a separate issue. The PR makes no behavior changes and should be trivial to review. ## Testing All tests pass. These changes are not expected to change any behavior. None of the changes are interleaving, so it should be easy to review top-down. Reasoning for each change can be read from individual commit messages. Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
67341c7d9e |
editor: Fix Git blame gutter width with avatars (#61287)
# Objective When using column Git blame with avatars enabled, blame entries whose author name is the longest in the buffer can exceed the blame border. For example, line 10 of `crates/vim/src/visual.rs` is displayed as follows: <img width="998" height="121" alt="issue" src="https://github.com/user-attachments/assets/eff3e1ff-bd1c-42af-ae9b-da8efb0a7c22" /> The blame contents exceeds the width. The root cause is in the blame width calculation: https://github.com/zed-industries/zed/blob/4feae499a62c4ab971a47dfbbd0667e944322ee1/crates/editor/src/editor.rs#L11583-L11598 The calculation accounts for the commit SHA, author name, and timestamp. Other elements, including spacing, margins, and the avatar, are represented by the fixed `SPACING_WIDTH` constant. For typical fonts, `ch_advance` is approximately `0.5rem` to `0.6rem`, so `SPACING_WIDTH` provides approximately `2rem` to `2.4rem` for non-text content. However, the avatar itself occupies `1rem`: https://github.com/zed-industries/zed/blob/4feae499a62c4ab971a47dfbbd0667e944322ee1/crates/ui/src/components/avatar.rs#L81 When avatars are displayed, the entry also contains three `0.5rem` gaps and also one `0.5rem` right margin: https://github.com/zed-industries/zed/blob/4feae499a62c4ab971a47dfbbd0667e944322ee1/crates/git_ui/src/blame_ui.rs#L170-L188 This requires approximately `3.0rem`, which can exceed the space provided by `SPACING_WIDTH`. When an entry contains both the longest author name in the buffer and a long timestamp, its content can therefore exceed the blame border. ## Solution The simplest fix would be to increase `SPACING_WIDTH`, but that would still rely on an approximate conversion between editor character widths and UI dimensions. Instead, this PR adds a method to the blame renderer for calculating the non-text width of a blame entry. The editor uses this value together with the measured text width when calculating the final blame width. ## Testing Tested locally. A before-and-after comparison is included 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) 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 | Before | After | | :--: | :--: | | <img width="551" height="94" alt="Before" src="https://github.com/user-attachments/assets/b6741a41-6531-4fae-adaa-f9ae0b298e0f" /> |<img width="566" height="93" alt="After" src="https://github.com/user-attachments/assets/e8d75d2a-6b07-43f6-b2a8-bfb76d118611" /> | Release Notes: - Fixed Git blame entries overflowing the gutter when avatars are displayed. |
||
|
|
a07c26f03a |
editor: Fix line selection disappears when the cursor goes off screen (#60054)
# Objective
When you make a line selection in a row that is long enough to multiple
lines long while wrapped the selection box will disappear when the
cursor (or just origin of the line selection goes off screen).
## Solution
The when you are in line selection mode the `SelectionsCollection` just
enables `line_mode`, instead of storing the whole ranges of those line
selections, so the Anchor of the selection is a single point.
`disjoint_in_range` filters all the disjoint selections of the
collection to fit inside some range, this is used to render the
selection boxes on screen. `disjoint_in_range` had no special case for
`line_mode` causing it to filter on the point instead of the bounds of
the selection.
My fix is too add a case for `line_mode` that changes the filtering
`Anchor` -> `Point` and then only filters on the row. Then use the
proper bounds of the selection with that:
```rust
let (start_ix, end_ix) = if self.line_mode {
let start_row = range.start.to_point(buffer).row;
let end_row = range.end.to_point(buffer).row;
let start_ix = self
.disjoint
.partition_point(|probe| probe.end.to_point(buffer).row < start_row);
let end_ix = self
.disjoint
.partition_point(|probe| probe.start.to_point(buffer).row <= end_row);
(start_ix, end_ix)
} else {
...
```
## Testing
Before:
https://github.com/user-attachments/assets/a443de39-53d7-4ee4-b3af-d3be99ca1fcf
After:
https://github.com/user-attachments/assets/18c1c7ef-45cc-4dc8-9a8b-241252c376ab
I also added some tests `disjoint_in_range_line_mode_matches_whole_row`,
being the one that really tests this behavior. the other two are just
for `disjoint_in_range`
I am using macOS 27.0 Beta (26A5368g), but I noticed this bug before
upgrading.
## 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:
- editor: Fixed bug where selection boxes wouldn't render when the
cursor was offscreen.
|
||
|
|
1625b90fd1 |
Preserve Markdown emphasis delimiters when joining lines (#61298)
# Objective When joining lines, Zed checks the next line and strips comment, documentation-comment, and unordered-list delimiters. The logic trims whitespace from these delimiters, then checks whether the next line starts with the trimmed delimiter. If it does, Zed removes the delimiter before joining the lines. This works for comment and documentation-comment delimiters, where trailing whitespace does not affect their meaning. However, it causes unexpected behavior for unordered-list delimiters, which, as far as I know, are unique to Markdown. In Markdown, `* ` is an unordered-list marker, while `*` is also used as an emphasis delimiter, such as `*italics*` and `**bold**`. The current logic strips the leading `*` from these emphasis cases, which it should not. ## Solution For unordered-list delimiters, Zed should strip the exact delimiter, such as `* `, rather than the trimmed `*`. It should strip a bare `*` only when the next line contains only `*`. ## Testing Tested locally and new GPUI tests were added. ## 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 markdown emphasis delimiters being removed when joining lines. |
||
|
|
78652e2f50 |
Fix several small performance inefficiencies in hot paths (#61275)
# Objective Land five small, independent performance fixes found during an audit of hot paths (anchor resolution, line shaping, worktree scanning, and sorting in multibuffers). ## Solution Each fix is its own commit, so **this PR is best reviewed commit-by-commit** — every commit message contains the full reasoning for that change: - `text`: Avoid redundant rope traversal in `Anchor → usize` conversion — call `offset_for_anchor` directly instead of `summary_for_anchor`, which recomputed the same byte offset with ~4 extra O(log n) tree walks. This is the hottest anchor-resolution path. - `editor`: Avoid double allocation per shaped line — `line.as_str().into()` instead of `line.clone().into()`, which allocated twice per visible line, every frame. - `text`: Use `sort_unstable_by_key` in operation queue insertion — Lamport timestamps are unique keys and duplicates are deduped right after, so stability buys nothing. - `multi_buffer`: Sort with an explicit comparator instead of `sort_unstable_by_key`, which cloned a `PathKey` (`Arc` refcount bump) on every comparison. - `worktree`: Replace O(n²) `Vec::remove` in the deferred-directory pass with an O(1) `None` assignment — the vec is already `Vec<Option<ScanJob>>` and is consumed with `.flatten()`. ## Testing - No behavior changes intended; all changes are mechanical and tests affected crates pass: `text`, `editor`, `multi_buffer`, `worktree`. ## 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: - Improved editor performance through several micro-optimizations in anchor resolution, line shaping, and worktree scanning. |
||
|
|
37d372036d |
git: Add possibility to open specific line in a diff using the CLI (#45499)
this pr enables opening a specific line in a diff using zed's cli Release Notes: - refactor: add possibility to open specific line in a diff using the cli --------- Co-authored-by: Cole Miller <cole@zed.dev> |
||
|
|
728cb247e9 |
buffer_diff: Canonicalize ambiguous hunk placement to fix staging corruption (#60584)
Closes #60424 ## Problem With the repro from #60424, staging the first deletion hunk marked the second deletion as staged in the UI even though git still had it unstaged, and clicking the (incorrectly shown) Unstage button inserted a duplicate copy of the hunk's contents into the git index on every click. The root cause is ambiguous hunk placement. The committed text contains repeated `end\n\n` line runs, so the deletion hunks can "slide": more than one placement produces a minimal diff. The uncommitted diff (HEAD vs worktree) anchored the remaining deletion at one row while the unstaged diff (index vs worktree), recomputed after the partial stage, anchored the same logical deletion at a different row. Everything that correlates hunks across those two diffs assumes they agree on positions: - the secondary-status matching in `hunks_intersecting_range_impl` found no unstaged hunk at the uncommitted hunk's rows and reported it as staged (`NoSecondaryHunk`); - the worktree→index projection in `compute_uncommitted_index_edits` treated the hunk's position as unchanged text and, on unstage, inserted the hunk's HEAD content at an index position that already contained it, duplicating it on every request. ## Fix Upgrade `imara-diff` from 0.1.8 to 0.2.0 and run `Diff::postprocess_lines` (imara-diff's port of git's xdiff slider/indent heuristic) after computing hunks in `buffer_diff`. This canonicalizes the placement of ambiguous hunks based only on their local content, so diffs of the same buffer against different base texts anchor the same logical change at the same rows. A bonus is that Zed's hunk placement now matches `git diff`'s output for such cases (git has used the indent heuristic by default since 2.11). As defense in depth, `compute_uncommitted_index_edits` now drops a pure-insertion index edit whose content is already present at the target position, so a stale secondary status can no longer duplicate index content. The imara-diff 0.2 API removed the `Sink` trait and the top-level `diff()` function, so the other call sites (`language/text_diff.rs`, `zeta_prompt/udiff.rs`, `edit_prediction_metrics/reversal.rs`) are migrated mechanically to `Diff::compute` + `hunks()` with unchanged behavior (0.2 also renamed `lines_with_terminator` to `lines` and changed the default `&str` tokenization to include terminators; the unified-diff builders keep terminator-less tokens via `str::lines()`). ## Testing - New regression test `test_staging_hunks_with_ambiguous_placement` replays the exact repro from #60424 (same file contents): stages the first deletion, asserts the remaining hunks keep their unstaged status and the index matches exactly, then issues repeated unstage requests for the unstaged hunk and asserts the index is unchanged. Before the fix this test showed the second hunk flipping to staged and the index growing by one copy of the deleted block per unstage request. - `buffer_diff`, `language`, `zeta_prompt`, `edit_prediction_metrics`, `multi_buffer`, `git_ui`, `editor`, and the `project` integration suite pass. - One test expectation updated: `editor::test_fold_function_bodies` asserted the old placement of an ambiguous deletion (blank line before comment); the canonicalized placement (comment before blank line) matches what `git diff` produces for the same texts. Release Notes: - Fixed staging a hunk sometimes marking a different hunk as staged (and subsequent unstaging corrupting the git index) when the diff contained repeated lines ([#60424](https://github.com/zed-industries/zed/issues/60424)). --------- Co-authored-by: Cole Miller <cole@zed.dev> |
||
|
|
641daf4f8c |
editor: Fix Shift-click selection after cursor movement (#61045)
## Context Shift-click sometimes extended a selection from an earlier word boundary after double-clicking a word and moving the cursor with the arrow keys. Cursor movement changed the selection but left the word or line selection mode active, so the next Shift-click reused stale selection bounds. Selection movement now resets the mode to character mode whenever it changes the selection, while preserving valid empty line selections that have not been moved. Closes #59913. Behavior before the fix : [Screencast from 2026-07-15 13-21-51.webm](https://github.com/user-attachments/assets/c126adfe-f9db-4a04-91c2-6db6e8070182) Behavior after the fix : [Screencast from 2026-07-15 13-19-38.webm](https://github.com/user-attachments/assets/19c9f5b6-aaf8-4e8b-b4c5-70327411d1b9) ## How to Review **`crates/editor/src/selections_collection.rs`**: `MutableSelectionsCollection::move_with` now resets the selection mode to character mode when movement changes a selection. **`crates/editor/src/editor_tests.rs`**: Regression tests cover Shift-click after collapsing a word selection and confirm that a valid empty line selection retains line-wise extension behavior. ## 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 Shift-click sometimes extending selections from a previous word or line boundary. |
||
|
|
7eaddbc5d9 |
editor: Blink cursors only in the focused editor (#61086)
Every editor associated with a window observed window activation. The handler enabled the blink manager for every editor, including hidden and unfocused editors. Their independent 500 ms timers invalidated the window out of phase and caused redundant full-window presents. Window activation and deactivation are already represented as focus transitions by GPUI: an inactive window has an empty effective focus path. Remove the redundant activation observer and rely on the editor focus and blur handlers to stop blinking on deactivation and restart it only for the editor that owns focus on activation. In a 40-second idle diagnostic run before this change, the steady-state tail repeatedly contained invalidations from one or two editors per frame. After the change, no unfocused-editor invalidations appeared. Bounded scrollbar fades and visible activity animations remain unchanged. Add a regression test with focused and unfocused editors that covers activation, deactivation, and reactivation. Release Notes: - Fixed cursors blinking in unfocused editors, reducing idle redraws. --------- Signed-off-by: Daan De Meyer <daan@amutable.com> |
||
|
|
d54b7d693b |
editor: Preserve non-breaking whitespace during rewrap (#59893)
## Objective Prevent rewrap from breaking at whitespace that Unicode classifies as non-breaking. The original approach, prompted by #59664, treated every non-ASCII whitespace character as unbreakable. Unicode classifies `U+2009 THIN SPACE` as breakable and `U+202F NARROW NO-BREAK SPACE` as its non-breaking counterpart. ## Solution - Treat `U+00A0 NO-BREAK SPACE`, `U+2007 FIGURE SPACE`, and `U+202F NARROW NO-BREAK SPACE` as part of the surrounding word - Keep thin spaces, em spaces, and other Unicode breaking spaces as line-break opportunities - Cover all three non-breaking whitespace variants in tokenizer and wrapping tests ## Testing - `cargo test -p editor rewrap::tests` Release Notes: - Fixed rewrap breaking lines at non-breaking spaces. --------- Co-authored-by: Nathan Sobo <nathan@zed.dev> |
||
|
|
919ec316f3 |
search: Add LSP location pickers for references, definitions, and diagnostics (#59838)
# Objective Closes #59829 Provide a filterable, preview-backed picker for LSP results as an alternative to the multi-buffer view, for references, definitions, implementations. ## Solution Update the 3 existing LSP actions (definitions, implementations, find all references) to add a `open_results_in` parameter which accepts either `multi_buffer` (default) or `picker` to show the results in a filterable picker with preview. This behavior can be configured globally in the settings via `lsp_results_location`. UX: - The 3 existing LSP actions each accept a `open_results_in` parameter so that each action can be configuring individually with a custom keybind - The `lsp_results_location` global setting can be used to set a default behavior with `open_results_in == None` - Go to definition falls back to find all references (if configured) on empty results which is consistent with the non-picker path - Results are grouped by file; each row shows the line number and the syntax-highlighted source line with the match emphasized. - Typing filters by line text or path; the preview updates with the selection. - Enter/click opens the selection, `cmd/ctrl-enter` opens it in a split, and re-invoking the command toggles the picker closed. - Empty results show a toast so the command never silently does nothing. - Note: the new pickers do not open on cmd-click, only when invoked via the command palette or keybind ## Testing - No automated tests yet — holding for first-round feedback on the approach and UX before adding tests. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] 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 - [ ] Performance impact has been considered and is acceptable ## Showcase https://github.com/user-attachments/assets/41538f23-9b54-4dfc-bfa7-a61564a675a8 --- Release Notes: - The find all references, go to definitions, and go to implementations LSP actions can be configured to open results in a picker with preview instead of a multibuffer. |