A row was one TextEdit holding the whole message, so every delta re-shaped every paragraph of a long reply through parley -- the one phase where iris trails Compose on the phone (p50 18.2ms vs 13.4ms, bench v2). - client-core/src/markdown_blocks.rs: split a message into its top-level blocks with their source, through the same pulldown-cmark the renderer parses with so the two cannot disagree about where a block starts, plus common_prefix. Appending markdown can rewrite an earlier block (a trailing --- turns the paragraph above into a heading), so the fast path compares the prefix it keeps rather than assuming it -- with the test that says so. - transcript-ui: a row is a Span of one TextEdit per block; RowBlocks::apply_delta replaces the block a delta lands in; TranscriptScreen keeps the tail row's blocks, seeded in build_tree as well as push_row (a screen opened onto a streaming reply took the rebuild path for its first delta otherwise, with nothing to say so). - A block is the selection unit: Selection is keyed by (RowKey, u32), which is reading order at both levels, and the pointer-captured half of a drag resolves the block under the finger from its drawn box (Selection::locate) instead of from the row's extent. Pass condition: a_delta_into_a_long_reply_redraws_the_same_widgets_as_a_short_one drives a real UiRenderState and asserts the draw count for a delta into a 100-paragraph (3,000+ char) reply equals the count for a one-paragraph one. 30 either way; it read 630 against 30 twice on the way there. Emulator stream phase, same AVD before and after: p50 61.5 -> 54.5ms, p90 211.7 -> 113.1ms, p99 342.6 -> 137.4ms, worst 403.6 -> 143.0ms, 202 -> 293 frames in the same 21 seconds. Selection across blocks verified with a real long-press drag. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
44 lines
2.1 KiB
TOML
44 lines
2.1 KiB
TOML
[package]
|
|
name = "client-core"
|
|
version = "0.1.0"
|
|
edition = "2024"
|
|
|
|
# The app's pure logic, held once instead of twice: the event model (shared
|
|
# with `server/` via `event-model`), the REST + SSE clients for its HTTP
|
|
# surface (see `server/src/routes.rs`'s module doc for the table), the
|
|
# transcript fold and cache, the markdown block model, the syntax
|
|
# highlighter and the ANSI parser. See `docs/CLIENT_CORE.md` for
|
|
# what this holds today, what it does not yet, and how it corresponds to
|
|
# the Kotlin it replaces.
|
|
#
|
|
# No UI framework dependency of any kind -- this crate is meant to outlive
|
|
# whichever one the app ends up drawing with (see RUST.md).
|
|
|
|
[dependencies]
|
|
event-model = { path = "../event-model" }
|
|
serde = { version = "1", features = ["derive"] }
|
|
# "raw_value" is `fetch_transcript_lines`'s reason -- it needs the exact
|
|
# bytes the server sent, not this crate's own re-serialization of a parsed
|
|
# `Value`, so a cached line and a live SSE frame for the same event agree
|
|
# byte-for-byte (see that method's doc). "float_roundtrip" is why they
|
|
# agree on a `ts` at all -- see server/Cargo.toml's identical comment.
|
|
serde_json = { version = "1", features = ["float_roundtrip", "raw_value"] }
|
|
# The blocking HTTP client for the REST calls and the long-lived SSE GETs.
|
|
# `server/` already depends on ureq for its own outbound HTTPS (the usage
|
|
# poll in usage.rs) and it is rustls-backed like the rest of this project's
|
|
# TLS, so this reuses that choice rather than pulling in reqwest's async
|
|
# stack -- a client that runs one blocking request at a time, the way
|
|
# Api.kt's `HttpURLConnection` calls and Sse.kt's blocking read loop do, has
|
|
# no need of an async runtime, and RUST.md's brief for this port is
|
|
# "lightweight" throughout.
|
|
ureq = { version = "3", features = ["json"] }
|
|
# The markdown block split (`markdown_blocks`), which has to agree with the
|
|
# renderer in `iris/transcript-ui` about where a block begins -- so it is
|
|
# the same parser at the same version, rather than a hand-written splitter
|
|
# that would drift from it.
|
|
pulldown-cmark = "0.13.4"
|
|
|
|
|
|
[dev-dependencies]
|
|
tempfile = "3"
|