mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-10-04 00:02:04 +00:00
fix(terminal): stop the git retry check from redrawing every poll tick (#1015)
The retry added in #1011 went through update_global on every 300ms poll while a pane's repo was unanswered, even when the probe was still in flight or throttled and nothing was claimed. Each mutable touch of the GitStatusCache global wakes its observers, so the window redrew about three times a second for as long as a probe was pending or failing. That is what a_commit_detail_reads_its_own_files_and_draws_them caught on Linux CI (2 idle frames where 0 are expected). Ask whether a retry is due read-only (GitStatusCache::probe_due) and only touch the global when one is.
This commit is contained in:
@@ -87,21 +87,32 @@ impl GitStatusCache {
|
||||
cwd: &Path,
|
||||
min_interval: Duration,
|
||||
) -> bool {
|
||||
if !self.probe_due(host, cwd, min_interval) {
|
||||
return false;
|
||||
}
|
||||
let cwd = key(host, cwd);
|
||||
let throttle = self.throttle_key(host, &cwd).to_path_buf();
|
||||
self.last_probe.insert(host, throttle, Instant::now());
|
||||
self.probes.begin((host, cwd.into_owned()));
|
||||
true
|
||||
}
|
||||
|
||||
/// Whether [`GitStatusCache::begin_probe_throttled`] would start a probe,
|
||||
/// asked without claiming anything.
|
||||
///
|
||||
/// For a caller polling on a timer: reaching this cache through
|
||||
/// `update_global` wakes everything observing it even when the answer is
|
||||
/// "not yet", and a pane asking three times a second redraws the window
|
||||
/// three times a second to be told no.
|
||||
pub fn probe_due(&self, host: HostId, cwd: &Path, min_interval: Duration) -> bool {
|
||||
let cwd = key(host, cwd);
|
||||
if self.probes.is_pending(&(host, cwd.to_path_buf())) {
|
||||
return false;
|
||||
}
|
||||
let throttle = self.throttle_key(host, &cwd).to_path_buf();
|
||||
if self
|
||||
!self
|
||||
.last_probe
|
||||
.get(host, throttle.as_path())
|
||||
.get(host, self.throttle_key(host, &cwd))
|
||||
.is_some_and(|at| at.elapsed() < min_interval)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
self.last_probe.insert(host, throttle, Instant::now());
|
||||
self.probes.begin((host, cwd.into_owned()));
|
||||
true
|
||||
}
|
||||
|
||||
/// `cwd` is already in the cache's own spelling — every caller of this one
|
||||
|
||||
+14
-9
@@ -2168,17 +2168,22 @@ impl TerminalView {
|
||||
}
|
||||
|
||||
/// This pane sits somewhere the repo cache cannot place yet — neither a
|
||||
/// repository nor "not one". A probe in flight looks the same, and the
|
||||
/// throttle turns the retry away; the case this exists for is a probe that
|
||||
/// failed, which leaves the answer open instead of recording a wrong one,
|
||||
/// and would otherwise wait for the cwd to change or a command to finish
|
||||
/// before anyone asked again.
|
||||
fn git_repo_unanswered(&self, cx: &App) -> bool {
|
||||
/// repository nor "not one" — and a retry is due. Only a failed probe
|
||||
/// leaves a cwd that way; without this it would wait for the cwd to change
|
||||
/// or a command to finish before anyone asked again.
|
||||
///
|
||||
/// Read-only on purpose: this runs on every poll tick, and the cache is a
|
||||
/// global whose every mutable touch redraws the window — while a probe is
|
||||
/// in flight or throttled, the answer has to be "no" at no cost.
|
||||
fn git_retry_due(&self, cx: &App) -> bool {
|
||||
let Some(cwd) = self.git_status_cwd.as_deref() else {
|
||||
return false;
|
||||
};
|
||||
cx.try_global::<crate::terminal::git_status::GitStatusCache>()
|
||||
.is_none_or(|cache| cache.known_repo_for(self.host_id, cwd).is_none())
|
||||
let Some(cache) = cx.try_global::<crate::terminal::git_status::GitStatusCache>() else {
|
||||
return false;
|
||||
};
|
||||
cache.known_repo_for(self.host_id, cwd).is_none()
|
||||
&& cache.probe_due(self.host_id, cwd, GIT_RETRY_GAP)
|
||||
}
|
||||
|
||||
/// Plant the cwd the git-status poll would have found. For tests that
|
||||
@@ -4035,7 +4040,7 @@ impl TerminalView {
|
||||
self.refresh_git_status(cwd_now, GitRefresh::Edge, cx);
|
||||
} else if tool_activity {
|
||||
self.refresh_git_status(cwd_now, GitRefresh::Opportunistic, cx);
|
||||
} else if self.git_repo_unanswered(cx) {
|
||||
} else if self.git_retry_due(cx) {
|
||||
self.refresh_git_status(cwd_now, GitRefresh::Retry, cx);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user