use super::{AppModel, desired_watches, needs_liveness_reprobe};
use crate::binding;
use crate::world::toolgate::{self, ToolchainState};
use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
impl AppModel {
pub fn tick(&mut self) -> bool {
let delivered = self.dirty.drain();
self.dispatch_dirty(delivered);
let sweep = self.schedule.sweep();
if sweep == super::dirty::Sweep::Full {
self.full_sweep();
} else if sweep == super::dirty::Sweep::Cheap {
self.cheap_sweep();
}
let _ = self.ui.flush_if_due();
let mut changed = false;
for root in self.schedule.due() {
changed |= self.rederive(&root);
}
changed
}
fn dispatch_dirty(&mut self, roots: BTreeSet<PathBuf>) {
let mut workspaces = Vec::new();
for root in roots {
if root == self.roots.yog_state {
self.adopt_ui();
self.refresh_ops();
} else if root == self.roots.balls_clones {
self.refresh_balls();
} else if self.is_enum_root(&root) {
self.reconcile();
} else {
workspaces.push(root);
}
}
self.schedule.mark(workspaces);
}
fn is_enum_root(&self, root: &Path) -> bool {
root == self.roots.names()
|| root == self.roots.workspaces()
|| root == self.roots.replays()
}
fn adopt_ui(&mut self) {
if let Ok(bytes) = std::fs::read(self.roots.ui_json())
&& !self.ui.is_echo(&bytes)
{
self.ui.adopt(&bytes);
}
}
fn reconcile(&mut self) {
self.workspaces = binding::workspaces(&self.roots.yog_data, &self.roots.lernie_data);
let desired = desired_watches(&self.roots, &self.workspaces);
crate::state::lock_watchset(&self.watchset).reconcile(&desired);
let known: BTreeSet<PathBuf> = self.workspaces.iter().map(|w| w.path.clone()).collect();
self.trees.retain(|path, _| known.contains(path));
let mut missing = Vec::new();
for w in &self.workspaces {
if !self.trees.contains_key(&w.path) {
missing.push(w.path.clone());
}
}
self.schedule.mark(missing);
let cloned: Vec<PathBuf> = self.balls_by_project.keys().cloned().collect();
self.rebuild_join(&cloned);
}
fn cheap_sweep(&mut self) {
self.reconcile();
let mut live: Vec<(PathBuf, Vec<String>)> = Vec::new();
for (path, tree) in &self.trees {
if needs_liveness_reprobe(tree) {
let ids = tree.agents.iter().map(|a| a.agent_id.clone()).collect();
live.push((path.clone(), ids));
}
}
for (path, ids) in live {
self.probes.invalidate_liveness(&path, &ids);
self.schedule.mark([path]);
}
}
fn full_sweep(&mut self) {
self.reconcile();
self.refresh_balls();
self.refresh_ops();
let all: Vec<PathBuf> = self.workspaces.iter().map(|w| w.path.clone()).collect();
self.schedule.mark(all);
}
fn rederive(&mut self, workspace: &Path) -> bool {
let Ok(tree) = self.probes.derive(workspace) else {
return false;
};
if self.trees.get(workspace) == Some(&tree) {
return false;
}
self.trees.insert(workspace.to_path_buf(), tree);
true
}
pub(crate) fn toolchain(&self) -> &ToolchainState {
&self.toolchain
}
pub fn refresh_toolchain(&mut self) {
self.toolchain = toolgate::probe(self.probe.as_ref());
}
}