display underline for diagnostics
This commit is contained in:
@@ -10,6 +10,7 @@ using Microsoft.CodeAnalysis.Host.Mef;
|
|||||||
using Microsoft.CodeAnalysis.MSBuild;
|
using Microsoft.CodeAnalysis.MSBuild;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
using Microsoft.CodeAnalysis.Text;
|
||||||
using NuGet.Packaging;
|
using NuGet.Packaging;
|
||||||
|
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
|
||||||
namespace SharpIDE.Application.Features.Analysis;
|
namespace SharpIDE.Application.Features.Analysis;
|
||||||
@@ -125,6 +126,23 @@ public static class RoslynAnalysis
|
|||||||
return diagnostics;
|
return diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<ImmutableArray<Diagnostic>> GetDocumentDiagnostics(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);
|
||||||
|
//var document = _workspace!.CurrentSolution.GetDocument(fileModel.Path);
|
||||||
|
Guard.Against.Null(document, nameof(document));
|
||||||
|
|
||||||
|
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
|
||||||
|
Guard.Against.Null(semanticModel, nameof(semanticModel));
|
||||||
|
|
||||||
|
var diagnostics = semanticModel.GetDiagnostics(cancellationToken: cancellationToken);
|
||||||
|
diagnostics = diagnostics.Where(d => d.Severity is not DiagnosticSeverity.Hidden).ToImmutableArray();
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|||||||
@@ -14,6 +14,17 @@ public interface IExpandableSharpIdeNode
|
|||||||
public interface IChildSharpIdeNode
|
public interface IChildSharpIdeNode
|
||||||
{
|
{
|
||||||
public IExpandableSharpIdeNode Parent { get; set; }
|
public IExpandableSharpIdeNode Parent { get; set; }
|
||||||
|
|
||||||
|
// TODO: Profile/redesign
|
||||||
|
public SharpIdeProjectModel? GetNearestProjectNode()
|
||||||
|
{
|
||||||
|
var current = this;
|
||||||
|
while (current is not SharpIdeProjectModel && current?.Parent is not null)
|
||||||
|
{
|
||||||
|
current = current.Parent as IChildSharpIdeNode;
|
||||||
|
}
|
||||||
|
return current as SharpIdeProjectModel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SharpIdeSolutionModel : ISharpIdeNode, IExpandableSharpIdeNode
|
public class SharpIdeSolutionModel : ISharpIdeNode, IExpandableSharpIdeNode
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Runtime.Loader;
|
|
||||||
using Godot;
|
using Godot;
|
||||||
using Microsoft.Build.Locator;
|
using Microsoft.Build.Locator;
|
||||||
using Microsoft.CodeAnalysis.CodeFixes;
|
|
||||||
using Microsoft.CodeAnalysis.Host.Mef;
|
|
||||||
using SharpIDE.Application.Features.Analysis;
|
using SharpIDE.Application.Features.Analysis;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
using SharpIDE.Application.Features.SolutionDiscovery.VsPersistence;
|
||||||
|
|
||||||
@@ -16,14 +12,18 @@ public partial class IdeRoot : Control
|
|||||||
{
|
{
|
||||||
private Button _openSlnButton = null!;
|
private Button _openSlnButton = null!;
|
||||||
private FileDialog _fileDialog = null!;
|
private FileDialog _fileDialog = null!;
|
||||||
|
private SharpIdeCodeEdit _sharpIdeCodeEdit = null!;
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
MSBuildLocator.RegisterDefaults();
|
MSBuildLocator.RegisterDefaults();
|
||||||
|
|
||||||
_openSlnButton = GetNode<Button>("%OpenSlnButton");
|
_openSlnButton = GetNode<Button>("%OpenSlnButton");
|
||||||
|
_sharpIdeCodeEdit = GetNode<SharpIdeCodeEdit>("%SharpIdeCodeEdit");
|
||||||
_fileDialog = GetNode<FileDialog>("%OpenSolutionDialog");
|
_fileDialog = GetNode<FileDialog>("%OpenSolutionDialog");
|
||||||
_fileDialog.FileSelected += OnFileSelected;
|
_fileDialog.FileSelected += OnFileSelected;
|
||||||
|
_openSlnButton.Pressed += () => _fileDialog.Visible = true;
|
||||||
//_fileDialog.Visible = true;
|
//_fileDialog.Visible = true;
|
||||||
|
OnFileSelected(@"C:\Users\Matthew\Documents\Git\BlazorCodeBreaker\BlazorCodeBreaker.slnx");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnFileSelected(string path)
|
private async void OnFileSelected(string path)
|
||||||
@@ -33,6 +33,12 @@ public partial class IdeRoot : Control
|
|||||||
GD.Print($"Selected: {path}");
|
GD.Print($"Selected: {path}");
|
||||||
var solutionModel = await VsPersistenceMapper.GetSolutionModel(path);
|
var solutionModel = await VsPersistenceMapper.GetSolutionModel(path);
|
||||||
RoslynAnalysis.StartSolutionAnalysis(path);
|
RoslynAnalysis.StartSolutionAnalysis(path);
|
||||||
|
var infraProject = solutionModel.AllProjects.Single(s => s.Name == "Infrastructure");
|
||||||
|
var diFile = infraProject.Files.Single(s => s.Name == "DependencyInjection.cs");
|
||||||
|
var fileContents = await File.ReadAllTextAsync(diFile.Path);
|
||||||
|
_sharpIdeCodeEdit.SetText(fileContents);
|
||||||
|
var diagnostics = await RoslynAnalysis.GetDocumentDiagnostics(diFile);
|
||||||
|
_sharpIdeCodeEdit.ProvideDiagnostics(diagnostics);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ split_offset = 250
|
|||||||
layout_mode = 2
|
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
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
theme_override_fonts/font = ExtResource("2_rk34b")
|
theme_override_fonts/font = ExtResource("2_rk34b")
|
||||||
highlight_current_line = true
|
highlight_current_line = true
|
||||||
@@ -56,7 +57,6 @@ gutters_draw_line_numbers = true
|
|||||||
code_completion_enabled = true
|
code_completion_enabled = true
|
||||||
auto_brace_completion_enabled = true
|
auto_brace_completion_enabled = true
|
||||||
script = ExtResource("2_qjf5e")
|
script = ExtResource("2_qjf5e")
|
||||||
HighlightStartOffset = 0
|
|
||||||
|
|
||||||
[node name="OpenSolutionDialog" type="FileDialog" parent="."]
|
[node name="OpenSolutionDialog" type="FileDialog" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using Microsoft.CodeAnalysis;
|
||||||
|
|
||||||
namespace SharpIDE.Godot;
|
namespace SharpIDE.Godot;
|
||||||
|
|
||||||
@@ -7,15 +9,11 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
[Signal]
|
[Signal]
|
||||||
public delegate void CodeFixesRequestedEventHandler();
|
public delegate void CodeFixesRequestedEventHandler();
|
||||||
|
|
||||||
[Export]
|
|
||||||
public int HighlightStartOffset = 0;
|
|
||||||
|
|
||||||
[Export]
|
|
||||||
public int HighlightEndOffset = 0;
|
|
||||||
|
|
||||||
private int _currentLine;
|
private int _currentLine;
|
||||||
private int _selectionStartCol;
|
private int _selectionStartCol;
|
||||||
private int _selectionEndCol;
|
private int _selectionEndCol;
|
||||||
|
|
||||||
|
private ImmutableArray<Diagnostic> _diagnostics = [];
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
@@ -44,18 +42,19 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
int lineLength = GetLine(line).Length;
|
int lineLength = GetLine(line).Length;
|
||||||
caretStartCol = Mathf.Clamp(caretStartCol, 0, lineLength);
|
caretStartCol = Mathf.Clamp(caretStartCol, 0, lineLength);
|
||||||
caretEndCol = Mathf.Clamp(caretEndCol, 0, lineLength);
|
caretEndCol = Mathf.Clamp(caretEndCol, 0, lineLength);
|
||||||
|
|
||||||
var charRect = GetRectAtLineColumn(line, caretEndCol);
|
|
||||||
var charWidth = charRect.Size.X;
|
|
||||||
|
|
||||||
var startPos = GetPosAtLineColumn(line, caretStartCol);
|
// GetRectAtLineColumn returns the rectangle for the character before the column passed in, or the first character if the column is 0.
|
||||||
|
var startRect = GetRectAtLineColumn(line, caretStartCol);
|
||||||
|
var endRect = GetRectAtLineColumn(line, caretEndCol);
|
||||||
|
//DrawLine(startRect.Position, startRect.End, color);
|
||||||
|
//DrawLine(endRect.Position, endRect.End, color);
|
||||||
|
|
||||||
|
var startPos = startRect.End;
|
||||||
if (caretStartCol is 0)
|
if (caretStartCol is 0)
|
||||||
{
|
{
|
||||||
startPos.X -= 9; // Seems to be a bug or intended "feature" of GetPosAtLineColumn
|
startPos.X -= startRect.Size.X;
|
||||||
}
|
}
|
||||||
var endPos = GetPosAtLineColumn(line, caretEndCol);
|
var endPos = endRect.End;
|
||||||
startPos.X += charWidth;
|
|
||||||
endPos.X += charWidth;
|
|
||||||
startPos.Y -= 1;
|
startPos.Y -= 1;
|
||||||
endPos.Y -= 1;
|
endPos.Y -= 1;
|
||||||
DrawLine(startPos, endPos, color, thickness);
|
DrawLine(startPos, endPos, color, thickness);
|
||||||
@@ -63,7 +62,28 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
public override void _Draw()
|
public override void _Draw()
|
||||||
{
|
{
|
||||||
UnderlineRange(_currentLine, _selectionStartCol, _selectionEndCol, new Color(1, 0, 0));
|
UnderlineRange(_currentLine, _selectionStartCol, _selectionEndCol, new Color(1, 0, 0));
|
||||||
//UnderlineRange(_currentLine, 0, 7, new Color(1, 0, 0));
|
foreach (var diagnostic in _diagnostics)
|
||||||
|
{
|
||||||
|
if (diagnostic.Location.IsInSource)
|
||||||
|
{
|
||||||
|
var mappedLineSpan = (diagnostic.Location.SourceTree?.GetMappedLineSpan(diagnostic.Location.SourceSpan))!.Value;
|
||||||
|
var line = mappedLineSpan.StartLinePosition.Line;
|
||||||
|
var startCol = mappedLineSpan.StartLinePosition.Character;
|
||||||
|
var endCol = mappedLineSpan.EndLinePosition.Character;
|
||||||
|
var color = diagnostic.Severity switch
|
||||||
|
{
|
||||||
|
DiagnosticSeverity.Error => new Color(1, 0, 0),
|
||||||
|
DiagnosticSeverity.Warning => new Color(1, 1, 0),
|
||||||
|
_ => new Color(0, 1, 0) // Info or other
|
||||||
|
};
|
||||||
|
UnderlineRange(line, startCol, endCol, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProvideDiagnostics(ImmutableArray<Diagnostic> diagnostics)
|
||||||
|
{
|
||||||
|
_diagnostics = diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCodeFixesRequested()
|
private void OnCodeFixesRequested()
|
||||||
|
|||||||
Reference in New Issue
Block a user