Preserve runs of compact assignment rows - #6
Merged
Merged
Conversation
A label or banner row re-emits its body behind the canonical prefix rather than replaying its raw source line, so a drifted marker and a stripped decorative bookend land like every reflowed sibling. Line 0 of a "/* <content>" block was excluded from that and took raw replay, which is the source line as it arrived, from before strip_decorative_bookends ran. The opener's line therefore kept a decoration its siblings had already lost. The result is a pass that never settles. Pass one emits the mixed shape, pass two sees the bookend on a line that is no longer first, strips it, and produces different bytes, so --check reports a diff forever. The exclusion bought nothing: text is already the stripped body with the opener removed, which is exactly what the raw-replay branch rebuilds by hand for that line.
jserv
force-pushed
the
assignment-rows
branch
from
September 21, 2026 03:20
a41044d to
81ef659
Compare
A comment that documents a mapping one row at a time, the shape a decoder or a register table is written in, was packed into a paragraph like prose, which loses the mapping. Those rows now classify as a preformatted kind and go out verbatim. What decides a row is the left-hand side, which must be a single code-like token, so a sentence that merely carries an equals sign stays prose. The operator may be bare or compound, spaced or not, and alignment padding before it is layout rather than a disqualifier, since column-aligned tables are the common spelling. Comparisons and arrows are not assignments and do not open a row. A run of two or more adjacent rows freezes whole and whatever follows is simply the next paragraph, so a table sitting directly above the sentence that explains it survives intact. One row is not a table: a lone "count = zero when the queue drained" is a sentence, and wrapping it is correct. Requiring a neighbour is also what keeps a lone overlong sentence out of the frozen set, though a run of them may sit over the column limit, the same way a table row or an indented code sample may, because a mapping row cannot be wrapped without destroying the mapping. Membership is decided after every other check, over the lines nothing else claimed, so a run cannot reach through a code sample, a table, a fence or a verbatim block. Deciding it on how a line looks in the source instead let an indented "ret = foo(a, b);" pair with the sentence under it and freeze that sentence alone, which is the case the run rule exists to reflow. Two rules this leans on needed work. Art declines a mapping row, because the equals sign is a member of the art alphabet and a short row cleared the density threshold on the very characters that make it a row; a rule-decorated line is excepted, or the packer builds a line ruled on both ends that the next pass strips. The merge gate reads through a bookend, because strip_decorative_bookends runs between the two stages, and answering on the raw line let a prose comment merge into a table that then froze around it. Two questions about a LineKind were remote matches! lists a new variant could fall out of, answering "reflow it as prose", which is the damage the enum exists to prevent. is_preformatted is an exhaustive method now, so the next variant is a compile error until it is answered. Verified against the base branch over 900 headers and Rust sources, at four column limits. Five files differ, each a mapping table the old binary had run together, and no comment word moves. The set of files whose second pass differs is unchanged.
jserv
force-pushed
the
assignment-rows
branch
from
September 21, 2026 03:27
81ef659 to
86c7ba7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A comment that documents a mapping one row at a time, the
ir->imm = lui immediateshape a decoder or a register table is written in, was packed into a paragraph like prose, which loses the mapping. Those rows now classify as a preformatted kind and go out verbatim. What decides a row is the left-hand side, which must be a single code-like token, so a sentence that merely carries an equals sign stays prose; the operator may be bare or compound, spaced or not, and alignment padding before it is layout rather than a disqualifier, since column-aligned tables are the common spelling. A run of two or more adjacent rows freezes whole and whatever follows is simply the next paragraph, so a table sitting directly above the sentence that explains it survives intact, while a lonecount = zero when the queue drainedis a sentence and still wraps.Run membership is decided after every other check, over the lines nothing else claimed, so a run cannot reach through a code sample, a table, a fence or a verbatim block. Deciding it on how a line looks in the source instead let an indented
ret = foo(a, b);pair with the sentence under it and freeze that sentence alone, which is the case the run rule exists to reflow and a common shape in C headers. Two rules this leans on needed work: art declines a mapping row, since=is in the art alphabet and a short row cleared the density threshold on the very characters that make it a row, except where the line is rule-decorated, or the packer builds a line ruled on both ends that the next pass strips; and the merge gate reads through a bookend, becausestrip_decorative_bookendsruns between the two stages.The first commit is independent and stands on its own against the base branch: line 0 of a
/* <content>block was excluded from canonical re-emit and took raw replay, so it kept a decoration its siblings had lost and the pass never converged. That affects label and banner rows with no assignment row involved.Verified against the pre-change binary over 900 system headers and Rust sources, about 550k lines, at column limits 40, 60, 80 and 100. Five files differ at 80 and each is a mapping table the old binary had run together: the adler32 derivation in adler2, the write defaults in brlapi.h, the size definitions in nettle/ccm.h, the permission rows in xenstore.h, and two lines of literal example code in webp/decode.h. Preserved rows match their source bytes including the alignment indent, no comment word moves in any file, and the set of files whose second pass differs is unchanged. A 4000-case fuzz over an operator-heavy vocabulary and a 1500-case fuzz mixing multibyte characters with every operator byte, both run against the base binary for comparison, found no new non-convergence and no panics. Run handling is linear, measured at 3000, 10000 and 20000 rows in one comment, and the branch costs about 0.5% more instructions on real headers.
cargo testis 452 green, withcargo clippy --all-targetsandcargo fmt --checkclean, andcommentflow --checkon the changed files matches the base branch.Left as it stands: a run of two or more overlong rows keeps sitting over the column limit, the same way a table row or an indented code sample does, because a real mapping row cannot be wrapped without destroying the mapping. That boundary is pinned by a test rather than fixed. Two pre-existing issues found during validation are untouched here: a
/*-opener merge that does not converge, visible in two lz4 headers, and a quadratic prefix rescan inis_file_start_prefixthat a one-line conjunct reorder would fix, measured at 5% of instructions on real headers and 53% on comment-dense input.