| 343 |
343 |
|
fn walk(node: &Node, out: &mut Vec<Node>) {
|
| 344 |
344 |
|
out.push(node.clone());
|
| 345 |
345 |
|
if let Node::Region(slot) = node {
|
| 346 |
|
- |
for placed in &slot.body {
|
|
346 |
+ |
for placed in slot.body.iter() {
|
| 347 |
347 |
|
walk(&placed.node, out);
|
| 348 |
348 |
|
}
|
| 349 |
349 |
|
}
|
| 358 |
358 |
|
walk(&placed.node, &mut out);
|
| 359 |
359 |
|
}
|
| 360 |
360 |
|
}
|
| 361 |
|
- |
for placed in &slot.body {
|
|
361 |
+ |
for placed in slot.body.iter() {
|
| 362 |
362 |
|
walk(&placed.node, &mut out);
|
| 363 |
363 |
|
}
|
| 364 |
364 |
|
}
|
| 565 |
565 |
|
/// 2026-09-06 collapse: both are `Node::Table`, so without the guard this takes
|
| 566 |
566 |
|
/// whichever comes first and the shell's own lists come first.
|
| 567 |
567 |
|
fn table_of(screen: &Screen) -> (Vec<quasi_router::Column>, Vec<quasi_router::Row>) {
|
| 568 |
|
- |
fn find(
|
| 569 |
|
- |
body: &[quasi_router::Ranked],
|
|
568 |
+ |
fn find<'a>(
|
|
569 |
+ |
body: impl Iterator<Item = &'a quasi_router::Ranked>,
|
| 570 |
570 |
|
) -> Option<(Vec<quasi_router::Column>, Vec<quasi_router::Row>)> {
|
| 571 |
571 |
|
for placed in body {
|
| 572 |
572 |
|
match &placed.node {
|
| 574 |
574 |
|
return Some((columns.clone(), rows.clone()));
|
| 575 |
575 |
|
}
|
| 576 |
576 |
|
Node::Region(slot) => {
|
| 577 |
|
- |
if let Some(found) = find(&slot.body) {
|
|
577 |
+ |
if let Some(found) = find(slot.body.iter()) {
|
| 578 |
578 |
|
return Some(found);
|
| 579 |
579 |
|
}
|
| 580 |
580 |
|
}
|
| 587 |
587 |
|
screen
|
| 588 |
588 |
|
.slots
|
| 589 |
589 |
|
.iter()
|
| 590 |
|
- |
.find_map(|slot| find(&slot.body))
|
|
590 |
+ |
.find_map(|slot| find(slot.body.iter()))
|
| 591 |
591 |
|
.expect("the screen draws a table")
|
| 592 |
592 |
|
}
|
| 593 |
593 |
|
|
| 680 |
680 |
|
fn fields(screen: &Screen) -> BTreeMap<String, Option<String>> {
|
| 681 |
681 |
|
let mut found = BTreeMap::new();
|
| 682 |
682 |
|
for slot in &screen.slots {
|
| 683 |
|
- |
for placed in &slot.body {
|
|
683 |
+ |
for placed in slot.body.iter() {
|
| 684 |
684 |
|
match &placed.node {
|
| 685 |
685 |
|
Node::Field(field) => {
|
| 686 |
686 |
|
found.insert(field.name.clone(), field.value.clone());
|
| 1117 |
1117 |
|
let picker = screen_of(&response)
|
| 1118 |
1118 |
|
.slots
|
| 1119 |
1119 |
|
.iter()
|
| 1120 |
|
- |
.flat_map(|slot| &slot.body)
|
|
1120 |
+ |
.flat_map(|slot| slot.body.iter())
|
| 1121 |
1121 |
|
.find_map(|placed| match &placed.node {
|
| 1122 |
1122 |
|
Node::Field(field) if field.name == ConfigKey::Theme.as_str() => Some(field),
|
| 1123 |
1123 |
|
_ => None,
|
| 1457 |
1457 |
|
let carried: Vec<_> = screen_of(&response)
|
| 1458 |
1458 |
|
.slots
|
| 1459 |
1459 |
|
.iter()
|
| 1460 |
|
- |
.flat_map(|slot| &slot.body)
|
|
1460 |
+ |
.flat_map(|slot| slot.body.iter())
|
| 1461 |
1461 |
|
.filter_map(|placed| match &placed.node {
|
| 1462 |
1462 |
|
Node::Form { fields, .. } => Some(fields.clone()),
|
| 1463 |
1463 |
|
_ => None,
|
| 1481 |
1481 |
|
let now = screen_of(&response)
|
| 1482 |
1482 |
|
.slots
|
| 1483 |
1483 |
|
.iter()
|
| 1484 |
|
- |
.flat_map(|slot| &slot.body)
|
|
1484 |
+ |
.flat_map(|slot| slot.body.iter())
|
| 1485 |
1485 |
|
.find_map(|placed| match &placed.node {
|
| 1486 |
1486 |
|
Node::Act(act) if act.label == "Sync now" => Some(act),
|
| 1487 |
1487 |
|
_ => None,
|
| 1525 |
1525 |
|
let response = syncing(&sync, Request::get("/sync")).expect("answered");
|
| 1526 |
1526 |
|
let screen = screen_of(&response);
|
| 1527 |
1527 |
|
|
| 1528 |
|
- |
let said = screen.slots.iter().flat_map(|slot| &slot.body).any(
|
|
1528 |
+ |
let said = screen.slots.iter().flat_map(|slot| slot.body.iter()).any(
|
| 1529 |
1529 |
|
|placed| matches!(&placed.node, Node::Notice { text, .. } if text.contains("said no")),
|
| 1530 |
1530 |
|
);
|
| 1531 |
1531 |
|
assert!(said, "{state:?} swallowed the error");
|
| 1545 |
1545 |
|
screen
|
| 1546 |
1546 |
|
.slots
|
| 1547 |
1547 |
|
.iter()
|
| 1548 |
|
- |
.flat_map(|slot| &slot.body)
|
|
1548 |
+ |
.flat_map(|slot| slot.body.iter())
|
| 1549 |
1549 |
|
.flat_map(|placed| match &placed.node {
|
| 1550 |
1550 |
|
Node::Region(slot) => slot.body.iter().map(|inner| inner.node.clone()).collect(),
|
| 1551 |
1551 |
|
other => vec![other.clone()],
|
| 1574 |
1574 |
|
let region = screen_of(&response)
|
| 1575 |
1575 |
|
.slots
|
| 1576 |
1576 |
|
.iter()
|
| 1577 |
|
- |
.flat_map(|slot| &slot.body)
|
|
1577 |
+ |
.flat_map(|slot| slot.body.iter())
|
| 1578 |
1578 |
|
.find_map(|placed| match &placed.node {
|
| 1579 |
1579 |
|
Node::Region(slot) if slot.id == "subscription" => Some(slot),
|
| 1580 |
1580 |
|
_ => None,
|
| 1685 |
1685 |
|
let meter = screen_of(&response)
|
| 1686 |
1686 |
|
.slots
|
| 1687 |
1687 |
|
.iter()
|
| 1688 |
|
- |
.flat_map(|slot| &slot.body)
|
|
1688 |
+ |
.flat_map(|slot| slot.body.iter())
|
| 1689 |
1689 |
|
.flat_map(|placed| match &placed.node {
|
| 1690 |
1690 |
|
Node::Region(slot) => slot.body.iter().map(|inner| inner.node.clone()).collect(),
|
| 1691 |
1691 |
|
other => vec![other.clone()],
|
| 2565 |
2565 |
|
let stand_in = screen_of(&response)
|
| 2566 |
2566 |
|
.slots
|
| 2567 |
2567 |
|
.iter()
|
| 2568 |
|
- |
.flat_map(|slot| &slot.body)
|
|
2568 |
+ |
.flat_map(|slot| slot.body.iter())
|
| 2569 |
2569 |
|
.find_map(|placed| match &placed.node {
|
| 2570 |
2570 |
|
Node::StandIn { message, act, .. } => Some((message.clone(), act.clone())),
|
| 2571 |
2571 |
|
_ => None,
|
| 4182 |
4182 |
|
/// the first it finds -- would assert about the Bulk group and call it the
|
| 4183 |
4183 |
|
/// whole screen.
|
| 4184 |
4184 |
|
fn shortcut_sections(screen: &Screen) -> Vec<(Option<String>, Vec<(String, String)>)> {
|
| 4185 |
|
- |
fn walk(
|
| 4186 |
|
- |
body: &[quasi_router::Ranked],
|
|
4185 |
+ |
fn walk<'a>(
|
|
4186 |
+ |
body: impl Iterator<Item = &'a quasi_router::Ranked>,
|
| 4187 |
4187 |
|
found: &mut Vec<(Option<String>, Vec<(String, String)>)>,
|
| 4188 |
4188 |
|
heading: &mut Option<String>,
|
| 4189 |
4189 |
|
) {
|
| 4196 |
4196 |
|
.map(|row| (cell_text(row, 0), cell_text(row, 1)))
|
| 4197 |
4197 |
|
.collect(),
|
| 4198 |
4198 |
|
)),
|
| 4199 |
|
- |
Node::Region(slot) => walk(&slot.body, found, heading),
|
|
4199 |
+ |
Node::Region(slot) => walk(slot.body.iter(), found, heading),
|
| 4200 |
4200 |
|
_ => {}
|
| 4201 |
4201 |
|
}
|
| 4202 |
4202 |
|
}
|
| 4205 |
4205 |
|
let mut found = Vec::new();
|
| 4206 |
4206 |
|
let mut heading = None;
|
| 4207 |
4207 |
|
for slot in &screen.slots {
|
| 4208 |
|
- |
walk(&slot.body, &mut found, &mut heading);
|
|
4208 |
+ |
walk(slot.body.iter(), &mut found, &mut heading);
|
| 4209 |
4209 |
|
}
|
| 4210 |
4210 |
|
found
|
| 4211 |
4211 |
|
}
|
| 4366 |
4366 |
|
/// address and nothing here sends a fragment any more.
|
| 4367 |
4367 |
|
fn tab_strip(screen: &Screen) -> &quasi_router::Slot {
|
| 4368 |
4368 |
|
fn find(slot: &quasi_router::Slot) -> Option<&quasi_router::Slot> {
|
| 4369 |
|
- |
if slot.showing.selective() {
|
|
4369 |
+ |
if slot.showing().selective() {
|
| 4370 |
4370 |
|
return Some(slot);
|
| 4371 |
4371 |
|
}
|
| 4372 |
4372 |
|
slot.body.iter().find_map(|placed| match &placed.node {
|
| 4393 |
4393 |
|
let strip = tab_strip(overlay(&response));
|
| 4394 |
4394 |
|
|
| 4395 |
4395 |
|
assert_eq!(strip.labels(), vec!["Shortcuts", "Features"]);
|
| 4396 |
|
- |
for placed in &strip.body {
|
|
4396 |
+ |
for placed in strip.body.iter() {
|
| 4397 |
4397 |
|
let Node::Region(panel) = &placed.node else {
|
| 4398 |
4398 |
|
panic!("a tab is not a region: {:?}", placed.node);
|
| 4399 |
4399 |
|
};
|
| 4420 |
4420 |
|
let response = helping(Request::get("/help")).unwrap();
|
| 4421 |
4421 |
|
let strip = tab_strip(overlay(&response));
|
| 4422 |
4422 |
|
|
| 4423 |
|
- |
let Node::Region(features) = &strip.body[1].node else {
|
|
4423 |
+ |
let Node::Region(features) = &strip.body.get(1).expect("a second member").node else {
|
| 4424 |
4424 |
|
panic!("the second tab is not a region");
|
| 4425 |
4425 |
|
};
|
| 4426 |
4426 |
|
assert!(matches!(
|
| 4427 |
|
- |
features.body.first().map(|placed| &placed.node),
|
|
4427 |
+ |
features.body.get(0).map(|placed| &placed.node),
|
| 4428 |
4428 |
|
Some(Node::Rich { .. })
|
| 4429 |
4429 |
|
));
|
| 4430 |
4430 |
|
}
|
| 5130 |
5130 |
|
.slots
|
| 5131 |
5131 |
|
.iter()
|
| 5132 |
5132 |
|
.filter(|slot| slot.id == "library-side")
|
| 5133 |
|
- |
.flat_map(|slot| &slot.body)
|
|
5133 |
+ |
.flat_map(|slot| slot.body.iter())
|
| 5134 |
5134 |
|
.find_map(|placed| match &placed.node {
|
| 5135 |
5135 |
|
Node::Heading { text, .. } => {
|
| 5136 |
5136 |
|
under_tags = text == "Tags";
|
| 6557 |
6557 |
|
fn only_field(response: &Response) -> quasi_router::Field {
|
| 6558 |
6558 |
|
let screen = screen_of(response);
|
| 6559 |
6559 |
|
let mut found = Vec::new();
|
| 6560 |
|
- |
fn walk(body: &[quasi_router::Ranked], found: &mut Vec<quasi_router::Field>) {
|
|
6560 |
+ |
fn walk<'a>(
|
|
6561 |
+ |
body: impl Iterator<Item = &'a quasi_router::Ranked>,
|
|
6562 |
+ |
found: &mut Vec<quasi_router::Field>,
|
|
6563 |
+ |
) {
|
| 6561 |
6564 |
|
for placed in body {
|
| 6562 |
6565 |
|
match &placed.node {
|
| 6563 |
6566 |
|
Node::Field(field) => found.push((**field).clone()),
|
| 6564 |
6567 |
|
Node::Form { fields, .. } => found.extend(fields.iter().cloned()),
|
| 6565 |
|
- |
Node::Region(slot) => walk(&slot.body, found),
|
|
6568 |
+ |
Node::Region(slot) => walk(slot.body.iter(), found),
|
| 6566 |
6569 |
|
_ => {}
|
| 6567 |
6570 |
|
}
|
| 6568 |
6571 |
|
}
|
| 6569 |
6572 |
|
}
|
| 6570 |
6573 |
|
for slot in &screen.slots {
|
| 6571 |
|
- |
walk(&slot.body, &mut found);
|
|
6574 |
+ |
walk(slot.body.iter(), &mut found);
|
| 6572 |
6575 |
|
}
|
| 6573 |
6576 |
|
assert_eq!(found.len(), 1, "{found:?}");
|
| 6574 |
6577 |
|
found.remove(0)
|
| 7692 |
7695 |
|
/// puts a field inside a group per folder and its review stage puts two panes
|
| 7693 |
7696 |
|
/// inside a split, so a test of either has to go down.
|
| 7694 |
7697 |
|
fn deep_nodes(screen: &Screen) -> Vec<Node> {
|
| 7695 |
|
- |
fn walk(body: &[quasi_router::Ranked], into: &mut Vec<Node>) {
|
|
7698 |
+ |
fn walk<'a>(body: impl Iterator<Item = &'a quasi_router::Ranked>, into: &mut Vec<Node>) {
|
| 7696 |
7699 |
|
for placed in body {
|
| 7697 |
7700 |
|
into.push(placed.node.clone());
|
| 7698 |
7701 |
|
if let Node::Region(slot) = &placed.node {
|
| 7709 |
7712 |
|
/// answering about the body alone.
|
| 7710 |
7713 |
|
fn inside(slot: &quasi_router::Slot, into: &mut Vec<Node>) {
|
| 7711 |
7714 |
|
if let Some(run) = slot.run.as_ref() {
|
| 7712 |
|
- |
walk(&run.members, into);
|
|
7715 |
+ |
walk(run.members.iter(), into);
|
| 7713 |
7716 |
|
}
|
| 7714 |
|
- |
walk(&slot.body, into);
|
|
7717 |
+ |
walk(slot.body.iter(), into);
|
| 7715 |
7718 |
|
}
|
| 7716 |
7719 |
|
|
| 7717 |
7720 |
|
let mut found = Vec::new();
|
| 10044 |
10047 |
|
) -> BTreeMap<String, (Option<String>, Option<String>, Option<String>)> {
|
| 10045 |
10048 |
|
let mut found = BTreeMap::new();
|
| 10046 |
10049 |
|
for slot in &screen.slots {
|
| 10047 |
|
- |
for placed in &slot.body {
|
|
10050 |
+ |
for placed in slot.body.iter() {
|
| 10048 |
10051 |
|
let regions = match &placed.node {
|
| 10049 |
10052 |
|
Node::Region(region) => std::slice::from_ref(region),
|
| 10050 |
10053 |
|
_ => &[][..],
|
| 10051 |
10054 |
|
};
|
| 10052 |
10055 |
|
for region in regions {
|
| 10053 |
|
- |
for inner in ®ion.body {
|
|
10056 |
+ |
for inner in region.body.iter() {
|
| 10054 |
10057 |
|
if let Node::Form { fields, .. } = &inner.node {
|
| 10055 |
10058 |
|
for field in fields {
|
| 10056 |
10059 |
|
if field.kind == quasi_router::layout::FieldKind::Interval {
|
| 10127 |
10130 |
|
/// One axis's field, by the name its lower end submits under.
|
| 10128 |
10131 |
|
fn axis_field(screen: &Screen, name: &str) -> quasi_router::Field {
|
| 10129 |
10132 |
|
for slot in &screen.slots {
|
| 10130 |
|
- |
for placed in &slot.body {
|
|
10133 |
+ |
for placed in slot.body.iter() {
|
| 10131 |
10134 |
|
if let Node::Region(region) = &placed.node {
|
| 10132 |
|
- |
for inner in ®ion.body {
|
|
10135 |
+ |
for inner in region.body.iter() {
|
| 10133 |
10136 |
|
if let Node::Form { fields, .. } = &inner.node {
|
| 10134 |
10137 |
|
for field in fields {
|
| 10135 |
10138 |
|
if field.name == name {
|
| 10229 |
10232 |
|
}
|
| 10230 |
10233 |
|
};
|
| 10231 |
10234 |
|
for slot in &screen.slots {
|
| 10232 |
|
- |
for placed in &slot.body {
|
|
10235 |
+ |
for placed in slot.body.iter() {
|
| 10233 |
10236 |
|
visit(&placed.node);
|
| 10234 |
10237 |
|
if let Node::Region(region) = &placed.node {
|
| 10235 |
|
- |
for inner in ®ion.body {
|
|
10238 |
+ |
for inner in region.body.iter() {
|
| 10236 |
10239 |
|
visit(&inner.node);
|
| 10237 |
10240 |
|
}
|
| 10238 |
10241 |
|
}
|
| 11676 |
11679 |
|
// Every slot says what takes it away, on itself: only the slot knows which
|
| 11677 |
11680 |
|
// one it is.
|
| 11678 |
11681 |
|
for group in [conditions, actions] {
|
| 11679 |
|
- |
for placed in &group.body {
|
|
11682 |
+ |
for placed in group.body.iter() {
|
| 11680 |
11683 |
|
let Node::Region(slot) = &placed.node else {
|
| 11681 |
11684 |
|
panic!("a slot is not a region: {:?}", placed.node);
|
| 11682 |
11685 |
|
};
|