Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ Container directives from Markdown-it and GitHub-style alerts are extension synt
:::

> [!NOTE]
> GitHub alert syntax is included as another block quote extension. Unsupported renderers should display it as quoted text.
> GitHub alert syntax is included as another block quote extension. This should display with a colored bar and icon to the left.

> [!WARNING]
> Alerts with multiple paragraphs should still wrap and stream without corrupting following content.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,13 @@ 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] GitHub alerts (`> [!NOTE]`) — rendered as block quotes with icon and color

### Not yet supported

- [ ] Footnotes (`[^1]`)
- [ ] Highlight (`==text==`), superscript (`^x^`), subscript (`~x~`)
- [ ] Raw HTML (`<details>`, `<kbd>`, `<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
33 changes: 29 additions & 4 deletions Sources/MarkdownText/Block/BlockQuote+.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,43 @@ import SwiftUI
extension BlockQuote: BlockConvertible {
var quoteTypes: BlockQuoteType {
var finalQuoteTypes = [BlockQuoteType]()
var alertKind: BlockQuoteAlertKind?

for child in children {
if let inlineContainer = child as? InlineContainer {
// Use our custom extractPlainText method instead of the built-in plainText property
// to properly handle attachment citations
finalQuoteTypes.append(.text(inlineContainer.extractPlainText(removeHeading: false)))
let text = inlineContainer.extractPlainText(removeHeading: false)
if alertKind == nil, let (kind, rest) = Self.parseAlertTag(text) {
alertKind = kind
if !rest.isEmpty {
finalQuoteTypes.append(.text(rest, alertKind))
}
} else {
finalQuoteTypes.append(.text(text, alertKind))
}
} else if let blockQuoteContainer = child as? BlockQuote {
finalQuoteTypes.append(blockQuoteContainer.quoteTypes)
}
}

return .nested(finalQuoteTypes)
return .nested(finalQuoteTypes, alertKind)
}

/// Recognizes a leading GitHub-style `[!KIND]` alert marker, returning the
/// parsed kind and the remaining text with the marker stripped.
static func parseAlertTag(_ text: String) -> (kind: BlockQuoteAlertKind, rest: String)? {
guard text.hasPrefix("[!"),
let close = text.firstIndex(of: "]"),
close > text.index(text.startIndex, offsetBy: 2),
let kind = BlockQuoteAlertKind(rawValue: String(text[text.index(text.startIndex, offsetBy: 2)..<close]).lowercased())
else {
return nil
}

var rest = String(text[text.index(after: close)...])
if rest.hasPrefix(" ") {
rest.removeFirst()
}
return (kind, rest)
}

func convert(attributeContainer: NSAttributeContainer, config: MarkdownRenderConfig) -> MarkdownRenderable {
Expand Down
Loading