Skip to content

git: Add notification to git clone#41712

Merged
cole-miller merged 6 commits intozed-industries:mainfrom
AlvaroParker:notification-on-git-clone
Nov 11, 2025
Merged

git: Add notification to git clone#41712
cole-miller merged 6 commits intozed-industries:mainfrom
AlvaroParker:notification-on-git-clone

Conversation

@AlvaroParker
Copy link
Contributor

@AlvaroParker AlvaroParker commented Nov 1, 2025

Adds a simple notification when cloning a repo using the integrated git clone on Zed. Before this, the user had no feedback after starting the cloning action.

Demo:

2025-11-05.21-20-38.mp4

Not sure about that icon I'm using for the animation, but that can be easily changed.

Release Notes:

  • Added notification when cloning a repo from zed

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Nov 1, 2025
@github-actions github-actions bot added the community champion Issues filed by our amazing community champions! 🫶 label Nov 1, 2025
@cole-miller
Copy link
Member

cole-miller commented Nov 4, 2025

Thanks! What do you think about putting this with a spinner in the activity bar at the bottom instead (where it says Click to restart and update Zed in the screenshot)? That's a bit more consistent with our current conventions for signalling ongoing work.

image

@AlvaroParker
Copy link
Contributor Author

AlvaroParker commented Nov 6, 2025

Since git clone is implemented on the Fs trait I went ahead and did something similar to how long running jobs are handled for LanguageRegistry:

fn subscribe(&self) -> mpsc::UnboundedReceiver<(LanguageServerName, BinaryStatus)> {
let (tx, rx) = mpsc::unbounded();
self.txs.lock().push(tx);
rx
}

That is, using channels to send status for long running fs jobs and using fs::subscribe_to_job_events() to subscribe to this long running jobs.

@AlvaroParker AlvaroParker force-pushed the notification-on-git-clone branch from 837f8c3 to c507c9c Compare November 6, 2025 00:49
Copy link
Member

@cole-miller cole-miller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! A follow-up comment about the code structure but this is looking good.

Comment on lines +222 to +278
pub type JobId = usize;

#[derive(Clone, Debug)]
pub struct JobInfo {
pub start: Instant,
pub message: SharedString,
pub id: JobId,
}

#[derive(Debug, Clone)]
pub enum JobEvent {
Started { info: JobInfo },
Completed { id: JobId },
}

pub type JobEventSender = futures::channel::mpsc::UnboundedSender<JobEvent>;
pub type JobEventReceiver = futures::channel::mpsc::UnboundedReceiver<JobEvent>;

type JobEventBroadcast = Vec<JobEventSender>;

static GLOBAL_JOB_EVENTS_SUBSCRIBERS: std::sync::Mutex<JobEventBroadcast> =
std::sync::Mutex::new(Vec::new());

pub fn subscribe_to_job_events() -> JobEventReceiver {
let (sender, receiver) = futures::channel::mpsc::unbounded();

if let Ok(mut subscribers) = GLOBAL_JOB_EVENTS_SUBSCRIBERS.lock() {
subscribers.push(sender);
}

receiver
}

fn send_job_event(event: JobEvent) {
if let Ok(mut subscribers) = GLOBAL_JOB_EVENTS_SUBSCRIBERS.lock() {
subscribers.retain(|sender| sender.unbounded_send(event.clone()).is_ok());
}
}

struct JobTracker {
id: JobId,
}

impl JobTracker {
fn new(info: JobInfo) -> Self {
let id = info.id;
send_job_event(JobEvent::Started { info });
Self { id }
}
}

impl Drop for JobTracker {
fn drop(&mut self) {
send_job_event(JobEvent::Completed { id: self.id });
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if we can find a way to structure this code without a global subscription. What if the ActivityIndicator held an Arc<dyn Fs>, and the Fs trait had a peek_current_job method that just returned an Option<String>? (And I guess a start instant.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be done, however peek_current_job would have to be called inside the ActivityIndicator::content_to_render function, which is called on every render. And because we have an Arc<dyn Fs> we will have to keep the jobs inside a Mutex hence locking on every render to get the current job, and sometimes when two or more windows are open, multiple ActivityIndicator instances will be calling on that function.

I could try to rework this and make a function on that trait that returns a JobEventReceiver like I'm currently doing only this is more integrated to the Fs trait and we loose that global subscription

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the explanation! That makes sense, and I like the new in-between structure with a method on the Fs trait.

Copy link
Member

@cole-miller cole-miller left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@cole-miller cole-miller merged commit f90d078 into zed-industries:main Nov 11, 2025
24 checks passed
11happy pushed a commit to 11happy/zed that referenced this pull request Dec 1, 2025
Adds a simple notification when cloning a repo using the integrated git
clone on Zed. Before this, the user had no feedback after starting the
cloning action.

Demo:


https://github.com/user-attachments/assets/72fcdf1b-fc99-4fe5-8db2-7c30b170f12f

Not sure about that icon I'm using for the animation, but that can be
easily changed.

Release Notes:

- Added notification when cloning a repo from zed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement community champion Issues filed by our amazing community champions! 🫶

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants