Skip to main content

max / quasi

Say a toast, a lexed line and a form that is sometimes not there Three productions, each from the one thing its screen does that no other screen does: - `toast` as a node member, beside `banner`. Node::toast is banner's sibling and the table had one of the two. project_members is the site: a write answers with the panel it changed, carrying what the route had to say about it. - `code` as a node member. Node::literal's own doc reserved the constructor for the screen that asks for runs a lexer classified, and git_browse asks: a file is drawn one row per line, because #L42 is the address of a line and a block that owned its own lines would have nothing to hang one on. Node::code(runs, language) is inline; the block half is still unasked for. - A form takes a guard, before its body, where act, offering, column and cell already put theirs. auth_pages is the site twice over: the login form is drawn only where there is a local password, and the reset form only where the signed link still resolves. quasi-router 0.101.9 carries three additions, all of them gaps the earlier waves already named: - Field::option(Choice), the accreting half of Field::options. The fifth constructor of this shape after Table::column, Cells::cell, options itself and Node::figure. git_nav's ref chooser offers one per ref and has no expression to hold a list in. - From<Field> for Node, the third after From<Slot> and From<Act> and for their reason: a shape returning a Field has to be placeable where a node goes. - Node::code, above. Consumers pin version = "0.101", so nothing is owed a forward fix.
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-04 14:33 UTC
Signed with PGP, not checked
Commit: 9a8a8c37e1f58bf02a5017a4bc993465291838d7
Parent: ef56831
3 files changed, +61 insertions, -5 deletions
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-router"
3 - version = "0.101.8"
3 + version = "0.101.9"
4 4 description = "Host-agnostic router: a request in, a renderer-agnostic description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -82,10 +82,12 @@
82 82 "list",
83 83 "stats",
84 84 "banner",
85 + "toast",
85 86 "failed",
86 87 "empty",
87 88 "rich",
88 89 "literal",
90 + "code",
89 91 "picture",
90 92 "canvas",
91 93 ];
@@ -646,10 +648,20 @@
646 648 }
647 649 "form" => {
648 650 let action: Action = input.parse()?;
649 - Ok(Self::Form {
650 - action,
651 - body: block(input)?,
652 - })
651 + // Before the body, where `act`, `offering`, `column` and `cell`
652 + // already put theirs. `auth_pages` is the site twice over: the
653 + // login form is drawn only where there is a local password to
654 + // type, and the reset form only where the signed link still
655 + // resolves. Both are one screen with two shapes rather than two
656 + // screens, because everything around them is the same.
657 + let guard = guard(input)?;
658 + Ok(guarded(
659 + guard,
660 + Self::Form {
661 + action,
662 + body: block(input)?,
663 + },
664 + ))
653 665 }
654 666 "field" => {
655 667 let kind: Ident = input.parse()?;
@@ -3557,6 +3557,20 @@
3557 3557 self
3558 3558 }
3559 3559
3560 + /// Offer one more option, chaining.
3561 + ///
3562 + /// The accreting half of [`Self::options`], which takes the whole list. The
3563 + /// fifth constructor of exactly this shape, after [`Table::column`],
3564 + /// [`Cells::cell`], [`Self::options`] itself and [`Node::figure`]: a caller
3565 + /// building its options one at a time has no expression to hold a list in.
3566 + /// MNW's repository bar is the site -- its ref chooser offers a branch or a
3567 + /// tag per ref, and which of the two decides only the label.
3568 + #[must_use]
3569 + pub fn option(mut self, option: Choice) -> Self {
3570 + self.options.push(option);
3571 + self
3572 + }
3573 +
3560 3574 pub fn select(name: impl Into<String>, label: impl Into<String>, options: Vec<Choice>) -> Self {
3561 3575 Self {
3562 3576 options,
@@ -7671,6 +7685,17 @@
7671 7685 }
7672 7686 }
7673 7687
7688 + impl From<Field> for Node {
7689 + /// A question inside a body, without the enclosing container naming the
7690 + /// variant. The third of these, after `From<Slot>` and `From<Act>` above,
7691 + /// and for their reason: a shape that returns a `Field` has to be placeable
7692 + /// where a node goes. MNW's repository bar is the site -- its ref chooser
7693 + /// is a shape of its own and the bar holds it beside the tab strip.
7694 + fn from(field: Field) -> Self {
7695 + Self::Field(::std::boxed::Box::new(field))
7696 + }
7697 + }
7698 +
7674 7699 impl From<Table> for Node {
7675 7700 fn from(table: Table) -> Self {
7676 7701 Self::Table {
@@ -8674,6 +8699,25 @@
8674 8699 }
8675 8700 }
8676 8701
8702 + /// Machine text a lexer has been over, inline.
8703 + ///
8704 + /// The constructor [`literal`](Self::literal) reserved for the screen that
8705 + /// asked, and MNW's source browser is it: a file is drawn one row per line,
8706 + /// because `#L42` is the address of a line and a block that owned its own
8707 + /// lines would have nothing to hang one on. So every line is classified
8708 + /// runs plus the extension, and `literal`'s one-plain-run shape cannot say
8709 + /// it.
8710 + ///
8711 + /// Still inline. A block is the other half and is still unasked for.
8712 + #[must_use]
8713 + pub fn code(runs: Vec<Lexeme>, language: Option<String>) -> Self {
8714 + Self::Code {
8715 + runs,
8716 + language,
8717 + inline: true,
8718 + }
8719 + }
8720 +
8677 8721 /// Prose written in markdown, by somebody the app does not vouch for.
8678 8722 ///
8679 8723 /// [`Richness::Sentence`] and [`Trust::Untrusted`], which is what this member