display code fixes popup
This commit is contained in:
@@ -127,7 +127,7 @@ public static class RoslynAnalysis
|
|||||||
return diagnostics;
|
return diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<ImmutableArray<Diagnostic>> GetDocumentDiagnostics(SharpIdeFile fileModel)
|
public static async Task<ImmutableArray<(FileLinePositionSpan fileSpan, Diagnostic diagnostic)>> GetDocumentDiagnostics(SharpIdeFile fileModel)
|
||||||
{
|
{
|
||||||
await _solutionLoadedTcs.Task;
|
await _solutionLoadedTcs.Task;
|
||||||
var cancellationToken = CancellationToken.None;
|
var cancellationToken = CancellationToken.None;
|
||||||
@@ -141,7 +141,8 @@ public static class RoslynAnalysis
|
|||||||
|
|
||||||
var diagnostics = semanticModel.GetDiagnostics(cancellationToken: cancellationToken);
|
var diagnostics = semanticModel.GetDiagnostics(cancellationToken: cancellationToken);
|
||||||
diagnostics = diagnostics.Where(d => d.Severity is not DiagnosticSeverity.Hidden).ToImmutableArray();
|
diagnostics = diagnostics.Where(d => d.Severity is not DiagnosticSeverity.Hidden).ToImmutableArray();
|
||||||
return diagnostics;
|
var result = diagnostics.Select(d => (semanticModel.SyntaxTree.GetMappedLineSpan(d.Location.SourceSpan), d)).ToImmutableArray();
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<IEnumerable<(FileLinePositionSpan fileSpan, ClassifiedSpan classifiedSpan)>> GetDocumentSyntaxHighlighting(SharpIdeFile fileModel)
|
public static async Task<IEnumerable<(FileLinePositionSpan fileSpan, ClassifiedSpan classifiedSpan)>> GetDocumentSyntaxHighlighting(SharpIdeFile fileModel)
|
||||||
@@ -161,12 +162,14 @@ public static class RoslynAnalysis
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<ImmutableArray<CodeAction>> GetCodeFixesAsync(Diagnostic diagnostic)
|
public static async Task<ImmutableArray<(FileLinePositionSpan fileSpan, CodeAction codeAction)>> GetCodeFixesAsync(Diagnostic diagnostic)
|
||||||
{
|
{
|
||||||
var cancellationToken = CancellationToken.None;
|
var cancellationToken = CancellationToken.None;
|
||||||
var document = _workspace!.CurrentSolution.GetDocument(diagnostic.Location.SourceTree);
|
var document = _workspace!.CurrentSolution.GetDocument(diagnostic.Location.SourceTree);
|
||||||
Guard.Against.Null(document, nameof(document));
|
Guard.Against.Null(document, nameof(document));
|
||||||
var result = await GetCodeFixesAsync(document, diagnostic);
|
var codeActions = await GetCodeFixesAsync(document, diagnostic);
|
||||||
|
var result = codeActions.Select(action => (diagnostic.Location.SourceTree!.GetMappedLineSpan(diagnostic.Location.SourceSpan), action))
|
||||||
|
.ToImmutableArray();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
private static async Task<ImmutableArray<CodeAction>> GetCodeFixesAsync(Document document, Diagnostic diagnostic)
|
private static async Task<ImmutableArray<CodeAction>> GetCodeFixesAsync(Document document, Diagnostic diagnostic)
|
||||||
|
|||||||
@@ -61,6 +61,11 @@ code_completion_enabled = true
|
|||||||
auto_brace_completion_enabled = true
|
auto_brace_completion_enabled = true
|
||||||
script = ExtResource("2_qjf5e")
|
script = ExtResource("2_qjf5e")
|
||||||
|
|
||||||
|
[node name="CodeFixesMenu" type="PopupMenu" parent="VBoxContainer/HBoxContainer/HSplitContainer/SharpIdeCodeEdit"]
|
||||||
|
item_count = 1
|
||||||
|
item_0/text = "Getting Context Actions..."
|
||||||
|
item_0/id = 0
|
||||||
|
|
||||||
[node name="OpenSolutionDialog" type="FileDialog" parent="."]
|
[node name="OpenSolutionDialog" type="FileDialog" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
title = "Open a File"
|
title = "Open a File"
|
||||||
|
|||||||
8
src/SharpIDE.Godot/InputStringNames.cs
Normal file
8
src/SharpIDE.Godot/InputStringNames.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace SharpIDE.Godot;
|
||||||
|
|
||||||
|
public static class InputStringNames
|
||||||
|
{
|
||||||
|
public static readonly StringName CodeFixes = "CodeFixes";
|
||||||
|
}
|
||||||
1
src/SharpIDE.Godot/InputStringNames.cs.uid
Normal file
1
src/SharpIDE.Godot/InputStringNames.cs.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://c8dler1dxpwda
|
||||||
@@ -1,8 +1,14 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
using Godot;
|
using Godot;
|
||||||
|
using Microsoft.Build.Utilities;
|
||||||
using Microsoft.CodeAnalysis;
|
using Microsoft.CodeAnalysis;
|
||||||
using Microsoft.CodeAnalysis.Classification;
|
using Microsoft.CodeAnalysis.Classification;
|
||||||
|
using Microsoft.CodeAnalysis.Text;
|
||||||
|
using SharpIDE.Application.Features.Analysis;
|
||||||
|
using Task = System.Threading.Tasks.Task;
|
||||||
|
|
||||||
namespace SharpIDE.Godot;
|
namespace SharpIDE.Godot;
|
||||||
|
|
||||||
@@ -16,12 +22,17 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
private int _selectionEndCol;
|
private int _selectionEndCol;
|
||||||
|
|
||||||
private CustomHighlighter _syntaxHighlighter = new();
|
private CustomHighlighter _syntaxHighlighter = new();
|
||||||
|
private PopupMenu _popupMenu = null!;
|
||||||
|
|
||||||
private ImmutableArray<Diagnostic> _diagnostics = [];
|
private ImmutableArray<(FileLinePositionSpan fileSpan, Diagnostic diagnostic)> _diagnostics = [];
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
//AddThemeFontOverride("Cascadia Code", ResourceLoader.Load<Font>("res://CascadiaCode.ttf"));
|
_popupMenu = GetNode<PopupMenu>("CodeFixesMenu");
|
||||||
|
_popupMenu.IdPressed += (id) =>
|
||||||
|
{
|
||||||
|
GD.Print($"Code fix selected: {id}");
|
||||||
|
};
|
||||||
this.CodeCompletionRequested += OnCodeCompletionRequested;
|
this.CodeCompletionRequested += OnCodeCompletionRequested;
|
||||||
this.CodeFixesRequested += OnCodeFixesRequested;
|
this.CodeFixesRequested += OnCodeFixesRequested;
|
||||||
this.CaretChanged += () =>
|
this.CaretChanged += () =>
|
||||||
@@ -67,14 +78,13 @@ 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));
|
||||||
foreach (var diagnostic in _diagnostics)
|
foreach (var (fileSpan, diagnostic) in _diagnostics)
|
||||||
{
|
{
|
||||||
if (diagnostic.Location.IsInSource)
|
if (diagnostic.Location.IsInSource)
|
||||||
{
|
{
|
||||||
var mappedLineSpan = (diagnostic.Location.SourceTree?.GetMappedLineSpan(diagnostic.Location.SourceSpan))!.Value;
|
var line = fileSpan.StartLinePosition.Line;
|
||||||
var line = mappedLineSpan.StartLinePosition.Line;
|
var startCol = fileSpan.StartLinePosition.Character;
|
||||||
var startCol = mappedLineSpan.StartLinePosition.Character;
|
var endCol = fileSpan.EndLinePosition.Character;
|
||||||
var endCol = mappedLineSpan.EndLinePosition.Character;
|
|
||||||
var color = diagnostic.Severity switch
|
var color = diagnostic.Severity switch
|
||||||
{
|
{
|
||||||
DiagnosticSeverity.Error => new Color(1, 0, 0),
|
DiagnosticSeverity.Error => new Color(1, 0, 0),
|
||||||
@@ -86,7 +96,15 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProvideDiagnostics(ImmutableArray<Diagnostic> diagnostics)
|
public override void _UnhandledKeyInput(InputEvent @event)
|
||||||
|
{
|
||||||
|
if (@event.IsActionPressed(InputStringNames.CodeFixes))
|
||||||
|
{
|
||||||
|
EmitSignalCodeFixesRequested();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProvideDiagnostics(ImmutableArray<(FileLinePositionSpan fileSpan, Diagnostic diagnostic)> diagnostics)
|
||||||
{
|
{
|
||||||
_diagnostics = diagnostics;
|
_diagnostics = diagnostics;
|
||||||
}
|
}
|
||||||
@@ -105,13 +123,50 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
|
|
||||||
private void OnCodeFixesRequested()
|
private void OnCodeFixesRequested()
|
||||||
{
|
{
|
||||||
GD.Print("Code fixes requested");
|
var (caretLine, caretColumn) = GetCaretPosition();
|
||||||
|
var test = GetCaretDrawPos();
|
||||||
|
_popupMenu.Position = new Vector2I((int)test.X, (int)test.Y);
|
||||||
|
_popupMenu.Clear();
|
||||||
|
_popupMenu.AddItem("Getting Context Actions...", 0);
|
||||||
|
_popupMenu.Popup();
|
||||||
|
GD.Print($"Code fixes requested at line {caretLine}, column {caretColumn}");
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var linePos = new LinePosition(caretLine, caretColumn);
|
||||||
|
var diagnostic = _diagnostics.FirstOrDefault(d =>
|
||||||
|
d.fileSpan.StartLinePosition <= linePos && d.fileSpan.EndLinePosition >= linePos);
|
||||||
|
if (diagnostic is (_, null)) return;
|
||||||
|
var codeActions = await RoslynAnalysis.GetCodeFixesAsync(diagnostic.diagnostic);
|
||||||
|
Callable.From(() =>
|
||||||
|
{
|
||||||
|
_popupMenu.Clear();
|
||||||
|
foreach (var (index, (fileSpan, codeAction)) in codeActions.Index())
|
||||||
|
{
|
||||||
|
_popupMenu.AddItem(codeAction.Title, index);
|
||||||
|
//_popupMenu.SetItemMetadata(menuItem, codeAction);
|
||||||
|
}
|
||||||
|
GD.Print($"Code fixes found: {codeActions.Length}, displaying menu");
|
||||||
|
}).CallDeferred();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
GD.Print(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCodeCompletionRequested()
|
private void OnCodeCompletionRequested()
|
||||||
{
|
{
|
||||||
var caretColumn = GetCaretColumn();
|
var (caretLine, caretColumn) = GetCaretPosition();
|
||||||
var caretLine = GetCaretLine();
|
|
||||||
GD.Print($"Code completion requested at line {caretLine}, column {caretColumn}");
|
GD.Print($"Code completion requested at line {caretLine}, column {caretColumn}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private (int, int) GetCaretPosition()
|
||||||
|
{
|
||||||
|
var caretColumn = GetCaretColumn();
|
||||||
|
var caretLine = GetCaretLine();
|
||||||
|
return (caretLine, caretColumn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -20,3 +20,11 @@ config/icon="res://icon.svg"
|
|||||||
[dotnet]
|
[dotnet]
|
||||||
|
|
||||||
project/assembly_name="SharpIDE.Godot"
|
project/assembly_name="SharpIDE.Godot"
|
||||||
|
|
||||||
|
[input]
|
||||||
|
|
||||||
|
CodeFixes={
|
||||||
|
"deadzone": 0.2,
|
||||||
|
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":true,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194309,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user