Map bare autolinks from their end, not their start column - #11
Merged
Merged
Conversation
cmark's GFM autolink extension gets a bare URL's start wrong in two ways,
and its end right in both. Both are now handled by measuring back from the
end, which needs no knowledge of where the line began.
**Wrong by the length of the preceding lines.** The start is reported as an
offset into the paragraph's *content buffer*, not a column on its line. On a
single-line paragraph the two coincide to within one character, which is why
the `+1` adjustment looked right. After a soft line break the error grows:
"line one\na https://one.example.com and https://two.example.com b"
↑ column 3, reported as 12 ↑ column 31, reported as 40
Highlighting therefore painted a *suffix* of each URL — "ne.example.com" —
and left the front as plain text. Reported against 1.4.0 from a wrapped
paragraph holding two links.
**Missing entirely.** A URL that opens a paragraph is reported at column 0,
so `position(in:)` — all-or-nothing by design — mapped neither end, and the
URL went unhighlighted anywhere. Bare autolinks are now adjusted before that
check, and the end is mapped from its own line and column when needed.
The start is derived by walking back the length of the URL *as written in
the source*. The source length matters: GFM expands `www.example.com` to
`http://www.example.com`, so measuring the destination would walk back too
far.
The two text nodes around the link were wrong for the same reason and are
repaired with it — the autolink's own child takes the link's whole position,
and the run in front of it stops where the link starts. Where the URL opens
the line, cmark emits a leading text node with an *empty literal* whose span
cannot be clamped without inverting it; that one is left alone and documented.
`CI=true swift test`: 130 passed, 1 skipped.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #11 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 1 1
Lines 133 133
=========================================
Hits 133 133 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Follow-up to #10, reported against 1.4.0 from a wrapped paragraph holding two links: the second URL was highlighted from partway through —
e.comin the link colour,https://www.examplas plain text.cmark's GFM autolink extension gets a bare URL's start wrong in two different ways, and its end right in both. Both are now handled by measuring back from the end, which needs no knowledge of where the line began.
1. Wrong by the length of the preceding lines
The start is reported as an offset into the paragraph's content buffer, not a column on its line. On a single-line paragraph the two coincide to within one character — which is exactly why the
+1adjustment in #10 looked correct. After a soft line break the error grows by every byte of the preceding lines:https://one.example.com"line one"+ newline)https://two.example.comSo highlighting painted a suffix of each URL and left the front as plain text.
2. Missing entirely
A URL that opens a paragraph is reported at column 0.
position(in:)is all-or-nothing by design — it is used by every node type — so it mapped neither end, and the URL went unhighlighted anywhere. This was called out as a known gap in the 1.4.0 notes.Bare autolinks are now adjusted before that check, and the end is mapped from its own line and column when
position(in:)declined to.The fix
The start is derived by walking back the length of the URL as written in the source. The source length matters, and is pinned by a test: GFM expands
www.example.comtohttp://www.example.com, so measuring the destination would walk back too far.The two text nodes around the link were wrong for the same reason and are repaired with it — the autolink's own child takes the link's whole position, and the run in front of it stops where the link starts. Where the URL opens the line, cmark emits a leading text node with an empty literal whose span cannot be clamped without inverting it; that one is left alone and documented, since it carries no text and every consumer reads the literal rather than the span.
Tests
Tests/MarkdownSyntaxTests/BareAutolinkLineOffsetTests.swift— 14 cases: the reported two-links-on-a-wrapped-line shape, a URL alone on a later line, two bare links after a soft break, a link on line 5,www.expansion, both text-node repairs, paragraph-opening URLs (document-initial and later), and four that pin the single-line and inline/angle-link behaviour that was already right.CI=true swift test→ 130 passed, 1 skipped.🤖 Generated with Claude Code