use crate::git_tree::{Agent, AgentState, DescentRow, descent_order};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Tone {
Plain,
Weak,
Good,
Bad,
Live,
InFlight,
}
pub mod census;
pub mod doing;
pub mod expand;
pub mod flight;
pub mod group;
pub mod naming;
pub mod row;
pub mod select;
pub mod titles;
pub use census::{liveness_of_rows, names_in_rows};
pub use doing::{Doing, Seat, doing, seats};
pub use expand::{ancestors, forest_rows, parent_of, step, visible};
pub use flight::{Flight, FlightStrip, STRIP_HOVER, conversation_flight, strip};
pub use naming::{StartedAt, display_name, display_name_of, member_title, preview_of, started_at};
pub(crate) use naming::{id_floor, is_stamp};
pub use row::{ConvBall, ConvRow, age_label, build};
pub use select::{Selection, selection};
pub use titles::Titles;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Conversation {
pub name: String,
pub live: bool,
}
pub fn liveness(agents: &[Agent]) -> Vec<Conversation> {
let mut out = Vec::new();
for subtree in conversations(agents) {
let members: Vec<&Agent> = subtree.iter().filter_map(|r| agents.get(r.index)).collect();
let root = members.first().copied();
out.push(Conversation {
name: display_name_of(agents, root.map_or("", |a| a.agent_id.as_str())),
live: members
.iter()
.any(|a| running(a.state) || a.state_uncertain),
});
}
out
}
pub fn members(agents: &[Agent], root_id: &str) -> Vec<DescentRow> {
conversations(agents)
.into_iter()
.find(|subtree| {
subtree
.first()
.and_then(|r| agents.get(r.index))
.is_some_and(|a| a.agent_id == root_id)
})
.unwrap_or_default()
}
pub fn root_of(agents: &[Agent], agent_id: &str) -> Option<String> {
for subtree in conversations(agents) {
let root = subtree.first().and_then(|r| agents.get(r.index))?;
if subtree
.iter()
.filter_map(|r| agents.get(r.index))
.any(|a| a.agent_id == agent_id)
{
return Some(root.agent_id.clone());
}
}
None
}
fn conversations(agents: &[Agent]) -> Vec<Vec<DescentRow>> {
let mut out: Vec<Vec<DescentRow>> = Vec::new();
for r in descent_order(agents) {
if r.depth == 0 {
out.push(vec![r]);
} else if let Some(current) = out.last_mut() {
current.push(r);
}
}
out
}
fn running(state: AgentState) -> bool {
matches!(state, AgentState::Live | AgentState::InFlight)
}
#[cfg(test)]
pub(crate) mod tests;