Currently when we render text with differing styles adjacently we might
form a ligature between the text, causing the ligature forming
characters to take on one of the two styles. This can especially become
confusing when a ligature is formed between actual text and inlay hints.
Annoyingly, the only ways to prevent this with core text is to either
render each run separately, or to insert a zero-width non-joiner to
force core text to break the ligatures apart, as it otherwise will merge
subsequent font runs of the same fonts.
We currently do layouting on a per line basis and it is unlikely we want
to change that as it would incur a lot of complexity and annoyances to
merge things back into a line, so this goes with the other approach of
inserting ZWNJ characters instead.
Note that neither linux nor windows seem to currently render ligatures,
so this only concerns macOS rendering at the moment.
Release Notes:
- Fixed ligatures forming between real text and inlay hints on macOS
Follow up of https://github.com/zed-industries/zed/pull/33334
After chatting with @MrSubidubi we found out that he had an old defaults
setting (most likely from when he encountered a previous window tabbing
bug):
```
❯ defaults read dev.zed.Zed-Nightly
{
NSNavPanelExpandedSizeForOpenMode = "{800, 448}";
NSNavPanelExpandedSizeForSaveMode = "{800, 448}";
NSNavPanelExpandedStateForSaveMode = 1;
NSOSPLastRootDirectory = {length = 828, bytes = 0x626f6f6b 3c030000 00000410 30000000 ... dc010000 00000000 };
"NSWindow Frame NSNavPanelAutosaveName" = "557 1726 800 448 -323 982 2560 1440 ";
"NSWindowTabbingShoudShowTabBarKey-GPUIWindow-GPUIWindow-(null)-HT-FS" = 1;
}
```
> That suffix is AppKit’s fallback autosave name when no tabbing
identifier is set. It encodes the NSWindow subclass (GPUIWindow), plus
traits like HT (hidden titlebar) and FS (fullscreen).
Which explains why it only happened on the Nightly build, since each
bundle has it's own defaults. It also explains why the tabbar would
disappear when he activated the `use_system_window_tabs` setting,
because with that setting activated, the tabbing identifier becomes
"zed" (instead of the default one when omitted) for which he didn't have
the `NSWindowTabbingShoudShowTabBarKey` default.
The original implementation was perhaps a bit naive and relied fully on
macOS to determine if the tabbar should be shown. I've updated the code
to always hide the tabbar, if the setting is turned off and there is
only 1 tab entry.
While testing, I also noticed that the menu's like 'merge all windows'
wouldn't become active when the setting was turned on, only after a full
workspace reload. So I added a setting observer as well, to immediately
set the correct window properties to enable all the features without a
reload.
Release Notes:
- N/A
This PR fixes a deserialization issue in GitHub Copilot Chat that was
causing warnings when encountering xAI models from the GitHub Copilot
API and skipping the Grok model from model selector.
Release Notes:
- Fixed support for xAI models that are now available through GitHub
Copilot Chat.
Removes excess log which got through on each start of Zed
```
ERROR [agent_ui::language_model_selector] Failed to authenticate provider: Anthropic: credentials not found
```
The `AnthropicLanguageModelProvider::api_key` method returned a
`anyhow::Result` which would convert
`AuthenticateError::CredentialsNotFound` into a generic error because of
the implicit `Into` when using the `?` operator. This would then get
converted into a `AuthenticateError::Other` later.
By specifying the error type as `AuthenticateError`, we remove this
implicit conversion and the log gets removed.
Release Notes:
- N/A
See discussion on #36564
Adds a simple ad-hoc substring matching pattern language which allows
skipping a bounded number of chars between matched substrings. Before
this change compiling the regex was taking ~120ms on a fast machine and
~8mb of memory. This new version is way faster and uses minimal memory.
Checked the behavior of this vs by running it against 10k licenses that
happened to be in my home dir. There were only 4 differences of behavior
with the regex implementation, and these were false negatives for the
regex implementation that are true positives with the new one.
Of the ~10k licenses in my home dir, ~1k do not match one of these
licenses, usually because it's GPL/MPL/etc.
Release Notes:
- N/A
See discussion on #36564. Makes the license regexes a less fragile by
not matching on symbols, while also excluding cases where a long file
ends with a valid license. Also adds Zlib license, a commented out test
to check all license-like files discovered in the homedir, and more
testcases.
Not too happy with the efficiency here, on my quite good computer it
takes ~120ms to compile the regex and allocates ~8mb for it. This is
just not a great use of regexes, I think something using eager substring
matching would be much more efficient - hoping to followup with that.
Release Notes:
- Edit Prediction: Added Zlib license to open-source licenses eligible
for data collection.
Closes#37171
Release Notes:
- agent: Fixed a bug that caused the agent information in the panel
header to be incorrect when opening a thread from history.
Closes #ISSUE
Adds a dependency on `serde_path_to_error` to the workspace allowing us
to include the path to the setting that failed to parse on settings
parse failure.
Release Notes:
- N/A *or* Added/Fixed/Improved ...
Closes#37025
This PR fixes GitHub Copilot thread summary failures by removing the
unnecessary `noop` tool insertion logic. The code was originally added
as a workaround in https://github.com/zed-industries/zed/pull/30007 for
supposed GitHub Copilot API issues when tools were used previously in a
conversation but no tools are provided in the current request. However,
testing revealed that this scenario works fine without the workaround,
and the `noop` tool insertion was actually causing "Invalid schema for
function 'noop'" errors that prevented thread summarization from
working. Removing this logic eliminates the errors and allows thread
summarization to function correctly with GitHub Copilot models.
The best way to see if removing that part of code works is just
triggering thread summarisation.
Error Log:
```
2025-08-27T13:47:50-04:00 ERROR [workspace::notifications] "Failed to connect to API: 400 Bad Request {"error":{"message":"Invalid schema for function 'noop': In context=(), object schema missing properties.","code":"invalid_function_parameters"}}\n"
```
Release Notes:
- Fixed GitHub Copilot thread summary failures by removing unnecessary
noop tool insertion logic.
Follow-up to https://github.com/zed-industries/zed/pull/37035
In the WSL PR, `ssh_connection_id` was renamed to
`remote_connection_id`. However, that was not accounted for within the
`recent_workspaces_query`. This caused a query fail:
```
2025-08-30T14:45:44+02:00 ERROR [recent_projects] Prepare call failed for query:
SELECT
workspace_id,
paths,
paths_order,
ssh_connection_id
FROM
workspaces
WHERE
paths IS NOT NULL
OR ssh_connection_id IS NOT NULL
ORDER BY
timestamp DESC
Caused by:
Sqlite call failed with code 1 and message: Some("no such column: ssh_connection_id")
```
and resulted in no recent workspaces being shown within the recent
projects picker.
This change updates the column name to the new name and thus fixes the
error.
Release Notes:
- N/A
After setting a `grok` model via the agent panel, the settings complains
that it doesn't recognize the language model provider:
<img width="1005" height="188" alt="SCR-20250829-tqqd"
src="https://github.com/user-attachments/assets/a25fc7e0-60f0-44fd-96d2-b1cb316d06b6"
/>
Also, sorted the list, in the follow-up commit.
Release Notes:
- N/A
Fixes#36866
- Updated internal naming for Claude 4 models to be consistent.
- Corrected max output tokens for Anthropic Bedrock models to match docs
Shoutout to @tlehn for noticing the bug, and finding the resolution.
Release Notes:
- bedrock: Fixed inference config errors causing Opus 4 Thinking and
Opus 4.1 Thinking to fail (thanks [@tlehn](https://github.com/tlehn) and
[@5herlocked](https://github.com/5herlocked])
- bedrock: Fixed an issue which prevented Rules / System prompts not
functioning with Bedrock models (thanks
[@tlehn](https://github.com/tlehn) and
[@5herlocked](https://github.com/5herlocked])
## Goal
This PR creates the initial settings ui structure with the primary goal
of making a settings UI that is
- Comprehensive: All settings are available through the UI
- Correct: Easy to understand the underlying JSON file from the UI
- Intuitive
- Easy to implement per setting so that UI is not a hindrance to future
settings changes
### Structure
The overall structure is settings layer -> data layer -> ui layer.
The settings layer is the pre-existing settings definitions, that
implement the `Settings` trait. The data layer is constructed from
settings primarily through the `SettingsUi` trait, and it's associated
derive macro. The data layer tracks the grouping of the settings, the
json path of the settings, and a data representation of how to render
the controls for the setting in the UI, that is either a marker value
for the component to use (avoiding a dependency on the `ui` crate) or a
custom render function.
Abstracting the data layer from the ui layer allows crates depending on
`settings` to implement their own UI without having to add additional UI
dependencies, thus avoiding circular dependencies. In cases where custom
UI is desired, and a creating a custom render function in the same crate
is infeasible due to circular dependencies, the current solution is to
implement a marker for the component in the `settings` crate, and then
handle the rendering of that component in `settings_ui`.
### Foundation
This PR creates a macro and a trait both called `SettingsUi`. The
`SettingsUi` trait is added as a new trait bound on the `Settings`
trait, this allows the type system to guarantee that all settings
implement UI functionality. The macro is used to derived the trait for
most types, and can be modified through attributes for unique cases as
well.
A derive-macro is used to generate the settings UI trait impl, allowing
it the UI generation to be generated from the static information in our
code base (`default.json`, Struct/Enum names, field names, `serde`
attributes, etc). This allows the UI to be auto-generated for the most
part, and ensures consistency across the UI.
#### Immediate Follow ups
- Add a new `SettingsPath` trait that will be a trait bound on
`SettingsUi` and `Settings`
- This trait will replace the `Settings::key` value to enable
`SettingsUi` to infer the json path of it's derived type
- Figure out how to render `Option<T> where T: SettingsUi` correctly
- Handle `serde` attributes in the `SettingsUi` proc macro to correctly
get json path from a type's field and identity
Release Notes:
- N/A
---------
Co-authored-by: Ben Kunkle <ben@zed.dev>
Add support for scrolling the contents rendered aside an
`editor::code_context_menus::CodeContextMenu` by introducing the
`scroll_aside` method.
For now this method is only implemented for the
`CodeContextMenu::Completions` variant, which will scroll the aside
contents for an `editor::code_context_menus::CompletionsMenu` element,
as a `ScrollHandle` is added to the aside content that is rendered.
In order to be possible to trigger this via keybindings, a new editor
action is introduced, `ContextMenuScrollAside`, which accepts a number
of lines or pages to scroll the content by.
Lastly, the default keymaps for both MacOS and Linux, as well as for
Zed's vim mode, are updated to ensure that the following keybindings are
supported when a completion menu is open and the completion item's
documentation is rendered aside:
- `ctrl-e`
- `ctrl-y`
- `ctrl-d`
- `ctrl-u`
### Recording
https://github.com/user-attachments/assets/02043763-87ea-46f5-9768-00e907127b69
---
Closes#13194
Release Notes:
- Added support for scrolling the documentation panel shown alongside
the completion menu in the editor with `cltr-d`, `ctrl-u`, `ctrl-e` and
`ctrl-y`
---------
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: MrSubidubi <finn@zed.dev>
Closes#36981
- Add completion text and position caching to reduce redundant API calls
- Only trigger new completion requests on text changes, not cursor
movement
- Validate cursor position to ensure completions show at correct
location
- Improve end-of-line range calculation for more accurate deletions
- Extract reset_completion_cache helper for cleaner code organization
- Update completion diff algorithm documentation for clarity
Edit: Sorry this is the 2nd PR, I forgot that the forks history was
messy; I cherrypicked and cleaned it properly with this PR
Release Notes:
- supermaven: Improved caching of predictions
- supermaven: Fixed an issue where changing cursor position would
incorrectly trigger new completions
In the case where we fail to create an ACP connection to Gemini, only
report the "unsupported version" error if the version for the found
binary is at least our minimum version. That means we'll surface the
real error in this situation.
This also fixes incorrect sorting of downloaded Gemini versions--as @kpe
pointed out we were effectively using the version string as a key. Now
we'll correctly use the parsed semver::Version instead.
Release Notes:
- N/A
Closes https://github.com/zed-industries/zed/issues/36383
The project symbols modal didn't use the buffer font and highlighted
matches through modifying the font weight, which is inconsistent with
the outline picker, which presents code in list items in a similar way,
as well as project _and_ buffer search highlighting design.
Release Notes:
- N/A
Closes#35787Closes#17890Closes#28789Closes#36495
How it works:
For highlights (and selections) within the visible rows of the editor,
we split them row by row. This is efficient since the number of visible
rows is constant. For each row, all highlights and selections, which may
overlap, are flattened using a line sweep. This produces non-overlapping
consecutive segments for each row, each with a blended background color.
Next, for each row, we split text runs into smaller runs to adjust its
color using APCA contrast. Since both text runs and segment are
non-overlapping and consecutive, we can use two-pointer on them to do
this.
For example, a text run for the variable red might be split into two
runs if a highlight partially covers it. As a result, one part may
appear as red, while the other appears as a lighter red, depending on
the background behind it.
Result:
<img width="1458" height="949" alt="image"
src="https://github.com/user-attachments/assets/4814c93d-12e7-4b4d-8542-d912acccfb8e"
/>
<img width="1459" height="952" alt="image"
src="https://github.com/user-attachments/assets/9e497b6c-3e66-43e8-8e5b-f634dd5ee8d3"
/>
<img width="1457" height="621" alt="image"
src="https://github.com/user-attachments/assets/8dfa6ce5-f46b-45b9-8008-66169d5aecd4"
/>
Release Notes:
- Improved text contrast when selected or highlighted in the editor.
Follow-up of https://github.com/zed-industries/zed/pull/36764
* Fix `anyhow!({e})` conversion lossing Collab error codes context when
opening a buffer remotely
* Use this context to only allow opening files that had not specific
Collab error code
Release Notes:
- N/A
Follow-up https://github.com/zed-industries/zed/pull/37083
Noisy RPC LSP logs were functioning this way already, but to keep Collab
loaded even less, do not send any kind of logs to the client if the
client has a corresponding log tab not opened.
This change is pretty raw and does not fully cover scenarious with
multiple clients: if one client has a log tab open and another opens tab
with another kind of log, the 2nd kind of logs will be streamed only.
Also, it should be possible to forward the host logs to the client on
enabling — that is not done to keep the change smaller.
Release Notes:
- N/A
To show these notifications, Zeta was being initialized with the initial
workspace it's used on - which may not even still exist! This removes a
confusing/misleading workspace field from Zeta.
Release Notes:
- N/A
We have a bug in our ACP implementation where sometimes the
Accept/Reject buttons are disabled (and stay disabled even after the
thread has finished). I haven't found a complete fix for this yet, so in
the meantime I'm putting out the fire by making it so those buttons are
always enabled. That way you're never blocked, and the only consequence
of the bug is that sometimes they should be disabled but are enabled
instead.
Release Notes:
- N/A
@JosephTLyons pointed out that it's a bit weird that we only show a
preview for items selected after the initial one, so this does it for
that too.
It makes tab switching feel even faster!
Release Notes:
- N/A
Co-authored-by: David Kleingeld <davidsk@zed.dev>
Closes: https://github.com/zed-industries/zed/issues/37089
Instead of looking for the gemini command on `$PATH`, by default we'll
install our own copy on demand under our data dir, as we already do for
language servers and debug adapters. This also means we can handle
keeping the binary up to date instead of prompting the user to upgrade.
Notes:
- The download is only triggered if you open a new Gemini thread
- Custom commands from `agent_servers.gemini` in settings are respected
as before
- A new `agent_servers.gemini.ignore_system_version` setting is added,
similar to the existing settings for language servers. It's `true` by
default, and setting it to `false` disables the automatic download and
makes Zed search `$PATH` as before.
- If `agent_servers.gemini.ignore_system_version` is `false` and no
binary is found on `$PATH`, we'll fall back to automatic installation.
If it's `false` and a binary is found, but the version is older than
v0.2.1, we'll show an error.
Release Notes:
- acp: By default, Zed will now download and use a private copy of the
Gemini CLI binary, instead of searching your `$PATH`. To make Zed search
your `$PATH` for Gemini CLI before attempting to download it, use the
following setting:
```
{
"agent_servers": {
"gemini": {
"ignore_system_version": false
}
}
}
```
This PR makes it so the channel list will still be shown while
reconnecting to Collab instead of showing the signed-out state.
In order to model the transitional states that occur while reconnecting,
we needed to introduce a new `Status::Reauthenticated` state that we go
through when signing in as part of a reconnect. This is because we
cannot tell from `Status::Authenticated` alone if we're authenticating
for the first time or reauthenticating.
Release Notes:
- N/A
Closes#36420
## Synopsis
The issue in #36420 is caused by #7276, which bound the appropriate
tree-sitter queries to the `@variable.member` color. However, I have
found neither this color's declaration nor its other usages in the
codebase (neither on the latest `main` nor on
79c1003b34).
Other languages use for such situations the `@property` color.
## Solution
Just change the used `@variable.member` color to the `@property` one.
Seems fully inline with the changes illustrated in #7276.
## Screenshots
<img width="856" height="465" alt="Screenshot 2025-08-28 at 13 18 38"
src="https://github.com/user-attachments/assets/9d1f3542-8749-421f-864f-959c1242cc64"
/>
<img width="837" height="462" alt="Screenshot 2025-08-28 at 13 20 08"
src="https://github.com/user-attachments/assets/36a80c22-9de9-46b1-87e3-7fdeaa62978f"
/>
## Changelog
Release Notes:
- go: Fixed highlighting of fields.
Use the latest Copilot Chat model schema, matching what is used in
VSCode, to get more data about available models than was previously
accessible. Replace hardcoded default model (gpt-4.1) with the default
model included in JSON. Other data like premium request multipliers
could be used in the future if Zed implements a way for models to
display additional details about themselves, such as with tooltips on
hover.
Release Notes:
- N/A
---------
Co-authored-by: Peter Tripp <peter@zed.dev>
Closes#37022Closes#36994
This update ensures all Grok models use the JsonSchemaSubset format for
tool schemas.
A previous fix for this issue was too specific, only targeting grok-4
models. This caused other variants, like grok-code-fast-1, to be missed.
We've now broadened the logic to correctly apply the setting to the
entire Grok model family.
Release Notes:
- Fix tool calling for `x-ai/grok-code-fast-1` model via OpenRouter.