Skip to content

Skip code spans anywhere in a table cell, not just at its start - #364

Merged
kjk merged 1 commit into
gomarkdown:masterfrom
youdie006:table-row-codespan
Sep 16, 2026
Merged

kjk merged 1 commit into
gomarkdown:masterfrom
youdie006:table-row-codespan

Conversation

@youdie006

Copy link
Copy Markdown
Contributor

tableRow runs its code-span check once, before the scan loop (parser/block_table.go:32-37), so it only fires when a cell starts with a backtick. tableFooter (:97-103) and tableHeader (:140-146) run the identical check, comment and all, inside their scan loops.

So a cell whose code span starts anywhere but the first character is split at the pipe inside it, and the last cell is dropped because the column count came from the header:

| h1 | h2 |
| --- | --- |
| x`|`y | z |
<td>x`</td>
<td>`y</td>     <!-- and z is gone -->

tableHeader only counts columns; it hands the header line to tableRow to split (:278), so header rows are affected the same way.

This moves the check into the loop. The i < n guard goes away because the loop condition already asserts it.

The behaviour was added in #217, whose body says "Check for a codespan in the table (header, row or footer) and simply skip to the end of it and resume scanning" - header and footer resume, the row never did. Every golden that PR added puts the code span at the start of a cell, which is why this survived. #195 is the original request.

Verification

go test -count=1 -run 'TestTable$' ., Go 1.26.3. md5sum parser/block_table.go on every row.

parser/block_table.go md5 result
this PR 2389f3e8 pass
pristine HEAD f2994f1a 3 failures, one per new golden
check moved back outside the loop b8f6a10e 3 failures
i += isCode instead of i += isCode - 1 9a956f46 1 failure
drop the data[i] == ''` fast path fe3a27d8 pass, equivalent
'`' to '~' 363b04be 7 failures

The i += isCode row only dies on the third golden, | x`|`| z |. With the first two the byte after the code span is ordinary text, so both forms stop at the same pipe; the two disagree only when that byte is the delimiter.

The fast-path row is a genuine equivalent mutant. For a non-backtick byte codeSpan sets nb = 0 (parser/inline.go:135), the delimiter loop never runs, and fBegin == fEnd == 0 returns 0 at parser/inline.go:180-181, so isCode > 0 is false either way. The guard saves a call per byte, and tableHeader/tableFooter both keep it.

Goldens go in testdata/Table.tests, which is where #217 put its own.

Gates as .github/workflows/go.yml runs them: go test . ./ast ./parser ./html all ok, go test -bench=BenchmarkReference -benchmem passes. Not run: CI pins Go 1.18.x and this box has 1.26.3 only.

Disclosure: this change was written with AI assistance (Claude). The measurements above were reproduced and checked by me before opening this PR.

tableRow ran the code-span check once before its scan loop, so it only
fired when a cell began with a backtick. tableHeader and tableFooter run
the same check inside their scan loops. A cell whose code span starts
later was split at the pipe inside it, and because the column count came
from the header, the last cell was dropped.

tableHeader only counts columns; it hands the header line to tableRow to
split, so header rows were affected too.

Move the check into the loop, matching the other two. The i < n guard
goes away because the loop condition already asserts it.
@kjk
kjk merged commit f785043 into gomarkdown:master Sep 16, 2026
1 check passed
@kjk

kjk commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants