Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update view on input changes #28

Merged
merged 2 commits into from
Mar 6, 2024
Merged
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
6 changes: 4 additions & 2 deletions Sources/LaTeXSwiftUI/LaTeX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public struct LaTeX: View {
// MARK: Private properties

/// The view's renderer.
@StateObject private var renderer: Renderer
@StateObject private var renderer = Renderer()

/// The view's preload task, if any.
@State private var preloadTask: Task<(), Never>?
Expand All @@ -171,7 +171,6 @@ public struct LaTeX: View {
/// - Parameter latex: The LaTeX input.
public init(_ latex: String) {
self.latex = latex
_renderer = StateObject(wrappedValue: Renderer(latex: latex))
}

// MARK: View body
Expand Down Expand Up @@ -239,6 +238,7 @@ extension LaTeX {
/// cached.
private func isCached() -> Bool {
renderer.isCached(
latex: latex,
unencodeHTML: unencodeHTML,
parsingMode: parsingMode,
processEscapes: processEscapes,
Expand All @@ -250,6 +250,7 @@ extension LaTeX {
/// Renders the view's components.
@Sendable private func renderAsync() async {
await renderer.render(
latex: latex,
unencodeHTML: unencodeHTML,
parsingMode: parsingMode,
processEscapes: processEscapes,
Expand All @@ -263,6 +264,7 @@ extension LaTeX {
/// - Returns: The rendered components.
private func renderSync() -> [ComponentBlock] {
renderer.renderSync(
latex: latex,
unencodeHTML: unencodeHTML,
parsingMode: parsingMode,
processEscapes: processEscapes,
Expand Down
52 changes: 33 additions & 19 deletions Sources/LaTeXSwiftUI/Models/Renderer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,22 @@ import Cocoa
/// values.
internal class Renderer: ObservableObject {

// MARK: Public properties
// MARK: Types

/// A set of values used to create an array of parsed component blocks.
struct ParsingSource: Equatable {

/// The LaTeX input.
let latex: String

/// Whether or not the HTML should be unencoded.
let unencodeHTML: Bool

/// The parsing mode.
let parsingMode: LaTeX.ParsingMode
}

/// The view's input string.
let latex: String
// MARK: Public properties

/// Whether or not the view's blocks have been rendered.
@MainActor @Published var rendered: Bool = false
Expand All @@ -57,18 +69,12 @@ internal class Renderer: ObservableObject {
/// The LaTeX input's parsed blocks.
private var _parsedBlocks: [ComponentBlock]? = nil

/// The set of values used to create the parsed blocks.
private var _parsingSource: ParsingSource? = nil

/// Semaphore for thread-safe access to `_parsedBlocks`.
private var _parsedBlocksSemaphore = DispatchSemaphore(value: 1)

// MARK: Initializers

/// Initializes a render state with an input string.
///
/// - Parameter latex: The view's input string.
init(latex: String) {
self.latex = latex
}

}

// MARK: Public methods
Expand All @@ -78,14 +84,15 @@ extension Renderer {
/// Returns whether the view's components are cached.
///
/// - Parameters:
/// - latex: The LaTeX input string.
/// - unencodeHTML: The `unencodeHTML` environment variable.
/// - parsingMode: The `parsingMode` environment variable.
/// - processEscapes: The `processEscapes` environment variable.
/// - errorMode: The `errorMode` environment variable.
/// - font: The `font environment` variable.
/// - displayScale: The `displayScale` environment variable.
/// - texOptions: The `texOptions` environment variable.
func isCached(
latex: String,
unencodeHTML: Bool,
parsingMode: LaTeX.ParsingMode,
processEscapes: Bool,
Expand All @@ -95,7 +102,7 @@ extension Renderer {
) -> Bool {
let texOptions = TeXInputProcessorOptions(processEscapes: processEscapes, errorMode: errorMode)
return blocksExistInCache(
parsedBlocks(unencodeHTML: unencodeHTML, parsingMode: parsingMode),
parsedBlocks(latex: latex, unencodeHTML: unencodeHTML, parsingMode: parsingMode),
font: font,
displayScale: displayScale,
texOptions: texOptions)
Expand All @@ -104,14 +111,15 @@ extension Renderer {
/// Renders the view's components synchronously.
///
/// - Parameters:
/// - latex: The LaTeX input string.
/// - unencodeHTML: The `unencodeHTML` environment variable.
/// - parsingMode: The `parsingMode` environment variable.
/// - processEscapes: The `processEscapes` environment variable.
/// - errorMode: The `errorMode` environment variable.
/// - font: The `font environment` variable.
/// - displayScale: The `displayScale` environment variable.
/// - texOptions: The `texOptions` environment variable.
func renderSync(
latex: String,
unencodeHTML: Bool,
parsingMode: LaTeX.ParsingMode,
processEscapes: Bool,
Expand All @@ -121,7 +129,7 @@ extension Renderer {
) -> [ComponentBlock] {
let texOptions = TeXInputProcessorOptions(processEscapes: processEscapes, errorMode: errorMode)
return render(
blocks: parsedBlocks(unencodeHTML: unencodeHTML, parsingMode: parsingMode),
blocks: parsedBlocks(latex: latex, unencodeHTML: unencodeHTML, parsingMode: parsingMode),
font: font,
displayScale: displayScale,
texOptions: texOptions)
Expand All @@ -130,14 +138,15 @@ extension Renderer {
/// Renders the view's components asynchronously.
///
/// - Parameters:
/// - latex: The LaTeX input string.
/// - unencodeHTML: The `unencodeHTML` environment variable.
/// - parsingMode: The `parsingMode` environment variable.
/// - processEscapes: The `processEscapes` environment variable.
/// - errorMode: The `errorMode` environment variable.
/// - font: The `font environment` variable.
/// - displayScale: The `displayScale` environment variable.
/// - texOptions: The `texOptions` environment variable.
func render(
latex: String,
unencodeHTML: Bool,
parsingMode: LaTeX.ParsingMode,
processEscapes: Bool,
Expand All @@ -156,7 +165,7 @@ extension Renderer {

let texOptions = TeXInputProcessorOptions(processEscapes: processEscapes, errorMode: errorMode)
let renderedBlocks = await render(
blocks: parsedBlocks(unencodeHTML: unencodeHTML, parsingMode: parsingMode),
blocks: parsedBlocks(latex: latex, unencodeHTML: unencodeHTML, parsingMode: parsingMode),
font: font,
displayScale: displayScale,
texOptions: texOptions)
Expand Down Expand Up @@ -313,21 +322,26 @@ extension Renderer {
/// Gets the LaTeX input's parsed blocks.
///
/// - Parameters:
/// - latex: The LaTeX input string.
/// - unencodeHTML: The `unencodeHTML` environment variable.
/// - parsingMode: The `parsingMode` environment variable.
/// - Returns: The parsed blocks.
private func parsedBlocks(
latex: String,
unencodeHTML: Bool,
parsingMode: LaTeX.ParsingMode
) -> [ComponentBlock] {
_parsedBlocksSemaphore.wait()
defer { _parsedBlocksSemaphore.signal() }
if let _parsedBlocks {

let currentSource = ParsingSource(latex: latex, unencodeHTML: unencodeHTML, parsingMode: parsingMode)
if let _parsedBlocks, _parsingSource == currentSource {
return _parsedBlocks
}

let blocks = Parser.parse(unencodeHTML ? latex.htmlUnescape() : latex, mode: parsingMode)
_parsedBlocks = blocks
_parsingSource = currentSource
return blocks
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/LaTeXSwiftUI/Views/ComponentBlockText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,6 @@ struct ComponentBlockTextPreviews: PreviewProvider {
static var previews: some View {
ComponentBlockText(block: ComponentBlock(components: [
Component(text: "Hello, World!", type: .text)
]), renderer: Renderer(latex: "Hello, World!"))
]), renderer: Renderer())
}
}
2 changes: 1 addition & 1 deletion Sources/LaTeXSwiftUI/Views/ComponentBlocksText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ struct ComponentBlocksTextPreviews: PreviewProvider {
ComponentBlocksText(blocks: [ComponentBlock(components: [
Component(text: "Hello, World!", type: .text)
])], forceInline: false)
.environmentObject(Renderer(latex: "Hello, World!"))
.environmentObject(Renderer())
}
}
2 changes: 1 addition & 1 deletion Sources/LaTeXSwiftUI/Views/ComponentBlocksViews.swift
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,6 @@ struct ComponentBlocksViewsPreviews: PreviewProvider {
ComponentBlocksViews(blocks: [ComponentBlock(components: [
Component(text: "Hello, World!", type: .text)
])])
.environmentObject(Renderer(latex: "Hello, World!"))
.environmentObject(Renderer())
}
}
Loading