From d44400070f82b6271a8576b077d8dd8ab3fbf8ff Mon Sep 17 00:00:00 2001 From: Daniel Rothmann Date: Sun, 15 Mar 2026 22:01:27 +0100 Subject: [PATCH 1/2] Convert code to owned string before async tokenisation --- .../Internal/Highlighter/HighlightedTextFragment.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/Textual/Internal/Highlighter/HighlightedTextFragment.swift b/Sources/Textual/Internal/Highlighter/HighlightedTextFragment.swift index 7d44068d..d9527555 100644 --- a/Sources/Textual/Internal/Highlighter/HighlightedTextFragment.swift +++ b/Sources/Textual/Internal/Highlighter/HighlightedTextFragment.swift @@ -29,13 +29,13 @@ struct HighlightedTextFragment: View { } var body: some View { + // Convert to an owned String before the async boundary + let code = String(content.characters[...]) + TextFragment(model.highlightedCode ?? AttributedString(content)) .foregroundStyle(theme.foregroundColor) - .task(id: content) { - await model.tokenize( - content: content, - languageHint: languageHint - ) + .task(id: code) { + await model.tokenize(code: code, languageHint: languageHint, theme: theme) } .onChange(of: Tuple(model.tokens, textEnvironment)) { _, newValue in model.highlight( From 4b284b314c53a9e4e06639aefcd0add60bc093f4 Mon Sep 17 00:00:00 2001 From: Daniel Rothmann Date: Sun, 15 Mar 2026 22:01:43 +0100 Subject: [PATCH 2/2] Skip code tokenisation if there is no theme to apply --- .../Internal/Highlighter/HighlightedTextFragment.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Sources/Textual/Internal/Highlighter/HighlightedTextFragment.swift b/Sources/Textual/Internal/Highlighter/HighlightedTextFragment.swift index d9527555..4483b3c9 100644 --- a/Sources/Textual/Internal/Highlighter/HighlightedTextFragment.swift +++ b/Sources/Textual/Internal/Highlighter/HighlightedTextFragment.swift @@ -53,11 +53,12 @@ extension HighlightedTextFragment { var tokens: [CodeToken] = [] var highlightedCode: AttributedString? - func tokenize(content: AttributedSubstring, languageHint: String?) async { - let code = String(content.characters[...]) + func tokenize(code: String, languageHint: String?, theme: StructuredText.HighlighterTheme) async { tokens = [CodeToken(content: code, type: .plain)] - if let tokenizer = CodeTokenizer.shared, let languageHint { + // Skip the expensive tokenizer when the theme has no token properties + if !theme.tokenProperties.isEmpty, + let tokenizer = CodeTokenizer.shared, let languageHint { tokens = await tokenizer.tokenize(code: code, language: languageHint) } }