From b6060e34f55fb102018b54c593a1b93219a72e8d Mon Sep 17 00:00:00 2001 From: Matt Parker <61717342+MattParkerDev@users.noreply.github.com> Date: Fri, 17 Oct 2025 22:17:14 +1000 Subject: [PATCH] refactor diagnostic v2 --- .../Features/Analysis/RoslynAnalysis.cs | 8 ++++---- .../Features/Analysis/SharpIdeClassifiedSpan.cs | 6 ++++++ .../CodeEditor/CustomSyntaxHighlighter.cs | 15 ++++++++------- .../Features/CodeEditor/SharpIdeCodeEdit.cs | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) create mode 100644 src/SharpIDE.Application/Features/Analysis/SharpIdeClassifiedSpan.cs diff --git a/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs b/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs index f51db5f..b0cd2c1 100644 --- a/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs +++ b/src/SharpIDE.Application/Features/Analysis/RoslynAnalysis.cs @@ -294,7 +294,7 @@ public static class RoslynAnalysis return diagnostics; } - public static async Task> GetDocumentDiagnostics(SharpIdeFile fileModel, CancellationToken cancellationToken = default) + public static async Task> GetDocumentDiagnostics(SharpIdeFile fileModel, CancellationToken cancellationToken = default) { if (fileModel.IsRoslynWorkspaceFile is false) return []; using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(GetDocumentDiagnostics)}"); @@ -308,7 +308,7 @@ public static class RoslynAnalysis var diagnostics = semanticModel.GetDiagnostics(cancellationToken: cancellationToken); diagnostics = diagnostics.Where(d => d.Severity is not DiagnosticSeverity.Hidden).ToImmutableArray(); - var result = diagnostics.Select(d => (semanticModel.SyntaxTree.GetMappedLineSpan(d.Location.SourceSpan), d)).ToImmutableArray(); + var result = diagnostics.Select(d => new SharpIdeDiagnostic(semanticModel.SyntaxTree.GetMappedLineSpan(d.Location.SourceSpan).Span, d)).ToImmutableArray(); return result; } @@ -441,7 +441,7 @@ public static class RoslynAnalysis } // This is expensive for files that have just been updated, making it suboptimal for real-time highlighting - public static async Task> GetDocumentSyntaxHighlighting(SharpIdeFile fileModel, CancellationToken cancellationToken = default) + public static async Task> GetDocumentSyntaxHighlighting(SharpIdeFile fileModel, CancellationToken cancellationToken = default) { using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(GetDocumentSyntaxHighlighting)}"); await _solutionLoadedTcs.Task; @@ -459,7 +459,7 @@ public static class RoslynAnalysis var root = await syntaxTree!.GetRootAsync(cancellationToken); var classifiedSpans = await Classifier.GetClassifiedSpansAsync(document, root.FullSpan, cancellationToken); - var result = classifiedSpans.Select(s => (syntaxTree.GetMappedLineSpan(s.TextSpan), s)).ToList(); + var result = classifiedSpans.Select(s => new SharpIdeClassifiedSpan(syntaxTree.GetMappedLineSpan(s.TextSpan).Span, s)).ToList(); return result; } diff --git a/src/SharpIDE.Application/Features/Analysis/SharpIdeClassifiedSpan.cs b/src/SharpIDE.Application/Features/Analysis/SharpIdeClassifiedSpan.cs new file mode 100644 index 0000000..0c5ecf5 --- /dev/null +++ b/src/SharpIDE.Application/Features/Analysis/SharpIdeClassifiedSpan.cs @@ -0,0 +1,6 @@ +using Microsoft.CodeAnalysis.Classification; +using Microsoft.CodeAnalysis.Text; + +namespace SharpIDE.Application.Features.Analysis; + +public readonly record struct SharpIdeClassifiedSpan(LinePositionSpan FileSpan, ClassifiedSpan ClassifiedSpan); diff --git a/src/SharpIDE.Godot/Features/CodeEditor/CustomSyntaxHighlighter.cs b/src/SharpIDE.Godot/Features/CodeEditor/CustomSyntaxHighlighter.cs index e979ce9..34545ac 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/CustomSyntaxHighlighter.cs +++ b/src/SharpIDE.Godot/Features/CodeEditor/CustomSyntaxHighlighter.cs @@ -3,6 +3,7 @@ using Godot; using Godot.Collections; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Classification; +using SharpIDE.Application.Features.Analysis; using SharpIDE.Godot.Features.CodeEditor; using SharpIDE.RazorAccess; @@ -13,10 +14,10 @@ public partial class CustomHighlighter : SyntaxHighlighter private readonly Dictionary _emptyDict = new(); private System.Collections.Generic.Dictionary> _razorClassifiedSpansByLine = []; - private System.Collections.Generic.Dictionary> _classifiedSpansByLine = []; + private System.Collections.Generic.Dictionary> _classifiedSpansByLine = []; - public void SetHighlightingData(IEnumerable<(FileLinePositionSpan fileSpan, ClassifiedSpan classifiedSpan)> classifiedSpans, IEnumerable razorClassifiedSpans) + public void SetHighlightingData(IEnumerable classifiedSpans, IEnumerable razorClassifiedSpans) { // separate each line here var razorSpansForLine = razorClassifiedSpans @@ -26,8 +27,8 @@ public partial class CustomHighlighter : SyntaxHighlighter _razorClassifiedSpansByLine = razorSpansForLine.ToDictionary(g => g.Key, g => g.ToImmutableArray()); var spansGroupedByFileSpan = classifiedSpans - .Where(s => s.classifiedSpan.TextSpan.Length is not 0) - .GroupBy(span => span.fileSpan.StartLinePosition.Line) + .Where(s => s.ClassifiedSpan.TextSpan.Length is not 0) + .GroupBy(span => span.FileSpan.Start.Line) .ToList(); _classifiedSpansByLine = spansGroupedByFileSpan.ToDictionary(g => g.Key, g => g.ToImmutableArray()); } @@ -195,8 +196,8 @@ public partial class CustomHighlighter : SyntaxHighlighter // consider no linq or ZLinq // group by span (start, length matches) var spansGroupedByFileSpan = spansForLine - .GroupBy(span => span.fileSpan) - .Select(group => (fileSpan: group.Key, classifiedSpans: group.Select(s => s.classifiedSpan).ToList())); + .GroupBy(span => span.FileSpan) + .Select(group => (fileSpan: group.Key, classifiedSpans: group.Select(s => s.ClassifiedSpan).ToList())); foreach (var (fileSpan, classifiedSpans) in spansGroupedByFileSpan) { @@ -207,7 +208,7 @@ public partial class CustomHighlighter : SyntaxHighlighter if (staticClassifiedSpan is not null) classifiedSpans.Remove(staticClassifiedSpan.Value); } // Column index of the first character in this span - int columnIndex = fileSpan.StartLinePosition.Character; + int columnIndex = fileSpan.Start.Character; // Build the highlight entry var highlightInfo = new Dictionary diff --git a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs index acfe17f..8f64461 100644 --- a/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs +++ b/src/SharpIDE.Godot/Features/CodeEditor/SharpIdeCodeEdit.cs @@ -454,7 +454,7 @@ public partial class SharpIdeCodeEdit : CodeEdit } [RequiresGodotUiThread] - private void SetSyntaxHighlightingModel(IEnumerable<(FileLinePositionSpan fileSpan, ClassifiedSpan classifiedSpan)> classifiedSpans, IEnumerable razorClassifiedSpans) + private void SetSyntaxHighlightingModel(IEnumerable classifiedSpans, IEnumerable razorClassifiedSpans) { _syntaxHighlighter.SetHighlightingData(classifiedSpans, razorClassifiedSpans); //_syntaxHighlighter.ClearHighlightingCache();