Commit Graph
2511 Commits
Author SHA1 Message Date
Danilo Leal 08090f496f agent_ui: Add a menu for inserting context (#47768)
This PR swaps the @ icon button in the message editor for a + one, which
opens a dropdown that displays context options you can add to the agent.
Aside from removing one step if you're wanting to add context first with
the mouse (in comparison to just inserting @ in the message editor),
this menu will also house skills you've created, whenever we get to
support to that. It also works to surface images and selections in a bit
more visible way as context options. So, effectivelly, this is a bit of
foundation work for further features to come. Here's what it looks like:

<img width="500" height="586" alt="Screenshot 2026-01-27 at 11  38@2x"
src="https://github.com/user-attachments/assets/551686ba-4629-4317-9177-1e942512a23c"
/>

Note that all the options you see in the menu should also be available
through simply typing @ in the message editor.

Release Notes:

- Agent: Added a menu for inserting context more easily with the mouse
in the agent panel.
2026-01-27 15:37:32 -03:00
Ran Benitaanddino 1169dff02b vim: Add gdefault setting to set /g as a default substitution flag (#47664)
Add support for Vim's `gdefault` option which makes the `:substitute`
command replace all matches in a line by default, instead of just the
first match. When enabled, the `/g` flag inverts this behavior.

- Add `vim.gdefault` setting
- Add `:set gdefault`, `:set nogdefault` (and short forms `:set gd`, `:set nogd`)
- Fix handling of multiple `/g` flags so that each one inverts the one before

Closes #36209

Release Notes:

- vim: Add `vim.gdefault` setting to make `/g` (replace all matches in a line) the default for substitutions, along with `:set gdefault` and `:set nogdefault` commands (short forms: `gd`, `nogd`)

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
2026-01-27 17:04:10 +00:00
Conrad Irwin c729dc7d09 Use semibold (#47725)
New on the left, old on the right:

<img width="1612" height="1047" alt="Screenshot 2026-01-26 at 20 31 04"
src="https://github.com/user-attachments/assets/3e0d01b6-05e9-4c9c-8c15-6c525ce9fa9f"
/>
<img width="1604" height="915" alt="Screenshot 2026-01-26 at 20 30 49"
src="https://github.com/user-attachments/assets/77d0f9e0-778b-45df-a8e1-ade63ee9e798"
/>


Release Notes:

- Bold UI text will now render using Plex SemiBold instead of Bold.
2026-01-27 08:50:52 -07:00
Kirill Bulatov 515aadbfb7 Tidy up signature help delays (#47762)
Follow-up of https://github.com/zed-industries/zed/pull/46745

Release Notes:

- N/A
2026-01-27 15:53:15 +02:00
Ichimura TomooandConrad Irwin 7e35e566b3 encoding: Add "reopen with encoding" (#46553)
# Add "Reopen with Encoding" feature (Local/Single user)

## Summary

This PR adds a "Reopen with Encoding" feature to allow users to manually
specify an encoding and reload the active buffer.

This feature allows users to explicitly specify the encoding and reload
the file to resolve garbled text caused by incorrect detection.

## Changes

1.  Added encoding picker logic to `encoding_selector`

- Implemented a modal UI accessible via the command palette, shortcuts,
or by clicking the encoding status in the status bar.
- Allows users to select from a list of supported encodings (Shift JIS,
EUC-JP, UTF-16LE, etc.).

2.  Updated Buffer logic (crates/language)

- Added a `force_encoding_on_next_reload` flag to the Buffer struct.
- Updated the `reload` method to check this flag and apply the following
logic:
- **Non-Unicode (e.g., Shift JIS):** Bypasses heuristics (like BOM
checks) to force the specified encoding.
- **Unicode (e.g., UTF-8):** Performs standard BOM detection. This
ensures that the BOM is correctly handled/consumed when switching back
to UTF-8.

3.  UI / Keymap

- Made the encoding status in the status bar (ActiveBufferEncoding)
clickable.
- Added default keybindings:
  - macOS: cmd-k n
  - Linux/Windows: ctrl-k n
  - Windows: ctrl-k n

## Limitations & Scope

To ensure stability and keep the PR focused, the following scenarios are
intentionally out of scope:

1. **Collaboration and Remote Connections**

- Encoding changes are disabled when collaboration (is_shared) or SSH
remote connections (is_via_remote_server) are active.
- **Reason:** Synchronizing encoding state changes between host/guest or
handling remote reloads involves complex synchronization logic. This PR
focuses on local files only.

`Remote Connection (SSH/WSL)`

|Via status bar|Via shortcut/command|
|:---:|:---:|
|<img width="767" height="136" alt="remote_tooltip"
src="https://github.com/user-attachments/assets/6c7cb293-2486-4f6d-a3ff-2086d939398e"
width="400" />|<img width="742" height="219" alt="remote_shortcut"
src="https://github.com/user-attachments/assets/5448f199-2066-4baf-b349-a983ab2fa77a"
width="400" />|

`Collaboration Session `

|Via status bar|Via shortcut/command|
|:---:|:---:|
|<img width="734" height="86" alt="collab_tooltip"
src="https://github.com/user-attachments/assets/37de99a9-dd33-4c78-98bf-20654d41fdd0"
/>|<img width="720" height="182" alt="collab_pop"
src="https://github.com/user-attachments/assets/91d03ea7-f029-442a-8236-55234576f7ed"
/>|

2. Dirty State

- The feature is disabled if the buffer has unsaved changes to prevent
data loss during reload.

|Via status bar|Via shortcut/command|
|:---:|:---:|
|<img width="545" height="103" alt="local_dirty_tooltip"
src="https://github.com/user-attachments/assets/d9ae658e-52b3-4ecd-9873-d0ec8bd51b5d"
/>|<img width="707" height="178" alt="local_dirty_pop"
src="https://github.com/user-attachments/assets/d170ea1e-9fcb-42e7-aa3e-0555b4a19d86"
/>|

3. Files detected as Binary

Files that worktree detects as "binary" (e.g., UTF-16 files without BOM
containing non-ASCII characters) are not opened in the editor, so this
feature cannot be triggered.
**Future Work**: Fixing this would require modifying crates/worktree
heuristics or exposing a "Force Open as Text" action for InvalidItemView
to trigger. Given the scope and impact, this is deferred to a future PR.

## Test Plan

I verified the feature and BOM handling using the following scenarios:

### Preparation

Used the following test files:

-
[**test_utf8.txt**](https://github.com/user-attachments/files/24548803/test_utf8.txt):
English-only text file. No BOM.
-
[**test_utf8_bom.txt**](https://github.com/user-attachments/files/24548822/test_utf8_bom.txt):
English-only text file. With BOM.
-
[**test_utf8_jp_bom.txt**](https://github.com/user-attachments/files/24548825/test_utf8_jp_bom.txt):
UTF-8 with BOM file containing Japanese characters.
-
[**test_shiftjis_jp.txt**](https://github.com/user-attachments/files/24548827/test_shiftjis_jp.txt):
Shift-JIS file containing Japanese characters (content designed to
trigger misdetection, e.g., using only half-width katakana).

Used an external editor (VS Code or Notepad) for verification.

### Case 1: English-only file behavior

1.  Open an English-only UTF-8 file (test_utf8.txt).
2.  Reopen as Shift JIS.
3.  **Result:**

- Text appearance remains unchanged (since ASCII is compatible).
- Status bar updates to "Shift JIS".

### Case 2: Fixing Mojibake

1. Open a Shift-JIS file (test_shiftjis_jp.txt) that causes detection
failure.
    ※Confirm it opens with mojibake
2.  Select Shift JIS from the status bar selector.
3.  **Result:**

- Mojibake is resolved, and Japanese text is displayed correctly.
- Status bar updates to "Shift JIS".

### Case 3: Unicode file with BOM behavior

1.  Open an English-only UTF-8 with BOM file (test_utf8_bom.txt).
2.  Reopen as `Shift JIS`.
3.  **Result:**

- The BOM bytes are displayed as mojibake at the beginning of the file.
- The rest of the English text is displayed normally (ASCII
compatibility).
- Status bar updates to "Shift JIS".

### Case 4: Non-Unicode file with BOM behavior

1. Open a UTF-8 with BOM file containing Japanese
(test_utf8_jp_bom.txt).
2.  Reopen as Shift JIS.
3.  **Result:**

- The BOM bytes at the start are displayed as mojibake.
- The Japanese text body is displayed as mojibake (UTF-8 bytes
interpreted as Shift JIS).
- Status bar updates to "Shift JIS" (no BOM indicator).

### Case 5: Revert to Unicode

1.  From the state in Case 4 (Shift JIS with mojibake), reopen as UTF-8.
2.  **Result:**

- The BOM mojibake at the start disappears (consumed).
- The text returns to normal.
- Status bar updates to "UTF-8 (BOM)".

### Case 6: External BOM removal (State sync)

1.  Open a UTF-8 with BOM file in Zed (test_utf8_bom.txt).
2. Open the same file in an external editor and save it as UTF-8 (No
BOM).
3.  Refocus Zed.
4.  **Result:**

- Text appearance remains unchanged.
- The (BOM) indicator disappears from the status bar.
- Saving in Zed and checking externally confirms the BOM is gone.

### Case 7: External BOM addition

1. From the state in Case 6 (UTF-8 No BOM), save as UTF-8 with BOM in
the external editor.
2.  Refocus Zed.
3.  **Result:**

- The (BOM) indicator appears in the status bar.
- Saving in Zed and checking externally confirms the BOM is present.

### Case 8: External Encoding Change (Auto-detect sync)

1.  Open an English-only UTF-8 file in Zed (`test_utf8.txt`).
    * *Status bar shows: "UTF-8".*
2. Open the same file in an external editor and save it as **UTF-16LE
with BOM**.
3.  Refocus Zed.
4.  **Result:**
    * The text remains readable (no mojibake).
* **Status bar automatically updates to "UTF-16LE (BOM)".** (Verifies
that `buffer.encoding` is correctly updated during reload).

Release Notes:

- Added "Reopen with Encoding" feature (currently supported for local
files).

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2026-01-27 05:27:26 +00:00
Danilo Leal a5d70922a3 agent: Add setting for controlling terminal tool stop button behavior (#47521)
Addressing the feedback left on a previous PR of mine:
https://github.com/zed-industries/zed/pull/46663. I feel like this is
worthy of a setting. Note, however, that this does not apply to typing
`ctrl-c` in the terminal from within the agent panel; this is purely
controlling what happens when you click on the "Stop" button in the
terminal tool call card.

Release Notes:

- Agent: Added a setting for controlling the behavior of the stop button
in the terminal tool call card (between cancelling the command to run
and the thread, or just the command).
2026-01-23 20:41:07 -03:00
Piotr OsiewiczandMarshall Bowers e1ad3f3e4b copilot: Rename enabled_next_edit_suggestions setting to enable_next_edit_suggestions (#47484)
Co-authored-by: Marshall Bowers <marshall@zed.dev>

Closes #ISSUE

Release Notes:

- N/A

Co-authored-by: Marshall Bowers <marshall@zed.dev>
2026-01-23 16:02:48 +00:00
Jakub Konka 4809599e7b Revert " Add vim/emacs modeline support " (#47479)
Reverts zed-industries/zed#44210

I am forced to revert this PR as it completely breaks release builds
with the following panic:

```
thread 'main' (2648653) panicked at crates/rope/src/rope.rs:893:25:
byte index 73 is not a char boundary; it is inside 'স' (bytes 71..74) of `কৰক</translation>
<translation id="9216898458513705996">টেবসমূহ এই ডিভাইচত খোলা `
stack backtrace:
2026-01-23T15:37:48+01:00 INFO  [node_runtime] using Zed managed Node.js at /Users/kubkon/Library/Application Support/Zed/node/node-v24.11.0-darwin-arm64 since system Node.js wasn't found on PATH: cannot find binary path
   0: __rustc::rust_begin_unwind
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/std/src/panicking.rs:698:5
   1: core::panicking::panic_fmt
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/panicking.rs:80:14
   2: core::str::slice_error_fail_rt
   3: core::str::slice_error_fail
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/str/mod.rs:69:5
   4: core::str::traits::<impl core::slice::index::SliceIndex<str> for core::ops::range::Range<usize>>::index
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/str/traits.rs:248:21
   5: <str as core::ops::index::Index<core::ops::range::Range<usize>>>::index
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/str/traits.rs:63:15
   6: <rope::Chunks>::peek
             at /Users/kubkon/dev/zed/crates/rope/src/rope.rs:893:25
   7: <rope::Lines>::next
             at /Users/kubkon/dev/zed/crates/rope/src/rope.rs:1111:45
   8: <project::lsp_store::LspStore>::parse_modeline
             at /Users/kubkon/dev/zed/crates/project/src/lsp_store.rs:4570:43
   9: <project::lsp_store::LspStore>::on_buffer_added
             at /Users/kubkon/dev/zed/crates/project/src/lsp_store.rs:4301:14
  10: <project::lsp_store::LspStore>::on_buffer_store_event
             at /Users/kubkon/dev/zed/crates/project/src/lsp_store.rs:4166:22
  11: <<project::lsp_store::LspStore>::on_buffer_store_event as core::ops::function::FnMut<(&mut project::lsp_store::LspStore, gpui::app::entity_map::Entity<project::buffer_store::BufferStore>, &project::buffer_store::BufferStoreEvent, &mut gpui::app::context::Context<project::lsp_store::LspStore>)>>::call_mut
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/ops/function.rs:166:5
  12: <gpui::app::context::Context<project::lsp_store::LspStore>>::subscribe::<project::buffer_store::BufferStore, project::buffer_store::BufferStoreEvent, <project::lsp_store::LspStore>::on_buffer_store_event>::{closure#0}::{closure#0}
             at /Users/kubkon/dev/zed/crates/gpui/src/app/context.rs:111:44
  13: <gpui::app::App as gpui::AppContext>::update_entity::<project::lsp_store::LspStore, (), <gpui::app::context::Context<project::lsp_store::LspStore>>::subscribe<project::buffer_store::BufferStore, project::buffer_store::BufferStoreEvent, <project::lsp_store::LspStore>::on_buffer_store_event>::{closure#0}::{closure#0}>::{closure#0}
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:2281:26
  14: <gpui::app::App>::update::<(), <gpui::app::App as gpui::AppContext>::update_entity<project::lsp_store::LspStore, (), <gpui::app::context::Context<project::lsp_store::LspStore>>::subscribe<project::buffer_store::BufferStore, project::buffer_store::BufferStoreEvent, <project::lsp_store::LspStore>::on_buffer_store_event>::{closure#0}::{closure#0}>::{closure#0}>
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:818:22
  15: <gpui::app::App as gpui::AppContext>::update_entity::<project::lsp_store::LspStore, (), <gpui::app::context::Context<project::lsp_store::LspStore>>::subscribe<project::buffer_store::BufferStore, project::buffer_store::BufferStoreEvent, <project::lsp_store::LspStore>::on_buffer_store_event>::{closure#0}::{closure#0}>
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:2279:14
  16: <gpui::app::entity_map::Entity<project::lsp_store::LspStore>>::update::<(), gpui::app::App, <gpui::app::context::Context<project::lsp_store::LspStore>>::subscribe<project::buffer_store::BufferStore, project::buffer_store::BufferStoreEvent, <project::lsp_store::LspStore>::on_buffer_store_event>::{closure#0}::{closure#0}>
             at /Users/kubkon/dev/zed/crates/gpui/src/app/entity_map.rs:445:12
  17: <gpui::app::context::Context<project::lsp_store::LspStore>>::subscribe::<project::buffer_store::BufferStore, project::buffer_store::BufferStoreEvent, <project::lsp_store::LspStore>::on_buffer_store_event>::{closure#0}
             at /Users/kubkon/dev/zed/crates/gpui/src/app/context.rs:111:22
  18: <gpui::app::App>::subscribe_internal::<project::buffer_store::BufferStore, project::buffer_store::BufferStoreEvent, <gpui::app::context::Context<project::lsp_store::LspStore>>::subscribe<project::buffer_store::BufferStore, project::buffer_store::BufferStoreEvent, <project::lsp_store::LspStore>::on_buffer_store_event>::{closure#0}>::{closure#0}
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:964:25
  19: <alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>> as core::ops::function::FnMut<(&dyn core::any::Any, &mut gpui::app::App)>>::call_mut
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/alloc/src/boxed.rs:2012:9
  20: <gpui::app::App>::apply_emit_effect::{closure#0}
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:1407:21
  21: <gpui::subscription::SubscriberSet<gpui::app::entity_map::EntityId, (core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>::retain::<<gpui::app::App>::apply_emit_effect::{closure#0}>::{closure#1}
             at /Users/kubkon/dev/zed/crates/gpui/src/subscription.rs:132:17
  22: <alloc::collections::btree::map::BTreeMap<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>>::retain::<<gpui::subscription::SubscriberSet<gpui::app::entity_map::EntityId, (core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>::retain<<gpui::app::App>::apply_emit_effect::{closure#0}>::{closure#1}>::{closure#0}
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/alloc/src/collections/btree/map.rs:1177:37
  23: <alloc::collections::btree::map::ExtractIfInner<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>, core::ops::range::RangeFull>>::next::<<alloc::collections::btree::map::BTreeMap<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>>::retain<<gpui::subscription::SubscriberSet<gpui::app::entity_map::EntityId, (core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>::retain<<gpui::app::App>::apply_emit_effect::{closure#0}>::{closure#1}>::{closure#0}, alloc::alloc::Global>
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/alloc/src/collections/btree/map.rs:2036:16
  24: <alloc::collections::btree::map::ExtractIf<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>, core::ops::range::RangeFull, <alloc::collections::btree::map::BTreeMap<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>>::retain<<gpui::subscription::SubscriberSet<gpui::app::entity_map::EntityId, (core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>::retain<<gpui::app::App>::apply_emit_effect::{closure#0}>::{closure#1}>::{closure#0}> as core::iter::traits::iterator::Iterator>::next
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/alloc/src/collections/btree/map.rs:2002:20
  25: <alloc::collections::btree::map::ExtractIf<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>, core::ops::range::RangeFull, <alloc::collections::btree::map::BTreeMap<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>>::retain<<gpui::subscription::SubscriberSet<gpui::app::entity_map::EntityId, (core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>::retain<<gpui::app::App>::apply_emit_effect::{closure#0}>::{closure#1}>::{closure#0}> as core::iter::traits::iterator::Iterator>::fold::<(), core::iter::traits::iterator::Iterator::for_each::call<(usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>), core::mem::drop<(usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>)>>::{closure#0}>
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/iter/traits/iterator.rs:2602:34
  26: <alloc::collections::btree::map::ExtractIf<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>, core::ops::range::RangeFull, <alloc::collections::btree::map::BTreeMap<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>>::retain<<gpui::subscription::SubscriberSet<gpui::app::entity_map::EntityId, (core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>::retain<<gpui::app::App>::apply_emit_effect::{closure#0}>::{closure#1}>::{closure#0}> as core::iter::traits::iterator::Iterator>::for_each::<core::mem::drop<(usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>)>>
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/iter/traits/iterator.rs:828:14
  27: <alloc::collections::btree::map::BTreeMap<usize, gpui::subscription::Subscriber<(core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>>::retain::<<gpui::subscription::SubscriberSet<gpui::app::entity_map::EntityId, (core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>::retain<<gpui::app::App>::apply_emit_effect::{closure#0}>::{closure#1}>
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/alloc/src/collections/btree/map.rs:1177:46
  28: <gpui::subscription::SubscriberSet<gpui::app::entity_map::EntityId, (core::any::TypeId, alloc::boxed::Box<dyn for<'a, 'b> core::ops::function::FnMut<(&'a dyn core::any::Any, &'b mut gpui::app::App), Output = bool>>)>>::retain::<<gpui::app::App>::apply_emit_effect::{closure#0}>
             at /Users/kubkon/dev/zed/crates/gpui/src/subscription.rs:130:21
  29: <gpui::app::App>::apply_emit_effect
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:1405:14
  30: <gpui::app::App>::flush_effects
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:1308:31
  31: <gpui::app::App>::finish_update
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:830:18
  32: <gpui::app::App>::update::<core::result::Result<(), anyhow::Error>, <gpui::app::App as gpui::AppContext>::update_entity<project::buffer_store::BufferStore, core::result::Result<(), anyhow::Error>, <project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}::{closure#0}::{closure#3}>::{closure#0}>
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:819:14
  33: <gpui::app::App as gpui::AppContext>::update_entity::<project::buffer_store::BufferStore, core::result::Result<(), anyhow::Error>, <project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}::{closure#0}::{closure#3}>
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:2279:14
  34: <gpui::app::async_context::AsyncApp as gpui::AppContext>::update_entity::<project::buffer_store::BufferStore, core::result::Result<(), anyhow::Error>, <project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}::{closure#0}::{closure#3}>
             at /Users/kubkon/dev/zed/crates/gpui/src/app/async_context.rs:65:13
  35: <gpui::app::entity_map::WeakEntity<project::buffer_store::BufferStore>>::update::<gpui::app::async_context::AsyncApp, core::result::Result<(), anyhow::Error>, <project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}::{closure#0}::{closure#3}>
             at /Users/kubkon/dev/zed/crates/gpui/src/app/entity_map.rs:750:15
  36: <project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}::{closure#0}::<i32>
             at /Users/kubkon/dev/zed/crates/project/src/buffer_store.rs:683:18
  37: <gpui::app::context::Context<project::buffer_store::BufferStore>>::spawn::<<project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>>::{closure#0}::{closure#0}::<i32>
             at /Users/kubkon/dev/zed/crates/gpui/src/app/context.rs:244:52
  38: <gpui::app::App>::spawn::<<gpui::app::context::Context<project::buffer_store::BufferStore>>::spawn<<project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>>::{closure#0}, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>>::{closure#0}
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:1532:44
  39: <scheduler::executor::spawn_local_with_source_location::Checked<<gpui::app::App>::spawn<<gpui::app::context::Context<project::buffer_store::BufferStore>>::spawn<<project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>>::{closure#0}, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>>::{closure#0}> as core::future::future::Future>::poll
             at /Users/kubkon/dev/zed/crates/scheduler/src/executor.rs:393:64
  40: <async_task::raw::RawTask<scheduler::executor::spawn_local_with_source_location::Checked<<gpui::app::App>::spawn<<gpui::app::context::Context<project::buffer_store::BufferStore>>::spawn<<project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>>::{closure#0}, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>>::{closure#0}>, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>, <scheduler::executor::ForegroundExecutor>::spawn<<gpui::app::App>::spawn<<gpui::app::context::Context<project::buffer_store::BufferStore>>::spawn<<project::buffer_store::LocalBufferStore>::open_buffer::{closure#1}, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>>::{closure#0}, core::result::Result<gpui::app::entity_map::Entity<language::buffer::Buffer>, anyhow::Error>>::{closure#0}>::{closure#0}, scheduler::RunnableMeta>>::run
             at /Users/kubkon/.cargo/git/checkouts/async-task-e468f817236eac43/b4486cd/src/raw.rs:296:17
  41: <async_task::runnable::Runnable<scheduler::RunnableMeta>>::run
             at /Users/kubkon/.cargo/git/checkouts/async-task-e468f817236eac43/b4486cd/src/runnable.rs:788:18
  42: gpui::platform::mac::dispatcher::trampoline
             at /Users/kubkon/dev/zed/crates/gpui/src/platform/mac/dispatcher.rs:248:14
  43: <unknown>
  44: <unknown>
  45: <unknown>
  46: <unknown>
  47: <unknown>
  48: <unknown>
  49: <unknown>
  50: <unknown>
  51: <unknown>
  52: <unknown>
  53: <unknown>
  54: <unknown>
  55: <unknown>
  56: <unknown>
  57: <unknown>
  58: <gpui::platform::mac::platform::MacPlatform as gpui::platform::Platform>::run
             at /Users/kubkon/dev/zed/crates/gpui/src/platform/mac/platform.rs:473:17
  59: <gpui::app::Application>::run::<zed::main::{closure#9}>
             at /Users/kubkon/dev/zed/crates/gpui/src/app.rs:192:18
  60: zed::main
             at /Users/kubkon/dev/zed/crates/zed/src/main.rs:419:9
  61: <fn() as core::ops::function::FnOnce<()>>::call_once
             at /rustc/ded5c06cf21d2b93bffd5d884aa6e96934ee4234/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```

cc @ConradIrwin @elmarco
2026-01-23 15:24:37 +00:00
André Eriksson 0ce68b3e3b copilot: Add the option to disable Next Edit Suggestions (#47438)
Adds a new setting to GitHub Copilot to toggle the Next Edit Suggestions
feature, it is enabled by default.

## Motivations
Due to some current usability issues with this feature, see #46880, and
some personal anecdotes of using it, it is currently rough to utilize,
so this gives the option to disable it.

## Related
- #47071 
- #30124
- #44486
## Release Notes
- Adds the ability to disable GitHub Copilot's Next Edit Suggestions
feature.
## User Interface

![image](https://github.com/user-attachments/assets/5a3d7166-68dd-4f5b-a220-0a9bd9282cd5)
## Text Example
The text example will be adding a `z` variable to a `Point3D` class in
TypeScript.
### With Next Edit Suggestions
In this example I am able to just press auto-complete (press TAB) 3x.
```ts
class Point3D {
    x: number;
    y: number;
    z: number; // <-- Cursor before z: suggested

    constructor(x: number, 
                y: number
                , z: number // <-- Next Suggestion
                ) { 
        this.x = x;
        this.y = y;
        this.z = z; // <-- Last Suggestion
    }
}
```
### Without Next Edit Suggestions
```ts
class Point3D {
    x: number;
    y: number;
    z: number; // <-- Cursor before z: the only suggestion

    constructor(x: number, y: number) {
        this.x = x;
        this.y = y;
    }
}
```
2026-01-23 15:57:38 +01:00
a3174dab48 Add vim/emacs modeline support (#44210)
Many editors such as vim and emacs support "modelines", a comment at the
beginning of the file that allows the file type to be explicitly
specified along with per-file specific settings

- The amount of configurations, style and settings mapping cannot be
handled in one go, so this opens up a lot of potential improvements.
- I left out the possiblity to have "zed" specific modelines for now,
but this could be potentially interesting.
- Mapping the mode or filetype to zed language names isn't obvious
either. We may want to make it configurable.

This is my first contribution to zed, be kind. I struggled a bit to find
the right place to add those settings. I use a similar approach as done
with editorconfig (merge_with_editorconfig). There might be better ways.

Closes #4762

Release Notes:

- Add basic emacs/vim modeline support.

Supersedes #41899, changes:
- limit reading to the first and last 1kb
- add documentation
- more variables handled
- add Arc around ModelineSettings to avoid extra cloning
- changed the way mode -> language mapping is done, thanks to
`modeline_aliases` language config
- drop vim ex: support
- made "Local Variables:" handling a separate commit, so we can drop it
easily
- various code style improvements

---------

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2026-01-23 07:55:39 +00:00
Jens KourosandKirill Bulatov 90dc94b66e Enable configurable dismissal of language server notifications that do not require user interaction (#46708)
Closes #38769

Release Notes:

- Dismiss server notifications automatically with
`"global_lsp_settings": { "notifications": { "dismiss_timeout_ms": 5000
} }` settings defaults.

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-01-22 15:12:21 +00:00
MostlyK cb13a19d8a repl: Add initial notebook execution + KernelSession abstraction (#43553)
Coming from discussion on #25936 and
https://github.com/zed-industries/zed/pull/19756 .
This PR introduces the KernelSession abstraction and adds basic notebook
cell execution inside NotebookEditor.

The following provides a base starter for the development on Notebooks.

What this PR includes today:

Release Notes:

- KernelSession trait extracted. Both REPL and NotebookEditor now share
the same routing mechanism.
- NotebookEditor can launch kernels, execute code cells, and display
outputs.
- Basic cell operations: run current cell, run all, move up/down, add
code/markdown blocks. Keybindings follow Jupyter defaults.


Next Steps:

- [x] Editing support for markdown and code blocks.
- Buffer integration instead of temporary cell text.
- [x] Proper focus behavior when executing or adding cells.
- Kernel control UI.

A little far fetched steps:

- Vim Support
- Cell Handling Improvement and other convenient features and design
from other editors
- Ability to have better parsing for AI Support. 


I have attached a video of showcasing some of the features:


https://github.com/user-attachments/assets/37e6f3e5-2022-45f0-a73d-2dd01ebc2932
2026-01-22 09:00:29 -06:00
MostlyKandMrSubidubi b162fb4019 Support zooming and panning in the image viewer (#43944)
Implemented Pan and Zoom on the Image Viewer.

Demo:



https://github.com/user-attachments/assets/855bafe8-fdc2-4945-9bfb-e48382264806





Closes #9584



Release Notes:

- Add zoom in/out, reset, fit-to-view and zoom-to-actual actions 
- Support scroll-wheel zoom with modifier, click-and-drag panning 
- Renders a zoom percentage overlay. 
- ImageView Toolbar Added to control zoom in/out and fit view.

---------

Co-authored-by: MrSubidubi <finn@zed.dev>
2026-01-21 22:48:30 +01:00
Mateo Kruk 658773ce3f themes: Fix One Light terminal cyan color (#45691)
Closes #45075

The cyan terminal colors in One Light were incorrectly set to the same
values as green, making them indistinguishable. This was introduced in
https://github.com/zed-industries/zed/pull/44912

Release Notes:

- Fixed terminal cyan color displaying as green in One Light theme
2026-01-21 08:14:36 -06:00
Danilo Leal c17dc773bf agent_ui: Fix keybinding conflict with editing queued messages (#47290)
This PR fixes `shift-e` being used for triggering edits in queued
messages, which breaks writing simple capital E in the editor.

Release Notes:

- N/A
2026-01-21 11:00:16 -03:00
Danilo Leal 6e7945a778 agent_ui: Fix keybinding conflict with action to clean up the queue (#47254)
This PR frees up `shift-backspace` to work as it did before. Now, the
action to remove the first queued message is now assigned to the
`cmd-shfit-backspace` keybinding, whereas the action to clear the entire
message queue is assigned to `cmd-alt-backspace`.

Release Notes:

- N/A
2026-01-20 20:54:13 -03:00
Danilo Leal b46d364533 agent_ui: Add support for editing queued messages (#47234)
This PR adds the ability to edit a queued message, which you can now do
by hitting `cmd-e` from the message editor, which will focus the first
queued message. To pull that off, I'm also making the queued messages
render as an editor, the same way we do with regular user messages. That
way, we ensure less layout shift when focusing in and out of the queued
message for editing and gain the ability to render context
buttons/creases the same way we do in the main message editor.


https://github.com/user-attachments/assets/fb68fd48-c0cd-491f-a7d9-5065a9151b0b

Note that in the video, I show the state in which you're still editing
in the moment in which the queued message would be sent. If that
happens, your queued message won't be sent even if you unfocus the
queued message editor. In this case, you need to explicitly hit "Send
Now".

Release Notes:

- Agent: Added the ability to edit queued messages.
2026-01-20 17:26:30 -03:00
Ben Brandt caa5d2be95 acp: Allow installing ACP agents from the registry (#47218)
This is still behind a feature flag as the registry is still WIP, but
allows downloading binary agents from the registry on github.

Release Notes:

- N/A
2026-01-20 14:06:21 +00:00
Richard Feldman 87f862a2d5 Make always_allow_tool_actions override always_confirm and default_mode (#47012)
Previously, `always_confirm` patterns would force confirmation even when
`always_allow_tool_actions` was set to true. This was counterintuitive
since the global setting should provide a way to skip all confirmations.

The new precedence order is:
1. **`always_deny`** - still blocks for security
2. **`always_allow_tool_actions`** - when true, allows all non-denied
actions
3. **`always_confirm`** - prompts if `always_allow_tool_actions` is
false
4. **`always_allow`** - allows without prompting
5. **`default_mode`** - fallback behavior

This means setting `always_allow_tool_actions=true` will now skip
confirmation prompts from `always_confirm` patterns and override
`default_mode: Deny` settings, while still respecting `always_deny`
patterns for security.

(No release notes because granular tool permissions are still
feature-flagged.)

Release Notes:

- N/A
2026-01-16 18:18:39 -05:00
Danilo Leal 2f9a611cb7 agent_ui: Make it easier to interrupt with message in queue (#46954)
Follow up to https://github.com/zed-industries/zed/pull/46797

When you send a message, as per the PR linked above, Zed will now queue
it by default. But if you want to fast-track it/interrupt the agent
immediately, effectively sending the first message in the queue, you can
just hit enter again and it will get sent right away.


https://github.com/user-attachments/assets/5e6230f6-c56e-4496-9bcb-8d6ffb9e19cb

Release Notes:

- Agent: Made it easier to interrupt the agent while having messages in
the queue.
2026-01-15 20:07:16 -03:00
Danilo Leal f959f58789 agent_ui: Fix review buttons getting cut-off (#46948)
Closes https://github.com/zed-industries/zed/issues/46922

Release Notes:

- N/A
2026-01-15 18:39:59 -03:00
Marshall Bowers 846512f5cb Remove Burn Mode code (#46950)
This PR removes the code for Burn Mode, as we won't need it anymore
after the 17th.

Closes CLO-79.

Release Notes:

- N/A
2026-01-15 21:28:33 +00:00
Carl Jackson b84621eb77 Implement Vim's tag stack (#46002)
Happy New Years! This PR is a second take at
https://github.com/zed-industries/zed/pull/38127 (cc @ConradIrwin)

This PR is significantly less complicated than the last attempt: while
we still keep our data on the `NavigationHistory` object, we no longer
tightly integrate it with the existing back/forward "browser history."
Instead, we keep our own stack of `(origin, target)` pairs (in a struct
to make it easy to extend with e.g., tag names in the future).

The PR is split into two separable commits. Most of the implementation
is in the second commit, which:
- Defines the stack data structure
- Implements `pane::GoToOlderTag` and `pane::GoToNewerTag` in terms of
the stack
- Hooks into `navigate_to_hover_links` to push tag stack entries

This last bit is the most fiddly. The core challenge is that we need to
keep track of the `origin` location and calculate the `target` location
across three codepaths that might involve creating a new editor and/or
splitting the pane. One thing in particular I found difficult was that
an editor's `nav_history` (an `ItemNavHistory`) seems to be populated
asynchronously. Instead of relying on it, I decided in this code to make
my own `ItemNavHistory`. I briefly tried to refactor the code in
question, but it seemed like it would significantly increase the scope
of the change.

I prefer this all-in-one tracking centered around
`navigate_to_hover_links ` to the `start/finish` approach taken in
https://github.com/zed-industries/zed/commit/aebd394fb60641a2dd32b1f1b76a7c79ec4aa2ea
because I find it easier to convince myself that the right data is being
populated at the right times. Of course, let me know if you think
there's a better solution.

Closes #14206

Release Notes:
- ??? I don't know what to write here! Suggestions welcome
2026-01-15 17:48:15 +00:00
dd4699dc72 Granular Tool Permission Buttons (#46284)
Adds buttons for confirming (and optionally persisting) granular
permissions on tool calls:

<img width="688" height="302" alt="Screenshot 2026-01-14 at 1 58 40 PM"
src="https://github.com/user-attachments/assets/3228cc39-efd5-4a73-989f-ddb28969847f"
/>
<img width="690" height="282" alt="Screenshot 2026-01-14 at 1 58 31 PM"
src="https://github.com/user-attachments/assets/8367a888-5728-4877-a502-1ff20ac929ec"
/>

## Features

### Tool Permission Settings
- **Per-tool rules** in `agent.tool_permissions.tools.<tool_name>`:
  - `default_mode`: `"allow"`, `"deny"`, or `"confirm"` (default)
  - `always_allow`: Array of regex patterns to auto-approve
  - `always_deny`: Array of regex patterns to block
  - `always_confirm`: Array of regex patterns requiring confirmation
- **Supported tools**: `terminal`, `edit_file`, `delete_path`,
`move_path`, `create_directory`, `save_file`, `copy_path`, `fetch`,
`web_search`
- **MCP tool support**: Third-party tools from context servers with
`mcp:<server>:<tool>` naming

### Smart Permission Buttons
When a tool requires confirmation, the dialog shows contextual buttons:
- **"Always allow \`<tool>\`"** - Sets `default_mode = "allow"` for the
tool
- **"Always allow \`<pattern>\`"** - Adds a pattern to `always_allow`:
  - Terminal: Command name (e.g., `cargo`, `npm`, `git`)
  - File tools: Parent directory path
  - URL tools: Domain name
- **"Allow"** / **"Deny"** - One-time decision

### Pattern Extraction
Automatically extracts meaningful patterns from tool inputs:
- Terminal commands → `^cargo\s`, `^npm\s`, etc.
- File paths → `^/Users/alice/project/src/`
- URLs → `^https?://github\.com`

### Invalid Pattern Handling
- Malformed regex patterns are detected at settings load time
- Tools with invalid patterns show an error and block execution
- Clear error messages identify which pattern failed

## Changes

### New Files
- `crates/agent/src/tool_permissions.rs` - Permission evaluation logic
- `crates/agent/src/pattern_extraction.rs` - Pattern extraction
functions

### Modified Files
- `crates/agent_settings/src/agent_settings.rs` - `ToolPermissions`,
`ToolRules` structs
- `crates/settings/src/settings_content/agent.rs` - Settings schema and
serialization
- `crates/settings/src/settings_file.rs` - Helper methods for modifying
settings
- `crates/agent/src/thread.rs` - `authorize_with_context()`,
`authorize_third_party_tool()` methods
- `crates/agent/src/tools/*.rs` - Updated all granular tools to use
permission system
- `crates/agent/src/tools/context_server_registry.rs` - MCP tool
authorization
- `crates/agent_ui/src/acp/thread_view.rs` - Permission button UI,
removed Keep/Reject buttons

## Example Configuration

```json
{
  "agent": {
    "tool_permissions": {
      "tools": {
        "terminal": {
          "default_mode": "confirm",
          "always_allow": ["^cargo\\s", "^npm\\s", "^git\\s"],
          "always_deny": ["^rm\\s+-rf", "^sudo\\s"]
        },
        "edit_file": {
          "default_mode": "allow",
          "always_deny": ["^\\.env", "^/etc/"]
        },
        "mcp:filesystem:write_file": {
          "default_mode": "confirm"
        }
      }
    }
  }
}
```

Release Notes:

- You can now set per-tool permissions when confirming/denying tool use

---------

Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com>
Co-authored-by: Michael Benfield <mbenfield@zed.dev>
2026-01-14 19:39:04 +00:00
Richard FeldmanandAmp be110b3836 Render subagents in thread (#46188)
## Summary

This PR adds the UI for displaying subagent tool calls:

### Thread view changes
- Add `expanded_subagents` state HashMap for tracking expanded cards  
- Implement `render_subagent_tool_call()` for collapsed card with label
and chevron
- Add subagent detection via `is_subagent()` and `tool_name` field
- Handle `SubagentThread` content type in tool call rendering
- Add expand/collapse toggle button for subagent cards
- Style collapsed cards similar to terminal tool calls
- Support inline image rendering in content blocks

### Agent panel changes
- Add `open_external_thread_with_server()` for testing with stubbed
servers

### Test support
- Add `acp_thread/test-support` feature to agent_ui
- Add base64 dev dependency for image tests

Release Notes:

- N/A

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-14 13:49:51 -05:00
Danilo Leal 8e786bcd87 agent_ui: Queue prompts by default when sending them while generating (#46797)
This PR makes queueing a prompt the default behavior when sending a new
one while there's an on-going generation. You can still send a prompt
that will immediately interrupt the agent with the `cmd-shift-enter`
keybinding, though, which preserves the current behavior.

The main motivation for this change is to make the queueing not only
more discoverable, but more useful as well, as we're parting from the
assumption that most of the time, what you want is to queue it as
opposed to interrupting it (even though it's still possible to do either
through the keybinding I mentioned above or simply by stopping the
generation and sending a new one).

Here's a quick video:


https://github.com/user-attachments/assets/37f92433-70ef-459f-98ff-41ed80e3e43f

In the video, I show sending one prompt and then sending two others that
fall straight into the queue. Then, in the middle of the generation of
my first prompt, I use the `cmd-shift-enter` keybinding to send a prompt
immediately, interrupting the agent, effectively being sent in front of
the queue.

Release Notes:

- Agent: Made queueing prompts the default behavior when sending them
while there's an on-going generation.
2026-01-14 13:12:46 -03:00
Danilo Leal f0d0b40901 workspace: Improve the multi-project UX (#46641)
This PR introduces a project dropdown when working with multiple
folders/projects in one workspace. Here are some interaction details
that I hope improves the UX of working on this scenario significantly:

- The dropdown shows the currently "active" project, which is determined
by:
  - Either the file you're currently editing
  - Or the file you have just recently switched to
  - Some example cases:
- If you are focused on file from project A but switch to project B in
the titlebar, nothing happens. However, as soon as you type on the file
from project A, the title bar will update and your active project will
return to being project A.
- If you're focused on file from project A and change tabs to a file
from project B, the title bar will update, showing project B as the
active one.
- The content you'll see in the branch picker will correspond to the
currently active project
- It's still possible to reach the "Recent Projects" picker through the
project dropdown
- It's possible to do all interactions (trigger dropdown, select active
project, and remove project from workspace) with the keyboard


https://github.com/user-attachments/assets/e2346757-74df-47c5-bf4d-6354623b6f47

Note that this entire UX is valid only for a multiple folder workspace
scenario; nothing changes for the single project case.

Release Notes:

- Workspace: Improved the UX of working with multiple projects in the
same workspace through introducing a project dropdown that more clearly
shows the currently active project as well as allowing you to change it.
2026-01-13 18:48:51 -03:00
Ben Kunkle d3638498d2 settings_ui: Add vim settings (#46634)
Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2026-01-13 14:52:44 -05:00
Danilo Leal a2b8ae507c agent_ui: Fix reject all and keep all keybinding conflict (#46725)
This PR changes the keybinding for the `agent::RejectAll` and
`agent::KeepAll` actions. My initial goal was to free up `cmd-shift-n`
to open a new fresh window again, but that was being used for the reject
all action. Given I had to change the reject all, I figured I had to
change the keep all action, too, to keep them consistent.

Release Notes:

- Agent: Removed keybinding conflict (`cmd-shift-n`) between rejecting
all changes in the agent panel vs. opening a new fresh window.
2026-01-13 17:59:02 +00:00
Danilo Leal ba07805ad5 debugger_ui: Make view in the new session picker keyboard navigable (#46662)
This makes the new session picker in the Debugger panel consistent with
the new unified Git picker
(https://github.com/zed-industries/zed/pull/46621):


https://github.com/user-attachments/assets/e94662da-31cc-48d8-b633-a6f0a2812569

Release Notes:

- Debugger: Make possible to navigate with the keyboard between the
views in the new session picker.
2026-01-13 17:36:40 +00:00
Yaroslav YenkalaandMatt Miller 166e6b582a Add option to show pinned tabs in a separate row (#46573)
## Problem:

When working with many `pinned tabs`, they consume significant
horizontal space in the tab bar, leaving less room for unpinned (active
working) tabs, especially on small screens. This creates a poor user
experience as users must constantly scroll to find their working tabs,
or the tabs become too narrow to read file names.


![8_tabs](https://github.com/user-attachments/assets/087a0b4d-8f1c-42f0-851c-b774228f11dd)

##  Solution:

Added a new opt-in setting `tab_bar.show_pinned_tabs_in_separate_row`
that displays pinned and unpinned tabs in two separate rows:
  - Top row: Pinned tabs with navigation buttons and tab bar controls
  - Bottom row: Unpinned (working) tabs with full horizontal space
 
- when pinned and not pinned tabs we show 2 rows:  

<img width="1512" height="159" alt="2_rows"
src="https://github.com/user-attachments/assets/62a85fcc-8073-40d2-a8e4-270efd0d0f21"
/>

This is a well-established UX pattern used in many popular IDEs
including JetBrains products (IntelliJ IDEA, WebStorm, PyCharm,
RubyMine), Visual Studio, and Eclipse.

The two-row layout only appears when both pinned AND unpinned tabs
exist. If only one type is present, a single row is displayed:
  
- when only not pinned tabs we show one row:

<img width="1510" height="111" alt="when only not pinned"
src="https://github.com/user-attachments/assets/048df4fc-4b17-4ea2-9c5b-b4db91cdfc78"
/>

- when only pinned tabs we show one row:

<img width="1510" height="111" alt="when only pinned tabs"
src="https://github.com/user-attachments/assets/7ccf2517-8711-4114-815d-6cbb1e89d7e2"
/>

  **Important** - Default Behavior Preserved:

- The setting defaults to false - existing users will see no change
whatsoever
- Original tab bar logic is preserved in a dedicated
`render_single_row_tab_bar` method, while the new two-row layout lives
in `render_two_row_tab_bar`. Both methods share common components
(`configure_tab_bar_start`, `configure_tab_bar_end`,
`render_unpinned_tabs_container`, `render_tab_bar_drop_target`) ensuring
DRY code and consistent behavior.
- Purely opt-in - users must explicitly enable this feature via Settings
UI or settings.json
- No impact on default UX - Zed's default tab bar appearance and
behavior remains identical

This implementation ensures zero risk to the existing user experience
while providing an optional enhancement for users who prefer separated
tab rows.

  Configuration

  Via Settings UI:
  - Open Settings (Cmd+,) → Editor section → "Pinned Tabs Layout" toggle
  
  

![settings_ui](https://github.com/user-attachments/assets/59b9bb94-1c10-4c32-b942-13aa01943526)


  Via settings.json:
  
  ```json
  {
    "tab_bar": {
      "show_pinned_tabs_in_separate_row": true
    }
  }
  ```
  
<img width="468" height="67" alt="manual_settings"
src="https://github.com/user-attachments/assets/d21f6dde-7683-47b3-8dca-d190049d32fb"
/>

## Video of implemented feature:


https://github.com/user-attachments/assets/b1e52074-a5a1-4c4e-ad59-e55e2213509d

## Tested:

- Verify default behavior unchanged (single row with pinned + unpinned
tabs inline)
- Enable setting → verify two rows appear when both pinned and unpinned
tabs exist
  - Enable setting → verify single row when only pinned tabs exist
  - Enable setting → verify single row when only unpinned tabs exist
  - Verify drag & drop works in both layouts
  - Verify navigation buttons and tab bar buttons render correctly
  - Verify setting toggle works in Settings UI
  - Verify setting works via settings.json

  Tested on: MacBook Pro M4, macOS 26.2
  
   ## Release Notes:

- Added `tab_bar.show_pinned_tabs_in_separate_row` setting to display
pinned and unpinned tabs in separate rows, giving unpinned tabs full
horizontal space

---------

Co-authored-by: Matt Miller <mattrx@gmail.com>
2026-01-13 09:30:27 -06:00
Danilo Leal 57c5d00afb git_ui: Unify branch, worktree, and stash pickers in one (#46621)
This PR creates a unified picker for all the Git-related pickers:
branch, worktree and stash. The main motivation for this is to bring
awareness and ease of access for the worktree and stash pickers that
were previously (and arguably) hidden amidst the sea of commands in the
command palette. As worktrees in particular become more relevant for
AI-related flows, having an easier way to reach for its picker will be
beneficial.

Note that the actions/commands remain the same; you can still look for
`git: worktree` or `git: view stash`. The difference is that these
actions will take you to the unified picker with the correct
corresponding active view.


https://github.com/user-attachments/assets/99d1cd6f-a19d-47d3-9bca-d7257e7ed5b8

Release Notes:

- Git: Unify the branch, worktree, and stash pickers into one, making it
easier to find and access them from one another.
2026-01-12 12:48:57 -03:00
Hansanddino 8cd3bd90aa vim: Add use_match_quotes setting for % motion, default is true (#42615)
Add a `match_quotes` parameter to the `vim::Matching` action that
controls whether the `%` motion should treat quote characters (', ", `)
as matching pairs.

In Neovim, `%` only matches bracket pairs (([{}])), not quotes. Zed's
existing behavior includes quote matching, which some users prefer. To
preserve backwards compatibility while allowing users to opt into
Neovim's behavior, this PR:

1. Adds an optional `match_quotes` boolean parameter to the
   `vim::Matching` action
2. Updates the default vim keymap to use ["vim::Matching", {
   "match_quotes": true }], preserving Zed's current behavior
3. Users who prefer Neovim's behavior can rebind `%` in their keymap:

```
{
    "context": "VimControl && !menu",
    "bindings": {
        "%": ["vim::Matching", { "match_quotes": false }]
    }
}
```

When `match_quotes` is `false`, the `%` motion will skip over quote
characters and only match brackets/parentheses, matching Neovim's
default behavior.

Release Notes:

- vim: Added match_quotes parameter to the vim::Matching action to control
whether % matches quote characters

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
2026-01-09 18:04:44 +00:00
Ben Brandt 83fd6fe96b agent: Split up Agent and Text Thread History (#46457)
Scopes the history to the individual panes and paves the way for history
per external agent.

Release Notes:

- N/A
2026-01-09 17:13:00 +00:00
Mikayla Maki 6e7b6edf64 agent: Add turn statistics to agent panel (#46390)
I really enjoyed this feature in Claude Code. Helps me get a sense of
how effortful something is.

Release Notes:

- Added a "show_turn_stats" setting, default to false, that shows the
timer and the number of tokens down.
2026-01-09 00:33:38 +00:00
Richard FeldmanandAmp 53f0370546 Add granular tool permissions settings (#46112)
Adds granular per-tool permission settings for the Zed agent with
regex-based rules.

Release Notes:

- N/A

---------

Co-authored-by: Amp <amp@ampcode.com>
2026-01-08 14:32:18 -08:00
Danilo Leal 4d0d5068cb agent: Make reject/accept keybindings consistent with restore/stage (#46373)
This primarily frees up, for example, `cmd-n` to create a new untitled
file if you're in the agent diff tab.

Release Notes:

- N/A
2026-01-08 12:48:06 -03:00
Cory Wilhite 9fa1cf5e3f settings: Add Sapling directory to default file_scan_exclusions (#45837)
[Sapling](https://sapling-scm.com/docs/git/git_support_modes/) is
similar to git / hg / jj in that it creates a /.sl directory when
initializing a repository. This can be added alongside the other source
control scan exclusions

includes a docs update for these defaults

Release Notes:
- Settings: Add Sapling directory to default `file_scan_exclusions`
2026-01-07 05:44:29 -05:00
Ichimura Tomoo 3bed1cc093 status_bar: Add encoding indicator (#45476)
## Context / Related PRs This PR is the third part of the encoding
support improvements, following:
- #44819: Introduced initial legacy encoding support (Shift-JIS, etc.).
- #45243: Fixed UTF-16 saving behavior and improved binary detection.

## Summary
This PR implements a status bar item that displays the character
encoding of the active buffer (e.g., `UTF-8`, `Shift_JIS`). It provides
visibility into the file's encoding and indicates the presence of a Byte
Order Mark (BOM).

## Features
- **Encoding Indicator**: Displays the encoding name in the status bar.
- **BOM Support**: Appends `(BOM)` to the encoding name if a BOM is
detected (e.g., `UTF-8 (BOM)`).
- **Configuration**: The active_encoding_button setting in status_bar
accepts "enabled", "disabled", or "non_utf8". The default is "non_utf8",
which displays the indicator for all encodings except standard UTF-8
(without BOM).
- **Settings UI**: Provides a dropdown menu in the Settings UI to
control this behavior.
- **Documentation**: Updated `configuring-zed.md` and
`visual-customization.md`.

## Implementation Details
- Created `ActiveBufferEncoding` component in
`crates/encoding_selector`.
- The click handler for the button is currently a **no-op**.
Implementing the functionality to reopen files with a specific encoding
has potential implications for real-time collaboration (e.g., syncing
buffer interpretation across peers). Therefore, this PR focuses strictly
on the visualization and configuration aspects to keep the scope simple
and focused.
- Updated schema and default settings to include
`active_encoding_button`.

## Screenshots

<img width="487" height="104" alt="image"
src="https://github.com/user-attachments/assets/041f096d-ac69-4bad-ac53-20cdcb41f733"
/>
<img width="454" height="99" alt="image"
src="https://github.com/user-attachments/assets/ed76daa2-2733-484f-bb1f-4688357c035a"
/>


## Configuration
To hide the button, add the following to `settings.json`:
```json
"status_bar": {
  "active_encoding_button": "disabled"
}
```

- **enabled**: Always show the encoding.
- **disabled**: Never show the encoding.
- **non_utf8**: Shows for non-UTF-8 encodings and UTF-8 with BOM. Only
hides for standard UTF-8 (Default).

<img width="1347" height="415" alt="image"
src="https://github.com/user-attachments/assets/7f4f4938-3320-4d21-852c-53ee886d9a44"
/>

## Heuristic Limitations:
The underlying detection logic (implemented in #44819 and #45243)
prioritizes UTF-8 opening performance and does not guarantee perfect
detection for all encodings. We consider this margin of error
acceptable, similar to the behavior seen in VS Code. A future "Reopen
with Encoding" feature would serve as the primary fallback for any
misdetections.

Release Notes:

- Added a status bar item to display the active file's character encoding (e.g. `UTF-16`). This shows for non-utf8 files by default and can be configured with `{"status_bar":{"active_encoding_button":"disabled|enabled|non_utf8"}}`
2026-01-07 07:24:46 +00:00
Leon Qadirie e3dce59f5d Add helix match surround operations (#44317)
Partially addresses #38151

Release Notes:

- Added Helix match surround operations
2026-01-06 15:42:13 +00:00
9628d817ad Multibuffer breadcrumbs toolbar redesign (#45547)
Breadcrumb visual reorchestration which makes a couple of key changes:
- Breadcrumbs are now displayed in file headers for multibuffer views.
Singleton buffers are unchanged.
- Multibuffer views now have collapse/expand all buttons available in
the toolbar
- Search in multibuffer views now takes up less space, by occupying the
primary toolbar location erstwhile taken up by breadcrumbs

<img width="1721" height="823" alt="Screenshot 2025-12-22 at 4 15 41 PM"
src="https://github.com/user-attachments/assets/38e924f7-fe9e-4c83-84fb-2eee98137f43"
/>

<img width="1722" height="762" alt="Screenshot 2025-12-22 at 4 15 51 PM"
src="https://github.com/user-attachments/assets/ccc98ca3-75ce-4aca-bceb-890817b0f04d"
/>


Release Notes:

- Moved breadcrumbs to file headers in multibuffer views
- Added collapse/expand all options for multibuffer views
- Improved use of space for multibuffer search by taking the place of
the former breadcrumb toolbar location

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-01-06 09:42:00 -03:00
John TurandMax Brunsfeld 9010a6f18a Add support for subpixel text rendering (#45423)
Subpixel text rendering is now implemented on Windows and Linux.

Comparison screenshots:

|Before|After|
| ------------- | ------------- |
| <img width="400"
src="https://github.com/user-attachments/assets/9d720d2c-2ec4-4adf-a83f-7c2d81d30025"
/> | <img width="400"
src="https://github.com/user-attachments/assets/8fd7dc2a-8ca0-4f71-86cd-55460f568f7a"
/> |


Release Notes:

- Added support for subpixel (ClearType-style) text rendering. This
improves the legibility of text on standard DPI displays. Subpixel
rendering is enabled by default on Windows and Linux and can be
configured using the `text_rendering_mode` setting.

---------

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2026-01-06 03:46:31 -05:00
Alvaro Parker 28f1671bb2 git: Add basic vim motions to git file history view (#45412)
Closes #ISSUE

Related discussion #44629 

Release Notes:

- Added simple `g g`, `G`, `j` and `k` motions for the file history view
on vim mode.
2026-01-06 01:47:07 +00:00
John D. SwansonandBen Kunkle 198380afe8 Add global and HTTP context server timeout settings (#45378)
### Closes 
- Maybe https://github.com/zed-industries/zed/issues/38252 (there might
be something going on with NPX too)
- Also addresses
https://github.com/zed-industries/zed/pull/39021#issuecomment-3644818347



### Why
Some more involved MCP servers timeout often, especially on first setup.
I got tired of having to set timeouts manually per server. I also
noticed a timeout could not be set for http context servers, which
causes Context7 or GitHub's remote servers to timeout at 60s sometimes.

### Overview

MCP Timeout Configuration Feature

This PR adds additional configurable timeout settings for Model Context
Protocol servers including a global timeout and the addition of timeouts
for http servers, addressing issues where servers were timing out after
a fixed 60 seconds regardless of user needs.

**Key Features:**
- **Global timeout setting** (`context_server_timeout`) - default
timeout for all MCP servers (default: 60s, max: 10min)
- **Per-server timeout overrides** - individual servers can specify
custom timeouts via `timeout` field
- **Precedence hierarchy** - per-server timeout > global timeout >
default (60s)
- **Automatic bounds checking** - enforces 10-minute maximum to prevent
resource exhaustion
- **Support for both transports** - works with stdio and HTTP-based
context servers
- **Comprehensive test coverage** - 3 new tests validating global,
override, and stdio timeout behavior
- **Full backward compatibility** - existing configurations work
unchanged with sensible defaults


### Release Notes:

- Added the ability to configure timeouts for context server tool calls.
The new global `context_server_timeout` setting controls the default
timeout (default is 60s, max: 10min). Additionally, per-server timeouts
can be configured using the `timeout` field within servers defined in
the `"context_servers" setting

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
2026-01-05 13:45:22 -05:00
Xiaobo Liu f9543ac15a settings_ui: Add proxy edit box (#45684)
Release Notes:

- settings_ui: Added a field to configure the network proxy.

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
2026-01-05 11:06:31 -05:00
legsandDanilo Leal 739ef96a3e editor: Add alignment setting to code completion context menu detail text (#45892)
Closes #5154

Release Notes:

- Added a setting (`completion_detail_alignment`) to change the detail
text alignment in code completion context menus.

<table>
<tr>
 <td>Right Alignment
 <td>Left Alignment
<tr>
 <td>
<img width="802" height="427" alt="image"
src="https://github.com/user-attachments/assets/46202f3d-32cc-4431-aebd-aa3c52d84993"
/>
 <td>
<img width="783" height="427" alt="image"
src="https://github.com/user-attachments/assets/d26559d2-c433-4bf7-a302-e683bd5fa9f7"
/>
</table>

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2026-01-04 19:15:22 -03:00
Smit ChaudharyandDanilo Leal b9a4701463 keymap_editor: Allow to open the keymap.json with a keybinding (#45987)
Just like #43747 added the keybinding(s) for `settings.json`, added them
here for keymaps and added the tooltip to show those.

<img width="500" height="282" alt="Screenshot 2026-01-04 at 2  47@2x"
src="https://github.com/user-attachments/assets/d4dbdd6e-24eb-4b7f-baa8-6e1d9810ff94"
/>

Release Notes:

- keymap editor: Added the ability to open the `keymap.json` file with a
keybinding.

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2026-01-04 17:54:25 +00:00
Danilo Leal c9c5c91e5a keymap_editor: Add a "create keybinding" modal (#46030)
Ever since we launched the keymap editor, we've received feedback about
how "_creating_" a new keybinding was not obvious. At first, I was
confused about this feedback because you can't "create" a keybinding,
you need to rather _assign it_ to an action... so what always made sense
to me was to start with searching for the action, which is an use case
we already support. Regardless, having an easy to reach "create" button,
which essentially still asks for action > keystroke > arguments (if
needed) > and context, feels like a win UX-wise; a bit of a redundant
flow that feels ultimately positive.

So, this PR adds a "Create Keybinding" button to the keymap editor,
which you can reach with `cmd-k`. That will open up a modal with an
action autocomplete, the keystroke recording input, the arguments input
(if needed), and the context input.


https://github.com/user-attachments/assets/86f64314-4685-47bb-bb0d-72ca4c469d1f

Release Notes:

- keymap editor: Added a keybinding creation modal to make it easier to
assign an action to a keystroke.
2026-01-04 14:41:46 -03:00
Danilo Leal 63e97c18ac agent: Add ability to queue messages (#46019)
Closes https://github.com/zed-industries/zed/issues/37905
Closes https://github.com/zed-industries/zed/discussions/42338
Closes https://github.com/zed-industries/zed/discussions/33501
Closes https://github.com/zed-industries/zed/discussions/41414

This PR introduces a way to queue messages in the agent panel through
the `cmd-shift-enter` keybinding. Queued up messages get sent as soon as
the current generation wraps up. It's also possible to send a queued
message before time, effectively interrupting the ongoing generation.
You can also clean up the entire queue through another keybinding. Then,
if you normally interrupt the thread and if there are queued up
messages, those will get sent as soon as the interruption generation
wraps up. Lastly, if you queue up a message with an idle thread, that's
sent immediately, given that there can never exist a "stuck queue" with
this implementation.


https://github.com/user-attachments/assets/54e68d95-5abb-477c-aecb-9325dcb99175

Release Notes:

- agent: Added the ability to queue messages in the agent panel.
2026-01-04 14:27:34 -03:00
Lukas WirthandDanilo Leal 2613a8ccb7 worktree: Implement read_only_files worktree setting (#44376)
This mimics VSCode's `files.readonlyExclude` setting, to allow setting
specific path matches as readonly locations like lockfiles and generated
sources etc.

Also renders a lock icon to the right side of the path names for
readonly files now.
This does a couple more things for completion sake:
- Tabs of readonly buffers now render a file lock icon
- Multibuffer buffer headers now render a file lock icon if the excerpts
buffer is readonly
- ReadWrite multibuffers now no longer allow edits to read only buffers
contained within

Release Notes:

- Added `read_only_files` setting to allow specifying glob patterns of
files that should not be editable by default

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2026-01-04 13:18:34 +00:00