Skip to main content

max / quasi

Let `beside` place a question, and rank one with a hole Two inconsistencies rather than two productions. Both were found by audiofiles' toolbar, which had been blocked since wave 15 on whether `Run` should join the shaped set, and neither needs it. A region's `beside` went through `panel_member` and a run's through `node`, so a question could stand in a region and not in a row. The toolbar's search box is a field on a bar, and a question standing in a row is the same narrow allowance as one standing in a region. `beside`'s rank parsed a bare `Ident` while `tone`, `width`, `priority` and `fit` have all taken a hole since wave 2. The six panel toggles each carry a `Panel::worth()`, which a literal cannot say. R1(4)'s existing machinery covers it: a bare uppercase ident still reads as the variant, so every existing site is unchanged, and the three containers now read their enum through `variant` rather than pasting it.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01MptwXZ8k65v19rFmdGAyki
Author: Max Johnson <me@maxj.phd> · 2026-09-05 01:36 UTC
Signed with PGP, not checked
Commit: 5764c3d10b693fd88e2df895a181725951276ad5
Parent: 56b0605
4 files changed, +30 insertions, -21 deletions
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-declare"
3 - version = "0.1.6"
3 + version = "0.1.7"
4 4 description = "The declare! form: a screen description compiled to Rust at build time."
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -310,10 +310,14 @@
310 310 /// `across <fallback> { .. }`
311 311 Across { fallback: Ident, body: Vec<Item> },
312 312 /// `beside <priority> <emission>`
313 - Beside {
314 - priority: Ident,
315 - inner: Box<Emission>,
316 - },
313 + ///
314 + /// An `Arg` rather than an `Ident`, which is rule R1(4) reaching the last
315 + /// vocabulary slot that did not have it: `tone`, `width`, `priority` and
316 + /// `fit` have all taken a hole since wave 2, and a bare uppercase ident
317 + /// still reads as the variant, so every existing site is unchanged.
318 + /// audiofiles' toolbar is what asked -- its six panel toggles each carry
319 + /// what they are worth, and a rank that has to be a literal cannot say it.
320 + Beside { priority: Arg, inner: Box<Emission> },
317 321 /// `at <arg> <emission>` -- one thing on an axis, and where it sits.
318 322 ///
319 323 /// Only inside a `timeline`, where the argument is a `Placement` and the
@@ -575,10 +575,10 @@
575 575 // every fact in it is stated nowhere else on the window except the
576 576 // focused sample's tags, which the detail panel repeats in full, so a
577 577 // window with no room loses the repetition and keeps the rest.
578 - (Container::Slot, Emission::Beside { priority, inner }) => Ok((
579 - panel_member(inner)?,
580 - quote!(.with_ranked(#held, ::quasi_router::layout::Priority::#priority)),
581 - )),
578 + (Container::Slot, Emission::Beside { priority, inner }) => {
579 + let rank = variant(priority, "Priority")?;
580 + Ok((panel_member(inner)?, quote!(.with_ranked(#held, #rank))))
581 + }
582 582 // The control one slot of a repeating question carries to take itself
583 583 // away, and the question the slots are of. Both are `Act`s the region is
584 584 // told, and neither could be said at all: written where the vocabulary
@@ -672,10 +672,10 @@
672 672 // says which. embeds' button strip is the site: a thumbnail and a title
673 673 // in `Primary`, the buy control in `Actions`, the price a setting
674 674 // between them.
675 - (Container::Row, Emission::Beside { priority, inner }) => Ok((
676 - node(inner)?,
677 - quote!(.part(::quasi_router::layout::RowPart::#priority, #held)),
678 - )),
675 + (Container::Row, Emission::Beside { priority, inner }) => {
676 + let part = variant(priority, "RowPart")?;
677 + Ok((node(inner)?, quote!(.part(#part, #held))))
678 + }
679 679 (Container::Row, other) => Err(syn::Error::new(
680 680 emission_span(other),
681 681 "a row holds controls, places its parts and says what opening it does: write \
@@ -706,10 +706,15 @@
706 706 emission_span(other),
707 707 "a repeating question holds nothing: its body says how few may be left",
708 708 )),
709 - (Container::Run, Emission::Beside { priority, inner }) => Ok((
710 - node(inner)?,
711 - quote!(.beside(#held, ::quasi_router::layout::Priority::#priority)),
712 - )),
709 + // `panel_member` rather than `node`, which is what a region's `beside`
710 + // already used: a question standing in a row is the same narrow
711 + // allowance as a question standing in a region, and audiofiles' search
712 + // box is a field in a toolbar. The two spellings of one keyword had
713 + // drifted apart, and nothing but the drift was stopping it.
714 + (Container::Run, Emission::Beside { priority, inner }) => {
715 + let rank = variant(priority, "Priority")?;
716 + Ok((panel_member(inner)?, quote!(.beside(#held, #rank))))
717 + }
713 718 (Container::Run, other) => Err(syn::Error::new(
714 719 emission_span(other),
715 720 "a row ranks what it holds: write `beside <priority> <emission>`",
@@ -1155,8 +1160,8 @@
1155 1160 action.verb.span(),
1156 1161 "`offering` is the way out an empty state offers; it is not a node",
1157 1162 )),
1158 - Emission::Beside { priority, .. } => Err(syn::Error::new(
1159 - priority.span(),
1163 + Emission::Beside { inner, .. } => Err(syn::Error::new(
1164 + emission_span(inner),
1160 1165 "`beside` needs a run in scope, which is rule R3",
1161 1166 )),
1162 1167 Emission::At { inner, .. } => Err(syn::Error::new(
@@ -1860,7 +1865,7 @@
1860 1865 RegionKind::Supplied(_) => Span::call_site(),
1861 1866 },
1862 1867 Emission::Across { fallback, .. } => fallback.span(),
1863 - Emission::Beside { priority, .. } => priority.span(),
1868 + Emission::Beside { inner, .. } => emission_span(inner),
1864 1869 Emission::At { inner, .. } => emission_span(inner),
1865 1870 Emission::Table(_) | Emission::Cells(_) => Span::call_site(),
1866 1871 Emission::Column { .. } | Emission::Cell { .. } => Span::call_site(),
@@ -526,7 +526,7 @@
526 526 let member: Ident = input.parse()?;
527 527 match member.to_string().as_str() {
528 528 "beside" => {
529 - let priority: Ident = input.parse()?;
529 + let priority: Arg = input.parse()?;
530 530 let inner: Self = input.parse()?;
531 531 // A guard on a placed member guards the placing. The run is
532 532 // what may hold nothing and `beside` is how a member reaches