Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,15 @@ The renderer targets the subset of CommonMark + GitHub-flavored Markdown that LL
- [x] Inline LaTeX math via `\( … \)`
- [x] Display LaTeX math via `$$ … $$`
- [x] Inline citation pills
- [x] Inline HTML formatting tags — `<br>`, `<b>`/`<strong>`, `<i>`/`<em>`, `<s>`/`<del>`/`<strike>`, `<u>`/`<ins>`, `<mark>`, `<sub>`/`<sup>`, `<code>`/`<kbd>`/`<samp>`/`<tt>`, `<a href>`, `<wbr>` (comments are dropped; unsupported or unmatched tags render as literal text)
- [x] Highlight (`==text==`)
- [x] Superscript (`^x^`)

### Not yet supported

- [ ] Footnotes (`[^1]`)
- [ ] Highlight (`==text==`), superscript (`^x^`), subscript (`~x~`)
- [ ] Raw HTML (`<details>`, `<kbd>`, `<aside>`, …) — kept inline as text
- [ ] Subscript — the `<sub>` tag renders it; `~x~` stays strikethrough per GFM (cmark treats single `~` as strike)
- [ ] Block-level raw HTML (`<details>`, `<aside>`, …) — kept inline as text
- [ ] GitHub alerts (`> [!NOTE]`) — rendered as plain block quotes
- [ ] Container directives (`::: warning … :::`) and admonitions (`!!! note`)
- [ ] Mermaid / PlantUML diagrams — rendered as fenced code
Expand Down
45 changes: 45 additions & 0 deletions Sources/MarkdownText/Inline/Markdown+InlineConvertible.swift
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,51 @@ extension Markdown.InlineCode: InlineConvertible {
}
}

extension Markdown.InlineAttributes: InlineConvertible {

/// Attribute keys this renderer understands inside `attributes`. Produced by
/// `InlineHTMLRewriter` for tags that have no dedicated Markdown node
/// (`<u>`/`<ins>`, `<mark>`, `<sub>`, `<sup>`).
private static let enabledKeyRegex = try? Regex(#"(?:^|[,{}\s])([a-zA-Z]+)\s*:\s*true\b"#)

private var enabledKeys: Set<String> {
guard let regex = Self.enabledKeyRegex else { return [] }
var keys = Set<String>()
for match in attributes.matches(of: regex) {
if let key = match.output[1].substring {
keys.insert(String(key))
}
}
return keys
}

func convert(attributeContainer: NSAttributeContainer, config: MarkdownRenderConfig) -> NSMutableAttributedString {
var container = attributeContainer
let font = attributeContainer[.font] as? MDFont ?? config.paragraphStyle.textFonts.normal
let keys = enabledKeys
if keys.contains("subscript") {
container[.font] = font.scaled(by: 0.75)
container[.baselineOffset] = -font.pointSize * 0.2
}
if keys.contains("superscript") {
container[.font] = font.scaled(by: 0.75)
container[.baselineOffset] = font.pointSize * 0.35
}
if keys.contains("underline") {
container[.underlineStyle] = NSUnderlineStyle.single.rawValue
container[.underlineColor] = container[.foregroundColor]
}
if keys.contains("highlight") {
container[.backgroundColor] = MDColor.systemYellow.withAlphaComponent(0.45)
}
let str = NSMutableAttributedString()
self.inlineConvertibleChildren.forEach { convertible in
str.append(convertible.convert(attributeContainer: container, config: config))
}
return str
}
}

extension Markdown.Table.Cell: InlineConvertible {

func convert(attributeContainer: NSAttributeContainer, config: MarkdownRenderConfig) -> NSMutableAttributedString {
Expand Down
18 changes: 18 additions & 0 deletions Sources/MarkdownText/Parser/MarkdownParserImpl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public final class MarkdownParserImpl: MarkdownParser {
PartialTableMarkupPostParsingRewriter()
]

private let inlineHTMLRewriter = InlineHTMLMarkupPostParsingRewriter()

private let delimiterRewriter = InlineDelimiterMarkupPostParsingRewriter()

private let imageBlockRewriter = ImageBlockMarkupPostParsingRewriter()

private let latexPreprocessor: LaTexPreProcessor
Expand All @@ -39,6 +43,20 @@ public final class MarkdownParserImpl: MarkdownParser {
}
}

if let rewrittenDoc = inlineHTMLRewriter.rewriteIfApplicable(document: result.document) {
result = MarkdownParseResult(
document: rewrittenDoc,
speculativeRewritten: result.speculativeRewritten
)
}

if let rewrittenDoc = delimiterRewriter.rewriteIfApplicable(document: result.document) {
result = MarkdownParseResult(
document: rewrittenDoc,
speculativeRewritten: result.speculativeRewritten
)
}

if option.imageSupport {
if let rewrittenDoc = imageBlockRewriter.rewriteIfApplicable(document: result.document) {
result = MarkdownParseResult(
Expand Down
Loading