Skip to main content

max / audiofiles

Say which container the test helpers mean, now that a list is a table `Node::List` is gone: a list is a `Node::Table` that declared no columns. The described screens needed nothing, and the parity walk got shorter -- its two arms had already been reduced to the same three lines by wave 2c, and now they are the same pattern too. The helpers are the part worth reading. `list_of`, `more_of`, `all_rows`, `deep_rows` and `table_of` searched for the first matching node, so with one node they began matching each other's containers: `table_of` picked up the shell's own list and `list_of` picked up the files table. Two tests failed, which is the good outcome -- the search was always ambiguous and the type system had been hiding it. Each now filters the way the renderers do: a helper meaning "the list" takes `columns.is_empty()` and `table_of` takes its negation. 720 lib tests green, clippy clean with -D warnings.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01P8ostB2UmZJGj5WjSHRSot
Author: Max Johnson <me@maxj.phd> · 2026-09-07 01:25 UTC
Signed with PGP, not checked
Commit: 99fe2697734c176cfee48cde8c122c65e120360f
Parent: 7aa535e
2 files changed, +15 insertions, -14 deletions
@@ -307,11 +307,6 @@
307 307 row_offers(row, out);
308 308 }
309 309 }
310 - Node::List { rows, .. } => {
311 - for row in rows {
312 - row_offers(row, out);
313 - }
314 - }
315 310 Node::Region(slot) => {
316 311 for placed in &slot.body {
317 312 walk(&placed.node, out);
@@ -560,13 +560,17 @@
560 560 /// Descends into a `Node::Region`, because a region is a slot inside a node and
561 561 /// `nodes` only walks the screen's own slots. The rename preview lives in one so
562 562 /// that a fragment can replace it.
563 + ///
564 + /// A table that declared columns, which is what tells one from a list since the
565 + /// 2026-09-06 collapse: both are `Node::Table`, so without the guard this takes
566 + /// whichever comes first and the shell's own lists come first.
563 567 fn table_of(screen: &Screen) -> (Vec<quasi_router::Column>, Vec<quasi_router::Row>) {
564 568 fn find(
565 569 body: &[quasi_router::Ranked],
566 570 ) -> Option<(Vec<quasi_router::Column>, Vec<quasi_router::Row>)> {
567 571 for placed in body {
568 572 match &placed.node {
569 - Node::Table { columns, rows, .. } => {
573 + Node::Table { columns, rows, .. } if !columns.is_empty() => {
570 574 return Some((columns.clone(), rows.clone()));
571 575 }
572 576 Node::Region(slot) => {
@@ -3007,7 +3011,7 @@
3007 3011 let rows = nodes(&screen)
3008 3012 .into_iter()
3009 3013 .find_map(|node| match node {
3010 - Node::List { rows, .. } => Some(rows.clone()),
3014 + Node::Table { columns, rows, .. } if columns.is_empty() => Some(rows.clone()),
3011 3015 _ => None,
3012 3016 })
3013 3017 .expect("the failures are a list");
@@ -3602,7 +3606,7 @@
3602 3606 nodes(screen)
3603 3607 .iter()
3604 3608 .find_map(|node| match node {
3605 - Node::List { rows, .. } => Some(rows.clone()),
3609 + Node::Table { columns, rows, .. } if columns.is_empty() => Some(rows.clone()),
3606 3610 _ => None,
3607 3611 })
3608 3612 .expect("the screen draws a list")
@@ -4437,7 +4441,7 @@
4437 4441 /// What the list on a screen says it is not showing.
4438 4442 fn more_of(screen: &Screen) -> Option<quasi_router::Rest> {
4439 4443 nodes(screen).iter().find_map(|node| match node {
4440 - Node::List { more, .. } => more.clone(),
4444 + Node::Table { columns, more, .. } if columns.is_empty() => more.clone(),
4441 4445 _ => None,
4442 4446 })
4443 4447 }
@@ -5014,7 +5018,7 @@
5014 5018 nodes(screen)
5015 5019 .iter()
5016 5020 .filter_map(|node| match node {
5017 - Node::List { rows, .. } => Some(rows.clone()),
5021 + Node::Table { columns, rows, .. } if columns.is_empty() => Some(rows.clone()),
5018 5022 _ => None,
5019 5023 })
5020 5024 .flatten()
@@ -5132,7 +5136,9 @@
5132 5136 under_tags = text == "Tags";
5133 5137 None
5134 5138 }
5135 - Node::List { rows, .. } if under_tags => Some(rows.clone()),
5139 + Node::Table { columns, rows, .. } if under_tags && columns.is_empty() => {
5140 + Some(rows.clone())
5141 + }
5136 5142 _ => None,
5137 5143 })
5138 5144 .expect("the tag outline")
@@ -7759,7 +7765,7 @@
7759 7765 deep_nodes(screen)
7760 7766 .into_iter()
7761 7767 .flat_map(|node| match node {
7762 - Node::List { rows, .. } => rows,
7768 + Node::Table { columns, rows, .. } if columns.is_empty() => rows,
7763 7769 _ => Vec::new(),
7764 7770 })
7765 7771 .collect()
@@ -9877,7 +9883,7 @@
9877 9883 let more = deep_nodes(&queue_screen(&queue))
9878 9884 .into_iter()
9879 9885 .find_map(|node| match node {
9880 - Node::List { more, .. } => more,
9886 + Node::Table { columns, more, .. } if columns.is_empty() => more,
9881 9887 _ => None,
9882 9888 })
9883 9889 .expect("the candidate list says what it is not showing");
@@ -9896,7 +9902,7 @@
9896 9902 assert!(
9897 9903 deep_nodes(&queue_screen(&small))
9898 9904 .into_iter()
9899 - .all(|node| !matches!(node, Node::List { more: Some(_), .. }))
9905 + .all(|node| !matches!(node, Node::Table { more: Some(_), .. }))
9900 9906 );
9901 9907 }
9902 9908