document syntax highlighting
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Ardalis.GuardClauses;
|
using Ardalis.GuardClauses;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Classification;
|
||||||
using Microsoft.CodeAnalysis.CodeActions;
|
using Microsoft.CodeAnalysis.CodeActions;
|
||||||
using Microsoft.CodeAnalysis.CodeFixes;
|
using Microsoft.CodeAnalysis.CodeFixes;
|
||||||
using Microsoft.CodeAnalysis.CodeRefactorings;
|
using Microsoft.CodeAnalysis.CodeRefactorings;
|
||||||
@@ -143,6 +144,23 @@ public static class RoslynAnalysis
|
|||||||
return diagnostics;
|
return diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<IEnumerable<(FileLinePositionSpan fileSpan, ClassifiedSpan classifiedSpan)>> GetDocumentSyntaxHighlighting(SharpIdeFile fileModel)
|
||||||
|
{
|
||||||
|
await _solutionLoadedTcs.Task;
|
||||||
|
var cancellationToken = CancellationToken.None;
|
||||||
|
var project = _workspace!.CurrentSolution.Projects.Single(s => s.FilePath == ((IChildSharpIdeNode)fileModel).GetNearestProjectNode()!.FilePath);
|
||||||
|
var document = project.Documents.Single(s => s.FilePath == fileModel.Path);
|
||||||
|
Guard.Against.Null(document, nameof(document));
|
||||||
|
|
||||||
|
var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken);
|
||||||
|
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));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task<ImmutableArray<CodeAction>> GetCodeFixesAsync(Diagnostic diagnostic)
|
public static async Task<ImmutableArray<CodeAction>> GetCodeFixesAsync(Diagnostic diagnostic)
|
||||||
{
|
{
|
||||||
var cancellationToken = CancellationToken.None;
|
var cancellationToken = CancellationToken.None;
|
||||||
|
|||||||
@@ -1,30 +1,87 @@
|
|||||||
using System.Linq;
|
using System.Collections.Generic;
|
||||||
using Godot;
|
using Godot;
|
||||||
using Godot.Collections;
|
using Godot.Collections;
|
||||||
using System.Text.RegularExpressions;
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Classification;
|
||||||
|
|
||||||
namespace SharpIDE.Godot;
|
namespace SharpIDE.Godot;
|
||||||
|
|
||||||
public partial class CustomHighlighter : SyntaxHighlighter
|
public partial class CustomHighlighter : SyntaxHighlighter
|
||||||
{
|
{
|
||||||
|
public IEnumerable<(FileLinePositionSpan fileSpan, ClassifiedSpan classifiedSpan)> ClassifiedSpans = [];
|
||||||
public override Dictionary _GetLineSyntaxHighlighting(int line)
|
public override Dictionary _GetLineSyntaxHighlighting(int line)
|
||||||
|
{
|
||||||
|
var highlights = MapClassifiedSpansToHighlights(line);
|
||||||
|
|
||||||
|
return highlights;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly StringName ColorStringName = "color";
|
||||||
|
private Dictionary MapClassifiedSpansToHighlights(int line)
|
||||||
{
|
{
|
||||||
var highlights = new Dictionary();
|
var highlights = new Dictionary();
|
||||||
var text = GetTextEdit().GetLine(line);
|
|
||||||
|
|
||||||
var regex = new Regex(@"\bTODO\b");
|
foreach (var (fileSpan, classifiedSpan) in ClassifiedSpans)
|
||||||
var matches = regex.Matches(text);
|
|
||||||
|
|
||||||
foreach (Match match in matches)
|
|
||||||
{
|
{
|
||||||
highlights[match.Index] = new Dictionary
|
// Only take spans on the requested line
|
||||||
|
if (fileSpan.StartLinePosition.Line != line)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (classifiedSpan.TextSpan.Length == 0)
|
||||||
|
continue; // Skip empty spans
|
||||||
|
|
||||||
|
// Column index of the first character in this span
|
||||||
|
int columnIndex = fileSpan.StartLinePosition.Character;
|
||||||
|
|
||||||
|
// Build the highlight entry
|
||||||
|
var highlightInfo = new Dictionary
|
||||||
{
|
{
|
||||||
{ "color", new Color(1, 0, 0) }, // red
|
{ ColorStringName, GetColorForClassification(classifiedSpan.ClassificationType) }
|
||||||
{ "underline", true }, // not implemented
|
|
||||||
{ "length", match.Length } // not implemented
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
highlights[columnIndex] = highlightInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
return highlights;
|
return highlights;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Color GetColorForClassification(string classificationType)
|
||||||
|
{
|
||||||
|
return classificationType switch
|
||||||
|
{
|
||||||
|
// Keywords
|
||||||
|
"keyword" => new Color("569cd6"),
|
||||||
|
"keyword - control" => new Color("569cd6"),
|
||||||
|
"preprocessor keyword" => new Color("569cd6"),
|
||||||
|
|
||||||
|
// Literals & comments
|
||||||
|
"string" => new Color("d69d85"),
|
||||||
|
"comment" => new Color("57a64a"),
|
||||||
|
"number" => new Color("b5cea8"),
|
||||||
|
|
||||||
|
// Types (User Types)
|
||||||
|
"class name" => new Color("4ec9b0"),
|
||||||
|
"struct name" => new Color("4ec9b0"),
|
||||||
|
"interface name" => new Color("b8d7a3"),
|
||||||
|
"namespace name" => new Color("dcdcdc"),
|
||||||
|
|
||||||
|
// Identifiers & members
|
||||||
|
"identifier" => new Color("dcdcdc"),
|
||||||
|
"method name" => new Color("dcdcaa"),
|
||||||
|
"extension method name" => new Color("dcdcaa"),
|
||||||
|
"property name" => new Color("dcdcdc"),
|
||||||
|
"static symbol" => new Color("dcdcdc"),
|
||||||
|
"parameter name" => new Color("9cdcfe"),
|
||||||
|
"local name" => new Color("9cdcfe"),
|
||||||
|
|
||||||
|
// Punctuation & operators
|
||||||
|
"operator" => new Color("dcdcdc"),
|
||||||
|
"punctuation" => new Color("dcdcdc"),
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
"excluded code" => new Color("a9a9a9"),
|
||||||
|
|
||||||
|
_ => new Color("dcdcdc")
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,11 @@ public partial class IdeRoot : Control
|
|||||||
var diFile = infraProject.Files.Single(s => s.Name == "DependencyInjection.cs");
|
var diFile = infraProject.Files.Single(s => s.Name == "DependencyInjection.cs");
|
||||||
var fileContents = await File.ReadAllTextAsync(diFile.Path);
|
var fileContents = await File.ReadAllTextAsync(diFile.Path);
|
||||||
_sharpIdeCodeEdit.SetText(fileContents);
|
_sharpIdeCodeEdit.SetText(fileContents);
|
||||||
|
var syntaxHighlighting = await RoslynAnalysis.GetDocumentSyntaxHighlighting(diFile);
|
||||||
|
_sharpIdeCodeEdit.ProvideSyntaxHighlighting(syntaxHighlighting);
|
||||||
var diagnostics = await RoslynAnalysis.GetDocumentDiagnostics(diFile);
|
var diagnostics = await RoslynAnalysis.GetDocumentDiagnostics(diFile);
|
||||||
_sharpIdeCodeEdit.ProvideDiagnostics(diagnostics);
|
_sharpIdeCodeEdit.ProvideDiagnostics(diagnostics);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -51,7 +51,10 @@ layout_mode = 2
|
|||||||
[node name="SharpIdeCodeEdit" type="CodeEdit" parent="VBoxContainer/HBoxContainer/HSplitContainer"]
|
[node name="SharpIdeCodeEdit" type="CodeEdit" parent="VBoxContainer/HBoxContainer/HSplitContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
theme_override_colors/current_line_color = Color(0.0588235, 0.0588235, 0.0588235, 1)
|
||||||
|
theme_override_colors/background_color = Color(0.117647, 0.117647, 0.117647, 1)
|
||||||
theme_override_fonts/font = ExtResource("2_rk34b")
|
theme_override_fonts/font = ExtResource("2_rk34b")
|
||||||
|
theme_override_font_sizes/font_size = 18
|
||||||
highlight_current_line = true
|
highlight_current_line = true
|
||||||
gutters_draw_line_numbers = true
|
gutters_draw_line_numbers = true
|
||||||
code_completion_enabled = true
|
code_completion_enabled = true
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Godot;
|
using Godot;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Classification;
|
||||||
|
|
||||||
namespace SharpIDE.Godot;
|
namespace SharpIDE.Godot;
|
||||||
|
|
||||||
@@ -12,6 +14,8 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
private int _currentLine;
|
private int _currentLine;
|
||||||
private int _selectionStartCol;
|
private int _selectionStartCol;
|
||||||
private int _selectionEndCol;
|
private int _selectionEndCol;
|
||||||
|
|
||||||
|
private CustomHighlighter _syntaxHighlighter = new();
|
||||||
|
|
||||||
private ImmutableArray<Diagnostic> _diagnostics = [];
|
private ImmutableArray<Diagnostic> _diagnostics = [];
|
||||||
|
|
||||||
@@ -27,7 +31,7 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
_currentLine = GetCaretLine();
|
_currentLine = GetCaretLine();
|
||||||
GD.Print($"Selection changed to line {_currentLine}, start {_selectionStartCol}, end {_selectionEndCol}");
|
GD.Print($"Selection changed to line {_currentLine}, start {_selectionStartCol}, end {_selectionEndCol}");
|
||||||
};
|
};
|
||||||
this.SyntaxHighlighter = new CustomHighlighter();
|
this.SyntaxHighlighter = _syntaxHighlighter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UnderlineRange(int line, int caretStartCol, int caretEndCol, Color color, float thickness = 1.5f)
|
public void UnderlineRange(int line, int caretStartCol, int caretEndCol, Color color, float thickness = 1.5f)
|
||||||
@@ -85,6 +89,12 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
{
|
{
|
||||||
_diagnostics = diagnostics;
|
_diagnostics = diagnostics;
|
||||||
}
|
}
|
||||||
|
public void ProvideSyntaxHighlighting(IEnumerable<(FileLinePositionSpan fileSpan, ClassifiedSpan classifiedSpan)> classifiedSpans)
|
||||||
|
{
|
||||||
|
_syntaxHighlighter.ClassifiedSpans = classifiedSpans;
|
||||||
|
_syntaxHighlighter.UpdateCache(); // not sure if correct
|
||||||
|
QueueRedraw(); // TODO: Not working
|
||||||
|
}
|
||||||
|
|
||||||
private void OnCodeFixesRequested()
|
private void OnCodeFixesRequested()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user