diff --git a/docs/design.md b/docs/design.md index c8b9f21..c8cf5d0 100644 --- a/docs/design.md +++ b/docs/design.md @@ -2331,7 +2331,7 @@ holds trees hidden *because* nothing live is in them, so opening it would contradict the rule it exists to serve. Hidden trees is a group nothing went wrong in — the filter put them there and a key takes them back out — so it is drawn without a warning and it names that key: *a to show all*. The roots -`Shift+F` holds back are the other group read that way. A group that said only how many trees it hides +`Shift+F` puts out of the way are the other group read that way. A group that said only how many trees it hides would read as "nothing to see here" while hiding broken ones, so it also says how many of them carry findings: *4 trees with no live agent · 1 with findings*. The findings stay hidden — the reader asked for that — but the group diff --git a/src/view/draw/groups.rs b/src/view/draw/groups.rs index eedcd0c..6ba085c 100644 --- a/src/view/draw/groups.rs +++ b/src/view/draw/groups.rs @@ -9,7 +9,7 @@ use crate::view::palette; use crate::view::phrase; use crate::view::row::{AGENT, WARNING}; -use super::{pane_marker, sentence}; +use super::{beside, pane_marker, sentence}; /// What lifts the live-agent filter, said beside the trees it is holding back. const SHOW_ALL: &str = "a to show all"; @@ -26,7 +26,7 @@ pub(super) fn group_line(prefix: &str, group: &Group) -> Fitted { GroupKind::FailedProjects => (phrase::failed_projects(group.count), false), GroupKind::Conflicts => (phrase::conflicts(group.count), false), GroupKind::HiddenTrees => (phrase::hidden_trees(group.count, group.with_findings), true), - GroupKind::HeldBack => (phrase::held_back(group.count), true), + GroupKind::OutOfTheWay => (phrase::other_beads(group.count), true), GroupKind::Unattributed => (phrase::unattributed(group.count), false), GroupKind::Unconfigured => (phrase::unconfigured(group.count), false), }; @@ -38,7 +38,7 @@ pub(super) fn group_line(prefix: &str, group: &Group) -> Fitted { }; let state = match group.kind { GroupKind::HiddenTrees => vec![Span::styled(SHOW_ALL, palette::QUIET)], - GroupKind::HeldBack => held_back_state(group), + GroupKind::OutOfTheWay => out_of_the_way_state(group), _ => Vec::new(), }; @@ -48,21 +48,21 @@ pub(super) fn group_line(prefix: &str, group: &Group) -> Fitted { state, ); match group.kind { - GroupKind::HeldBack => line.briefly(held_back_counts(group)), + GroupKind::OutOfTheWay => line.briefly(out_of_the_way_counts(group)), _ => line, } } -/// What a line standing over the roots the mode is holding back says beside -/// itself: the seats in there, the beads wanting looking at, and the key that -/// brings them back. +/// What a line standing over the beads the mode put out of the way says +/// beside itself: the seats in there, the beads wanting looking at, and the +/// key that brings them back. /// -/// The reader asked for one bead, so the roots go; what they did not ask for +/// The reader asked for one bead, so the rest go; what they did not ask for /// was to be told there is nobody on them. Said in the words a line resting /// shut over the same things already uses. -fn held_back_state(group: &Group) -> Vec> { - let mut said = held_back_counts(group); - said.push(Span::styled(WHOLE_FOREST, palette::QUIET)); +fn out_of_the_way_state(group: &Group) -> Vec> { + let mut said = out_of_the_way_counts(group); + beside(&mut said, Span::styled(WHOLE_FOREST, palette::QUIET)); said } @@ -70,22 +70,28 @@ fn held_back_state(group: &Group) -> Vec> { /// /// The hint goes first and goes whole, because `F for th…` names no key while /// the counts are the part of this line a reader can read nowhere else. -fn held_back_counts(group: &Group) -> Vec> { +fn out_of_the_way_counts(group: &Group) -> Vec> { let mut said = Vec::new(); let Some(counts) = &group.held else { return said; }; if counts.live_agents > 0 { - said.push(Span::styled( - format!("{AGENT} {}", phrase::agents_beneath(counts.live_agents)), - palette::AGENT, - )); + beside( + &mut said, + Span::styled( + format!("{AGENT} {}", phrase::agents_beneath(counts.live_agents)), + palette::AGENT, + ), + ); } if counts.anomalies > 0 { - said.push(Span::styled( - format!("{WARNING} {}", phrase::anomalies_beneath(counts.anomalies)), - palette::ATTENTION, - )); + beside( + &mut said, + Span::styled( + format!("{WARNING} {}", phrase::anomalies_beneath(counts.anomalies)), + palette::ATTENTION, + ), + ); } said } @@ -283,10 +289,14 @@ mod tests { /// behind this line, open work and the seats on it included. So the line /// says how many, rather than leaving a reader to read one number as the /// whole truth about what is back there. + /// + /// Asserted as one string rather than cell by cell, because two cells + /// that abut read as one that names neither, and a `contains` on each of + /// them alone passes either way. #[test] - fn a_line_over_held_back_roots_says_its_seats_and_what_wants_looking_at() { + fn a_line_over_the_beads_put_out_of_the_way_says_its_seats_and_what_wants_looking_at() { let group = Group { - kind: GroupKind::HeldBack, + kind: GroupKind::OutOfTheWay, project: Some("summit-works".into()), count: 3, with_findings: 0, @@ -300,10 +310,11 @@ mod tests { let drawn = Painted::of(group_line(SHUT, &group), 120, 1).rows(); - assert!(drawn[0].contains("3 roots held back"), "{drawn:?}"); - assert!(drawn[0].contains("2 agents beneath"), "{drawn:?}"); - assert!(drawn[0].contains("1 bead beneath"), "{drawn:?}"); - assert!(drawn[0].contains("F for the whole forest"), "{drawn:?}"); + assert!(drawn[0].contains("3 other beads"), "{drawn:?}"); + assert!( + drawn[0].contains("2 agents beneath ⚠ 1 bead beneath F for the whole forest"), + "{drawn:?}" + ); } /// A row with no room for the way out says the counts without it. The @@ -312,7 +323,7 @@ mod tests { #[test] fn a_row_too_narrow_for_the_way_out_still_says_what_is_back_there() { let group = Group { - kind: GroupKind::HeldBack, + kind: GroupKind::OutOfTheWay, project: Some("summit-works".into()), count: 3, with_findings: 0, @@ -326,9 +337,11 @@ mod tests { let drawn = Painted::of(group_line(SHUT, &group), 64, 1).rows(); - assert!(drawn[0].contains("3 roots held back"), "{drawn:?}"); - assert!(drawn[0].contains("2 agents beneath"), "{drawn:?}"); - assert!(drawn[0].contains("1 bead beneath"), "{drawn:?}"); + assert!(drawn[0].contains("3 other beads"), "{drawn:?}"); + assert!( + drawn[0].contains("2 agents beneath ⚠ 1 bead beneath"), + "{drawn:?}" + ); assert!(!drawn[0].contains("F for"), "{drawn:?}"); assert!(!drawn[0].contains(CUT), "{drawn:?}"); } @@ -336,9 +349,9 @@ mod tests { /// And says neither where there is neither. A nought said is a column /// spent telling a reader about nothing. #[test] - fn a_line_over_quiet_held_back_roots_says_nothing_of_seats_at_all() { + fn a_line_over_one_quiet_bead_put_out_of_the_way_says_nothing_of_seats_at_all() { let group = Group { - kind: GroupKind::HeldBack, + kind: GroupKind::OutOfTheWay, project: Some("summit-works".into()), count: 1, with_findings: 0, @@ -352,7 +365,7 @@ mod tests { let drawn = Painted::of(group_line(SHUT, &group), 120, 1).rows(); - assert!(drawn[0].contains("1 root held back"), "{drawn:?}"); + assert!(drawn[0].contains("1 other bead"), "{drawn:?}"); assert!(!drawn[0].contains("beneath"), "{drawn:?}"); assert!(drawn[0].contains("F for the whole forest"), "{drawn:?}"); } @@ -376,7 +389,7 @@ mod tests { assert_eq!( marked, - !matches!(kind, GroupKind::HiddenTrees | GroupKind::HeldBack), + !matches!(kind, GroupKind::HiddenTrees | GroupKind::OutOfTheWay), "{kind:?}: {drawn:?}" ); } diff --git a/src/view/forest/layout.rs b/src/view/forest/layout.rs index dd40fd7..a3d09a0 100644 --- a/src/view/forest/layout.rs +++ b/src/view/forest/layout.rs @@ -45,8 +45,8 @@ enum Child<'a> { /// question a fold raises — what did that just take off the screen — has one /// answer wherever it is asked. /// -/// The same reading answers a root drawn behind the line the mode holding -/// roots back puts them behind: the bead the forest is rooted at is beneath +/// The same reading answers a root drawn behind the line the mode puts the +/// rest of the forest behind: the bead the forest is rooted at is beneath /// that root and drawn at the top of the screen, and this count holds it, for /// the same reason two copies of a bead do not add up. fn shut_over(beneath: Counts, first: bool, folded: Option) -> Option { @@ -159,7 +159,7 @@ pub(super) fn first_bead_of( ) -> Option { let roots = match kind { GroupKind::HiddenTrees => hidden_trees(snapshot, project), - GroupKind::HeldBack => held_back(snapshot, project, rooted) + GroupKind::OutOfTheWay => out_of_the_way(snapshot, project, rooted) .into_iter() .map(|root| root.tree) .collect(), @@ -228,7 +228,7 @@ pub(super) fn walked<'a>( ); } drawn.extend( - held_back(snapshot, Some(project), Some(rooted)) + out_of_the_way(snapshot, Some(project), Some(rooted)) .into_iter() .map(|root| (root.tree, vec![0])), ); @@ -257,8 +257,8 @@ fn group_of( // Counted off the beads behind the line rather than off the roots they // came from: this line is all a reader gets of what is behind it, and // the bead the forest is rooted at is on the screen already. - GroupKind::HeldBack => { - let held = held_back(snapshot, project, rooted); + GroupKind::OutOfTheWay => { + let held = out_of_the_way(snapshot, project, rooted); let counts = Counts::over(held.iter().flat_map(Behind::beads)); (held.len(), 0, Some(counts)) } @@ -325,15 +325,15 @@ fn reached( walked } -/// What one project is holding back because the forest is rooted at one bead: -/// every root it collected but the one that bead stands in, and that one for -/// the part of it the mode stopped drawing. None at all where the forest is -/// rooted at no bead. +/// What one project put out of the way because the forest is rooted at one +/// bead: every root it collected but the one that bead stands in, and that +/// one for the part of it the mode stopped drawing. None at all where the +/// forest is rooted at no bead. /// -/// Shown and hidden alike. The mode holds back what the filter was showing as -/// well as what it was not, and one line standing for both sets is the only -/// line that adds up. -fn held_back<'a>( +/// Shown and hidden alike. The mode moves what the filter was showing as well +/// as what it was not, and one line standing for both sets is the only line +/// that adds up. +fn out_of_the_way<'a>( snapshot: &'a Snapshot, project: Option<&str>, rooted: Option<&Rooted>, @@ -548,7 +548,7 @@ impl<'a> Layout<'a> { trunk.push(!last); } match kind { - GroupKind::HiddenTrees | GroupKind::HeldBack => { + GroupKind::HiddenTrees | GroupKind::OutOfTheWay => { let roots = self.roots_in(kind, project.as_deref()); let count = roots.len(); for (n, root) in roots.into_iter().enumerate() { @@ -578,7 +578,7 @@ impl<'a> Layout<'a> { /// for the project it is one of. fn roots_in(&self, kind: GroupKind, project: Option<&str>) -> Vec> { match kind { - GroupKind::HeldBack => held_back(self.snapshot, project, self.rooted), + GroupKind::OutOfTheWay => out_of_the_way(self.snapshot, project, self.rooted), _ => hidden_trees(self.snapshot, project) .into_iter() .map(|tree| Behind { @@ -861,7 +861,7 @@ fn group_items(snapshot: &Snapshot, kind: GroupKind, project: Option<&str>) -> V .collect(), // These two hold whole roots, drawn as trees rather than as things in // a group. - GroupKind::HiddenTrees | GroupKind::HeldBack => Vec::new(), + GroupKind::HiddenTrees | GroupKind::OutOfTheWay => Vec::new(), GroupKind::Unattributed => snapshot .unattributed .iter() diff --git a/src/view/forest/mod.rs b/src/view/forest/mod.rs index b230f41..9dd2fdc 100644 --- a/src/view/forest/mod.rs +++ b/src/view/forest/mod.rs @@ -360,7 +360,7 @@ impl Forest { // drawn at all while the forest is rooted at one bead. if self.held_back(place) { chain.push(Handle::Group( - GroupKind::HeldBack, + GroupKind::OutOfTheWay, Some(place.tree.project.clone()), )); } else if self.hidden(&place.tree) { @@ -5351,7 +5351,7 @@ credential_command = "secret harbour" // Neither holds a finding of its own: each stands over // whole roots, and what is wrong inside one of those is // the root's to report when the group is opened. - GroupKind::HiddenTrees | GroupKind::HeldBack => {} + GroupKind::HiddenTrees | GroupKind::OutOfTheWay => {} }, _ => {} } @@ -7124,10 +7124,10 @@ credential_command = "secret harbour" " │ └─▸ … 3 more", " └── [Unattributed orbital] 2", "▾ ferry", - " ├─▸ [HeldBack ferry] 1", + " ├─▸ [OutOfTheWay ferry] 1", " └── [Unattributed ferry] 1", "▾ harbour", - " └─▸ [HeldBack harbour] 1", + " └─▸ [OutOfTheWay harbour] 1", "▸ [FailedProjects] 1", "▾ [Unconfigured] 1", "▾ [Conflicts] 1", @@ -7152,13 +7152,13 @@ credential_command = "secret harbour" "▾ orbital", " ├─▸ ○ orb-7.1 re-point the dish", " │ └── ! Dangling(1)", - " ├─▸ [HeldBack orbital] 1", + " ├─▸ [OutOfTheWay orbital] 1", " └── [Unattributed orbital] 2", "▾ ferry", - " ├─▸ [HeldBack ferry] 1", + " ├─▸ [OutOfTheWay ferry] 1", " └── [Unattributed ferry] 1", "▾ harbour", - " └─▸ [HeldBack harbour] 1", + " └─▸ [OutOfTheWay harbour] 1", "▸ [FailedProjects] 1", "▾ [Unconfigured] 1", "▾ [Conflicts] 1", @@ -7193,7 +7193,7 @@ credential_command = "secret harbour" .iter() .position(|line| { matches!(&line.content, Content::Group(group) - if group.kind == GroupKind::HeldBack + if group.kind == GroupKind::OutOfTheWay && group.project.as_deref() == Some(project)) }) .unwrap_or_else(|| panic!("no line holds {project} back: {:#?}", sketch(forest))) @@ -7213,7 +7213,7 @@ credential_command = "secret harbour" .iter() .find_map(|line| match &line.content { Content::Group(group) - if group.kind == GroupKind::HeldBack + if group.kind == GroupKind::OutOfTheWay && group.project.as_deref() == Some(project) => { group.held.clone() @@ -7578,7 +7578,7 @@ credential_command = "secret harbour" " │ ├── ! Dangling(1)", " │ ├── ○ .1 true the mount", " │ └── ○ .2 seal the feed horn", - " ├─▸ [HeldBack orbital] 1", + " ├─▸ [OutOfTheWay orbital] 1", ] ); } @@ -7603,7 +7603,7 @@ credential_command = "secret harbour" "▾ orbital", " ├─▸ ○ orb-7.1 re-point the dish", " │ └── ! Dangling(1)", - " ├── [HeldBack orbital] 1", + " ├── [OutOfTheWay orbital] 1", " │ └─▸ ◐ orb-7 lift the ground station", " │ └── ! Dangling(1)", ] @@ -7797,7 +7797,7 @@ credential_command = "secret harbour" sketch(&forest) ); assert!( - drawn_here(&forest, "[HeldBack orbital]"), + drawn_here(&forest, "[OutOfTheWay orbital]"), "still rooted at one bead: {:#?}", sketch(&forest) ); diff --git a/src/view/lines.rs b/src/view/lines.rs index fe6f6ac..cc732f4 100644 --- a/src/view/lines.rs +++ b/src/view/lines.rs @@ -216,8 +216,8 @@ pub struct Group { /// known by, so a fold on one project's group is not a fold on another's. pub project: Option, pub count: usize, - /// What the roots this group is holding back add up to, for the group that - /// holds whole roots back because the forest is rooted at one bead. + /// What the roots behind this group's line add up to, for the group that + /// holds whole roots because the forest is rooted at one bead. /// /// Nothing for the groups that hold things rather than roots: a pane, a /// failed project and a conflict are each drawn whole when the group opens, @@ -242,8 +242,8 @@ pub enum GroupKind { Unconfigured, Conflicts, /// The roots the forest is not drawing because the reader rooted it at one - /// bead. *coined* - HeldBack, + /// bead. + OutOfTheWay, HiddenTrees, Unattributed, } @@ -264,7 +264,7 @@ impl GroupKind { /// its paths that no bead claims. Everything beneath a project is under /// its one line, so a reader has one place to look. pub const UNDER_A_PROJECT: [GroupKind; 3] = [ - GroupKind::HeldBack, + GroupKind::OutOfTheWay, GroupKind::HiddenTrees, GroupKind::Unattributed, ]; @@ -277,7 +277,7 @@ impl GroupKind { pub(crate) fn live(self) -> bool { match self { GroupKind::Unconfigured | GroupKind::Conflicts | GroupKind::Unattributed => true, - GroupKind::FailedProjects | GroupKind::HiddenTrees | GroupKind::HeldBack => false, + GroupKind::FailedProjects | GroupKind::HiddenTrees | GroupKind::OutOfTheWay => false, } } } diff --git a/src/view/phrase.rs b/src/view/phrase.rs index 6e068d1..6060663 100644 --- a/src/view/phrase.rs +++ b/src/view/phrase.rs @@ -469,19 +469,21 @@ pub fn conflicts(count: usize) -> String { format!("{count} {conflict} nothing could settle") } -/// The roots the forest is not drawing because the reader rooted it at one +/// The beads the forest is not drawing because the reader rooted it at one /// bead. /// -/// *Held back* rather than hidden: a key put them behind this line and the -/// same key brings them back, so nothing here has gone wrong and nothing here -/// is the tracker's doing. +/// *Beads* rather than roots, which is the word a reader has for them. Each +/// one counted here is a root of the forest, and the bead the mode stands on +/// is not among them — the root it stands in is, for the part of it the mode +/// stopped drawing, and that root is a bead other than the focused one like +/// any of the rest. /// -/// Not *other*, either. The root the focused bead stands in is behind this -/// line as well, for the part of it the mode stopped drawing, and every root -/// counted here has its own row nowhere but behind this line. -pub fn held_back(count: usize) -> String { - let root = if count == 1 { "root" } else { "roots" }; - format!("{count} {root} held back") +/// Nothing here says why they are behind the line. Why the reader asked for +/// one bead is theirs, and a line guessing at it would be a claim this +/// program cannot make. +pub fn other_beads(count: usize) -> String { + let bead = if count == 1 { "bead" } else { "beads" }; + format!("{count} other {bead}") } /// Trees the live-agent filter is holding back, and how many of those carry