Skip to main content

max / quasi

0.70.0: a change is complete before it is a write `8032fe61` and `de2376bd`, one answer. Only half of `8032fe61`, deliberately: that task carries a standing instruction not to answer it as written, and the half it means is re-filed rather than settled. Two shipped renderers disagreed about what a member means. quasi-webview hx-trigger="change" blur, Enter, a range released quasi-immediate buffer != last frame every keystroke, every drag frame quasi-tui every keystroke So a search box was one request per letter on two hosts and one per search on the third, and audiofiles' bounded `row_height` posted a row height of 3 on the way to 30, outside the bounds the field's own hint states. One description behaving two ways is the drift this stack exists to end, and the webview was again the host that was already right. `Field::changes` means the change is complete. A value the reader builds up, typed into or dragged across, writes when they are finished with the control; a value chosen in one go was complete when it changed and still writes then, which is what a browser's `change` does for those too. Leaving a control nobody altered writes nothing, which is the other half of that promise. Each `View` grew a `written` map beside `edits`, because a completed value needs a baseline: `edits` is what is in the box and `written` is what the route has been told. Reading an untouched box as empty wrote every prefilled field walked past, which the new terminal test caught. `de2376bd` closes with no member. It asked for `Field::settles` beside `changes` for three sliders writing once per drag frame; under this a drag is one write, so option (a) is unnecessary rather than declined. The shipped app's own `widgets::settled` helper, the workaround that prompted it, is what `changes` now means. Live search costs nothing under this, which is what makes it a rule rather than a restriction: a box asking a route about what is being typed carries a `Consult` with its own `after`, a wait the description states. Writes complete; questions debounce. Both renderers still fire consults per keystroke. Two quasi-tui tests asserted the old behaviour and were rewritten rather than deleted; one was really about ticks travelling with a picker's value, which is unchanged. The new egui test types into a focused box and asserts nothing fires until the caret leaves, which is the shape of the `row_height` defect, and it fails against the old code. `push_deadlines` split out of `field_node` while that was over clippy's line bound, and it is a whole idea: a keystroke pushes every question the box raises further out, which is what makes it a debounce. Consumers forward-fixed in the same pass: MNW server, goingson and audiofiles move to `^0.70` and each tests green.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-27 19:00 UTC
Signed with PGP, not checked
Commit: 0ec3b0bb41c930578ea2c13c3f96adc316405ebf
Parent: 27759c7
19 files changed, +343 insertions, -85 deletions
M Cargo.lock +15 -15
@@ -3425,11 +3425,11 @@
3425 3425
3426 3426 [[package]]
3427 3427 name = "quasi"
3428 - version = "0.69.1"
3428 + version = "0.69.2"
3429 3429
3430 3430 [[package]]
3431 3431 name = "quasi-axum"
3432 - version = "0.69.1"
3432 + version = "0.69.2"
3433 3433 dependencies = [
3434 3434 "axum",
3435 3435 "http",
@@ -3443,7 +3443,7 @@
3443 3443
3444 3444 [[package]]
3445 3445 name = "quasi-basics"
3446 - version = "0.69.1"
3446 + version = "0.69.2"
3447 3447 dependencies = [
3448 3448 "makeover-layout",
3449 3449 "quasi-http",
@@ -3453,7 +3453,7 @@
3453 3453
3454 3454 [[package]]
3455 3455 name = "quasi-bench"
3456 - version = "0.69.1"
3456 + version = "0.69.2"
3457 3457 dependencies = [
3458 3458 "dhat",
3459 3459 "makeover",
@@ -3468,7 +3468,7 @@
3468 3468
3469 3469 [[package]]
3470 3470 name = "quasi-http"
3471 - version = "0.69.1"
3471 + version = "0.69.2"
3472 3472 dependencies = [
3473 3473 "form_urlencoded",
3474 3474 "http",
@@ -3477,7 +3477,7 @@
3477 3477
3478 3478 [[package]]
3479 3479 name = "quasi-immediate"
3480 - version = "0.69.1"
3480 + version = "0.69.2"
3481 3481 dependencies = [
3482 3482 "docengine",
3483 3483 "egui",
@@ -3488,7 +3488,7 @@
3488 3488
3489 3489 [[package]]
3490 3490 name = "quasi-notifs"
3491 - version = "0.69.1"
3491 + version = "0.69.2"
3492 3492 dependencies = [
3493 3493 "quasi-router",
3494 3494 "synckit-config",
@@ -3496,7 +3496,7 @@
3496 3496
3497 3497 [[package]]
3498 3498 name = "quasi-router"
3499 - version = "0.69.1"
3499 + version = "0.69.2"
3500 3500 dependencies = [
3501 3501 "makeover-layout",
3502 3502 ]
@@ -3513,7 +3513,7 @@
3513 3513
3514 3514 [[package]]
3515 3515 name = "quasi-tauri"
3516 - version = "0.69.1"
3516 + version = "0.69.2"
3517 3517 dependencies = [
3518 3518 "http",
3519 3519 "quasi-http",
@@ -3526,7 +3526,7 @@
3526 3526
3527 3527 [[package]]
3528 3528 name = "quasi-tui"
3529 - version = "0.69.1"
3529 + version = "0.69.2"
3530 3530 dependencies = [
3531 3531 "docengine",
3532 3532 "makeover",
@@ -3539,7 +3539,7 @@
3539 3539
3540 3540 [[package]]
3541 3541 name = "quasi-webview"
3542 - version = "0.69.1"
3542 + version = "0.69.2"
3543 3543 dependencies = [
3544 3544 "docengine",
3545 3545 "makeover-layout",
@@ -6215,6 +6215,10 @@
6215 6215 name = "quasi-type"
6216 6216 version = "0.1.0"
6217 6217
6218 + [[patch.unused]]
6219 + name = "synckit-client"
6220 + version = "0.9.1"
6221 +
6218 6222 [[patch.unused]]
6219 6223 name = "kberg"
6220 6224 version = "0.1.0"
@@ -6230,7 +6234,3 @@
6230 6234 [[patch.unused]]
6231 6235 name = "tagtree"
6232 6236 version = "0.4.1"
6233 -
6234 - [[patch.unused]]
6235 - name = "synckit-client"
6236 - version = "0.9.1"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-axum"
3 - version = "0.69.2"
3 + version = "0.70.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.69.2" }
17 - quasi-http = { path = "../quasi-http", version = "0.69.2" }
16 + quasi-router = { path = "../quasi-router", version = "0.70.0" }
17 + quasi-http = { path = "../quasi-http", version = "0.70.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.69.2" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.70.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.69.2"
3 + version = "0.70.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.69.2" }
16 + quasi-router = { path = "../quasi-router", version = "0.70.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.69.2" }
24 - quasi-http = { path = "../quasi-http", version = "0.69.2" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.70.0" }
24 + quasi-http = { path = "../quasi-http", version = "0.70.0" }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-bench"
3 - version = "0.69.2"
3 + version = "0.70.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.69.2" }
26 - quasi-webview = { path = "../quasi-webview", version = "0.69.2" }
27 - quasi-tui = { path = "../quasi-tui", version = "0.69.2" }
25 + quasi-router = { path = "../quasi-router", version = "0.70.0" }
26 + quasi-webview = { path = "../quasi-webview", version = "0.70.0" }
27 + quasi-tui = { path = "../quasi-tui", version = "0.70.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.69.2" }
31 + quasi-http = { path = "../quasi-http", version = "0.70.0" }
32 32 makeover-layout = "0.35.0"
33 33 makeover-tui = { version = "0.35.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.69.2"
3 + version = "0.70.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.69.2" }
16 + quasi-router = { path = "../quasi-router", version = "0.70.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.69.2"
3 + version = "0.70.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.69.2" }
15 + quasi-router = { path = "../quasi-router", version = "0.70.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
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-notifs"
3 - version = "0.69.2"
3 + version = "0.70.0"
4 4 description = "Declared notification kinds and the registry that holds them: what a notification says and what it is for, apart from how it reaches a person"
5 5 edition.workspace = true
6 6 rust-version.workspace = true
@@ -24,5 +24,5 @@
24 24 describe = ["dep:quasi-router"]
25 25
26 26 [dependencies]
27 - quasi-router = { path = "../quasi-router", version = "0.69.2", optional = true }
27 + quasi-router = { path = "../quasi-router", version = "0.70.0", optional = true }
28 28 synckit-config = { git = "https://makenot.work/git/max/synckit.git", version = "0.2", optional = true }