Commit ede847ef53

ede847ef533caabe59ee413b870879ff3728e31d

parent: 8c99ef194e

Unsigned

cmc <hello@cleberg.net> · 2026-07-16 00:29 UTC

fix: render code span contents literally

processInline protected allowlisted HTML tags before it handled code spans, so
a `<b>` written inside backticks was carried through as a live tag and applied
formatting instead of rendering as text. Every other inline pass ran against
code span contents for the same reason, so `**x**` in backticks was emitted as
bold.

Protect code spans first with their contents escaped, which takes them out of
reach of the tag, emphasis, and link passes.

Layout: unified · split

Hutch/Views/Repositories/ReadmeView.swift +13 −7
@@ -371,8 +371,21 @@ nonisolated func processInline(
371371) -> String {
372372
373373 var protectedFragments: [String: String] = [:]
374
375 // Code spans render their contents literally, so they have to be taken out of
376 // the text before any later pass can treat those contents as markup — the tag
377 // pass below would otherwise promote an allowlisted `<b>` into a live tag.
374378 var result = protectMatches(
375379 in: text,
380 pattern: #"`([^`]+)`"#,
381 protectedFragments: &protectedFragments
382 ) { match, nsText in
383 let code = nsText.substring(with: match.range(at: 1))
384 return "<code>\(escapeHTML(code))</code>"
385 }
386
387 result = protectMatches(
388 in: result,
376389 pattern: #"</?[A-Za-z][^>]*?>"#,
377390 protectedFragments: &protectedFragments
378391 ) { match, nsText in
@@ -438,13 +451,6 @@ nonisolated func processInline(
438451 with: "<em>$1</em>",
439452 options: .regularExpression
440453 )
441 // Inline code: `text`
442 result = result.replacingOccurrences(
443 of: #"`([^`]+)`"#,
444 with: "<code>$1</code>",
445 options: .regularExpression
446 )
447
448454 for (token, fragment) in protectedFragments {
449455 result = result.replacingOccurrences(of: token, with: fragment)
450456 }