Skip to content
Merged
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
26 changes: 16 additions & 10 deletions src/MarpToPptx.Pptx/Rendering/SyntaxHighlighter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ public static class SyntaxHighlighter
// Lazy so the registry is only initialised when syntax highlighting is first needed.
private static readonly Lazy<HighlightState?> _state = new(CreateState);

// TextMateSharp's Registry/SyncRegistry is not thread-safe: concurrent
// LoadGrammar calls for the same scope can race on Dictionary.Add and
// throw "An item with the same key has already been added". Serialize
// grammar loading through this lock.
// TextMateSharp's Registry/SyncRegistry and Grammar instances are not
// thread-safe. Concurrent LoadGrammar calls for the same scope can race
// on Dictionary.Add, and concurrent TokenizeLine calls on the same Grammar
// instance can corrupt its lazy-compiled pattern cache. Serialize all
// registry and grammar operations through this lock.
private static readonly object _grammarLock = new();

/// <summary>Returns <c>true</c> when <paramref name="language"/> has grammar support.</summary>
Expand Down Expand Up @@ -75,14 +76,13 @@ public static IReadOnlyList<IReadOnlyList<TokenizedRun>> Tokenize(string languag
var scopeName = state.Options.GetScopeByLanguageId(canonicalId);
if (scopeName is not null)
{
IGrammar? grammar;
lock (_grammarLock)
{
grammar = state.Registry.LoadGrammar(scopeName);
}
if (grammar is not null)
{
return TokenizeWithGrammar(code, grammar, state.Theme);
var grammar = state.Registry.LoadGrammar(scopeName);
if (grammar is not null)
{
return TokenizeWithGrammar(code, grammar, state.Theme);
}
}
}
}
Expand All @@ -99,6 +99,12 @@ private static IReadOnlyList<IReadOnlyList<TokenizedRun>> TokenizeWithGrammar(st
foreach (var line in lines)
{
var lineResult = grammar.TokenizeLine(new LineText(line), ruleStack, TimeSpan.FromSeconds(5));
if (lineResult is null)
{
ruleStack = null;
result.Add([new TokenizedRun(line, null)]);
continue;
}
Comment thread
Copilot marked this conversation as resolved.
ruleStack = lineResult.RuleStack;
result.Add(BuildRuns(line, lineResult.Tokens, theme));
}
Expand Down