77d716d5ce67fbbef35bc76fa968737539365bda
2773
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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`. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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) |
||
|
|
5a4473f92a |
editor: Repaint gutter immediately when bookmarks change (#62847)
Closes #61005 The bookmark store notified on every change, but nothing was listening. Editors only repainted their bookmark icons because the toggle actions happened to notify the editor directly - so workspace::ClearBookmarks, which never touches an editor, left stale icons in the gutter until something else caused a repaint. Now editors observe the bookmark store, so any change repaints them. This also fixes toggling a bookmark in one split not updating another split showing the same file. Release Notes: - Fixed bookmarks not disappearing from the gutter immediately when running `workspace::ClearBookmarks`. |
||
|
|
5d473cc6af |
editor: Prevent auto save formatting on read only files (#62921)
# Objective Read-only marked files in zed could still be affected by format on save feature. This PR fixes that. FIXES #62899 ## Solution These changes add an early return on Editor's `Item::save` implementation so neither formatting nor the write to disk occurs. ## Testing I've tested by reproducing the issue in the original ticket. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Fixed read-only files being formatted and saved when `format_on_save` is enabled --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
1829879ca1 |
workspace: Persist recent navigation history across sessions (#55034)
Saves the recent navigation history (up to 20 entries) to the workspace DB so it survives restarts. When reopening a workspace, persisted paths that resolve to the current project are merged into the file finder's history, deduplicated against files already opened in the session. https://github.com/user-attachments/assets/3d8934e1-0da6-4445-8f3d-acc5597d7ac8 Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes: https://github.com/zed-industries/zed/issues/56271 Release Notes: - Improved file finder history to include recently opened files from previous sessions. |
||
|
|
459fe185a4 |
editor: Add in_preview boolean context for keybindings (#61777)
# Objective - Add an `in_preview` context that is available when the current editor is in preview mode (opened from project panel or go to definition). - closes https://github.com/zed-industries/zed/discussions/61765 ## Solution - In `editor.rs`, added a check in `key_context()` that detects if the editor is the active preview item in its pane, and if so, adds `"in_preview"` to the key context. - Uses existing `workspace.pane_for_item_id()` and `pane.is_active_preview_item()` methods — no new APIs introduced. ## Testing - Added two tests in `editor_tests.rs`: - `test_in_preview_context_added_when_in_preview_mode` — verifies `in_preview` is present when editor is set as preview item. - `test_in_preview_context_not_added_when_not_in_preview_mode` — verifies `in_preview` is absent for regular (non-preview) tabs. - Tested on Linux. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Added `in_preview` keybinding context for when an editor is in preview mode. |
||
|
|
c1dab7a0d3 |
Support blaming parent revisions (#62614)
Closes https://github.com/zed-industries/zed/discussions/42583 Adds more tooltip entries and `editor::BlameRevision`, `editor::BlamePreviousRevision` actions to use. Started to highlight gutter blame entries that belong to currently annotated commit. https://github.com/user-attachments/assets/ba754e0b-6431-407c-8d79-2f8b0324fde1 Release Notes: - Supported blaming parent revisions |
||
|
|
a5234566b4 |
editor: Treat blank rename as no-op (#62630)
Confirming an inline rename after deleting the entire symbol name or entering only whitespace currently submits an invalid rename request to the language server. This can remove the symbol text instead of leaving the source unchanged. Treat empty and whitespace-only replacements as successful no-ops after dismissing the inline rename UI. Returning a completed task also consumes the confirmation action, preventing Enter from propagating back into the editor. Non-blank rename behavior remains unchanged. The regression test covers both empty and whitespace-only rename fields, verifying that no LSP rename request is sent and the original buffer remains intact. Release Notes: - editor: Fixed confirming a blank symbol LSP-rename modifying the source code |
||
|
|
dda3143f2c |
editor: Align selections by display position instead of byte column (#61997)
# Objective Fixes #60192 Closes https://github.com/zed-industries/zed/issues/62308 `editor: align selection` lines cursors up by their buffer column, and that column counts bytes. If a multi-byte character sits before the cursor, the byte column is larger than the position the cursor is actually drawn at, so the row gets padded with the wrong number of spaces. The issue reports it with `←` (3 bytes) and `π` (2 bytes): ``` a ← 1 # one bc ← π # two ``` Put a cursor on each `#`, run the action, and the result is still misaligned: ``` a ← 1 # one bc ← π # two ``` This is not the columnar selection bug fixed in #57097. That one was `select_columns` in `selection.rs`, where the output is a selection range. This one is `align_selections` in `editor.rs`, where the output is inserted spaces, so the same byte-column assumption was left behind in a second place, and fixing it here needs a rounding step that the first fix did not. ## Solution Measure each cursor by its x offset in the laid-out display row (`DisplaySnapshot::x_for_display_point`), take the target for a column as the furthest x across the rows, then turn the difference into whole spaces by dividing by the advance width of `' '`. The offset that carries into later columns becomes an x offset instead of a column count. The display map has already expanded tabs by the time the row is laid out, so a leading tab now counts as its expanded width instead of as a single byte. Two things I would look at first in review: - The division rounds instead of truncating. The x offsets are built by repeated float addition, so a gap that should be exactly three spaces can arrive as 2.9999998, and truncating inserts two. - The function returns early if the space advance is missing or zero. Dividing by zero gives `inf`, which saturates to a huge `u32` and then tries to allocate that many spaces. I did not add any public items and did not touch `selection.rs`. ## Testing `cargo test -p editor align` on Windows: 6 passed, 0 failed. That is the new test plus the two existing `align_selections` tests, which I did not change and which still pass. `test_align_selections_with_multibyte_chars` covers the repro from the issue, a second column whose offset has to carry past a multi-byte character in the first, a leading tab, a non-BMP character, and a case where multi-byte characters sit after the cursors and nothing should move. I also checked that the test catches the bug rather than just passing: reverting the change in `editor.rs` and keeping the test makes it fail on the repro, inserting four spaces where three are right. Putting the change back makes it pass. The two older align tests pass either way, since they are pure ASCII. What I have not covered: - Wide CJK characters, combining marks, and ZWJ clusters. These should be right by construction, since the code measures advances rather than counting characters, but I have no tests for them. The headless text system behind `gpui::test` gives every BMP character the same advance, so a test there would assert the test double's behavior rather than the real renderer's. - Proportional fonts. Aligning with inserted spaces cannot be exact when glyph widths vary. The code rounds to the nearest whole space. - Soft-wrapped rows. I measure x from the start of the wrapped row but still group cursors by buffer row, so two cursors on one buffer row that sit either side of a wrap boundary get measured from different origins, and the carried offset crosses that boundary as if they shared one. The old byte-column code did not have that particular failure. I left it alone because fixing it is a different change, but I would rather flag it than have you find it. - I work on Windows and have no macOS machine. The arithmetic is platform independent, so I do not expect a difference, but I have not checked. To try it: paste the two lines from the issue, put a cursor on each `#` with `editor: select next`, then run `editor: align selection`. The two `#` should line up. ## Self-Review Checklist: - [ ] 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 `editor: align selections` misaligning rows and Vim `ctrl-d` / `ctrl-u` / `ctrl-f` leaving the cursor behind on lines with multi-byte characters or tabs. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
3e19851f8f |
editor: Keep the cursor before text inserted by on-type formatting (#61823)
## Why `textDocument/onTypeFormatting` edits that insert or replace text at an empty cursor use its right bias and move it past the new text. In paired tags, pressing Enter can therefore leave the cursor on the closing tag instead of between the tags. ## What - Capture a left-biased pin for each empty cursor before requesting on-type formatting. - Skip cursor tracking unless a matching language server advertises the trigger. - Restore only unchanged empty cursors whose displacement is fully covered by formatting transaction ranges, so intervening user edits are preserved. - Reset vertical movement state when restoring a cursor. ## Testing - `cargo test -p editor test_on_type_formatting` (5 passed) - `./script/clippy -p editor` ## References - Fixes https://github.com/zed-industries/zed/issues/61574 Release Notes: - Fixed the cursor being moved past text inserted or replaced at its position during on-type formatting. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
0d952edd5a |
text_finder: Highlight the query as a regex when the regex filter is on (#61128)
the buffer search and project search bars both already load the `regex` language and put it on their query buffer when the regex filter is on. the text finder never got that, so a regex you type in there is just plain text. did the same thing here. the only slightly annoying part was that the picker's head editor is `pub(crate)`, so text_finder couldn't get at it. added a small `query_editor()` accessor to `Picker` for that. `adjust_query_regex_language` mirrors the two existing ones. test asserts the query buffer's language is regex with the filter on, and gone once it's off. Closes #59945. Release Notes: - Improved the text finder by highlighting the query as a regex when the regex filter is on --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
b40afd1905 |
vim: Fix insert above auto-indentation (#52594)
Fixes InsertLineAbove (Shift + O) auto-indent handling by deciding whether to trim the first character or the last character based on direction. Previously, inserting a line above would auto format the line the cursor was originally on and not the new line (instead of the correct behavior which is to do the opposite). No tests because I couldn't find any Vim-specific auto-indent tests and this only affects Vim mode. If I'm missing something there LMK and I'll take a closer look. Closes #52588. Release Notes: - Vim: Fixed auto-indentation for insert above action. --------- Co-authored-by: dino <dinojoaocosta@gmail.com> |
||
|
|
0500fd9ee9 |
git: Add diff_base setting for showing changes since the default branch (#61501)
# Objective Let git indicators — the editor gutter, file colors, and `git::Diff` — show all changes on the current branch relative to its merge base with the default branch, instead of only uncommitted changes. Supersedes #60398; thanks to @samuelcolvin for the original implementation and motivation. Closes FR-135 ## Solution - New `git.diff_base` setting (`"head"` | `"default_branch"`), applied live and toggleable per session from the editor controls menu ("Diff Against Default Branch"). - Statuses come from a real merge-base-to-worktree tree diff (`git diff --merge-base`), so local edits that revert branch changes correctly show as unchanged. - `GitStore` shares one `DiffBufferList` per repository with the Branch Diff view; `repo_snapshots` and `project_path_git_status` keep returning index/worktree truth, while display surfaces use separate `display_*` APIs. - `BufferDiff` now records what its base is (`DiffBaseKind`); hunks whose base isn't HEAD are read-only in the gutter — stage/restore buttons and keybindings are inert, so committed work can't be silently rewritten. - `git::Diff` follows the setting; new `git::DiffHead` always opens the HEAD diff; `git::BranchDiff` is renamed `git::DiffBranch` (deprecated alias kept). Tradeoffs / known limitations: - Hunk-level staging is unavailable while in `default_branch` mode (whole-file staging via the git panel still works). Staging just the uncommitted sub-ranges of a branch hunk is a follow-up. - Remote hosts running an older server ignore the new `GetTreeDiff.includes_worktree` proto field and degrade to committed-changes-only branch diffs. - Repositories with no resolvable default branch fall back to HEAD-relative behavior; a failed first resolution retries on the next branch-list change. ## Testing - Real-git-repo tests for the merge-base-to-worktree diff's edge cases: files recreated after index deletion, committed deletions recreated on disk, and symlinks. - GPUI tests for status semantics (a branch change reverted on disk shows clean), `git::Diff` routing, live setting changes, and read-only hunk enforcement (restore/stage leave buffer and index untouched). ## 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: - Git: Added a `git.diff_base` setting (`"head"` or `"default_branch"`) that makes the editor gutter, file colors, and diff view show all changes on the current branch since its merge base with the default branch, instead of only uncommitted changes. --------- Co-authored-by: Ben Kunkle <ben@zed.dev> |
||
|
|
f22500a71b |
editor: Add multiple_selections key context (#60018)
# Objective - I would like to have the Vim command `z z` do different actions depending on if I have multiple selections. If I only have one selection I want `z z` to center my only selection (current behavior); however, if I have multiple selections I would like `z z` to run `editor::OpenSelectionsInMultibuffer`. This PR does not add this specific functionality (happy to be convinced otherwise), but it does let users add this type of functionality. ## Solution - Add a new key context field that is active only when there are multiple selections. ## Testing - Changes are quite small. A test on this would really be testing other parts of the code-base more than 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/2559e218-d6fa-492a-949b-f4ab8b880f28 This allows us to add something like the following to the `keymap.json`: ```json { "context": "VimControl && !menu && multiple_selections", "bindings": { "z z": "editor::OpenSelectionsInMultibuffer", }, }, ``` which lets us change the functionality of a keystroke based on if there are multiple selections. This video has the following keystroke sequence: `z z` (Center the cursor normally) `5 g l` (Select the 5 next occurrences of the word under the cursor) `z z` (Open selections in multi-buffer) (Previously `z z` in this context would just center the last selection) https://github.com/user-attachments/assets/a0dc1813-5420-4cda-a1ec-99e6681680e7 --- Release Notes: - Added `multiple_selections` keystroke context Co-authored-by: Lukas Wirth <lukas@zed.dev> |
||
|
|
d73ad3de55 |
gpui: Give divs (the option for) a better scrolling experience (#61797)
# Objective Closes #56127 Right now there is an issue where in certain contexts, specifically GPUI div elements, horizontal scrolling w/ a trackpad works very poorly, even when trying to scroll sideways, vertical scrolling will happen. This happens with both a trackpad and scrollwheel. The showcase video also shows the broken behavior. ## Solution The way that scrolling works in the editor is really nice, scrolls are locked to the axis they started on but with enough force can change axis. so by taking the ongoing scroll handler from the editor and moving it up into GPUI, we can get that same functionality for GPUI. I somewhat "take over" the functionality of the existing `restrict_scroll_to_axis` property, because it seems like its purpose was basically trying to fix this problem already, just unsuccessfully. The alternative, and would make things overall nicer to look at, would be to tie this to `allow_concurrent_scroll`, but the effect radius tied to that option is way bigger, so im holding off on that atleast right now. ## Testing Theres a good number of scroll related tests generally, so I don't think i've perturbed any common existing behaviors. attach the functionality to `restrict_scroll_to_axis` really limits the surface. There are also some new tests for the ongoing_scroll behaviors. Tested on my mac w/ both trackpad and mouse. ## 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 Video show casing all the behaviors: broken w/ trackpad working w/ trackpad broken w/ scroll working w/ scroll https://github.com/user-attachments/assets/1935cd2d-a255-4a77-81d5-daa9f72470a6 --- Release Notes: - markdown_preview: Fix horizontal scrolling inside certain elements |
||
|
|
b4f0eaf03f |
theme: Specify color format and pattern in schema (#49136)
## Purpose
While developing a theme for Zed I remarked that the schema available
doesn't mark colors in a way that Zed recognize to display the color
annotations:
```json
{
"$schema": "https://zed.dev/schema/themes/v0.2.0.json"
}
```
<img width="119" height="190" alt="Screenshot 2026-02-25 at 23 15 10"
src="https://github.com/user-attachments/assets/3f1bb703-cb26-4630-9598-3a7cb8873c20"
/>
But Zed has support for it when colors are marked with `"format":
"color"` in the schema:
<img width="127" height="186" alt="Screenshot 2026-02-25 at 23 14 58"
src="https://github.com/user-attachments/assets/1a9387a4-613a-4cf8-a3af-f6ac201bdf54"
/>
So I searched if the schema file was Open Source somewhere, discovered
it was generated from the codebase and attempted the change.
## Implementation
This is essentially done using a `ThemeColor` wrapper for the color
strings that implements `JsonSchema` with a dedicated regex for
validation and the color format specified. This ends up with a new
`$defs` of `Color` being specified and used:
```json
{
"$defs": {
"Color": {
"type": "string",
"format": "color",
"pattern": "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
}
}
}
```
## Other
- There is a small change I made for testing to the schema_generator
that adds an `--output` / `-o` flag. When provided it writes the
generated schema JSON to the specified file path instead of printing to
stdout. This was done to made testing easier but I can remove it or
split it to a separate PR (It's already a separate commit)
- For this PR to do anything a new schema version will need to be
published at something like `https://zed.dev/schema/themes/v0.3.0.json`
and documentation needs to be updated to point to it.
Before you mark this PR as ready for review, make sure that you have:
- [x] Added a solid test coverage and/or screenshots from doing manual
testing (Manual testing, couldn't find any existing good place to test
it)
- [x] Done a self-review taking into account security and performance
aspects
- [x] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
Release Notes:
- N/A
---------
Co-authored-by: MrSubidubi <finn@zed.dev>
|
||
|
|
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> |
||
|
|
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 |
||
|
|
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> |
||
|
|
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. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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. |
||
|
|
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. |
||
|
|
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> |
||
|
|
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. |
||
|
|
27a3512d00 |
Classify edit prediction lifecycle triggers (#60983)
# Objective Closes EP-89 - Replace ambiguous `Other` edit prediction telemetry for known editor lifecycle events. ## Solution - Classify editor creation, provider changes, user information changes, Vim mode changes, and settings changes through the existing trigger pipeline. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - N/A |
||
|
|
87c805c61e |
Use buffer line numbers when copying file locations (#60781)
# Objective Fixes #54250 `editor: copy file location` copies the row you're on in the multi-buffer, not the row in the actual file. In a git diff view with collapsed lines it copies the wrong line number. ## Solution It read the rows straight off the selection, which is in multi-buffer coordinates. `ClipboardSelection::for_buffer` already handles this with `range_to_buffer_range`, so I used the same thing. Path and line now come from the same buffer. `range_to_buffer_range` returns nothing when the selection ends in a different buffer than it starts in, which you can do in a git diff view. Rather than copy nothing, it falls back to the cursor's buffer. ## Testing Three tests: a multi-buffer excerpt, a selection dragged across two files, and a plain single-file editor. The multi-buffer ones fail on main; the singleton one passes either way, so normal editors are unaffected. ## 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 `editor: copy file location` copying the wrong line number in multibuffers ([#54250](https://github.com/zed-industries/zed/issues/54250)). --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
d9316bbcfd |
Invalidate hover state when a multibuffers paths change (#60443)
Fixes a panic when multibuffer paths change under a cursor hover Fixes ZED-9W1 Closes FR-112 Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
883bb315fd |
editor: Use raw head selection for rename (#60594)
Follow up to https://github.com/zed-industries/zed/pull/55542, which reused the shifted offset for the rename input's *initial selection*, cutting it one character short. <img width="524" height="512" alt="image" src="https://github.com/user-attachments/assets/37032614-2cfd-4ad4-9005-f2eac57924a1" /> <img width="435" height="158" alt="image" src="https://github.com/user-attachments/assets/7b1b9c52-08d6-48ce-928a-873f6e175f65" /> --- Release Notes: - Fixed symbol rename in vim mode omitting the last character of the symbol out of the rename input's initial selection |
||
|
|
1abef8fadf |
Suggest language extensions for untitled buffers (#55263)
Fixes #53527. ## Summary - Suggest `untitled.<extension>` when saving an untitled editor buffer with a selected non-Plain Text language. - Preserve the existing title-based suggestion for existing files, Plain Text buffers, and buffers without a language extension. - Add a regression test for an untitled Rust buffer suggesting `untitled.rs`. ## Testing - `mise exec rust@1.95.0 -- cargo fmt --check -p editor` - `mise exec rust@1.95.0 -- cargo test -p editor test_suggested_filename_uses_language_extension_for_untitled_buffer --lib` ## Suggested .rules additions None. Release Notes: - Fixed Save As suggestions for untitled buffers with a selected language. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
48192372a0 |
Git partially staged changes (#46541)
This PR explores the addition of a new feature and UI to improve visibility into partially staged commits. Currently, the Git panel shows tracked and untracked changes, but it does not clearly distinguish between staged and unstaged changes. As a result, it’s difficult to quickly see which changes are not staged in the current UI. Both staged and unstaged changes are combined into the `Uncommitted Changes` multibuffer. This developer experience differs from other editors, most notably VS Code; which presents separate Staged Changes and Changes lists. ### Staged and unstaged diffs in multibuffers This PR introduces an alternative UI for unstaged changes that aligns with the overall Zed experience. Instead of showing changes on a per-file basis, staged and unstaged diffs are each displayed in their own multibuffers, similar to how `Uncommitted Changes` currently works. For example the following screenshot shows the current `Uncommitted Changes` on the left, the `Staged Changes` in the middle and the `Unstaged Changes` buffer on the right for comparison <img width="1408" height="859" src="https://github.com/user-attachments/assets/aa709f7a-041d-4cb1-95d6-84c0f5fff688" /> ### Indicators/interactions The new multibuffers can be opened in two ways: 1. Via a new `U` chip, which appears when a file has unstaged changes 2. Via new menu options (See screenshots below for both interaction paths.) <table> <tr> <td style="text-align: center; vertical-align: top;"> <p>via the chip</p> <img height="400" src="https://github.com/user-attachments/assets/3ef69f02-b787-499c-959a-25f50b3728e8" alt="Via the chip" /> </td> <td style="text-align: center; vertical-align: top;"> <p>via the menu</p> <img height="400" src="https://github.com/user-attachments/assets/f5be8b6d-ccdc-4420-bd29-75570b558016" alt="Via the menu" /> </td> </tr> </table> ### Design goals - minimally intrusive UI changes (small new badge and menu items) - adhere by Zed'ism (use multibuffer where possible) - avoid disabling any current interactions (Uncommitted Changes ui is unchanged) - avoid introducing an app level view mode (no new settings needed) ### Experience goals - make it easy to see what changes are not staged - make it easy to see that a file has unstaged changes (avoid developers accidently leaving out changes in a commit; a personal issue that I have when using Zed) - elegantly handle large file's unstaged changes (follows the same collapse and expanding seen in `Uncommitted Changes`) ### How to try - Clone the repo and run `cargo run` - Make a change to a file and stage it - Make another change to the file (the `U` indicator will appear) - Click the `U` to see the unstaged view ### Open questions/rough edges - [ ] determine if this user experience is useful for others - [ ] ensure all interactions work as expected (response to all update cases) In general I'm really interested in hearing the community's feedback about this interface, more than happy to make any changes or explore a different solution! ### Related issue: - https://github.com/zed-industries/zed/pull/36646 - https://github.com/zed-industries/zed/issues/26560 Release Notes: - Support partially staged commit multibuffers via a staged and unstaged changes view. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Cole Miller <cole@zed.dev> |
||
|
|
e41a55c3c0 |
Improve diff tabs toolbar design (#60464)
This PR adds a bunch of design improvements to the toolbar of (tab) views that display diffs: the uncommitted changes, branch diff, and agent diff tabs. This involves adjusting spacing, sizing, and other small tweaks across all of these views, including touching up the divider component API a little bit, adjusting Git icons design, adding diff stat numbers to the uncommitted changes tab so its consistent with the others, and more (e.g., moving the split buttons into its own component to ensure they look the same across all uses). Ended up also going on a slight de-tour to make all uses of the split button in the Git panel consistent design-wise. All in all, this is just tidying up the design of all of these surfaces that are all relatively similar. | Branch Diff | Uncommitted Diff | Single-file Diff | Git Panel | |--------|--------|--------|--------| | <img width="800" alt="Screenshot 2026-07-06 at 11 25@2x" src="https://github.com/user-attachments/assets/4ebf87e7-c52d-41d9-9de3-7944125114a1" /> | <img width="800" alt="Screenshot 2026-07-06 at 11 25 2@2x" src="https://github.com/user-attachments/assets/51ccd2eb-904b-455a-a708-b4cb50b3a7cb" /> | <img width="800" alt="Screenshot 2026-07-06 at 11 26@2x" src="https://github.com/user-attachments/assets/6ae7df68-d1bd-4d36-a250-ba16e43c4e8e" /> | <img width="800" alt="Screenshot 2026-07-06 at 11 26 2@2x" src="https://github.com/user-attachments/assets/e032bc60-4551-41f0-b578-90ed305167c2" /> | Release Notes: - Added diff stat numbers to the uncommitted changes view. |
||
|
|
b3acc7518a |
Fix blame hover popover not showing on first trigger when inline blame is disabled (#50769)
● Closes #50285 ## Summary When `inline_blame` is disabled in settings and `editor::BlameHover` is triggered, the blame popover fails to appear on the first invocation because `start_git_blame` kicks off an async task to fetch blame data, but `blame_hover` immediately tries to read that data synchronously before it's available. This fix registers a one-shot observation on the blame entity when it's freshly created, so the popover is shown once blame data has finished generating. Before you mark this PR as ready for review, make sure that you have: - [x] Added a solid test coverage and/or screenshots from doing manual testing - [x] Done a self-review taking into account security and performance aspects - [ ] ~Aligned any UI changes with the [UI checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)~ (No UI changes) ## Videos: ### Before: https://github.com/user-attachments/assets/d2ca4f8e-8186-49af-9908-5a82bfca0de2 Ps: pressed the keybind two times ### After: https://github.com/user-attachments/assets/08575cd9-2bbc-462d-92fa-f0e7ef23d8d6 ## Release Notes: - Fixed blame hover popover not appearing on first trigger when inline blame is disabled (#50285) --------- Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com> |
||
|
|
a955005b6f |
editor: Update gutter hover tooltip on modifier changes (#58880)
## Context The gutter hover button can represent either adding a breakpoint or adding a bookmark depending on whether the secondary modifier is pressed. Previously, the visible tooltip did not update when the modifier changed while the popover was already open. This moves the gutter hover intent into a shared state used by both the button and tooltip, so the label, metadata, icon, color, click action, and displayed keybinding all stay in sync. Closes #58821 ## How to Review `crates/editor/src/editor.rs` adds a shared gutter hover intent type and a custom tooltip view that reads the current modifier state while rendering. Review that bookmark and breakpoint behavior map consistently across the button icon/color, click action, tooltip label, metadata, and keybinding. `crates/editor/src/editor_tests.rs` adds a regression test covering the tooltip intent selection with and without the secondary modifier. Manual test after the fix below : [Screencast from 2026-06-09 01-30-23.webm](https://github.com/user-attachments/assets/ef465eb9-e659-44da-93a6-a511c84e9401) ## 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 breakpoint/bookmark gutter popover not updating when modifier keys change. --------- Co-authored-by: Danilo Leal <daniloleal09@gmail.com> |
||
|
|
27b7fc4cbb |
editor: Fix panic when restoring empty selections on undo/redo (#59372)
Closes FR-81. Also updates the error log, as the linked issue is closed. Release Notes: - Fixed panic when restoring empty selections on undo/redo |
||
|
|
6bfbd4d09d |
Fix relative line number calculation when the first row is wrapped (#53759)
fixes #53726 Compute the base delta from the first visible, non-filtered row instead of using rows.start. This avoids off-by-one numbering when rows.start is a wrapped continuation that gets filtered out. Ensure deleted lines still advance the relative counter even when they are not numbered. Add a test for the wrapped scrolling case. P.S. This is my first time using rust for a serious pull request and let's say I'm a little bit rusty with it. 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 #ISSUE Release Notes: - N/A or Added/Fixed/Improved ... --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com> |
||
|
|
21b0a6821e |
editor: Add intelligent bracket colorization (#51580)
Closes #50210 Bracket colorization currently runs theme accents through `ensure_minimum_contrast`, which can significantly alter authored palette colors in order to satisfy a single foreground-vs-background target. In practice, that makes rainbow brackets drift away from the theme colors they are supposed to reflect. This PR keeps bracket colorization as a single automatic behavior, but changes how the palette is derived: - preserve authored accent colors when they already work - adjust only the specific accents that are too weak against the editor background - only reorder the palette when adjacent bracket levels are still too similar after that The implementation is staged because bracket colorization has to handle two separate problems: - **Bracket-vs-Background Readability**: is an individual bracket visible against the editor background? - **Adjacent Bracket Separation**: can you still distinguish one nesting level from the next? Those two constraints are also why the implementation cannot simply defer to whatever accent colors the theme provides. Some themes, including the bundled One and Ayu, do not define explicit accents at all, so bracket colorization falls back to Zed's shared default accent palette. That palette was not designed with any particular theme's background in mind, which makes the background contrast check especially important for those cases. That is why the previous `ensure_minimum_contrast(..., 55.0)` path is not enough on its own. It addresses foreground-vs-background readability, but if lightness-only adjustment cannot satisfy that target it escalates to saturation reduction and then black/white fallback. This PR instead keeps the bracket-specific background fix bounded and lightness-only in OKLCH, so the resulting color stays much closer to the authored accent. ### How it works - **Background Contrast Correction**: accents that fall below the APCA floor against the editor background are adjusted by changing OKLCH lightness only, preserving hue and chroma - **Adjacency Correction**: if the resulting palette is still too weak between neighboring nesting levels, the palette is reordered conservatively to improve adjacent separation That ordering matters. Doing the reorder first can easily be undone by the background-fix step. ### Color measurement - background contrast uses APCA, via the existing `apca_contrast` path - adjacent bracket separation uses OKLab Euclidean distance APCA is the right tool for bracket-vs-background readability, but it is not designed to compare two foreground colors against each other. OKLab distance is a better fit for detecting when neighboring bracket levels are perceptually too close. ### Thresholds - background APCA floor: `30` on dark themes, `35` on light themes - adjacent OKLab target: `0.08` on dark themes, `0.10` on light themes - light-theme reorder tolerance band: reorder only triggers below `0.095`, avoiding threshold-artifact reordering on palettes that are visually fine but narrowly miss `0.10` ### Validation - `cargo test -p editor bracket_colorization` - manual comparison on bundled One, Ayu, and Gruvbox theme families Release Notes: - Improved bracket colorization by preserving theme accent colors when possible and applying targeted contrast fixes only when needed. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
9177c5e747 |
Make the existing bookmark action add an unnamed bookmark again (#60185)
Zed don't surface the fact that bookmarks can have labels/names now anywhere except opening the bookmark name editor every time you place one. This keeps the label/name mechanism but makes the default add bookmark action add an unnamed one. Next step is probably to enable holding shift (or some other modifier) to place a named bookmark, or even a setting to switch between default named vs unnamed. Release Notes: - N/A |