This PR tackles how we communicate errors/warnings relative to skills.
It touches three major surfaces: callouts in the thread view, menu items
in the completion menu, and settings UI. These are all the places where
we display something to tell the user a skill might have a problem.
In the settings UI, we now clamp the skill description to five lines.
And if there's a warning, we show the warning icon and the description
in a tooltip when hovering it:
<img width="600" alt="Screenshot 2026-06-08 at 10 51@2x"
src="https://github.com/user-attachments/assets/1a1233b0-c24a-4082-9fe6-2ab1d00ba9fd"
/>
In the thread view, we display callouts with the warnings. I simplified
the long-description one specifically given we can click on each skill
item right there, so no need for a "manage global skills" button or
descriptions in each item:
<img width="600" alt="Screenshot 2026-06-08 at 10 52@2x"
src="https://github.com/user-attachments/assets/4b9aad23-7362-40cd-8ab5-6dfceb46badd"
/>
In the code completion menu, I removed the icon that appeared at the far
right and instead added the ability for it to render a colored warning
icon instead of the icon it'd already display in the left; I think this
simplifies it nicely:
<img width="350" alt="Screenshot 2026-06-08 at 10 53@2x"
src="https://github.com/user-attachments/assets/8d0c731a-31a0-4d30-abab-1eb40f61031e"
/>
Release Notes:
- Agent: Improved how we communicate problems relative to skills, in
both the agent panel and the settings UI.
---------
Co-authored-by: Martin Ye <martin@zed.dev>
Closes AI-230
This PR makes skills, added as /-mentions, be rendered in the agent
panel as creases, like anything you'd @-mention. Naturally, clicking on
the crease button opens the corresponding skill file in a buffer.
It turned out to be quite a bit of plumbing to make this work,
particularly as I am also introducing an interface to display dividers
and headers in the completion menu. This was relevant to me to add
because it sets a good foundation to convert many agent panel-related
actions as slash commands.
Release Notes:
- N/A
---------
Co-authored-by: MartinYe1234 <52641447+MartinYe1234@users.noreply.github.com>
## Summary
Fix completion ordering when two items are otherwise tied and only
differ by letter case.
In cases like `abc` vs `ABC`, if the user types `a`, Zed should prefer
`abc`. If the user types `A`, Zed should prefer `ABC`. This matches the
expectation described in #37081 and #27993, where `subscription` should
rank above `Subscription` for query `s`.
## What changed
In `CompletionsMenu::sort_string_matches`, I added a tie-breaker that
prefers completions with more exact case-sensitive matches at the
fuzzy-match positions.
This only applies after the existing higher-priority sort keys, so it
does not replace fuzzy score, match positions, snippet ordering, or LSP
`sortText`. It only resolves ambiguous ties more intuitively.
## Tests
Added regression coverage in `code_completion_tests` for abstract
case-only examples:
- `a` prefers `abc` over `ABC`
- `A` prefers `ABC` over `abc`
- `ab` prefers `abc` over `ABC`
- `AB` prefers `ABC` over `abc`
- mixed-case multi-letter queries like `Ab` and `aB`
## Verification
Ran:
```bash
cargo test -p editor code_completion_tests
```
PS: all code and description is generated by Codex
Release Notes:
- Fixed completions not tie braking by case
TODO:
- [x] merge main
- [x] nonshrinking `set_excerpts_for_path`
- [x] Test-drive potential problem areas in the app
- [x] prepare cloud side
- [x] test collaboration
- [ ] docstrings
- [ ] ???
## Context
### Background
Currently, a multibuffer consists of an arbitrary list of
anchor-delimited excerpts from individual buffers. Excerpt ranges for a
fixed buffer are permitted to overlap, and can appear in any order in
the multibuffer, possibly separated by excerpts from other buffers.
However, in practice all code that constructs multibuffers does so using
the APIs defined in the `path_key` submodule of the `multi_buffer` crate
(`set_excerpts_for_path` etc.) If you only use these APIs, the resulting
multibuffer will maintain the following invariants:
- All excerpts for the same buffer appear contiguously in the
multibuffer
- Excerpts for the same buffer cannot overlap
- Excerpts for the same buffer appear in order
- The placement of the excerpts for a specific buffer in the multibuffer
are determined by the `PathKey` passed to `set_excerpts_for_path`. There
is exactly one `PathKey` per buffer in the multibuffer
### Purpose of this PR
This PR changes the multibuffer so that the invariants maintained by the
`path_key` APIs *always* hold. It's no longer possible to construct a
multibuffer with overlapping excerpts, etc. The APIs that permitted
this, like `insert_excerpts_with_ids_after`, have been removed in favor
of the `path_key` suite.
The main upshot of this is that given a `text::Anchor` and a
multibuffer, it's possible to efficiently figure out the unique excerpt
that includes that anchor, if any:
```
impl MultiBufferSnapshot {
fn buffer_anchor_to_anchor(&self, anchor: text::Anchor) -> Option<multi_buffer::Anchor>;
}
```
And in the other direction, given a `multi_buffer::Anchor`, we can look
at its `text::Anchor` to locate the excerpt that contains it. That means
we don't need an `ExcerptId` to create or resolve
`multi_buffer::Anchor`, and in fact we can delete `ExcerptId` entirely,
so that excerpts no longer have any identity outside their
`Range<text::Anchor>`.
There are a large number of changes to `editor` and other downstream
crates as a result of removing `ExcerptId` and multibuffer APIs that
assumed it.
### Other changes
There are some other improvements that are not immediate consequences of
that big change, but helped make it smoother. Notably:
- The `buffer_id` field of `text::Anchor` is no longer optional.
`text::Anchor::{MIN, MAX}` have been removed in favor of
`min_for_buffer`, etc.
- `multi_buffer::Anchor` is now a three-variant enum (inlined slightly):
```
enum Anchor {
Min,
Excerpt {
text_anchor: text::Anchor,
path_key_index: PathKeyIndex,
diff_base_anchor: Option<text::Anchor>,
},
Max,
}
```
That means it's no longer possible to unconditionally access the
`text_anchor` field, which is good because most of the places that were
doing that were buggy for min/max! Instead, we have a new API that
correctly resolves min/max to the start of the first excerpt or the end
of the last excerpt:
```
impl MultiBufferSnapshot {
fn anchor_to_buffer_anchor(&self, anchor: multi_buffer::Anchor) -> Option<text::Anchor>;
}
```
- `MultiBufferExcerpt` has been removed in favor of a new
`map_excerpt_ranges` API directly on `MultiBufferSnapshot`.
## Self-Review Checklist
<!-- Check before requesting review: -->
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- N/A
---------
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
Co-authored-by: Conrad <conrad@zed.dev>
Closes#41723
This PR fixes an issue with accepting partial semver completions by
including `.` in the completion query. This makes the editor treat the
entire version string as the query, instead of breaking segment at last
`.` .
This PR also adds a test for sorting semver completions. The actual
sorting fix is handled in the `package-version-server` by having it
provide `sort_text`. More:
https://github.com/zed-industries/package-version-server/pull/10
<img width="600" alt="image"
src="https://github.com/user-attachments/assets/7657912f-c6da-4e05-956b-1c044918304f"
/>
Release Notes:
- Fixed an issue where accepting a completion for a semver version in
package.json would append the suggestion to the existing text instead of
replacing it.
- Improved the sorting of semver completions in package.json so the
latest versions appear at the top.
Co-Authored-By: Ben K <ben@zed.dev>
Co-Authored-By: Anthony <anthony@zed.dev>
Co-Authored-By: Mikayla <mikayla@zed.dev>
Release Notes:
- settings: Major internal changes to settings. The primary user-facing
effect is that some settings which did not make sense in project
settings files are no-longer read from there. (For example the inline
blame settings)
---------
Co-authored-by: Ben Kunkle <ben@zed.dev>
Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
Co-authored-by: Anthony <anthony@zed.dev>
Closes#33106
Instead of directly using `filter_text` in `StringMatchCandidate`, which
yields better results for fuzzy matching but messes up with highlighting
letters in bold, as `positions` list generated by fuzzy crate are now of
`filter_text` and not `label` shown to the user.
This PR fixes it by keeping use of `filter_range` in
`StringMatchCandidate`, which is range w.r.t to `label` shown to user.
And actually generating this `filter_range` at source by using
`filter_range` if exists.
- [x] Tests
Release Notes:
- Fixed issue where incorrect letters are marked as bold in completions.
This PR makes it a lot cleaner to write code completion tests. It
doesn't contain any logical changes, just refactoring.
Before, we used to depend on hard-coded values of fuzzy score and its
positions for tests. Now we don't need them, as fuzzy crate will handle
that for us. This is possible because fuzzy match score isn't dependent
on relative candidates or the number of candidates; rather, it's just a
one-to-one mapping for each candidate and its score.
This also makes it test robust for future purposes if there are changes
in fuzzy score logic.
Before:
```rs
SortableMatch {
string_match: StringMatch { // -> whole struct provided by fuzzy crate
candidate_id: 1115,
score: 1.0,
positions: vec![],
string: "Item".to_string(),
},
is_snippet: false, // -> changed to snippet kind
sort_text: Some("16"),
sort_kind: 3, // -> changed to function, constant, variable kind
sort_label: "Item",
},
```
After:
```rs
CompletionBuilder::function("Item", "16")
```
Release Notes:
- N/A
Closes#29725
Adds 3 more tests for Rust `into` and `await` cases, and Python
`__init__` case. Tweaks sort logic to accommodate them.
Release Notes:
- Improved code completion sort order, handling more cases with Rust and
Python.
Added `snippet_sort_order`, which determines how snippets are sorted
relative to other completion items. It can have the values `top`,
`bottom`, or `inline`, with `inline` being the default.
This mimics VS Code’s setting:
https://code.visualstudio.com/docs/editing/intellisense#_snippets-in-suggestions
Release Notes:
- Added support for `snippet_sort_order` to control snippet sorting
behavior in code completion menus.
Closes#27994, #29050, #27352, #27616
This PR implements new logic for code completions, which improve cases
where local variables, etc LSP based hints are not shown on top of code
completion menu. The new logic is explained in comment of code.
This new sort is similar to VSCode's completions sort where order of
sort is like:
Fuzzy > Snippet > LSP sort_key > LSP sort_text
whenever two items have same value, it proceeds to use next one as tie
breaker. Changing fuzzy score from float to int based makes it possible
for two items two have same fuzzy int score, making them get sorted by
next criteria.
Release Notes:
- Improved code completions to prioritize LSP hints, such as local
variables, so they appear at the top of the list.