Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
81 changes: 47 additions & 34 deletions src/view/draw/groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand 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),
};
Expand All @@ -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(),
};

Expand All @@ -48,44 +48,50 @@ 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<Span<'static>> {
let mut said = held_back_counts(group);
said.push(Span::styled(WHOLE_FOREST, palette::QUIET));
fn out_of_the_way_state(group: &Group) -> Vec<Span<'static>> {
let mut said = out_of_the_way_counts(group);
beside(&mut said, Span::styled(WHOLE_FOREST, palette::QUIET));
said
}

/// The same, where the row cannot afford the key as well.
///
/// 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<Span<'static>> {
fn out_of_the_way_counts(group: &Group) -> Vec<Span<'static>> {
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
}
Expand Down Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -326,19 +337,21 @@ 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:?}");
}

/// 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,
Expand All @@ -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:?}");
}
Expand All @@ -376,7 +389,7 @@ mod tests {

assert_eq!(
marked,
!matches!(kind, GroupKind::HiddenTrees | GroupKind::HeldBack),
!matches!(kind, GroupKind::HiddenTrees | GroupKind::OutOfTheWay),
"{kind:?}: {drawn:?}"
);
}
Expand Down
34 changes: 17 additions & 17 deletions src/view/forest/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<bool>) -> Option<Counts> {
Expand Down Expand Up @@ -159,7 +159,7 @@ pub(super) fn first_bead_of(
) -> Option<BeadKey> {
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(),
Expand Down Expand Up @@ -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])),
);
Expand Down Expand Up @@ -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))
}
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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<Behind<'a>> {
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 {
Expand Down Expand Up @@ -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()
Expand Down
24 changes: 12 additions & 12 deletions src/view/forest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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 => {}
},
_ => {}
}
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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)))
Expand All @@ -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()
Expand Down Expand Up @@ -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",
]
);
}
Expand All @@ -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)",
]
Expand Down Expand Up @@ -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)
);
Expand Down
Loading
Loading