fix completion insertion
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.CodeAnalysis.Completion;
|
using Microsoft.CodeAnalysis;
|
||||||
|
using Microsoft.CodeAnalysis.Completion;
|
||||||
using SharpIDE.Application.Features.FileWatching;
|
using SharpIDE.Application.Features.FileWatching;
|
||||||
using SharpIDE.Application.Features.SolutionDiscovery;
|
using SharpIDE.Application.Features.SolutionDiscovery;
|
||||||
|
|
||||||
@@ -9,9 +10,9 @@ public class IdeApplyCompletionService(RoslynAnalysis roslynAnalysis, FileChange
|
|||||||
private readonly RoslynAnalysis _roslynAnalysis = roslynAnalysis;
|
private readonly RoslynAnalysis _roslynAnalysis = roslynAnalysis;
|
||||||
private readonly FileChangedService _fileChangedService = fileChangedService;
|
private readonly FileChangedService _fileChangedService = fileChangedService;
|
||||||
|
|
||||||
public async Task ApplyCompletion(SharpIdeFile file, CompletionItem completionItem)
|
public async Task ApplyCompletion(SharpIdeFile file, CompletionItem completionItem, Document document)
|
||||||
{
|
{
|
||||||
var (updatedDocumentText, newLinePosition) = await _roslynAnalysis.GetCompletionApplyChanges(file, completionItem);
|
var (updatedDocumentText, newLinePosition) = await _roslynAnalysis.GetCompletionApplyChanges(file, completionItem, document);
|
||||||
await _fileChangedService.SharpIdeFileChanged(file, updatedDocumentText, FileChangeType.CompletionChange, newLinePosition);
|
await _fileChangedService.SharpIdeFileChanged(file, updatedDocumentText, FileChangeType.CompletionChange, newLinePosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -499,14 +499,18 @@ public class RoslynAnalysis(ILogger<RoslynAnalysis> logger, BuildService buildSe
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CompletionList> GetCodeCompletionsForDocumentAtPosition(SharpIdeFile fileModel, LinePosition linePosition)
|
// We store the document here, so that we have the correct version of the document when we compute completions
|
||||||
|
// This may not be the best way to do this, but it seems to work okay. It may only be a problem because I continue to update the doc in the workspace as the user continues typing, filtering the completion
|
||||||
|
// I could possibly pause updating the document while the completion list is open, but that seems more complex - handling accepted vs cancelled completions etc
|
||||||
|
public record IdeCompletionListResult(Document Document, CompletionList CompletionList);
|
||||||
|
public async Task<IdeCompletionListResult> GetCodeCompletionsForDocumentAtPosition(SharpIdeFile fileModel, LinePosition linePosition)
|
||||||
{
|
{
|
||||||
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(GetCodeCompletionsForDocumentAtPosition)}");
|
using var _ = SharpIdeOtel.Source.StartActivity($"{nameof(RoslynAnalysis)}.{nameof(GetCodeCompletionsForDocumentAtPosition)}");
|
||||||
await _solutionLoadedTcs.Task;
|
await _solutionLoadedTcs.Task;
|
||||||
var document = await GetDocumentForSharpIdeFile(fileModel);
|
var document = await GetDocumentForSharpIdeFile(fileModel);
|
||||||
Guard.Against.Null(document, nameof(document));
|
Guard.Against.Null(document, nameof(document));
|
||||||
var completions = await GetCompletionsAsync(document, linePosition).ConfigureAwait(false);
|
var completions = await GetCompletionsAsync(document, linePosition).ConfigureAwait(false);
|
||||||
return completions;
|
return new IdeCompletionListResult(document, completions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ImmutableArray<CodeAction>> GetCodeFixesForDocumentAtPosition(SharpIdeFile fileModel, LinePosition linePosition, CancellationToken cancellationToken = default)
|
public async Task<ImmutableArray<CodeAction>> GetCodeFixesForDocumentAtPosition(SharpIdeFile fileModel, LinePosition linePosition, CancellationToken cancellationToken = default)
|
||||||
@@ -602,12 +606,11 @@ public class RoslynAnalysis(ILogger<RoslynAnalysis> logger, BuildService buildSe
|
|||||||
return shouldTrigger;
|
return shouldTrigger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(string updatedText, SharpIdeFileLinePosition sharpIdeFileLinePosition)> GetCompletionApplyChanges(SharpIdeFile file, CompletionItem completionItem, CancellationToken cancellationToken = default)
|
public async Task<(string updatedText, SharpIdeFileLinePosition sharpIdeFileLinePosition)> GetCompletionApplyChanges(SharpIdeFile file, CompletionItem completionItem, Document document, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var documentId = _workspace!.CurrentSolution.GetDocumentIdsWithFilePath(file.Path).Single();
|
//var documentId = _workspace!.CurrentSolution.GetDocumentIdsWithFilePath(file.Path).Single();
|
||||||
var document = SolutionExtensions.GetRequiredDocument(_workspace.CurrentSolution, documentId);
|
//var document = SolutionExtensions.GetRequiredDocument(_workspace.CurrentSolution, documentId);
|
||||||
var completionService = CompletionService.GetService(document) ?? throw new InvalidOperationException("Completion service is not available for the document.");
|
var completionService = CompletionService.GetService(document) ?? throw new InvalidOperationException("Completion service is not available for the document.");
|
||||||
|
|
||||||
var completionChange = await completionService.GetChangeAsync(document, completionItem, commitCharacter: '.', cancellationToken: cancellationToken);
|
var completionChange = await completionService.GetChangeAsync(document, completionItem, commitCharacter: '.', cancellationToken: cancellationToken);
|
||||||
var sourceText = await document.GetTextAsync(cancellationToken);
|
var sourceText = await document.GetTextAsync(cancellationToken);
|
||||||
var newText = sourceText.WithChanges(completionChange.TextChange);
|
var newText = sourceText.WithChanges(completionChange.TextChange);
|
||||||
|
|||||||
@@ -174,12 +174,6 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
|
|
||||||
private void OnTextChanged()
|
private void OnTextChanged()
|
||||||
{
|
{
|
||||||
var codeCompletionPopupClosed = GetCodeCompletionSelectedIndex() is -1;
|
|
||||||
var shouldShowCodeCompletion = codeCompletionPopupClosed && HasFocus(); // This is a bad solution - it will be triggered on copy paste, undo redo, applying code fixes etc
|
|
||||||
if (codeCompletionPopupClosed)
|
|
||||||
{
|
|
||||||
EmitSignalCodeCompletionRequested();
|
|
||||||
}
|
|
||||||
_ = Task.GodotRun(async () =>
|
_ = Task.GodotRun(async () =>
|
||||||
{
|
{
|
||||||
var __ = SharpIdeOtel.Source.StartActivity($"{nameof(SharpIdeCodeEdit)}.{nameof(OnTextChanged)}");
|
var __ = SharpIdeOtel.Source.StartActivity($"{nameof(SharpIdeCodeEdit)}.{nameof(OnTextChanged)}");
|
||||||
@@ -426,14 +420,15 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
var selectedIndex = GetCodeCompletionSelectedIndex();
|
var selectedIndex = GetCodeCompletionSelectedIndex();
|
||||||
var selectedText = GetCodeCompletionOption(selectedIndex);
|
var selectedText = GetCodeCompletionOption(selectedIndex);
|
||||||
if (selectedText is null) return;
|
if (selectedText is null) return;
|
||||||
var completionItem = selectedText["default_value"].As<RefCountedContainer<CompletionItem>>().Item;
|
var completionItem = selectedText["default_value"].As<RefCountedContainer<IdeCompletionItem>>().Item;
|
||||||
_ = Task.GodotRun(async () =>
|
_ = Task.GodotRun(async () =>
|
||||||
{
|
{
|
||||||
await _ideApplyCompletionService.ApplyCompletion(_currentFile, completionItem);
|
await _ideApplyCompletionService.ApplyCompletion(_currentFile, completionItem.CompletionItem, completionItem.Document);
|
||||||
});
|
});
|
||||||
CancelCodeCompletion();
|
CancelCodeCompletion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private record struct IdeCompletionItem(CompletionItem CompletionItem, Document Document);
|
||||||
private void OnCodeCompletionRequested()
|
private void OnCodeCompletionRequested()
|
||||||
{
|
{
|
||||||
var (caretLine, caretColumn) = GetCaretPosition();
|
var (caretLine, caretColumn) = GetCaretPosition();
|
||||||
@@ -443,10 +438,10 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
{
|
{
|
||||||
var linePos = new LinePosition(caretLine, caretColumn);
|
var linePos = new LinePosition(caretLine, caretColumn);
|
||||||
|
|
||||||
var completions = await _roslynAnalysis.GetCodeCompletionsForDocumentAtPosition(_currentFile, linePos);
|
var completionsResult = await _roslynAnalysis.GetCodeCompletionsForDocumentAtPosition(_currentFile, linePos);
|
||||||
await this.InvokeAsync(() =>
|
await this.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
foreach (var completionItem in completions.ItemsList)
|
foreach (var completionItem in completionsResult.CompletionList.ItemsList)
|
||||||
{
|
{
|
||||||
var symbolKindString = CollectionExtensions.GetValueOrDefault(completionItem.Properties, "SymbolKind");
|
var symbolKindString = CollectionExtensions.GetValueOrDefault(completionItem.Properties, "SymbolKind");
|
||||||
var symbolKind = symbolKindString is null ? null : (SymbolKind?)int.Parse(symbolKindString);
|
var symbolKind = symbolKindString is null ? null : (SymbolKind?)int.Parse(symbolKindString);
|
||||||
@@ -465,14 +460,14 @@ public partial class SharpIdeCodeEdit : CodeEdit
|
|||||||
_ => CodeCompletionKind.PlainText
|
_ => CodeCompletionKind.PlainText
|
||||||
};
|
};
|
||||||
var isKeyword = wellKnownTags.Contains(WellKnownTags.Keyword);
|
var isKeyword = wellKnownTags.Contains(WellKnownTags.Keyword);
|
||||||
AddCodeCompletionOption(godotCompletionType, completionItem.DisplayText, completionItem.DisplayText, icon: icon, value: new RefCountedContainer<CompletionItem>(completionItem));
|
|
||||||
var isExtensionMethod = wellKnownTags.Contains(WellKnownTags.ExtensionMethod);
|
var isExtensionMethod = wellKnownTags.Contains(WellKnownTags.ExtensionMethod);
|
||||||
var icon = GetIconForCompletion(symbolKind, typeKind, accessibilityModifier, isKeyword, isExtensionMethod);
|
var icon = GetIconForCompletion(symbolKind, typeKind, accessibilityModifier, isKeyword, isExtensionMethod);
|
||||||
|
AddCodeCompletionOption(godotCompletionType, completionItem.DisplayText, completionItem.DisplayText, icon: icon, value: new RefCountedContainer<IdeCompletionItem>(new IdeCompletionItem(completionItem, completionsResult.Document)));
|
||||||
}
|
}
|
||||||
// partially working - displays menu only when caret is what CodeEdit determines as valid
|
// partially working - displays menu only when caret is what CodeEdit determines as valid
|
||||||
UpdateCodeCompletionOptions(true);
|
UpdateCodeCompletionOptions(true);
|
||||||
//RequestCodeCompletion(true);
|
//RequestCodeCompletion(true);
|
||||||
GD.Print($"Found {completions.ItemsList.Count} completions, displaying menu");
|
GD.Print($"Found {completionsResult.CompletionList.ItemsList.Count} completions, displaying menu");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user