Skip to content

Commit fd257ca

Browse files
Added custom inline nodes support
1 parent a9c7615 commit fd257ca

File tree

11 files changed

+223
-51
lines changed

11 files changed

+223
-51
lines changed

Package.resolved

Lines changed: 31 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
// swift-tools-version:5.6
1+
// swift-tools-version:5.7
22

33
import PackageDescription
44

55
let package = Package(
66
name: "swift-markdown-ui",
77
platforms: [
88
.macOS(.v12),
9-
.iOS(.v15),
9+
.iOS(.v16),
1010
.tvOS(.v15),
1111
.macCatalyst(.v15),
1212
.watchOS(.v8),
@@ -15,19 +15,19 @@ let package = Package(
1515
.library(
1616
name: "MarkdownUI",
1717
targets: ["MarkdownUI"]
18-
)
18+
),
1919
],
2020
dependencies: [
2121
.package(url: "https://github.com/gonzalezreal/NetworkImage", from: "6.0.0"),
2222
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.10.0"),
23-
.package(url: "https://github.com/swiftlang/swift-cmark", from: "0.4.0"),
23+
.package(id: "spm-external.cmark-gfm", exact: "0.5.0+3ccff77b2dc5b96b77db3da0d68d28068593fa53"),
2424
],
2525
targets: [
2626
.target(
2727
name: "MarkdownUI",
2828
dependencies: [
29-
.product(name: "cmark-gfm", package: "swift-cmark"),
30-
.product(name: "cmark-gfm-extensions", package: "swift-cmark"),
29+
.product(name: "cmark-gfm", package: "spm-external.cmark-gfm"),
30+
.product(name: "cmark-gfm-extensions", package: "spm-external.cmark-gfm"),
3131
.product(name: "NetworkImage", package: "NetworkImage"),
3232
]
3333
),

Sources/MarkdownUI/DSL/Blocks/MarkdownContent.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ public struct MarkdownContent: Equatable, MarkdownContentProtocol {
8787

8888
/// Creates a Markdown content value from a Markdown-formatted string.
8989
/// - Parameter markdown: A Markdown-formatted string.
90-
public init(_ markdown: String) {
91-
self.init(blocks: .init(markdown: markdown))
90+
public init(_ markdown: String, extensions: [CmarkExtension] = []) {
91+
self.init(blocks: .init(markdown: markdown, extensions: extensions))
9292
}
9393

9494
/// Creates a Markdown content value composed of any number of blocks.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// Describes extension to parse custom inline nodes in cmark.
2+
public struct CmarkExtension: Sendable {
3+
/// Extension name to pass to cmark
4+
public var name: String
5+
6+
/// Registers extension in cmark
7+
public var register: @Sendable () -> Void
8+
9+
/// Name to identify cmark node
10+
public var nodeName: String
11+
12+
/// This is pointer to `cmark_node`
13+
public var makeNode: @Sendable (UnsafeMutableRawPointer) -> CustomInline?
14+
15+
public init(
16+
name: String,
17+
register: @escaping @Sendable () -> Void,
18+
nodeName: String,
19+
makeNode: @escaping @Sendable (UnsafeMutableRawPointer) -> CustomInline?,
20+
) {
21+
self.name = name
22+
self.register = register
23+
self.nodeName = nodeName
24+
self.makeNode = makeNode
25+
}
26+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import SwiftUI
2+
3+
/// Describes custom inline node.
4+
/// As this is inline node, it is type erased to SwiftUI's `Text`
5+
/// to properly render inside surrounding text.
6+
public struct CustomInline: Hashable {
7+
/// Must uniquely identify renderers provided.
8+
/// Failure to do so will result in undefined behavior.
9+
public var id: String
10+
11+
/// Sync render must be as lightweight as possible.
12+
public var renderSync: @Sendable () -> Text
13+
14+
/// Optional async renderer for heavy operations like image render/load.
15+
public var renderAsync: (@Sendable () async -> Text)?
16+
17+
public init(
18+
id: String,
19+
renderSync: @escaping @Sendable () -> Text,
20+
renderAsync: (@Sendable () async -> Text)? = nil,
21+
) {
22+
self.id = id
23+
self.renderSync = renderSync
24+
self.renderAsync = renderAsync
25+
}
26+
27+
public static func == (lhs: CustomInline, rhs: CustomInline) -> Bool {
28+
lhs.id == rhs.id
29+
}
30+
31+
public func hash(into hasher: inout Hasher) {
32+
hasher.combine(self.id)
33+
}
34+
}

Sources/MarkdownUI/Parser/InlineNode.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ enum InlineNode: Hashable, Sendable {
1111
case strikethrough(children: [InlineNode])
1212
case link(destination: String, children: [InlineNode])
1313
case image(source: String, children: [InlineNode])
14+
case custom(CustomInline)
1415
}
1516

1617
extension InlineNode {

0 commit comments

Comments
 (0)