Skip to main content

max / quasi

0.51.0: a suggestion carries a second line, and picking is local by default Two rulings, one cascade, both by Max 2026-08-21. `1fcf2e9b`: `Outcome::Suggestions` carries `Candidate` rather than `Choice`. The two are near-identical and the mitigation is written on the type: an option and a candidate are submitted the same way and read differently. An option is picked out of a set the user can see whole; a candidate is offered out of a set nobody can see, so it carries what tells it from a row that reads alike. Both measured sites draw that string today by hand, in a second span, and MNW's tag box computes it as the parent path because "Format" is a leaf under audio, software, writing and video. This reverses what response.rs argued at 0.45.0 -- "a candidate is submitted under one string and read under another, which is what an option is". True, and never the half that differed. That paragraph is rewritten rather than left standing; a doc that argues against the shipped design is how the next session re-derives the rejected option. The "picking is local, by definition" paragraph on `Field::suggests` goes the same way. `ed1fa86f`: `Candidate::picks` carries an action, and absent one picking writes the value. Local stays the default, so every site that exists today is unchanged. It lands on `Candidate` rather than `Choice`, which is what makes it affordable: a per-row action on the most-consumed struct in the vocabulary would have reached every option list in the tree. `Candidate` is `#[non_exhaustive]` from birth and carries no `unavailable` -- a suggestion that cannot be picked is a row a route should not have offered. It also carries no `Hash`, unlike `Choice`, because an `Action` is not hashable. `picks` does not survive `as_layout`: the description layer has no `Action`, exactly as it has no `suggests`. Three renderers, three answers to the same description. The terminal draws the detail as the rest of the row, egui appends it dimmed in the same button, the webview gives it its own element because it is styled apart and is not part of what the typed value matches. Each renderer's pick path grows one branch, and the webview's acting row keeps the closing half of the hyperscript program and none of the writing half, with htmx emitting what the click does. Performed with no payload rule invented for this one place: an action already carries its own params and the view it was offered under. MNW's search box is what decides it -- its candidates are `Action::get(url)` to a project, item or creator page, and appending the typed value would be a description saying something the route never asked for. Also here: the template's quasi pins move to 0.51, its `makeover-build` pin off a stale 0.47.0 onto 0.49.0, and its `makeover-tui` off 0.30.0 onto 0.33.0.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-22 03:14 UTC
Signed with PGP, not checked
Commit: e01c9ecb070a7ced141333f87966b7f9fa558238
Parent: 1d3ef24
36 files changed, +407 insertions, -157 deletions
M Cargo.lock +16 -12
@@ -2631,7 +2631,7 @@
2631 2631
2632 2632 [[package]]
2633 2633 name = "makeover-webview"
2634 - version = "0.56.0"
2634 + version = "0.57.0"
2635 2635 dependencies = [
2636 2636 "makeover-geometry",
2637 2637 "makeover-layout",
@@ -3400,11 +3400,11 @@
3400 3400
3401 3401 [[package]]
3402 3402 name = "quasi"
3403 - version = "0.50.0"
3403 + version = "0.51.0"
3404 3404
3405 3405 [[package]]
3406 3406 name = "quasi-axum"
3407 - version = "0.50.0"
3407 + version = "0.51.0"
3408 3408 dependencies = [
3409 3409 "axum",
3410 3410 "http",
@@ -3418,7 +3418,7 @@
3418 3418
3419 3419 [[package]]
3420 3420 name = "quasi-basics"
3421 - version = "0.50.0"
3421 + version = "0.51.0"
3422 3422 dependencies = [
3423 3423 "makeover-layout",
3424 3424 "quasi-http",
@@ -3428,7 +3428,7 @@
3428 3428
3429 3429 [[package]]
3430 3430 name = "quasi-bench"
3431 - version = "0.50.0"
3431 + version = "0.51.0"
3432 3432 dependencies = [
3433 3433 "dhat",
3434 3434 "makeover",
@@ -3443,7 +3443,7 @@
3443 3443
3444 3444 [[package]]
3445 3445 name = "quasi-http"
3446 - version = "0.50.0"
3446 + version = "0.51.0"
3447 3447 dependencies = [
3448 3448 "form_urlencoded",
3449 3449 "http",
@@ -3452,7 +3452,7 @@
3452 3452
3453 3453 [[package]]
3454 3454 name = "quasi-immediate"
3455 - version = "0.50.0"
3455 + version = "0.51.0"
3456 3456 dependencies = [
3457 3457 "docengine",
3458 3458 "egui",
@@ -3462,7 +3462,7 @@
3462 3462
3463 3463 [[package]]
3464 3464 name = "quasi-notifs"
3465 - version = "0.50.0"
3465 + version = "0.51.0"
3466 3466 dependencies = [
3467 3467 "quasi-router",
3468 3468 "synckit-config",
@@ -3470,7 +3470,7 @@
3470 3470
3471 3471 [[package]]
3472 3472 name = "quasi-router"
3473 - version = "0.50.0"
3473 + version = "0.51.0"
3474 3474 dependencies = [
3475 3475 "makeover-layout",
3476 3476 ]
@@ -3487,7 +3487,7 @@
3487 3487
3488 3488 [[package]]
3489 3489 name = "quasi-tauri"
3490 - version = "0.50.0"
3490 + version = "0.51.0"
3491 3491 dependencies = [
3492 3492 "http",
3493 3493 "quasi-http",
@@ -3500,7 +3500,7 @@
3500 3500
3501 3501 [[package]]
3502 3502 name = "quasi-tui"
3503 - version = "0.50.0"
3503 + version = "0.51.0"
3504 3504 dependencies = [
3505 3505 "docengine",
3506 3506 "makeover",
@@ -3512,7 +3512,7 @@
3512 3512
3513 3513 [[package]]
3514 3514 name = "quasi-webview"
3515 - version = "0.50.0"
3515 + version = "0.51.0"
3516 3516 dependencies = [
3517 3517 "docengine",
3518 3518 "makeover-layout",
@@ -6183,6 +6183,10 @@
6183 6183 "winnow 1.0.4",
6184 6184 ]
6185 6185
6186 + [[patch.unused]]
6187 + name = "makeover-build"
6188 + version = "0.49.0"
6189 +
6186 6190 [[patch.unused]]
6187 6191 name = "makeover-timing"
6188 6192 version = "0.1.0"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-axum"
3 - version = "0.50.0"
3 + version = "0.51.0"
4 4 description = "The axum host adapter for quasi-router: an HTTP request in, a rendered description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,14 +13,14 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.50.0" }
17 - quasi-http = { path = "../quasi-http", version = "0.50.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.51.0" }
17 + quasi-http = { path = "../quasi-http", version = "0.51.0" }
18 18 axum = "0.8.8"
19 19 http = "1.3.1"
20 20 tokio = { version = "1.50.0", features = ["rt"] }
21 21
22 22 [dev-dependencies]
23 - quasi-webview = { path = "../quasi-webview", version = "0.50.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.51.0" }
24 24 tokio = { version = "1.50.0", features = ["macros", "rt-multi-thread"] }
25 25 tower = { version = "0.5.3", features = ["util"] }
26 26 http-body-util = "0.1.3"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-basics"
3 - version = "0.50.0"
3 + version = "0.51.0"
4 4 description = "The first-party widget set: named assemblies of primitives, shared across our apps"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,12 +13,12 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.50.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.51.0" }
17 17 makeover-layout = "0.35.0"
18 18
19 19 [dev-dependencies]
20 20 # A widget's guarantees are claims about what a renderer draws, so they are
21 21 # tested against a real one rather than by walking the tree the assembly just
22 22 # built. The webview is the renderer that recognises names today.
23 - quasi-webview = { path = "../quasi-webview", version = "0.50.0" }
24 - quasi-http = { path = "../quasi-http", version = "0.50.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.51.0" }
24 + quasi-http = { path = "../quasi-http", version = "0.51.0" }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-bench"
3 - version = "0.50.0"
3 + version = "0.51.0"
4 4 description = "What a described screen costs to render, in time and in allocations"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -22,13 +22,13 @@
22 22 count = ["dep:dhat"]
23 23
24 24 [dependencies]
25 - quasi-router = { path = "../quasi-router", version = "0.50.0" }
26 - quasi-webview = { path = "../quasi-webview", version = "0.50.0" }
27 - quasi-tui = { path = "../quasi-tui", version = "0.50.0" }
25 + quasi-router = { path = "../quasi-router", version = "0.51.0" }
26 + quasi-webview = { path = "../quasi-webview", version = "0.51.0" }
27 + quasi-tui = { path = "../quasi-tui", version = "0.51.0" }
28 28 # `Serves` is the trait carrying `screen` and `fragment`, which is what the
29 29 # webview is measured through. Taken directly rather than through quasi-webview
30 30 # because a bench calling a trait method should name the trait it calls.
31 - quasi-http = { path = "../quasi-http", version = "0.50.0" }
31 + quasi-http = { path = "../quasi-http", version = "0.51.0" }
32 32 makeover-layout = "0.35.0"
33 33 makeover-tui = { version = "0.33.0", features = ["theme"] }
34 34 # Only to load a bundled theme file. `makeover_tui::Theme` is `#[non_exhaustive]`,
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-http"
3 - version = "0.50.0"
3 + version = "0.51.0"
4 4 description = "The http-shaped seam quasi's webview host adapters share: decoding in, a rendered description out"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -13,6 +13,6 @@
13 13 workspace = true
14 14
15 15 [dependencies]
16 - quasi-router = { path = "../quasi-router", version = "0.50.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.51.0" }
17 17 http = "1.3.1"
18 18 form_urlencoded = "1.2.2"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-immediate"
3 - version = "0.50.0"
3 + version = "0.51.0"
4 4 edition = "2024"
5 5 description = "The immediate-mode renderer for quasi-router: a described screen in, an egui frame out. Immediate mode is the constraint that matters, not the library."
6 6 license = "MIT"
@@ -12,7 +12,7 @@
12 12 categories = ["gui"]
13 13
14 14 [dependencies]
15 - quasi-router = { path = "../quasi-router", version = "0.50.0" }
15 + quasi-router = { path = "../quasi-router", version = "0.51.0" }
16 16 # The node drawing, which is the makeover layer's and not this crate's. Every
17 17 # widget here that is not a container comes from it: a screen walk that painted
18 18 # its own meter would be the divergence the suite exists to end, one copy per