Skip to content

Commit

Permalink
Add rendering thread option
Browse files Browse the repository at this point in the history
  • Loading branch information
LiYanan2004 committed Jun 3, 2024
1 parent 34d4ee3 commit 763936e
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 27 deletions.
25 changes: 25 additions & 0 deletions Sources/MarkdownView/Helper/ContentUpdater.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,30 @@ struct MarkdownRenderingModeKey: EnvironmentKey {
static var defaultValue: MarkdownRenderingMode = .immediate
}

/// Thread to render markdown content on.
public enum MarkdownRenderingThread {
/// Render & Update markdown content on main thread.
case main
/// Render markdown content on background thread, while updating view on main thread.
case background
}

struct MarkdownRenderingThreadKey: EnvironmentKey {
static var defaultValue: MarkdownRenderingThread = .background
}

extension EnvironmentValues {
/// Markdown rendering mode
var markdownRenderingMode: MarkdownRenderingMode {
get { self[MarkdownRenderingModeKey.self] }
set { self[MarkdownRenderingModeKey.self] = newValue }
}

/// Markdown rendering thread
var markdownRenderingThread: MarkdownRenderingThread {
get { self[MarkdownRenderingThreadKey.self] }
set { self[MarkdownRenderingThreadKey.self] = newValue }
}
}

// MARK: - Markdown Rendering Mode
Expand All @@ -56,4 +74,11 @@ extension View {
public func markdownRenderingMode(_ renderingMode: MarkdownRenderingMode) -> some View {
environment(\.markdownRenderingMode, renderingMode)
}

/// The thread to render content.
///
/// - Parameter thread: The thread for rendering markdown content on.
public func markdownRenderingThread(_ thread: MarkdownRenderingThread) -> some View {
environment(\.markdownRenderingThread, thread)
}
}
59 changes: 32 additions & 27 deletions Sources/MarkdownView/MarkdownView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public struct MarkdownView: View {
@State private var scrollViewRef = ScrollProxyRef.shared

@Environment(\.markdownRenderingMode) private var renderingMode
@Environment(\.markdownRenderingThread) private var renderingThread
@Environment(\.lineSpacing) private var lineSpacing
@Environment(\.fontGroup) private var fontGroup
@Environment(\.markdownViewRole) private var role
Expand Down Expand Up @@ -53,28 +54,32 @@ public struct MarkdownView: View {

public var body: some View {
ScrollViewReader { scrollProxy in
ZStack {
switch configuration.role {
case .normal: representedView
case .editor:
representedView
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
if renderingThread == .main {
_makeView(text: text)
} else {
ZStack {
switch configuration.role {
case .normal: representedView
case .editor:
representedView
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}
.onAppear { scrollViewRef.proxy = scrollProxy }
}
.onAppear { scrollViewRef.proxy = scrollProxy }
}
.sizeOfView($viewSize)
.containerSize(viewSize)
.updateCodeBlocksWhenColorSchemeChanges()
.font(fontGroup.body) // Default font
.if(renderingMode == .optimized) { content in
.if(renderingMode == .optimized && renderingThread == .background) { content in
content
// Received a debouncedText, we need to reload MarkdownView.
.onReceive(contentUpdater.textUpdater, perform: makeView(text:))
// Push current text, waiting for next update.
.onChange(of: text, perform: contentUpdater.push(_:))
}
.if(renderingMode == .immediate) { content in
.if(renderingMode == .immediate && renderingThread == .background) { content in
content
// Immediately update MarkdownView when text changes.
.onChange(of: text, perform: makeView(text:))
Expand All @@ -86,26 +91,26 @@ public struct MarkdownView: View {
}

private func makeView(text: String) {
func view() -> AnyView {
var renderer = Renderer(
text: text,
configuration: configuration,
interactiveEditHandler: { text in
Task { @MainActor in
self.text = text
self.makeView(text: text)
}
},
blockDirectiveRenderer: blockDirectiveRenderer,
imageRenderer: imageRenderer
)
let parseBD = !blockDirectiveRenderer.providers.isEmpty
return renderer.representedView(parseBlockDirectives: parseBD)
}

representedView = view()
representedView = _makeView(text: text)
MarkdownTextStorage.default.text = text
}

private func _makeView(text: String) -> AnyView {
var renderer = Renderer(
text: text,
configuration: configuration,
interactiveEditHandler: { text in
Task { @MainActor in
self.text = text
self.makeView(text: text)
}
},
blockDirectiveRenderer: blockDirectiveRenderer,
imageRenderer: imageRenderer
)
let parseBD = !blockDirectiveRenderer.providers.isEmpty
return renderer.representedView(parseBlockDirectives: parseBD)
}
}

extension MarkdownView {
Expand Down

0 comments on commit 763936e

Please sign in to comment.