Draw replies as pieces of one parse, and lists an item at a time
A settled reply used to be cut into block *strings*, each parsed on its own and each a unit of the lazy list; the live reply split the same way with a whole-message parse per delta on top. Now a message is parsed once, and a Piece addresses a top-level block of that tree -- or one item of a top-level list, which was the one block still unbounded: a list of forty sources was one item composed whole in the frame it scrolled into. Units, the live reply's column and peer messages all draw from the same parse, so warm parses each message once instead of once per block, a delta costs one background parse instead of two, and a reference definition at the foot of a message resolves again because nothing is parsed apart from it. The renderer keeps parsing and providing its environment; MarkdownRoot wraps that around a piece, and a whole block still goes through its dispatch with our component table. List items are drawn here, with the renderer's own paddings so a split list looks like an unsplit one, and lists inside quotes come to the same code through the table -- the marker is drawn in one place, which is what a styled bullet would need later. Found on the way: a heading's words are a child of the heading node, and the inline builder draws nothing for a node type it does not know, so the span-link path had been drawing headings empty. LinkedHeading hands it the content child. Lint: profileable's shell attribute scoped to API 29 where it exists, and recordFrames renamed to the composable convention. What remains is the AGP 9.4.0 notice. Verified on the emulator against a fixture of every block kind (headings, nested and ordered lists with a start number, task items, a quote holding a list, a fence, a rule, a table with a linked cell, a setext heading), a forty-item list which the render report now shows as per-item units, a reply streamed live (34 deltas: 34 background reparses, one warm at settle, no crash), and the older link fixture. ktfmt, build and lint run. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
a9ab9b3e5a
commit
48bb7de304
12 files changed
+457
-221
No files matched your search
@@ -541,12 +541,12 @@ private val parsingThreads = Dispatchers.Default.limitedParallelism(2)
|
||||
* whole point: the work happens seconds before the reader reaches the rows it was done for. See
|
||||
* [ParsedReplies].
|
||||
*
|
||||
* What is warmed mirrors what the rows draw, unit by unit -- prose split into its blocks, a memory
|
||||
* note whole, a peer message split the same way prose is -- because a string warmed under a key no
|
||||
* row ever looks up is a miss that nothing reports; see [transcriptUnits], which is the flatten
|
||||
* this has to agree with. It reads the same [ParsedReplies.partsOf] and [ParsedReplies.blocksOf]
|
||||
* caches the flatten does, so a message is scanned once however many pages hand it back through
|
||||
* here, while the whole loaded transcript crosses this on every page.
|
||||
* What is warmed mirrors what the rows draw -- each prose part of a reply, a memory note, a peer
|
||||
* message, every one of them whole, since every piece of a message is drawn from its one parse --
|
||||
* because a string warmed under a key no row ever looks up is a miss that nothing reports; see
|
||||
* [transcriptUnits], which is the flatten this has to agree with. It reads the same
|
||||
* [ParsedReplies.partsOf] cache the flatten does, so a message is scanned once however many pages
|
||||
* hand it back through here, while the whole loaded transcript crosses this on every page.
|
||||
*
|
||||
* Every kind of row that draws markdown belongs in the `when` below. That is the rule the peer
|
||||
* message was missing: this used to filter for assistant replies alone, so the one row type nobody
|
||||
@@ -557,21 +557,12 @@ suspend fun warm(replies: ParsedReplies, rows: List<TranscriptItem>) {
|
||||
withContext(parsingThreads) {
|
||||
val texts = rows.flatMap { row ->
|
||||
when (row) {
|
||||
is TranscriptItem.AssistantMsg ->
|
||||
replies.partsOf(row.text).flatMap { part ->
|
||||
when (part) {
|
||||
is MessagePart.Prose -> replies.blocksOf(part.text)
|
||||
// Drawn as one MarkdownText, so its whole text is the key
|
||||
// looked up.
|
||||
is MessagePart.Remembered -> listOf(part.text)
|
||||
}
|
||||
}
|
||||
is TranscriptItem.AssistantMsg -> replies.partsOf(row.text).map { it.text }
|
||||
// A message from another agent is markdown too, and it is the longest thing
|
||||
// in a transcript often enough that leaving it out was the whole of why one
|
||||
// cost a fifth of a second to open: it was the only markdown in the app
|
||||
// parsed on the thread that draws. Its blocks, not its text, because
|
||||
// [PeerMessageRow] draws it a block at a time.
|
||||
is TranscriptItem.PeerNote -> replies.blocksOf(row.text)
|
||||
// parsed on the thread that draws.
|
||||
is TranscriptItem.PeerNote -> listOf(row.text)
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user