The annotation and form-filling surface is being dropped, so remove it
end to end rather than leave it half-maintained.
pdf_viewer loses the editing APIs and everything only they used:
add_ink_annotation, add_highlight_annotation, delete_annotation,
apply_form_edits, the form widget and annotation extraction, the
PdfFormWidget/PdfFormEdit/PdfAnnotation types, the document
serialization helper, and the pdfium guards and constants those
functions were the sole users of. Rendering, text, links, outline and
metadata are untouched; annotation rendering stays on because it paints
markup already embedded in viewed documents.
image_viewer loses the tool palette, form widget overlays, inline form
editors, pen canvas, option menus, the annotate toolbar button, the
Undo Edit and Delete Annotation actions and their key bindings, plus
the associated state and handlers. Text selection, find, links,
thumbnails, outline, properties, rotation, presentation and Save a Copy
remain.
Three layout issues kept horizontal scrolling from working when a page
was wider than the viewport: the viewport scrollbar was vertical-only,
so nothing could be dragged; centering the pages hid the left half of
an overflowing page, because scroll offsets cannot go positive; and the
centering came from a stretched flex child, which made the container
report no horizontal overflow at all.
The container now aligns children to the start so they keep their
content width, and pages center themselves with an auto margin only
while they still fit. The scrollbar covers both axes.
The interaction test asserts the invariants: the page's left edge
tracks the viewport edge plus the scroll offset, and the scroll range
spans the full page-minus-viewport overflow.
Zoom lag: page rasterization ran synchronously on the UI thread with the
exact zoom in the cache key, so every wheel tick re-rendered every
visible page before the next frame. Rasterization now happens in a
background task at a quantized zoom bucket (x1.25) while the closest
already-rendered bitmap stays on screen scaled to the layout; completed
renders swap in via notify. Frames the cache refuses (larger than the
budget) are never re-rendered, which previously spun an infinite
render loop.
The mock fallback renderer skipped the MAX_PAGE_DIMENSION clamp the
native path applies, so its frames grew past the cache budget at high
zoom and were refused on every attempt; the cap is now shared, and
lowered from 8192 to 4096 (a 1080p viewport is oversampled ~4x at that
point, and the worst-case frame drops from 207MB to 67MB).
Annotations: the bundled libpdfium.so was never loaded because the
loader only tried working-directory-relative paths; it now also
resolves next to the executable, matching the bundled layout. Ink,
highlight, and delete editing returned Ok with unchanged bytes when no
native engine was present, so strokes silently did nothing; they now
return errors that surface through the existing logging.
The PDF scroll container only scrolled vertically, so zoomed-in pages
could not be moved sideways. Switch it to two-axis scrolling: ctrl+wheel
and pinch zoom now anchor both axes, middle-drag pans both directions,
and the container shows a closed-hand cursor while panning. The anchor
scroll math is shared per axis.
The PDF viewport lacked the interaction set the image view already had:
ctrl/cmd+wheel and pinch zoomed nothing (plain wheel just scrolled),
middle-drag did not pan, and the zoom actions only applied image-mode
pan math, which does nothing for the scroll-based PDF layout.
- Ctrl/cmd+wheel zooms around the cursor: the native scroll handler on
the same element runs first in the bubble phase, so the applied wheel
delta is undone before anchoring the zoom.
- Pinch zooms around the touch point; zoom actions anchor the viewport
center.
- Middle-drag pans, keeping left-drag for text selection and pen input.
- extract_document_details now falls back to a single mock US-Letter
page when no native libpdfium is present, mirroring the mock
rasterizer, so PDFs open on machines without the engine instead of
failing with an image-format error.
- The annotation mouse test gates on native pdfium like the channel
order test, since mock pages carry no text.
Anchor math lives in pdf_anchored_scroll_y with unit tests, and a
gpui integration test drives real wheel/drag events to assert the
document point under the cursor stays put while zooming.
GPUI's RenderImage contract is BGRA (assets.rs) and every platform atlas
uploads the bytes raw into BGRA8 textures. All other decode paths swap
R/B before building a RenderImage; the PDF path fed pdfium's RGBA buffer
straight through, so PDF pages rendered with swapped channels on every
platform (white/gray unaffected, colors wrong).
Swap R/B at both RenderImage construction sites (page view + thumbnails)
and pin pdf_viewer's RGBA raster contract with a native channel-order
regression test (skips when no libpdfium is present).
script/bundle-mac now downloads the pinned pdfium-mac tarball from
bblanchon/pdfium-binaries into Zed.app/Contents/Frameworks, matching
what bundle-linux and bundle-windows.ps1 already do, so the bundled
pdf_viewer no longer falls back to synthetic rendering on macOS. The
runtime loader probes ../Frameworks next to the executable.
Gwen is not ready for 1.0.0; drop the crate version to 0.1.0 (README
along with it). Comment out the Check for Updates menu item and the
auto_update::init call — both query Zed's release infrastructure, which
does not apply to Gwen builds — until Gwen runs its own update server.
The appx identity versions in the Windows injector manifests are an
MSIX pairing contract and stay at 1.0.0.0.
Point feedback, flatpak and snap contact mailto at
yenru0604@proton.me, and comment out the Twitter and Join the Team help
menu items until Gwen has its own accounts.
Sweep every user-visible product string to Gwen: app menus (Quit,
Hide, Gwen Repository), feedback links (repo/issues now point at
github.com/kk376/zed, email to yenru@yrkaierx.com), move-to-Applications
and update dialogs, provider and settings copy, CLI help, installer and
desktop/flatpak/snap/plist metadata.
Rename user-facing settings values with back-compat aliases: base_keymap
"Gwen" (accepts "Zed"), fonts ".GwenMono"/".GwenSans" (accept
".ZedMono"/".ZedSans"), icon theme "Gwen (Default)". Fix F10
app-menu keymap arguments to "Gwen" and align the Windows installer
AppMutex with release_channel::app_identifier(). Internal identifiers,
wire protocol names, upstream service URLs and legal attribution are
intentionally kept.
Add a Background section to the welcome page: a file picker writes
background.path into user settings, a Clear button removes it, and the
chosen image is previewed in place. No default background is set; fit,
position and opacity remain in the Settings page.
The icon rename removed app-icon-*.png but left the cargo-bundle
metadata referencing them, so bundle-mac could not produce an app
bundle. Point every channel at app-icon-gwen*.png, align bundle
identifiers and names with release_channel (com.yrkaierx.Gwen*), and
rename the DMG artifact and volume to Gwen.
Bundle Gwen Dark (Hallowed Night) and Gwen Light in assets/themes/gwen,
derived from the champion's canon palette: hallowed mist cyan for
accents/functions, Gwen blue for types, violet for keywords, Camavor
gold for constants, pink-stitching rose for properties, mist mint for
strings over a Black Mist night base.
Set Gwen as the default theme pair in settings and the shipped settings
templates, surface it as the first tile in the onboarding theme picker
and the theme preview gallery, and guard the family with a bundled
theme regression test.
- Show the armed tool on the annotation palette via the button's
selected state; the previous selected_label workaround never rendered
because the selected state was never set
- Switch the page cursor to a crosshair while the pen tool is armed
- Let highlight and text drags start on blank space and form the
selection when the drag reaches text instead of dying silently
- Cover the palette click, highlight, pen, and blank-space drag flows
with a hermetic test
- Add a drag handle on the outline panel's right edge that resizes the
panel between 120 and 480 pixels
- Track the drag on the surrounding row so the pointer can roam, and
clamp the width to keep the panel usable
- Keep the chosen width while toggling the panel and inherit it when
the view is split
- Add ImageItemEvent::PageChanged and emit it from ImageItem::set_page
instead of Reloaded and MetadataUpdated, since turning a page does not
change the document bytes
- Handle PageChanged in ImageView by only refreshing layout state,
keeping the outline, page and thumbnail caches, form edits, undo
history, and annotations intact
- Jumping via the outline no longer resets the outline panel to
"No outline"
- Map the dev release channel to app-icon-gwen.ico and product name
Gwen in the Windows version resource instead of the upstream Zed Dev
icon and name
- Set CompanyName to yrkaierx to match the installer's AppPublisher
- Every committed document edit (annotations and form entries) pushes the
previous state onto a bounded history, so ctrl-z, the annotation
palette's Undo button, and the context menu's "Undo Edit" walk back
through them; undoing past the first edit returns to the file's bytes.
- Right clicking an annotation offers "Delete Annotation". The engine
lists a page's markup annotations (links, widgets, and popups are
excluded) and removes the one under the pointer by its annotation index.
- The palette's Undo button is disabled while the history is empty, and
every edit clears the annotation cache that hit testing reads.
- A toolbar toggle opens an annotation palette with select, highlight,
and pen tools plus four highlight colours.
- The highlight tool turns a text drag into highlight annotations, one
per page the selection spans, and clears the selection afterwards.
- The pen tool records a freehand stroke while dragging and commits it as
an ink annotation on release; the live stroke paints over the page.
- Links and form fields only take clicks while the select tool is armed,
and committed annotations share the edited-bytes path, so they travel
into the saved copy and into the rasterized pages.
- The engine layer appends quad points through pdfium's attachment-point
API and lets pdfium generate the highlight and ink appearances, which
keeps them rendering correctly at any zoom.
- Form widgets appear as overlays over the rasterized field appearances:
text fields take an inline editor (Enter commits, Escape leaves),
checkboxes and radios toggle on click, and dropdowns open their options.
- Committed edits rewrite the document once and swap renders over to the
rewritten bytes, so filled values are visible immediately and travel
into the saved copy.
- The engine layer drives pdfium's form API through the public bindings
trait, with RAII guards for the document, form environment, page, and
annotation handles, and it reports unmatched field names instead of
dropping edits silently.
- Selections are character ranges backed by pdfium character boxes,
fetched per page on demand and cached, so a drag stops mid-word and
copy yields the exact substring.
- Double clicks select the word under the pointer and right clicks
outside the selection select the word before opening the context menu.
- Highlight runs merge neighbouring characters on a line, keeping the
painted quad count low, and margins clicks resolve to the nearest glyph.
- Saving a copy of the document is available from the toolbar, the
context menu, and ctrl-s; picking the opened file itself is a no-op.
- Document properties render as a sidebar with everything pdfium reports:
title, author, subject, keywords, creator, producer, dates, page count,
and file size.
- Rotating pages turns all of them a quarter turn. Rendered bitmaps carry
the rotation, overlay geometry (links, selection, find hits) is mapped
into display space, and hit testing maps clicks back into page space.
- Presentation mode lays out a single fitted page with sidebars, find bar,
and page labels hidden; Escape leaves it.
- Fit to view now also works for PDFs by fitting the current page into the
viewport, which previously only applied to images.
- Page thumbnails render at a small DPI into their own cache and only for
the visible scroll window, mirroring the page viewport's lazy rendering.
- The document outline extracts on first open and renders as an indented
tree; entries with destinations jump the viewport, unresolvable ones stay
visible but inert.
- Both panels share the left sidebar and are mutually exclusive, and the
page bitmap window helper is now shared with the main viewport.
Chrome-parity navigation work for the PDF viewer:
- Find in document (ctrl-f): query editor, match counter, Enter/Shift+Enter
and ctrl-g navigation, yellow highlights with a stronger tint on the
active match, and a page jump per match.
- Internal link destinations: pdfium now reports dest_page for GoTo links,
so clicking a link that points inside the document jumps to that page
instead of being dropped.
- Space/Shift+Space scroll the viewport a screen at a time, unless the
find bar has focus so the query stays typeable.
Follow-up to #63195.
# Objective
When `cursor_animation` is enabled, moving a block cursor (e.g. in Vim
mode) leaves the character underneath hidden until the spring animation
fully finishes, after which the letter pops in.
This happens because `CursorLayout::paint` returned early while
animating, skipping `block_text`.
## Solution
Paint `block_text` upon the animated cursor's arrival at the target
cell, rather than waiting for the entire spring settling phase to
complete:
- Check if any animated corner has reached the target bounds
(`bounds.dilate(...)`).
- If the cursor is still in mid-air, return early so we don't draw the
destination letter prematurely.
- Once it touches the target cell, fall through and paint `block_text`
over the cursor polygon.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
Left: before, Right: after
https://github.com/user-attachments/assets/7057f40a-64a7-4035-b8e2-7c0b7dc40069
---
Release Notes:
- Fixed an issue where the block cursor hid the character underneath
until cursor animation completed.
---------
Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
# Objective
Zed on X11 could crash with `index out of bounds: the len is 0 but the
index is 0` in `WgpuAtlas::get_texture_info` right after recovering from
a lost GPU device (Sentry ZED-BVQ, Linear FR-488).
## Solution
When the device is lost, `X11Window::draw` recreates the renderer, which
clears the sprite atlas, and sets `force_render_after_recovery` so the
next frame rebuilds the scene instead of replaying the cached one. Only
the periodic refresh timer consumed that flag though. An `Expose` event
handled in the same event loop turn (a compositor repainting after the
same GPU reset, for example) requested a presentation-only frame with
`force_render: false`, so GPUI presented the previously rendered scene,
whose sprites still pointed at atlas textures that no longer exist.
We now consume the flag in `X11WindowStatePtr::refresh`, so every frame
request, Expose or timer, forces a full render after recovery. The field
is private now so a caller can't bypass it again.
## 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 a crash on Linux (X11) that could occur when a window was
redrawn immediately after recovering from a lost GPU device.
- [GPUI] Fixed a crash on Linux (X11) when an `Expose` event presented a
cached frame immediately after GPU device recovery.
# Objective
Fixes#63835.
Nearby related diagnostics omitted the link back to their primary
diagnostic.
## Solution
Always include the existing back link on related diagnostic blocks,
regardless of line distance. The primary diagnostic still suppresses
nearby related hints as before.
## 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
---
Release Notes:
- Improved diagnostic navigation by showing back links to the primary
diagnostic even for nearby related diagnostics.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
Previously, we created texture atlas bind groups every frame (once per
sprite group). This showed up in delta web mobile profiling.
This PR reuses them across frames, which saved ~5% frame time on the
delta web thread view on a pixel 10 pro.
---
Release Notes:
- [GPUI]: Improved performance on wgpu by caching atlas bind groups
## Objective
Allow custom terminal path regexes to extend inherited entries without
copying them. This PR also corrects the existing mismatch between the
documented and shipped default regexes.
This is the last submission in the #64399 series, following #62769,
#64222, #64440, #64484, and #64540.
## Solution
The `"..."` entry is intentionally supported at the top level only. A
`"..."` line inside a multiline entry remains regex text. Existing
configurations that use bare `...` as a three-character regex can
preserve that behavior by writing `["..."]` as an entry instead.
The shipped regexes and hyperlink matching behavior are unchanged.
## Testing
All focused tests and all hyperlink tests pass on macOS. The documented
default expressions were checked against the shipped values.
## 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 support for `"..."` in `terminal.path_hyperlink_regexes` to
extend inherited regexes without repeating them.
Make provider-owned terminal cards read-only for user input while
preserving local inspection. This builds on the explicit terminal
ownership introduced in #64544.
- Add a construction-time `TerminalView::with_read_only` option,
selected from ACP process ownership rather than PTY presence. Existing
views remain interactive by default, including client-owned headless
terminals.
- Reject typing, send actions, paste, file/path drops, IME input,
clear/rerun actions, and focus reports in read-only views.
- Preserve selection, copying, links, scrolling, search, and local Vi
navigation. Leaving Vi mode does not enable terminal input.
- Pass an explicit mouse-routing policy to the existing lower terminal
handlers so provider-requested mouse and alternate-scroll modes cannot
consume inspection gestures. Real modifiers remain unchanged, and
Linux/FreeBSD middle-click paste is suppressed.
Release Notes:
- N/A
## Objective
Group the threads sidebar settings together in JSON and the Settings
Editor, using consistent “Threads Sidebar” terminology.
This follows up on #63452 now that #62883 has added configurable default
width, and includes the auto-open setting added since then.
## Solution
- Group `position`, `default_width`, and `auto_open` under
`agent.threads_sidebar`, and display their controls together in
Settings.
- Automatically migrate `agent.sidebar_side`,
`agent.threads_sidebar_default_width`, and
`agent.threads_sidebar_auto_open` across supported settings scopes,
preserving existing nested values.
- Apply changes to the default width immediately, including when the
sidebar was manually resized, and clear the saved width override.
Unrelated settings changes preserve manual sizing.
- Document all three settings, including the previously missing position
entry.
## Testing
The following targeted checks passed on the local changes:
- `cargo test -p migrator nest_agent_threads_sidebar_settings` — 7 tests
passed.
- `cargo test -p sidebar -p workspace -p agent_settings -p gpui_platform
--features gpui_platform/runtime_shaders --lib -- width
threads_sidebar_settings test_open_directory_in_existing_window` — 9
tests passed.
- `cargo fmt --all` completed successfully.
- `git diff --check` passed.
- From `docs`: `npx prettier --check src/reference/all-settings.md
src/ai/parallel-agents.md` passed.
Coverage includes migration precedence and supported scopes, settings
defaults and width limits, manual sizing and resets, persisted widths,
and auto-open behavior.
Full application tests and manual UI testing were not run. Clippy was
not rerun after the final terminology changes.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Improved threads sidebar settings by grouping position, default width,
and auto-open together, and applying default-width changes even after
manual resizing.