Thin the app's comments
The same pass the server had, on the Kotlin side: comments restating what the code says are gone, and the ones recording a measurement, a constraint or an incident are kept but cut to a few lines each. 6540 comment lines to 5674, and 920 lines off the app. Two doc comments had drifted onto the item above the one they describe -- `contextAfter`'s onto `sessionWorking` in Events.kt, and `UsageMonitor`'s equivalent on the server was fixed in the previous commit. Each is back on its own item, which is the only non-comment line this diff moves. The comments are reflowed to the column limit at their own indentation: several were written wide, and ktfmt re-wrapped them into lines holding a single orphan word. `/tmp` script, not kept -- ktfmt is idempotent over the result, which is the check. Left alone deliberately: this codebase's remaining comment density is high because the comments carry things the code cannot say -- what a null means, what a number was measured against, which bug a guard exists for. Of the 238 one-line doc comments in the app, five were pure restatement of the name and were removed; the rest each say something the signature does not. ktfmtFormat, compileDebugKotlin, lintDebug and testDebugUnitTest pass; cargo test (127), clippy --all-targets and fmt still clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
79682f03a7
commit
edc39c7371
68 files changed
+2077
-2997
No files matched your search
@@ -12,8 +12,7 @@ import androidx.compose.ui.unit.dp
|
||||
* at the moment it scrolls into view, and that cost is proportional to the item -- a reply can be
|
||||
* twenty-five screens of markdown, which as one item is a hundred-millisecond frame exactly when
|
||||
* the list is moving fastest. A *block* is a paragraph, a fence, a table: bounded, so the worst
|
||||
* frame is bounded. This is the piece that was missing when a lazy list was last tried here; the
|
||||
* block splitting existed only inside the row, where the list could not see it.
|
||||
* frame is bounded. This is the piece that was missing when a lazy list was last tried here.
|
||||
*
|
||||
* Everything else about the row model is unchanged: rows come from [groupToolRuns], and a unit
|
||||
* points back at its row. The list draws units; anchors and paging still speak seq.
|
||||
@@ -27,10 +26,9 @@ sealed class TranscriptUnit {
|
||||
abstract val seq: Long
|
||||
|
||||
/**
|
||||
* This unit's position within its row, counted from the row's oldest end.
|
||||
*
|
||||
* What a saved scroll position carries besides the seq: a reply split into forty blocks needs
|
||||
* more than "somewhere in this row" to put a reader back where they stopped.
|
||||
* This unit's position within its row, counted from the row's oldest end. What a saved scroll
|
||||
* position carries besides the seq: a reply split into forty blocks needs more than "somewhere
|
||||
* in this row" to put a reader back where they stopped.
|
||||
*/
|
||||
abstract val ordinal: Int
|
||||
|
||||
@@ -66,15 +64,13 @@ sealed class TranscriptUnit {
|
||||
*
|
||||
* A peer message is the one row whose *opened* size is unbounded -- these are the longest
|
||||
* things a transcript holds -- so it is flattened the same way a settled reply is, and for the
|
||||
* same reason: as one item, every block of it is composed, measured, placed and kept alive
|
||||
* while any part of it is on screen. Measured on the emulator, opening a 43KB one took the
|
||||
* transcript's share of the draw phase from 0.81ms a frame to 3.85ms, and the framework's own
|
||||
* per-frame bookkeeping -- which grows with how many nodes are *alive* -- from 0.39ms to
|
||||
* 3.15ms.
|
||||
* same reason. Measured on the emulator, opening a 43KB one took the transcript's share of the
|
||||
* draw phase from 0.81ms a frame to 3.85ms, and the framework's own per-frame bookkeeping from
|
||||
* 0.39ms to 3.15ms.
|
||||
*
|
||||
* The card is drawn in pieces rather than given up: a filled Material card is elevation zero,
|
||||
* so it has no shadow to break, and each piece paints the same fill with only the corners it
|
||||
* owns. See [PeerHeadRow] and [PeerBlockRow].
|
||||
* owns.
|
||||
*/
|
||||
data class PeerHead(
|
||||
override val seq: Long,
|
||||
@@ -84,8 +80,7 @@ sealed class TranscriptUnit {
|
||||
) : TranscriptUnit() {
|
||||
/**
|
||||
* The note's own key, so opening and shutting does not change what the list is anchored on
|
||||
* -- and so two notes stamped with one turn's seq are still two items. See
|
||||
* [TranscriptItem.PeerNote].
|
||||
* -- and so two notes stamped with one turn's seq are still two items.
|
||||
*/
|
||||
override val key: Any
|
||||
get() = item.key
|
||||
@@ -119,8 +114,7 @@ sealed class TranscriptUnit {
|
||||
*
|
||||
* A user message is plain text, so cutting it costs a scan rather than a parse -- but the
|
||||
* reason is the same as for a settled reply: as one item, a pasted log is a hundred thousand
|
||||
* pixels of `Text` whose layout lands in the frame the row scrolls into. Measured as the
|
||||
* `measure: the whole transcript ... 112.1ms worst` in an otherwise smooth report.
|
||||
* pixels of `Text` whose layout lands in the frame the row scrolls into.
|
||||
*/
|
||||
data class UserChunk(
|
||||
override val seq: Long,
|
||||
@@ -152,14 +146,11 @@ sealed class TranscriptUnit {
|
||||
* The rows flattened into list units, newest first -- index zero is the item at the bottom of the
|
||||
* screen, which is what a reversed lazy list calls the start.
|
||||
*
|
||||
* Every settled reply is cut into its pieces ([pieces], via the caches on [replies] so a message is
|
||||
* only ever cut once), and so is an *opened* peer message -- [openNotes] is which ones those are,
|
||||
* which is why the flatten needs it. A shut one is a single heading and cannot be worth splitting.
|
||||
* The reply still arriving -- the newest row, until the status event that ends its turn marks it
|
||||
* [TranscriptItem.AssistantMsg.settled] -- stays whole: its text changes with every delta, and
|
||||
* splitting it here would parse the whole message per delta on whichever thread is composing.
|
||||
* [AssistantMessage]'s own streaming path already parses deltas off the main thread and gives the
|
||||
* live message a layer per piece. Once settled it splits like every other reply, which is what
|
||||
* Every settled reply is cut into its pieces (via the caches on [replies] so a message is only ever
|
||||
* cut once), and so is an *opened* peer message -- [openNotes] is which ones those are. A shut one
|
||||
* is a single heading and cannot be worth splitting. The reply still arriving stays whole: its text
|
||||
* changes with every delta, and splitting it here would parse the whole message per delta on
|
||||
* whichever thread is composing. Once settled it splits like every other reply, which is what
|
||||
* bounds the newest row's cost after a session ends on a long one.
|
||||
*
|
||||
* Runs per fold, so it must stay proportional to what is loaded with no parsing in it on the warm
|
||||
@@ -200,8 +191,8 @@ fun transcriptUnits(
|
||||
}
|
||||
}
|
||||
} else if (item is TranscriptItem.UserMsg && item.text.length > USER_SPLIT_CHARS) {
|
||||
// A scan, not a parse, so it is cheap enough for the fold path -- and cached like
|
||||
// the markdown splits so the scan too happens once per message, not once per fold.
|
||||
// A scan, not a parse, so it is cheap enough for the fold path -- and cached like the
|
||||
// markdown splits so the scan happens once per message rather than once per fold.
|
||||
val chunks = replies.chunksOf(item.text)
|
||||
chunks.forEachIndexed { at, chunk ->
|
||||
units +=
|
||||
@@ -252,8 +243,8 @@ fun transcriptUnits(
|
||||
}
|
||||
units.reverse()
|
||||
reportDuplicateKeys(units)
|
||||
// Timed because this runs per fold on the composing thread: "loading messages feels bumpy"
|
||||
// is this number growing, and it was invisible until it was written down.
|
||||
// Timed because this runs per fold on the composing thread: "loading messages feels bumpy" is
|
||||
// this number growing, and it was invisible until it was written down.
|
||||
DebugStats.record("units flattened", System.nanoTime() - started)
|
||||
return units
|
||||
}
|
||||
@@ -261,9 +252,8 @@ fun transcriptUnits(
|
||||
/**
|
||||
* Whether this reply should be drawn as blocks: settled, or anywhere but the newest row.
|
||||
*
|
||||
* Wanting is not being ready -- the flatten also asks [ParsedReplies.splitReady], and the two
|
||||
* questions are separate because they are answered by different things: this one by the fold, the
|
||||
* other by whether [warm] has run for the text. [unwarmedReplies] is the gap between them.
|
||||
* Wanting is not being ready -- the flatten also asks [ParsedReplies.splitReady], and the two are
|
||||
* answered by different things: this one by the fold, the other by whether [warm] has run.
|
||||
*/
|
||||
private fun splitWanted(item: TranscriptItem.AssistantMsg, index: Int, lastIndex: Int) =
|
||||
item.settled || index != lastIndex
|
||||
@@ -272,8 +262,7 @@ private fun splitWanted(item: TranscriptItem.AssistantMsg, index: Int, lastIndex
|
||||
* The replies among [rows] that should draw as blocks but whose parses are not made yet.
|
||||
*
|
||||
* Normally empty: every page's rows are warmed before the fold lands. The one row that can be cold
|
||||
* is the reply that just finished streaming -- nothing warms live deltas, so at the moment its turn
|
||||
* ends its split would cost a whole-message parse on the composing thread. The session screen warms
|
||||
* is the reply that just finished streaming -- nothing warms live deltas. The session screen warms
|
||||
* what this returns off-thread and re-flattens, so the whole-to-blocks swap always composes against
|
||||
* ready parses.
|
||||
*/
|
||||
|
||||
Reference in new issue
Block a user