Skip to main content

max / quasi

0.99.0: say code as classified runs, and a diff line as a change quasicoherent 19d7602d, option (d), and the last certain gap in the vocabulary. `Node::Code { runs, language, inline }` carries `Lexeme`s and never a bare string. That is the whole ruling: an app that browses source already has a lexer, a renderer does not and should not grow one, and three renderers each growing their own would disagree about the same file. The alternatives were a highlighter inside quasi-webview that goingson and audiofiles would pay for although neither browses source, or a `Node::Diff` putting git's data model in a vocabulary shared by a task manager and a sample browser. `inline` is a flag rather than a second member because the distinction is containment: a clone URL in a sentence and a file in a source browser are the same claim about the same text, and `Node::containment` reads the flag, so an inline literal is a leaf that may sit in a Row or a Cell and a block is not. `Lexeme` carries its own text rather than a range into a source string. A range would allocate less and would hand every renderer a byte offset that may not land on a character boundary; two of the three would get it wrong on the first file with a multi-byte character in it. The run carrying its text cannot express that bug. `Cells::change` is the diff half, so file, blame and a diff are all `Node::Table` and nothing here learns what a hunk is. `None` is not `Change::Context`: one says this table is not a diff, the other says this line did not change, and without the distinction every ordinary table in the tree would read as a diff whose lines are all context. All three renderers have an arm, and none took a dependency: - quasi-webview writes a span per classified run, `lex-<class>` off `Syntax::name`, and nothing at all for a plain run, which is most of a file. A diff row gets `data-change` beside `data-tone`, so a host that has never heard of a diff still gets the success and danger it already styles. - quasi-tui maps the classes onto the theme's status colours, following base16 Tomorrow, and puts the diff's sign in front of the row rather than a tint behind it: the sign survives a monochrome terminal and a colour does not. - quasi-immediate does the same in egui, monospaced. The two terminal-shaped choices are documented where they are made rather than here: a terminal spending status colours on syntax is deliberate, because the palette has no syntax colours and is not going to grow any.
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-02 15:28 UTC
Signed with PGP, not checked
Commit: 4612d4e35e425d97ca83940f47a13cca4db4f62d
Parent: 62671f1
19 files changed, +533 insertions, -66 deletions
M Cargo.lock +20 -26
@@ -2656,9 +2656,7 @@
2656 2656
2657 2657 [[package]]
2658 2658 name = "makeover-immediate"
2659 - version = "0.44.0"
2660 - source = "registry+https://github.com/rust-lang/crates.io-index"
2661 - checksum = "d34f96a7b5b7c26c79ea94b243e911b006e4899270bac418d215ff39f111cda9"
2659 + version = "0.45.0"
2662 2660 dependencies = [
2663 2661 "egui",
2664 2662 "egui_extras",
@@ -2668,9 +2666,7 @@
2668 2666
2669 2667 [[package]]
2670 2668 name = "makeover-layout"
2671 - version = "0.43.0"
2672 - source = "registry+https://github.com/rust-lang/crates.io-index"
2673 - checksum = "c0a9124f65373683ae4320b00bf4a6198b2554ef3ad3af2806b413ac164545fa"
2669 + version = "0.44.0"
2674 2670
2675 2671 [[package]]
2676 2672 name = "makeover-timing"
@@ -2683,9 +2679,7 @@
2683 2679
2684 2680 [[package]]
2685 2681 name = "makeover-touch"
2686 - version = "0.33.0"
2687 - source = "registry+https://github.com/rust-lang/crates.io-index"
2688 - checksum = "6281006f62d84f15c8c88662056e32f2027717bdd61f29d36f7917b9a694d64a"
2682 + version = "0.34.0"
2689 2683 dependencies = [
2690 2684 "makeover-geometry",
2691 2685 "makeover-layout",
@@ -2693,9 +2687,7 @@
2693 2687
2694 2688 [[package]]
2695 2689 name = "makeover-tui"
2696 - version = "0.43.0"
2697 - source = "registry+https://github.com/rust-lang/crates.io-index"
2698 - checksum = "39fc9343435bdcbaef8a5f5e2910254b841b08171919c19795dc50be7b1910ba"
2690 + version = "0.44.0"
2699 2691 dependencies = [
2700 2692 "makeover",
2701 2693 "makeover-layout",
@@ -2705,9 +2697,7 @@
2705 2697
2706 2698 [[package]]
2707 2699 name = "makeover-webview"
2708 - version = "0.72.0"
2709 - source = "registry+https://github.com/rust-lang/crates.io-index"
2710 - checksum = "ae1993234ce8b39b26b326b40cf92f455dfe0656b79d96cbe012c09c982df96d"
2700 + version = "0.73.0"
2711 2701 dependencies = [
2712 2702 "makeover-geometry",
2713 2703 "makeover-layout",
@@ -3476,11 +3466,11 @@
3476 3466
3477 3467 [[package]]
3478 3468 name = "quasi"
3479 - version = "0.98.0"
3469 + version = "0.99.0"
3480 3470
3481 3471 [[package]]
3482 3472 name = "quasi-axum"
3483 - version = "0.98.0"
3473 + version = "0.99.0"
3484 3474 dependencies = [
3485 3475 "axum",
3486 3476 "http",
@@ -3494,7 +3484,7 @@
3494 3484
3495 3485 [[package]]
3496 3486 name = "quasi-basics"
3497 - version = "0.98.0"
3487 + version = "0.99.0"
3498 3488 dependencies = [
3499 3489 "makeover-layout",
3500 3490 "quasi-http",
@@ -3504,7 +3494,7 @@
3504 3494
3505 3495 [[package]]
3506 3496 name = "quasi-bench"
3507 - version = "0.98.0"
3497 + version = "0.99.0"
3508 3498 dependencies = [
3509 3499 "askama",
3510 3500 "dhat",
@@ -3521,7 +3511,7 @@
3521 3511
3522 3512 [[package]]
3523 3513 name = "quasi-http"
3524 - version = "0.98.0"
3514 + version = "0.99.0"
3525 3515 dependencies = [
3526 3516 "form_urlencoded",
3527 3517 "http",
@@ -3530,7 +3520,7 @@
3530 3520
3531 3521 [[package]]
3532 3522 name = "quasi-immediate"
3533 - version = "0.98.0"
3523 + version = "0.99.0"
3534 3524 dependencies = [
3535 3525 "docengine",
3536 3526 "egui",
@@ -3541,7 +3531,7 @@
3541 3531
3542 3532 [[package]]
3543 3533 name = "quasi-notifs"
3544 - version = "0.98.0"
3534 + version = "0.99.0"
3545 3535 dependencies = [
3546 3536 "quasi-router",
3547 3537 "synckit-config",
@@ -3551,7 +3541,7 @@
3551 3541
3552 3542 [[package]]
3553 3543 name = "quasi-router"
3554 - version = "0.98.0"
3544 + version = "0.99.0"
3555 3545 dependencies = [
3556 3546 "makeover-layout",
3557 3547 ]
@@ -3568,7 +3558,7 @@
3568 3558
3569 3559 [[package]]
3570 3560 name = "quasi-tauri"
3571 - version = "0.98.0"
3561 + version = "0.99.0"
3572 3562 dependencies = [
3573 3563 "http",
3574 3564 "quasi-http",
@@ -3579,7 +3569,7 @@
3579 3569
3580 3570 [[package]]
3581 3571 name = "quasi-tui"
3582 - version = "0.98.0"
3572 + version = "0.99.0"
3583 3573 dependencies = [
3584 3574 "docengine",
3585 3575 "makeover",
@@ -3592,7 +3582,7 @@
3592 3582
3593 3583 [[package]]
3594 3584 name = "quasi-webview"
3595 - version = "0.98.0"
3585 + version = "0.99.0"
3596 3586 dependencies = [
3597 3587 "docengine",
3598 3588 "makeover-layout",
@@ -6290,3 +6280,7 @@
6290 6280 [[patch.unused]]
6291 6281 name = "tagtree"
6292 6282 version = "0.4.1"
6283 +
6284 + [[patch.unused]]
6285 + name = "makeover-build"
6286 + version = "0.66.0"
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-axum"
3 - version = "0.98.0"
3 + version = "0.99.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.98.0" }
17 - quasi-http = { path = "../quasi-http", version = "0.98.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.99.0" }
17 + quasi-http = { path = "../quasi-http", version = "0.99.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.98.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.99.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.98.0"
3 + version = "0.99.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.98.0" }
17 - makeover-layout = "0.43"
16 + quasi-router = { path = "../quasi-router", version = "0.99.0" }
17 + makeover-layout = "0.44"
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.98.0" }
24 - quasi-http = { path = "../quasi-http", version = "0.98.0" }
23 + quasi-webview = { path = "../quasi-webview", version = "0.99.0" }
24 + quasi-http = { path = "../quasi-http", version = "0.99.0" }
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-bench"
3 - version = "0.98.0"
3 + version = "0.99.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
@@ -26,18 +26,18 @@
26 26 askama = ["dep:askama"]
27 27
28 28 [dependencies]
29 - quasi-router = { path = "../quasi-router", version = "0.98.0" }
30 - quasi-webview = { path = "../quasi-webview", version = "0.98.0" }
31 - quasi-tui = { path = "../quasi-tui", version = "0.98.0" }
29 + quasi-router = { path = "../quasi-router", version = "0.99.0" }
30 + quasi-webview = { path = "../quasi-webview", version = "0.99.0" }
31 + quasi-tui = { path = "../quasi-tui", version = "0.99.0" }
32 32 # `Serves` is the trait carrying `screen` and `fragment`, which is what the
33 33 # webview is measured through. Taken directly rather than through quasi-webview
34 34 # because a bench calling a trait method should name the trait it calls.
35 - quasi-http = { path = "../quasi-http", version = "0.98.0" }
36 - makeover-layout = "0.43"
35 + quasi-http = { path = "../quasi-http", version = "0.99.0" }
36 + makeover-layout = "0.44"
37 37 # The renderer's own escaper, so the staged path fills a hole exactly the way
38 38 # `Node::Text` does and the guarantee is not quietly reimplemented.
39 - makeover-webview = "0.72"
40 - makeover-tui = { version = "0.43", features = ["theme"] }
39 + makeover-webview = "0.73"
40 + makeover-tui = { version = "0.44", features = ["theme"] }
41 41 # Only to load a bundled theme file. `makeover_tui::Theme` is `#[non_exhaustive]`,
42 42 # so `Theme::from_theme` is the one way to get one, the same reason quasi-tui's
43 43 # tests take this.
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-http"
3 - version = "0.98.0"
3 + version = "0.99.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.98.0" }
16 + quasi-router = { path = "../quasi-router", version = "0.99.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.98.0"
3 + version = "0.99.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,12 +12,12 @@
12 12 categories = ["gui"]
13 13
14 14 [dependencies]
15 - quasi-router = { path = "../quasi-router", version = "0.98.0" }
15 + quasi-router = { path = "../quasi-router", version = "0.99.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
19 19 # renderer instead of one copy per app.
20 - makeover-immediate = "0.44"
20 + makeover-immediate = "0.45"
21 21 # The one place a duration is named rather than numbered. `Intent::Dismiss` is
22 22 # how long a transient notice lives, and `notice_lifetime` is the seam: the
23 23 # description says a toast goes away on its own and declines to say when, so
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "quasi-notifs"
3 - version = "0.98.0"
3 + version = "0.99.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
@@ -28,7 +28,7 @@
28 28 tauri = ["dep:tauri", "dep:tauri-plugin-notification"]
29 29
30 30 [dependencies]
31 - quasi-router = { path = "../quasi-router", version = "0.98.0", optional = true }
31 + quasi-router = { path = "../quasi-router", version = "0.99.0", optional = true }
32 32 synckit-config = { git = "https://makenot.work/git/max/synckit.git", version = "0.2", optional = true }
33 33 tauri-plugin-notification = { version = "2.3.3", optional = true }
34 34 # Default features off, for `quasi-tauri`'s reason: this takes an `AppHandle`