fbda4f862a2fb03b854636b17bd04be3db3d94de
39175
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7de1701b71 |
fs: Retry watch registrations skipped during the native watch-limit cooldown (#60662)
GlobalWatcher::add returns Ok(None) while the native watch-limit cooldown is active, and FsWatcher::add_existing_path treated that as success: the path was never watched, with no retry and no error. A long-lived watch (like a repository's git directory) that happened to register during a cooldown window silently never received events. Route the skipped registration through the existing pending-path machinery, which already polls until registration succeeds and emits a rescan event for the path so that changes missed in the interim are picked up. --- Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
6bc0704b01 |
project_panel: Restore worktree drag-and-drop reordering (#55755)
Reordering worktree roots by drag-and-drop had silently broken: a worktree-root filter added to `disjoint_entries` for delete-safety stripped roots before the drop handler could see them, so root-to-root drops never reached the existing `move_worktree` reorder path. This PR is the minimal regression fix: - Move the worktree-root filter out of `disjoint_entries` and into `disjoint_effective_entries` (used by cut/copy/delete), so drag-and-drop keeps seeing roots and single-root reorder works again via the existing `move_worktree` path. - Filter worktree roots out of `drag_onto`'s copy branch, so holding the copy modifier over a drag that contains a root no longer returns `None` from `create_paste_path` and silently cancels the whole copy. - Add `test_drag_worktree_root_reorders_worktrees` exercising the drag-onto reorder flow end to end. The larger feature work (multi-root group reordering, blank-area "send to end", copy-mode drag feedback, and syncing worktree order to collaborators) has been split into a separate follow-up PR so this fix can land quickly. Note that worktree order was intentionally not synced during collaboration, so that change is discussed separately. Closes #46699 Release Notes: - Fixed drag and drop to reorder worktrees --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com> |
||
|
|
cb0a40db90 |
edit_prediction: Report patch apply failures (#60637)
# Objective - Report V4 edit prediction patch apply failures as cloud rejection events. - Closes EP-210 ## Solution - Added `PatchApplyFailed` as an edit prediction rejection reason. - Converted `prediction_edits_for_single_file_diff` errors into rejected prediction results so the existing rejection pipeline posts them to `/predict_edits/reject`. - Kept interpolation failures reported as `InterpolateFailed`. ## Testing - Ran `cargo fmt --check && cargo check -p edit_prediction`. ## 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 |
||
|
|
aec35a284c |
language_model: Add OpenAI Responses API custom tool support (#60638)
# Objective
Allow zed's language model stack to express OpenAI Responses API custom
tools (freeform text-input tools with an optional lark/regex grammar),
so downstream consumers can offer tools like a freeform `apply_patch` to
GPT models.
## Solution
- `LanguageModelRequestTool` now carries a Function-vs-Custom input
variant; `LanguageModelCustomToolFormat` models text/grammar formats.
- `LanguageModelToolUse.input` becomes a typed
`LanguageModelToolUseInput::{Json, Text}`. Serialization is tagged so
persisted Text inputs round-trip losslessly; legacy plain JSON values
still deserialize as `Json`.
- `open_ai` gains the custom tool wire types (tool definition,
`custom_tool_call`/`custom_tool_call_output` input items with
string-or-content-part outputs, output item, and
`custom_tool_call_input` delta/done stream events). The Responses event
mapper accumulates raw text deltas into `ToolUse` events, and history
replay derives custom-vs-function tool results from the matching
`ToolUse` by id.
- All non-OpenAI providers and the Chat Completions path error
explicitly when a request contains custom tools — no silent drops or
empty-schema coercions.
Release Notes:
- N/A
|
||
|
|
9b9923fb74 |
ci: Fix push permissions for cherry-pick workflow (#60673)
Release Notes: - N/A |
||
|
|
e4b99e7dab |
ci: Fix insufficient permissions for asset validation step (#60625)
Release Notes: - N/A |
||
|
|
aad0d05803 |
markdown: Improve selection copying to always yield valid markdown (#60657)
Closes https://github.com/zed-industries/zed/issues/59083 Closes https://github.com/zed-industries/zed/issues/42958 Closes https://github.com/zed-industries/zed/issues/59612 This PR improve selection copy of Agent Panel and Markdown Preview such that copied text is always valid markdown, following how VSCode handles it. The partial selection of styled text would not copy broken syntax like `bold**` or ```inline code` ``` like before. Now we follow simple rule: > Selecting any part, no matter from where, copies it as its markdown. Except when the selection sits entirely inside a single inline code span, in which case we copy plain text, for terminal and code use cases. Examples: This is **bold** text, this is *italic* text, and this is `code` all `in one` sentence. - selecting only bold → `**bold**` - selecting normal text and partial bold → `is is **bo**` - selecting a single code span completely → `code` - selecting partial code → `od` - selecting partial text and code → `` his is `cod` `` - selecting multiple code spans partially → `` `ode` all `in o` `` - selecting multiple code spans end to end → `` `code` all `in one` `` Nested spans, like **bold with `code` inside**: - partial text in bold → `**ld wi**` - partial code in bold → ``**`od`**`` - full code in bold → ``**`code`**`` - the whole sentence → ``**bold with `code` inside**`` Links, like [Visit Rust's website](https://rust.org): - partial link text → `[bsite](https://rust.org)` - full link text → `[Visit Rust's website](https://rust.org)` How it works: Selection boundaries that land inside delimiter syntax (`**`, backticks, etc.) first snap out so no delimiter is left half-selected. Then any spans the selection cuts through get their delimiters re-added, outermost first, so nested styling stays balanced. Only the root blocks containing the two selection boundaries are inspected, everything in between is copied right as is, which also keeps this cheap on large documents. Release Notes: - Improved copying selected text in Agent Panel and Markdown Preview. Partial selections of styled text now copy as well-formed markdown, and selections within a single inline code span copy as plain text. |
||
|
|
5460d079cf |
editor: Fix panic removing blocks in split diff with companion edit at EOF (#60445)
BlockMap::sync unwrapped the transform cursor for every edit, assuming each edit's old.start lands strictly inside the old transform tree. The companion (split-diff) branch of sync can compose an edit anchored at the trailing boundary of the old transforms, leaving the cursor past the end of the tree and aborting the process on the None unwrap. Only bind the transform when there are rows preceding the edit. Fixes ZED-9V4. Closes FR-113 Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
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 ... |
||
|
|
9045a3a19f |
cli: Restore workspace by default when cli_default_open_behavior="new_window" (#60652)
Closes #60325, Follow up to #59415 Fixes an issue where launching Zed from the cli (just `zed`, no path) would not restore the previous window when using `cli_default_open_behavior: new_window` Release Notes: - cli: Fixed an issue where the previous workspace would not be restored when using `cli_default_open_behavior: new_window` and no path was provided |
||
|
|
800c6a18be |
ruby: Mention kanayago and fuzzy-ruby-server in the documentation (#60640)
# Objective Hi! This PR updates the Ruby doc to mention 2 language servers `kanayago` and `fuzzy-ruby-server`. ## Testing N/A ## 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 N/A --- Release Notes: - N/A |
||
|
|
6946359c08 |
editor: Add actions to move between comment paragraphs (#58353)
Jump the caret straight to the next/previous block of prose comments —
like paragraph motion, but for comments.
The motivating workflow: reflowing a file's comments with `editor:
rewrap`. Today that means reaching for the mouse to click into each
comment block scattered through the file, or using other cursor motions
and undershooting or overshooting the target. With these two actions you
can step from one comment paragraph to the next, `rewrap`, and repeat —
reflowing every comment in a file without ever touching the mouse. It's
also handy for skimming a heavily-documented file: hop from doc comment
to doc comment without manually scrolling past the code in between.
Adds two editor actions:
- `editor::MoveToNextCommentParagraph`
- `editor::MoveToPreviousCommentParagraph`
Both move the caret to the first non-whitespace character of the
next/previous *comment paragraph*. They have no default keybinding and
are available from the command palette ("editor: move to next/previous
comment paragraph").
### What counts as a comment paragraph
A comment paragraph is a run of consecutive comment lines. A line is a
comment line when its **first non-whitespace character is in a `comment`
syntax scope** and the line contains prose (at least one alphanumeric
character). This is determined from the syntax tree
(`language_scope_at(...).override_name()`), the same mechanism `rewrap`
and comment folding already use, so it behaves correctly without
per-language string matching:
- **End-of-line comments preceded by code are ignored** — on `let x = 1;
// note` the first non-whitespace character is code, not a comment, so
the line is not a paragraph line.
- **`//` inside a string literal is ignored** — its scope is `string`,
not `comment`.
- **Blank/divider comment lines separate paragraphs** — a bare `//` or
`// -----` (no prose) acts as a separator, so you can hop between
paragraphs *within* one comment block as well as across blocks.
Both directions always move to a paragraph *other* than the one the
caret is in: when the caret is inside a paragraph, the whole current
paragraph is skipped, so `Prev` lands on the previous paragraph's start
rather than the current paragraph's own start.
### On the autoscroll
These two actions scroll the destination near the top of the viewport
(`Autoscroll::top_relative`) rather than using the default `Fit`
strategy that sibling motions use. This is deliberate and specific to
the feature: you are jumping to the **start** of a comment paragraph
that extends *downward*, so biasing the destination toward the top keeps
the whole paragraph visible after the jump. This matters for the rewrap
workflow above — you want to see the full comment you are about to
reflow, and the reflow itself changes the paragraph's line count. With
the default `Fit`, repeated forward jumps creep the caret to the bottom
edge and leave long paragraphs cut off below the fold — the opposite of
what this motion is for. Happy to revisit the exact strategy/offset if
you'd prefer consistency with the other motions.
### Tests
Two tests in `editor_tests.rs` (using a real grammar + comment override
query):
- `test_move_to_next_and_previous_comment_paragraph` — full
forward/backward round trip, covering blank comment-line separators,
code separators, trailing comments, and the no-more-paragraphs stop.
- `test_move_to_previous_comment_paragraph_skips_current_paragraph` —
`Prev` from mid-paragraph skips to the previous paragraph, and stays put
when there is no previous paragraph.
---
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments — N/A, no unsafe
- [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:
- Added `editor::MoveToNextCommentParagraph` and
`editor::MoveToPreviousCommentParagraph` actions to move the caret
between comment paragraphs
|
||
|
|
711e286c7f |
gpui: Store GPU-facing bools as PaddedBool32 to avoid uninitialized padding (#60482)
`PolychromeSprite` in `crates/gpui/src/scene.rs` is `#[repr(C)]` and had a `grayscale: bool` field followed by 3 compiler-inserted padding bytes that were never written. The wgpu renderer's `instance_bytes` reinterprets `&[PolychromeSprite]` as `&[u8]` via `slice::from_raw_parts` and passes it to `queue.write_buffer`, so those uninitialized padding bytes were exposed behind a shared `&[u8]` on every frame that draws an image or emoji, which is undefined behavior. Rather than widening the field to a raw `u32` (which would suggest values other than 0 and 1 are meaningful), this introduces `PaddedBool32`: a `#[repr(transparent)]` wrapper around `u32` whose only public constructor is `From<bool>`, so the 0-or-1 invariant is enforced by the type while the layout has no padding. `Underline.wavy`, which was already a raw `u32` for the same reason, is converted too. cbindgen emits the wrapper as `typedef uint32_t PaddedBool32;`, so the generated Metal header and shaders are unchanged. The WGSL and HLSL shaders already declared these fields as `u32`/`uint`; their `& 0xFFu` masks, which existed to ignore the garbage padding bytes, are now simplified to plain comparisons. Release Notes: - N/A |
||
|
|
a103d8322b |
Improve docs AI readiness (#59577)
Context This PR makes the Zed docs easier for AI tools, search crawlers, and users to consume without changing the visible docs content. The current production docs are primarily optimized for browser navigation. They do not expose first-class Markdown URLs, an `llms.txt` index, page-level copy affordances, or machine-readable freshness metadata that let users and agents grab clean, current page content. Changes - Generate Markdown copies for docs pages during the mdBook postprocess step, including `/docs/index.md` as an alias for Getting Started. - Generate `/docs/llms.txt` from the mdBook chapter list, grouped by `SUMMARY.md` sections and annotated with page frontmatter descriptions. - Generate `/docs/sitemap.xml` with `<lastmod>` values for every docs page. - Emit machine-readable freshness metadata in HTML via `last-modified` and `article:modified_time` meta tags. - Generate Cloudflare Pages `_redirects` for `.html`, extensionless, and `.md` redirect variants, with channel-aware docs destinations. - Add discovery hints for agents and crawlers: `rel="llms.txt"`, `rel="alternate" type="text/markdown"`, and a short generated `llms.txt` directive in copied Markdown pages. - Update the docs proxy so `Accept: text/markdown`, `/docs.md`, and direct `.md` requests can resolve to the generated Markdown artifacts. - Move primary docs content earlier in the HTML source while preserving the visible layout, so crawlers and agent scorers encounter the article before sidebar chrome. - Move the existing copy-as-Markdown control from the top navigation into the page-title row, using the generated Markdown alternate link as the source of truth. - Split AI-discovery artifact generation out of `docs_preprocessor/src/main.rs` into a focused module. Best Practices Adopted - Use `llms.txt` as a concise navigation index, not a dump of full page content. - Link to absolute, canonical Markdown URLs from `llms.txt`. - Preserve the docs hierarchy in `llms.txt` instead of emitting a flat sitemap-like list. - Include short per-link descriptions from existing metadata rather than inventing summaries. - Keep `llms.txt`, Markdown copies, sitemap data, redirects, and freshness metadata generated from the same mdBook source to avoid drift. - Advertise Markdown alternates with standard HTML metadata and same-origin URLs. - Support both explicit Markdown URLs and content negotiation for clients that prefer Markdown. - Keep browser copy behavior pointed at generated Markdown alternate links instead of duplicating route inference in JavaScript. - Keep the copy-as-Markdown affordance in the page title row without duplicating header chrome controls. Validation - `cargo check -p docs_preprocessor` - `cargo test -p docs_preprocessor` - `./script/clippy -p docs_preprocessor` - `mdbook build ./docs --dest-dir=../target/deploy/docs/` - `node --check docs/theme/plugins.js` - `pnpm dlx prettier@3.5.0 docs/theme/plugins.js --check` - `git diff --check` - Local artifact checks confirmed generated Markdown pages, `llms.txt`, `sitemap.xml` lastmod values, HTML freshness metadata, Markdown alternate links, redirect targets, and preprocessed action/keybinding tags resolve as expected. - Worker URL rewrite mock covered `/docs/`, `/docs.md`, `/docs/index.md`, extensionless docs routes, `.html` routes, `/docs/llms.txt`, and `/docs/sitemap.xml`. - High-effort adversarial subagent review found blockers around channel-aware redirects, shallow-checkout date fallback, file size, duplicated Markdown path inference, and process spawning. Those were addressed. Remaining Notes - Local `python -m http.server` does not emulate Cloudflare Pages pretty URLs, `_redirects`, or the docs-proxy Worker, so full local `afdocs` still cannot prove content negotiation end to end. - Existing production remains unchanged until this PR is deployed through the docs workflow. - Production baseline `npx afdocs check https://zed.dev/docs/ --fixes --verbose` still reports the original failures before this PR is deployed: 12 passed, 8 failed, 3 skipped. Release Notes: - Improved docs AI-readiness by adding machine-readable discovery, Markdown access, and freshness metadata. --------- Co-authored-by: Katie Geer <katie@zed.dev> Co-authored-by: Ben Kunkle <ben@zed.dev> |
||
|
|
4f6d05dde0 |
Update wayland-backend to fix Wayland file dialog crash (#60621)
On Wayland, closing a window in the brief gap between requesting a portal file dialog and ashpd exporting the window's surface (used to parent the dialog) crashed Zed with `Unknown opcode 0 for object <anonymous>@0` ([ZED-9KB](https://zed-dev.sentry.io/issues/7568720776/)). When the export request fails because the surface is already dead, wayland-scanner's generated code silently returns an inert proxy, and ashpd's `Drop` impl later sends `destroy` on it — which wayland-backend 0.3.11 answers with a panic, because it looks up the request opcode before checking whether the object is null. wayland-backend 0.3.15 fixes this ([Smithay/wayland-rs#890](https://github.com/Smithay/wayland-rs/issues/890)) by returning an error instead, which the generated destructor discards, so the drop becomes a harmless no-op. This bumps the lockfile to 0.3.15 and raises the version floor in `gpui_linux` so the fix can't silently regress via a fresh lockfile. Closes FR-100 Release Notes: - Fixed a crash on Linux (Wayland) when a window was closed just as a file dialog was being opened. |
||
|
|
01d5096a3f |
gpui: Fix hover state not clearing when mouse leaves window (#60275)
# Objective Fix two gaps in element hover tracking at window boundaries. Hover was only re-evaluated on `MouseMove`, so when the pointer left the window no event fired `on_hover(false)` and the element stayed hovered. Symmetrically on Wayland, no `Motion` follows `Enter` until the pointer moves again, so hover was not established at the entry pixel. Both cases are easy to miss since most hover-styled elements don't sit flush against the window edge, but they surfaced while implementing layer_shell popups with input_regions, which should close when stop hovering. ## Solution The hover compare-and-fire logic in `div` is refactored into a shared `update_hover` closure, and a second listener on `MouseExitEvent` clears hover when the pointer leaves the window. It clears unconditionally because `MouseExited` doesn't update the tracked mouse position, so a hit test during that dispatch would still report the element as hovered. On Wayland, a `MouseMove` is synthesized at the entry position on `wl_pointer.enter`, mirroring the `MouseExited` already dispatched on `Leave`. ## Testing Tested manually on Wayland/Linux: hover on a window-edge element clears when the pointer leaves the window, and hover is established immediately when the pointer enters a surface with an element under the entry pixel. Not tested on other platforms. The `div` change relies on each platform's existing `MouseExited` dispatch: macOS and X11 emit it, so they get the exit fix too. Windows never dispatches `MouseExited` (`WM_MOUSELEAVE` only flips the window-level hover flag), so the stuck-hover case might remain there, unchanged from before. Before: https://github.com/user-attachments/assets/6af83bb3-de9d-40e2-a64c-bdefc98fc96d After: https://github.com/user-attachments/assets/721a9b5c-108a-499f-867e-da111836a34a Here is an example application to test this: ```rs #![cfg_attr(target_family = "wasm", no_main)] use gpui::{ App, Bounds, Context, Window, WindowBounds, WindowOptions, div, prelude::*, px, rgb, size, }; use gpui_platform::application; struct HoverExit { hovered: bool, } impl Render for HoverExit { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { // Fills the whole window so its edge is the window edge: moving the mouse // out of the window is what exercises the MouseExited path. div() .id("hover-exit") .size_full() .flex() .justify_center() .items_center() .text_xl() .text_color(rgb(0xffffff)) .bg(if self.hovered { rgb(0x585f58) } else { rgb(0x505050) }) .child(if self.hovered { "HOVERED" } else { "not hovered" }) .on_hover(cx.listener(|this, hovered, _, cx| { this.hovered = *hovered; cx.notify(); })) } } fn run_example() { application().run(|cx: &mut App| { let bounds = Bounds::centered(None, size(px(240.), px(160.0)), cx); cx.open_window( WindowOptions { window_bounds: Some(WindowBounds::Windowed(bounds)), app_id: Some("gpui-hover-exit".to_string()), ..Default::default() }, |_, cx| cx.new(|_| HoverExit { hovered: false }), ) .unwrap(); cx.activate(true); }); } #[cfg(not(target_family = "wasm"))] fn main() { run_example(); } #[cfg(target_family = "wasm")] #[wasm_bindgen::prelude::wasm_bindgen(start)] pub fn start() { gpui_platform::web_init(); run_example(); } ``` ## 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 element hover state not clearing when the mouse leaves the window |
||
|
|
ae61c133f1 |
gpui_windows: Check composition attribute lookup (#60122)
Checks that SetWindowCompositionAttribute was found before transmuting and calling the function pointer, making the composition setup a no-op when the undocumented export is unavailable. Release Notes: - N/A |
||
|
|
636e764737 |
gpui: Add parent-anchored native popup windows (with wayland xdg_popup implementation only so far) (#60232)
# Objective gpui can't show UI that extends past the window it belongs to. Menus, dropdowns and tooltips are drawn as elements inside the window, so they clip at its edges. This PR adds a window kind for platform-native popups anchored to a parent window, as groundwork for real native menus, dropdowns and tooltips. ## Solution `WindowKind::AnchoredPopup(PopupOptions)` opens a popup positioned relative to a parent window. Instead of giving the popup an absolute position, you describe where it should go and the platform figures out the rest: - `parent`: the window to anchor to - `anchor_rect`: a rectangle in the parent, e.g. the button that opened the menu - `anchor` and `gravity`: which point of that rect to attach to, and which direction to grow - `constraint_adjustment`: what the platform may do if the popup would leave the screen (slide, flip, resize) - `grab`: menu behavior, the popup takes focus and is dismissed when clicking outside the app The popup's size comes from `WindowOptions::window_bounds`. This model mirrors Wayland's `xdg_positioner`, where the compositor owns positioning and the client can only describe intent. Since that's the most restrictive case, the other platforms can implement the same description later with simple math against screen bounds. Only Wayland is implemented so far, via `xdg_popup` on top of the existing surface implementation. Popups can be parented to toplevels, layer-shell surfaces (a menu opened from a panel) and other popups (nested menus). macOS, Windows, X11 and web reject the kind with `PopupNotSupportedError`, so callers can detect that and fall back to in-window popovers. Some Wayland details that might help during review: - Anchor rects are translated from gpui coordinates into the parent's window geometry space and clamped to it. A rect outside the geometry, or with zero size, is a fatal protocol error - Resizing a mapped popup goes through `xdg_popup.reposition` - Mouse press serials are now recorded on press only, not release. Compositors decline grabs and interactive moves that reference a release serial ## Testing Tested manually on Wayland with an example app: the menu opens anchored below its button, extends past the parent window, flips above the button near the bottom of the screen, and a grabbing popup is dismissed when clicking into another application. Nested menus were tested in one of my projects (ignore that they are ugly, that's just a prototype 😛): https://github.com/user-attachments/assets/2cd3e2e9-87f7-4b02-986f-48e5633e205c I also have a complete runnable example demonstrating it. I did not add it to the PR, because this might give the impression that `WindowKind::AnchoredPopup` are a complete implementation, despite only working on wayland so far: <details> <summary>Click to view example</summary> ```rust //! Example and manual test for platform-native popups (`WindowKind::AnchoredPopup`). //! //! A native popup is a real, parent-anchored window that can extend beyond its parent onto the //! screen, unlike gpui's in-window popovers. Run it, open the menu, and confirm the points listed //! in the window. On a platform without an implementation the button reports that popups are not //! supported instead of opening anything. //! //! Run with: cargo run -p gpui --example popup #![cfg_attr(target_family = "wasm", no_main)] use gpui::{ AnyWindowHandle, App, Bounds, Context, MouseButton, SharedString, Window, WindowBounds, WindowHandle, WindowKind, WindowOptions, div, point, popup::*, prelude::*, px, rgb, size, }; use gpui_platform::application; /// The trigger button, at a fixed position so the popup can anchor to a known rectangle. Real code /// would anchor to the measured bounds of whatever element opens the popup. const BUTTON_BOUNDS: Bounds<gpui::Pixels> = Bounds { origin: point(px(24.), px(24.)), size: size(px(200.), px(32.)), }; const POPUP_SIZE: gpui::Size<gpui::Pixels> = size(px(260.), px(320.)); struct Menu; impl Render for Menu { fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement { let item = |label: &str| { div() .id(label.to_string()) .px_3() .py_1() .rounded_sm() .hover(|this| this.bg(rgb(0x3a3a3a))) .cursor_pointer() .child(label.to_string()) .on_click(|_, window, _| window.remove_window()) }; div() .id("menu-root") .size_full() .p_1() .flex() .flex_col() .gap_0p5() .bg(rgb(0x2a2a2a)) .text_color(gpui::white()) .rounded_md() .border_1() .border_color(rgb(0x454545)) .child(item("Foo")) .child(item("Bar")) .child(item("Baz")) .child(item("Qux")) .child(item("Alice")) .child(item("Bob")) } } struct PopupExample { menu: Option<WindowHandle<Menu>>, status: SharedString, } impl Default for PopupExample { fn default() -> Self { Self { menu: None, status: "Click \"Open menu\" to open a native popup.".into(), } } } impl PopupExample { /// Closes the menu if it is open. Returns true if a menu was actually open. fn close_menu(&mut self, cx: &mut App) -> bool { match self.menu.take() { Some(menu) => menu .update(cx, |_, window, _| window.remove_window()) .is_ok(), None => false, } } fn toggle_menu(&mut self, parent: AnyWindowHandle, cx: &mut App) { if self.close_menu(cx) { return; } match open_menu(parent, cx) { Ok(menu) => { self.menu = Some(menu); self.status = "Menu open. Dismiss it by selecting an item, clicking elsewhere in \ this window, or clicking another application." .into(); } // A real application would fall back to an in-window popover here. Err(error) => { self.status = format!("Failed to open a native popup: {error}").into(); log::error!("failed to open popup: {error}"); } } } } impl Render for PopupExample { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { let bullet = |text: &str| div().child(format!("• {text}")); div() .id("root") .size_full() .bg(rgb(0xf7f7f7)) .text_color(rgb(0x222222)) // Same-app clicks don't auto-dismiss a grabbing popup (see `PopupOptions::grab`). .on_mouse_down( MouseButton::Left, cx.listener(|this, _, _window, cx| { this.close_menu(cx); }), ) .child( div() .size_full() .p_5() .pt(px(76.)) .flex() .flex_col() .gap_3() .child(div().text_xl().child("Native popup test")) .child(div().text_sm().child( "WindowKind::AnchoredPopup opens a real, parent-anchored window that can \ extend past this window onto the screen. Only some platforms implement \ it so far.", )) .child( div() .flex() .flex_col() .gap_1() .text_sm() .text_color(rgb(0x555555)) .child(div().child("Verify:")) .child(bullet("The menu opens anchored below the button.")) .child(bullet( "The menu extends past the bottom edge of this window.", )) .child(bullet( "Near the bottom of the screen, the menu flips above the button.", )) .child(bullet("Clicking another application dismisses the menu.")) .child(bullet( "Selecting an item or clicking in this window dismisses it.", )), ) .child( div() .text_sm() .text_color(rgb(0x333333)) .child(self.status.clone()), ), ) .child( div() .absolute() .left(BUTTON_BOUNDS.origin.x) .top(BUTTON_BOUNDS.origin.y) .w(BUTTON_BOUNDS.size.width) .h(BUTTON_BOUNDS.size.height) .flex() .items_center() .justify_center() .bg(rgb(0xffffff)) .border_1() .border_color(rgb(0xd0d0d0)) .rounded_md() .cursor_pointer() .id("open-menu") .active(|this| this.bg(rgb(0xeeeeee))) .child("Open menu ▾") // Open on mouse-down, not on click, so the grab is taken while the button is still held. .on_mouse_down( MouseButton::Left, cx.listener(|this, _, window, cx| { // Don't let the window handler above close the menu we are opening. cx.stop_propagation(); this.toggle_menu(window.window_handle(), cx); }), ), ) } } fn open_menu(parent: AnyWindowHandle, cx: &mut App) -> anyhow::Result<WindowHandle<Menu>> { cx.open_window( WindowOptions { titlebar: None, // Sizes the popup. The platform decides the position, so the origin is ignored. window_bounds: Some(WindowBounds::Windowed(Bounds { origin: point(px(0.), px(0.)), size: POPUP_SIZE, })), kind: WindowKind::AnchoredPopup(PopupOptions { parent, anchor_rect: BUTTON_BOUNDS, // Anchor to the button's bottom-left and grow down-right so the menu drops beneath it. anchor: PopupAnchor::BottomLeft, gravity: PopupGravity::BottomRight, // Slide horizontally and flip vertically if the menu would leave the screen. constraint_adjustment: PopupConstraintAdjustment::SLIDE_X | PopupConstraintAdjustment::FLIP_Y, offset: point(px(0.), px(4.)), // Grab input so the compositor dismisses the popup on clicks into other applications. grab: true, }), ..Default::default() }, |_, cx| cx.new(|_| Menu), ) } fn run_example() { application().run(|cx: &mut App| { cx.open_window( WindowOptions { window_bounds: Some(WindowBounds::Windowed(Bounds { origin: point(px(100.), px(100.)), size: size(px(420.), px(300.)), })), ..Default::default() }, |_, cx| cx.new(|_| PopupExample::default()), ) .unwrap(); cx.activate(true); }); } #[cfg(not(target_family = "wasm"))] fn main() { run_example(); } #[cfg(target_family = "wasm")] #[wasm_bindgen::prelude::wasm_bindgen(start)] pub fn start() { gpui_platform::web_init(); run_example(); } ``` </details> ## 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 |
||
|
|
bfd21aa8dc |
search: Bump fancy-regex dependency and enable CRLF mode (#55471)
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 #43396 Release Notes: - Project search now supports CRLF line endings correctly, as well as other regex features like subroutine calls |
||
|
|
2eeb3e9f47 |
Add support for format_on_save only changed lines (#49964)
## Summary Introduces `format_on_save` variants that format only modified lines, limiting formatting to lines changed since the last commit. This prevents massive diffs when editing legacy codebases. Aligns with VS Code's `editor.formatOnSaveMode` naming: - `"modifications"` — formats only git-diffed lines. Requires source control; skips formatting if no diff is available. - `"modifications_if_available"` — formats only git-diffed lines, falling back to full-file formatting for untracked files, when source control is unavailable, or when the LSP does not support range formatting. Also supports importing equivalent VS Code settings (`formatOnSaveMode`). This PR uses the range-based whitespace/newline infrastructure from the dependency PR above. ## Changes <details> <summary><b>New settings, modified ranges computation, VS Code import</b></summary> ### New settings (`language.rs`, `default.json`, `all-settings.md`) Two new `FormatOnSave` variants: `Modifications` and `ModificationsIfAvailable`. ### Modified ranges computation (`items.rs`) - `compute_format_decision()` — reads `format_on_save` setting across all buffers, determines whether to use ranged formatting (`Ranges`), full formatting (`Full`), or skip (`Skip`). - `compute_modified_ranges()` — extracts modified line ranges from git diff hunks via `BufferDiffSnapshot`. - `is_empty_range()` — helper to detect deletion-only hunks that produce no formatable content. The `save()` method calls `compute_format_decision()` and dispatches accordingly. ### Modifications mode in `lsp_store.rs` - Adds `FormatOnSave::Modifications | FormatOnSave::ModificationsIfAvailable` to the formatter selection match arm. - `ModificationsIfAvailable` falls back to full-file formatting when ranged formatting produces no results. ### VS Code settings import (`vscode_import.rs`, `settings_store.rs`) Imports `editor.formatOnSaveMode` mapping: - `"modifications"` → `FormatOnSave::Modifications` - `"modificationsIfAvailable"` → `FormatOnSave::ModificationsIfAvailable` - `"file"` → `FormatOnSave::On` </details> ## Tests - `test_modifications_format_on_save` — basic modifications mode formatting with dirty buffer - `test_modifications_format_no_changes` — clean buffer triggers no formatting - `test_modifications_format_lsp_no_range_support` — LSP without range formatting skips entirely for `Modifications` - `test_modifications_format_lsp_returns_empty_edits` — empty edits handled gracefully - `test_modifications_format_multiple_hunks` — two non-adjacent edits produce two separate range formatting requests --- 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 #16509 Depends on #53942 Release Notes: - Added `modifications` and `modifications_if_available` options to `format_on_save`, which format only git-changed lines instead of the entire file - When using modifications mode, `remove_trailing_whitespace_on_save` and `ensure_final_newline_on_save` are also scoped to changed lines, preventing unwanted diff jitter in legacy codebases - Added support for importing VS Code's `editor.formatOnSaveMode` setting --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
14efb2c376 |
Switch Guild board automation to role checks (#60606)
Outside collaborators can't be added to GitHub teams, team membership is restricted to org members. https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/managing-outside-collaborators/adding-outside-collaborators-to-repositories-in-your-organization#:~:text=Outside%20collaborators%20cannot%20be%20added%20to%20a%20team%2C%20team%20membership%20is%20restricted%20to%20members%20of%20the%20organization Release Notes: - N/A |
||
|
|
c1a0f53792 |
Make editor::LineUp & editor::LineDown honor vertical_scroll_margin like vim::LineUp & vim::LineDown (#52057)
## Context This is an implementation of this feature: https://github.com/zed-industries/zed/discussions/49821 Although, I'd argue it's a bug fix, not a feature. Either way : This copies the window scroll logic from the `vim` mode versions with out all the extra logic for visual mode. Could refactor the common logic out of the vim code and make it common. But that seems like a bigger PR. Happy to take a stab at it if that's what you prefer. Could also add new commands for the new behavior if you prefer. I didn't do that, because it seems like more clutter in the commands, and my belief that the existing behavior is a bug. But happy to do that if you prefer. ## How to Review creates new function `scroll_screen_with_cursor_margin` in `scroll.rs` wires up editor::LineUp/LineDown to new function in `elements.rs` adds a test in `editor_tests.rs` ## Self-Review Checklist <!-- Check before requesting review: --> - [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: - editor::LineUp/LineDown commands now honor vertical_scroll_margin (same as vim::LineUp/LineDown) --------- Co-authored-by: Kirill Bulatov <mail4score@gmail.com> |
||
|
|
7e786c264c |
Fix worktree entry IDs for symlinked files (#57846)
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 #55792 Release Notes: - Fixed files in pnpm workspaces moving to symlinked `node_modules` paths after saving. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
2a69b52459 |
Bump Zed to v1.12.0 (#60600)
Release Notes: - N/A Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com> |
||
|
|
3f135978df |
csv_preview: Add row filtering feature (#60339)
# Objective CSV feature needs row filtering feature by column values. This PR provides base implementation of it with barebones ui. > NOTE: Sleek UI with search & proper scrolling hanling is implemented in next PR. It's stacked on top to reduce review scope ## Solution - New `FilterEntry` / `FilterEntryState` model in `table_data_engine/filtering_by_column.rs` tracking per-column applied/candidate filter values - Filtering runs in the background (`feat: Implement background filtering`) so large CSVs don't block the UI thread while a filter is applied - Filter menu entries reflect live counts and support a configurable sort order (`FilterSortOrder`, added in `renderer/settings.rs` / `settings.rs`) - Filter/sort trigger buttons on column headers are hidden until hover, using `GradientFade` (new in `ui/src/components/gradient_fade.rs`) to fade content behind them ## Testing Filter chain tested on csv fixtures with multiple filters applied sequentially columns. ## Self-Review Checklist: (todo) - [ ] 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) (out of scope of this pr) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase <img width="664" height="249" alt="image" src="https://github.com/user-attachments/assets/0e9b0a91-1a27-4e0f-a8d4-fdce36735131" /> <img width="663" height="205" alt="image" src="https://github.com/user-attachments/assets/0428f5c6-6aaa-4891-b010-ca79803f6613" /> --- Release Notes: - Added initial row filtering UI & logic |
||
|
|
cf4a373230 |
Unify Render and RenderOnce into View (#58087)
This allows us to build powerful and flexible Input and TextArea components 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: - N/A --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
f1b91966fc |
agent_ui: Fix expanded message editor staying auto-height during streaming (#55916)
Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments (Unsafe: none) - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Summary When the agent is streaming output, expanding the message editor can appear to work (the container grows) but the input editor itself remains constrained to auto-height (only a few lines). Toggling minimize → expand makes it render correctly. This PR ensures the message editor stays in full mode while expanded, preventing automatic editor mode syncing on thread updates from overriding the user's explicit expand action during streaming. ## Steps to reproduce 1. Start an agent thread and send a message that causes streaming output 2. While streaming, click “Expand Message Editor” 3. Observe the input editor still shows only a few lines (auto-height) 4. Click “Minimize Message Editor” and then expand again; it becomes fully expanded ## Test plan - Start an agent thread and let it stream - Click “Expand Message Editor” while streaming - Verify the editor actually expands (not limited to the auto-height max lines) - Toggle minimize/expand multiple times during streaming; verify it remains correct ## Additional context Repro video: https://github.com/user-attachments/assets/6e328fa8-d431-456a-b70a-864ae617ea88 Release Notes: - Fixed message editor not fully expanding during agent generation --------- Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com> |
||
|
|
244a8d349c |
gpui: Add run_embedded and ApplicationHandle for externally driven run loops (#60574)
On ordinary platforms, `Platform::run` blocks for the lifetime of the app, and `Application::run`'s stack frame keeps the app state alive. Embedded platforms invert that: the run loop belongs to someone else. `Application::run_embedded` supports that shape: it starts the app exactly like `run()`, but returns an `ApplicationHandle` holding the strong app handle. Release Notes: - N/A |
||
|
|
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 |
||
|
|
5df865937a |
acp_thread: Log error when checkpoint comparison fails (#59196)
`update_last_checkpoint` swallows `compare_checkpoints` errors with `.unwrap_or(true)`. The "Restore checkpoint" button silently disappears and nothing gets logged, which is what made the linked issue painful to track down in the first place. The sibling `update_last_checkpoint_if_changed` a few lines up already handles the same call with `.context(...).log_err()` and an early return, so I did the same here. On error the checkpoint's visibility is left alone instead of being forced to hidden. I didn't propagate the error because the task result gets `?`'d in `run_turn`'s cleanup, and failing there would leave the panel stuck in its generating state. Added a regression test that breaks the comparison mid-turn (recreating `.git` makes the fake repo forget its checkpoints) and asserts an already-visible checkpoint stays visible. It fails on main and passes with this change. The new log line shows up when it runs: `failed to compare checkpoints: invalid left checkpoint: ...` Closes #59100 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 checkpoint comparison errors silently hiding the "Restore Checkpoint" button in the agent panel. Co-authored-by: pstemporowski <110726755+pstemporowski@users.noreply.github.com> Co-authored-by: Bennet Bo Fenner <bennet@zed.dev> |
||
|
|
8dcf9fd48c |
project_panel: Open files in a permanent tab on middle click (#60563)
# Objective Provide a means of quickly opening a permanent tab from project panel instead of a preview tab. Implements #51866 (_Middle click to open file in a new tab_ with 18×↑) which is also part of #31822 (_Middle Click Improvments_) titled "middle clicking on a file in the project panel should open the file in a non-transient state". With `preview_tabs.enable_preview_from_project_panel` enabled, a click in the project panel opens a preview tab, and there's no easy gesture to open a permanent one instead, simplest one currently being a double click. VS Code and VSCode-based editors recognize middle mouse click as a way to open a permanent tab since 2016 (microsoft/vscode#14453). ## Solution Wired up an `on_aux_click` handler for project panel entries: middle-clicking a file opens it in a permanent tab and focuses it, regardless of the preview tabs setting. Added a line to `docs/src/project-panel.md` to reflect the behavior. ## Testing - Manually tested on Windows: middle click opens a permanent tab, promotes an existing preview tab to a permanent one if already open, does nothing for directories - Haven't tested on macOS/Linux ## 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) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase <details> <summary>Click to view showcase</summary> https://github.com/user-attachments/assets/2de5f23d-637f-4ffc-8d03-02dc11714af4 </details> --- Release Notes: - Added support for middle-clicking a file in the project panel to open it in a permanent tab instead of a preview tab |
||
|
|
b98c695f55 |
terminal: Open links with Cmd/Ctrl-click when mouse mode is enabled (#60067)
This fixes #56956. The terminal link-open gesture was split between `mouse_down` and `mouse_up`, but both halves only ran in the non-mouse-reporting path. When a foreground app enabled terminal mouse reporting, a secondary click on a URL or file path was forwarded to the PTY instead of opening the link. This changes secondary-click link handling so it checks for a hyperlink before mouse reporting on press, and completes the matching hyperlink open before mouse reporting on release. The event is only consumed when the click actually lands on the same link, so normal clicks in mouse-reporting TUIs continue to be forwarded as before. Validation: - `CARGO_BUILD_JOBS=1 cargo test -j1 -p terminal test_hyperlink_ctrl_click_same_position_in_mouse_mode` - `CARGO_BUILD_JOBS=1 cargo check -j1 -p terminal` Release Notes: - Improved terminal links: Cmd/Ctrl-click now opens links even when the application has mouse reporting enabled (e.g. vim, opencode, claude). Disable `terminal.open_links_in_mouse_mode` to forward these clicks to the application instead. --------- Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com> |
||
|
|
ce9720d61b |
grammars: Recognize Gentoo ebuild files as bash script (#59068)
The Gentoo `ebuild` file format is a subset of a bash script, see https://wiki.gentoo.org/wiki/Ebuild. 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 Closes #ISSUE Release Notes: - Changed `ebuild` files to be recognized as bash. Signed-off-by: gcarq <egger.m@protonmail.com> Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
b099024705 |
Fix typos and grammatical mistakes in docs (#59495)
# Objective - Describe the objective or issue this PR addresses. -> ** Typo and grammar fixes!** ## Solution ## Testing ## 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 --- Release Notes: - N/A |
||
|
|
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> |
||
|
|
eb9b2b8341 |
go: Fix outline for methods with unnamed receivers (#58656)
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 This fixes Go outline extraction for methods whose receiver has no name, such as `func (v2) Method()`. These methods are now included in outline symbols, which also feed breadcrumbs and sticky scroll. Tested with: - `cargo test -p languages` - `cargo test -p grammars` - `./script/clippy -p languages` - `cargo fmt --check --package languages` Before: [before_cut.webm](https://github.com/user-attachments/assets/91eb5cb0-703a-4496-b0dd-5369c4c219fc) After: [after_cut.webm](https://github.com/user-attachments/assets/76d13d88-3671-4118-99fc-c073a6e64727) Release Notes: - Fixed Go methods with unnamed receivers not appearing in breadcrumbs and sticky scroll. Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
c09d59120c |
project: Fix content swap when an LSP rename also renames the file (#59104)
A "rename symbol" whose workspace edit also renames the file (a `TextDocumentEdit` followed by a `RenameFile` resource operation) only applied the text edit to the in-memory buffer. The on-disk file still held the pre-edit content, so the blind `fs.rename` moved stale bytes to the new path while the edited buffer was stranded at the old path, swapping the two files' contents. This persists a dirty buffer for the rename source before renaming, so the new file receives the edited content and the now-clean buffer can't be saved back to the old path. Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes #59077 Release Notes: - Fixed a symbol rename that also renames the file swapping the contents of the old and new files |
||
|
|
f6385d12c7 |
Consistently use context() to preserve sources for anyhow errors (#59112)
When you use `anyhow::anyhow!("{error}")` to convert a preexisting error
to an `anyhow::Error`, the error source can be lost (depending on the
`Display` impl of the error). Anyhow errors can display the whole source
chain when printed. This commit makes us consistently use `context()`
instead to preserve the underlying error's source.
Release Notes:
- N/A
|
||
|
|
657962ab30 |
Use more .array_windows::<N>() (#58877)
- [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 The fight against entropy continues... Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
9efc6f5e16 |
Fix should_log_lsp_request_failure logic inversion (#57554)
Was trying to debug an r-a issue and ran into this. Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliabilityx - [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: Kirill Bulatov <kirill@zed.dev> |
||
|
|
bb021d2004 |
workspace: Skip closed items that cannot be reopened (#56299)
Resolves https://github.com/zed-industries/zed/issues/55600 This diff fixes `pane::ReopenClosedItem` getting stuck when the closed-item stack contains entries that cannot be reopened, such as Project Search, untitled buffers, or Default Settings. Previously, `Workspace::navigate_history_impl` would pop the newest closed entry and stop if that item was no longer present in the pane and had no path recorded for reopening. That made `cmd- shift-t` appear to do nothing until enough attempts had consumed those unreopenable entries. With this change, closed-item navigation keeps scanning when it encounters an entry that cannot be activated or reopened by path. This preserves the current path-based reopening behavior for normal files, while avoiding no-op shortcuts caused by non-file items in the closed stack. This made me wonder whether or not we'd eventually want full reopen support for non-traditional items like Project Search or bundled settings editors. Supporting that properly would require storing item-specific restoration state, such as search query/options for Project Search or a bundled-file descriptor for Default Settings, and teaching closed-item navigation how to recreate those items from that state. Something definitely out of scope for this PR. | Before | After | | --- | --- | | <video src="https://github.com/user-attachments/assets/c7044423-4531-4857-84f2-4e9651826c6a" controls width="500" title="Before"></video> | <video src="https://github.com/user-attachments/assets/c89dcefb-1796-4cdf-bb21-f165145e678e" controls width="500" title="After"></video> | Release Notes: - Fixed reopening closed tabs getting stuck on closed items that cannot be reopened. |
||
|
|
057bd63412 |
editor: Decode escaped characters in hover popover links (#55973)
Decodes url escape sequences in hover preview `file:///` links like escaped spaces in the file path. I'm working on an LSP and happened to be working with some files in a directory with spaces. When adding Markdown links with `file:///` the `%20` escape for spaces was being included verbatim in the path that Zed tried to open. I'm reusing the lines from `markdown_preview_view.rs` for decoding. In the existing tests I don't see coverage for `file:///` links. If you'd like some tests for this can you point me to any examples to start from? Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Fixed decoding spaces and other escaped characters in `file://` links used in hover popovers --------- Co-authored-by: dino <dinojoaocosta@gmail.com> |
||
|
|
dedf4cbfe8 |
cloud_api_client: Make send_authenticated_json_request public (#60562)
This PR makes the `send_authenticated_json_request` method on the `CloudApiClient` public. This way we can use it to make requests by external callers. The `build_request` method was also inlined into `send_authenticated_request` to make the contract simpler. Release Notes: - N/A |
||
|
|
f47073a215 |
bedrock: Add native support for Bedrock Mantle models (#60480)
Adds native support for AWS Bedrock's Mantle endpoint (`bedrock-mantle`), which serves models with no `Converse`/`Invoke` support on `bedrock-runtime`, such as GPT-5.5, GPT-5.4, and Grok 4.3 but more importantly **open-weight** models Closes #60471 ## What's changed - Renamed the existing `Model` enum in the `bedrock` crate to `ConverseModel`, and added a new `MantleModel` enum for Mantle-only models. Mantle models reuse the existing OpenAI-compatible Chat Completions/Responses request and response plumbing (`into_open_ai`/`into_open_ai_response`, `OpenAiEventMapper`/`OpenAiResponseEventMapper`) already used by the native OpenAI and OpenAI-compatible providers, rather than introducing new marshalling code. - Added a `BedrockMantleModel` language model that routes requests to the `bedrock-mantle` endpoint, dispatching to Chat Completions or the Responses API depending on the model. Mantle models appear in the model picker alongside Converse models under the same Bedrock provider. - Added region gating: `bedrock-mantle` is only available in a subset of AWS Regions, so using a Mantle model outside of them surfaces a clear error naming the current Region and the supported ones, instead of an opaque HTTP failure. - Implemented Bedrock bearer token authentication for Mantle requests: a configured Bedrock API key is used as-is, and every other auth method (IAM credentials, named profile, SSO, automatic) derives a short-term token by locally SigV4-presigning a `CallWithBearerToken` request. This requires no extra network round trip and no token caching, since re-signing locally is cheap. - Added a specific error for the 403 you get when your credentials have `bedrock:CallWithBearerToken` but not the separate `bedrock-mantle:CallWithBearerToken` permission Mantle models require, since this is the most common misconfiguration. - Added a `mantle_available_models` setting so custom models served through `bedrock-mantle` can be configured, the same way other providers support custom models via `available_models`. - Documented Mantle models and the new setting in the Amazon Bedrock section of [Use a Gateway](https://zed.dev/docs/ai/use-a-gateway#amazon-bedrock). ## Testing - Added unit tests covering: the local SigV4 bearer-token signing (including a byte-for-byte cross-check against a reference implementation), Mantle endpoint URL construction, the Mantle-supported-regions list, thinking-effort normalization, and the settings-to-model protocol mapping. - `cargo test -p bedrock -p language_models -p settings_content -p settings` passes. - `./script/clippy` passes with no new warnings. Release Notes: - Added native support for AWS Bedrock's Mantle endpoint, enabling GPT-5.5, GPT-5.4, and Grok 4.3 through the Amazon Bedrock provider. |
||
|
|
07fa666c4e |
language_extension: Hold LspStore weakly in LspAccess::ViaLspStore (#60558)
# Objective Fix a Windows CI flake in `extension_host extension_store_test::test_extension_store_with_test_extension`, which panicked in GPUI's leak detector with three leaked `LspStore` handles ([example run](https://github.com/zed-industries/zed/actions/runs/28871529605/job/85635418351)). ## Solution `LspAccess::ViaLspStore` held a strong `Entity<LspStore>`, cloned into three `ExtensionHostProxy` registrations by `language_extension::init`. The proxy sits inside an `Arc` cycle (proxy → `LanguageServerRegistryProxy` → `LanguageRegistry` → `ExtensionLspAdapter` → `WasmExtension` → `WasmHost` → proxy), so whenever an extension LSP adapter was registered at app-drop time, the cycle pinned the `LspStore` entity after its owning `Project` dropped. The flake was purely timing: extension reload toggles the adapter registration, and an unclean LSP pipe shutdown on Windows shifted teardown into the pinned window. `ViaLspStore` now holds a `WeakEntity<LspStore>`, upgraded at its sole use site (`remove_language_server`), skipping the stop task when the store is gone — matching the existing `ViaWorkspaces` semantics. A dead store is the expected terminal state after the owning project drops, so no error is logged or propagated. `Project`/`HeadlessProject` remain the sole long-term owners of `LspStore`, which is already the convention everywhere else (e.g. `json_schema_store`, the `lsp_store` message handlers). ## Testing - Ran `cargo nextest run -p extension_host extension_store_test::test_extension_store_with_test_extension` locally: passes. - The flake is timing-dependent (reproduced on Windows CI), so a local pass doesn't prove absence; the fix removes the only strong non-owner handle, which the leak detector reported. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - N/A --------- Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com> |
||
|
|
042d22ce9c |
git_ui: Use pull request link from push output in push toast (#60522)
## Summary Fixes #60288 and #60454 . After a push, the push toast's "Create Pull Request" button fails with `Unsupported remote URL` when the repository's remote is not a plain, recognized host. This restores the pre-#53913 behavior as a fallback: use the create-PR/MR link that `git push` itself prints, and only build a URL from the provider registry when the push output had no link. ## Why this matters #53913 made the button always appear and changed `create_pull_request` to reconstruct the PR URL from the remote via `git::parse_git_remote_url` against the `GitHostingProviderRegistry`. When the remote is not recognized, parsing returns `None` and the action errors. This affects self-hosted GitLab/GitHub, an SSH-config host alias like `git@personal:owner/repo` (the duplicate #60076), and any non-standard host. Before #53913, the flow used the link git prints in the push output, which works regardless of host, so this is a regression for anyone not pushing to a plainly-recognized GitHub URL. ## Solution `git push` prints a `remote:` line with the hosting provider's create-PR/MR URL (GitHub: "Create a pull request for '\<branch>' on GitHub by visiting:", GitLab: "To create a merge request for \<branch>, visit:", Bitbucket: "Create pull request for \<branch>:"), and we already hold the push `RemoteCommandOutput`. - `remote_output.rs`: add `extract_pull_request_url`, which scans the push stderr for the first `http(s)` URL on a `remote:` line tied to a create-PR/MR prompt. It ignores unrelated URLs (for example the OpenSSH post-quantum warning line). - `git_panel.rs`: capture that URL in `show_remote_output` into `pending_pull_request_url`, and prefer it in `create_pull_request`, falling back to the existing provider construction only when the push output had no link. The cached URL is consumed once (`take()`) and cleared when the active repo, the active branch/head, or the pending remote operation changes, so a later `git: Create Pull Request` action never opens a stale URL from an earlier push. Recognized GitHub remotes are unaffected: they still get a link from the push output, with the provider path as the fallback. ## Testing Unit tests in `remote_output.rs` cover `extract_pull_request_url` for the GitHub, GitLab, and Bitbucket prompt formats, the no-link case (returns `None`, so the provider fallback runs), and an output containing an unrelated URL that must not be mistaken for the PR link. The existing remote-operation test also asserts the cached URL is cleared when a new operation starts. `cargo test -p git_ui remote_output` passes (5 tests). Tested on macOS. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Fixed "Create Pull Request" button in the toast shown after `git: push` failing for repositories on unrecognized Git hosts by using the link printed in the push output. - Fixed the button shown on the toast after `git: push` for GitLab branches with an existing merge request. It now shows "View Merge Request" and links to the existing merge request. --------- Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com> Co-authored-by: dino <dinojoaocosta@gmail.com> |
||
|
|
6a9bf6498f |
gpui_wgpu: Fix wgpu renderer teardown panic (#60160)
# Objective Opening and closing windows quickly on Linux could crash the renderer with a `GPU resources not available` panic. The `gpui_wgpu` renderer keeps its GPU resources in an `Option` that is cleared when a window is torn down, and also while device-loss recovery is pending. On Wayland the window's `Drop` releases those resources synchronously but defers unregistering the surface to a later task, so a compositor resize or transparency event can still reach the renderer in that short gap. `update_drawable_size` and `update_transparency` assumed the resources were always present and called an accessor that panics when they are not. I am not certain if there is a good case to reproduce this in zed, but I had encountered it in my own GPUI app. ## Solution Make `update_drawable_size` and `update_transparency` tolerate missing GPU resources by skipping the surface reconfiguration instead of panicking, matching how the rest of the renderer already guards this state. The requested size and alpha mode are still recorded before the guard, so they take effect if the renderer's resources are recreated, for example after device-loss recovery. ## Testing Tested on Linux with Wayland. - Reproduced by opening and closing windows quickly, which previously panicked with `GPU resources not available`. With this change the panic no longer occurs. This was reproducible on a debug build or a weak/slow device. ## 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 (not sure if worth mentioning): - Fixed a crash that could occur when opening and closing windows quickly on Linux Co-authored-by: Mikayla Maki <mikayla@zed.dev> |
||
|
|
aa7591f73f |
fs: Skip parent watch for poll watcher symlink targets (#57049)
# Problem Since the release of the new git UI, when `~/.gitconfig` on a remote server is a symlink pointing to a file on a virtual filesystem (a common setup when using [OrbStack](https://orbstack.dev/) on macOS), Zed fails to connect with "Timed out pinging remote client". # Cause When setting up a file watcher for gitconfig, `fs::watch()` reads the symlink target and adds its parent directory to the poll watcher. `notify::PollWatcher::watch()` does a full synchronous recursive directory scan at registration time to build an initial snapshot. If the parent is something like a Mac home directory mounted via virtiofs, that scan blocks the server's main thread long enough that it can't respond to the initial ping within the 5 second timeout. # Solution The fix I implemented for this was to skip the parent directory watch when using a poll watcher. As far as I can tell, it's redundant in the poll case since the poll watcher detects changes by periodically reading metadata at the registered path, so watching the parent doesn't add anything for change detection. From my limited testing this seems to work fine but if someone with more experience in this part of the codebase would like to weigh in, that would be very much appreciated. Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [ ] Unsafe blocks (if any) have justifying comments - [ ] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [ ] Performance impact has been considered and is acceptable Release Notes: - Fixed remote SSH connections timing out when `~/.gitconfig` is a symlink to a file on a virtual filesystem |
||
|
|
846c40cf0d |
Add missing panels to View menu (#60356)
# Objective Ensure that all existing panels have corresponding menu items in the "View" menu. I was onboarding a friend to Zed yesterday that was having a hard time figuring out how to interact with the Agent. Although he did open the "View" menu, I noticed that the Agent panel item was missing from there, making it hard for new users to discover it exists. ## Solution * Add both "Agent Panel" and "Git Panel" entries to the menu items for the "View" app menu. * Update the action used for the "Terminal Panel" menu item from `terminal_panel::ToggleFocus` to `terminal_panel::Toggle` to ensure we display a shortcut for this menu item. * Another valid option would be to update the default keymap to use `terminal_panel::ToggleFocus` instead but that would probably break existing user's expectations that the default shortcut toggles the terminal panel, instead of toggling its focus. * Introduce `zed_actions::git_panel` to be able to extract its `ToggleFocus` action, following the existing pattern. ### Next Steps It's worth noting that, even though there's now an "Agent Panel" item mapped to the `assistant::ToggleFocus` action, its default keybinding is not displayed (at least on macOS), because of the way it's defined as `cmd-?` . Using `cmd-shift-/` instead doesn't work, so we'll likely have to update `MacKeyboardMapper` to allow mapping between shifted and unshifted keys equivalent, that is, when `?` is detected, it is able to determine that, in the user's layout that is the result of `shift-/`. ## Testing Manually tested, screenshots can be seen in the "Showcase" section. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [ ] Unsafe blocks (if any) have justifying comments - [ ] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [ ] Tests cover the new/changed behavior - [ ] Performance impact has been considered and is acceptable ## Showcase <details> <summary>Before</summary> <img width="488" height="946" alt="CleanShot 2026-07-03 at 14 24 35@2x" src="https://github.com/user-attachments/assets/58b0497c-2929-4da3-86b6-a2e0ce0c5ca4" /> </details> <details> <summary>After</summary> <img width="524" height="1116" alt="CleanShot 2026-07-03 at 14 24 59@2x" src="https://github.com/user-attachments/assets/8e2c6320-97ad-4620-b595-182f6d0ded81" /> </details> --- Release Notes: - Added "Agent Panel" and "Git Panel" items to the "View" menu |
||
|
|
601690391b |
git: Load buffer git diff bases with a single batched git process (#59357)
# Objective Whenever the git repository state is updated on disk (e.g., via staging, committing, branch switching, or stashing), `reload_buffer_diff_bases` is scheduled to reload the diff for all active buffers. This causes 2 git processes to be spawned for each open file which can become noticeable when many files are open https://github.com/zed-industries/zed/blob/b2617baa21a83dfcbd8361e285bb2eba84e294ec/crates/project/src/git_store.rs#L5179 ## Solution This PR introduces `load_revisions` which uses a single `git cat-file --batch` command to compute the diff for all files in the same git process. This prevents the need to sequentially schedule 2 git subprocesses per open buffer. I also changed `load_index_text` and `load_commited_text` to rely on `load_revisions` which simplifies the code. ## Testing I added a unittest and manually verified that Zed now only runs a single `git cat-file --batch` command instead of 2 `git show` processes per open buffer. On macOS I viewed the currently running git processes using: ```shell sudo eslogger exec | jq --unbuffered -r ' select(.event.exec?.target?.executable?.path? | strings | contains("git")) | (.event.exec?.args? // []) | join(" ") ' ``` ## 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 /cc @Veykril Release Notes: - Reduced number of git processes for calculating diff of open buffers when the repo state changes on disk |