From 3ae6a0eed05e1fd09e96d547b95d969de17f1d15 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 13 Jun 2023 16:07:20 +0200 Subject: [PATCH] feat: Intellisense Enanched Prediction 1 - Close Element - Suggest Element before other type --- .../IntelliSense/XamlCompletion.cs | 17 ++++++++++--- .../XamlCompletionCommandHandler.cs | 2 +- .../Completion/Completion.cs | 13 ++++++---- .../Completion/CompletionEngine.cs | 25 ++++++++++++++++--- tests/CompletionEngineTests/BasicTests.cs | 6 ++--- 5 files changed, 46 insertions(+), 17 deletions(-) diff --git a/AvaloniaVS.Shared/IntelliSense/XamlCompletion.cs b/AvaloniaVS.Shared/IntelliSense/XamlCompletion.cs index 0b589636..7cc19d85 100644 --- a/AvaloniaVS.Shared/IntelliSense/XamlCompletion.cs +++ b/AvaloniaVS.Shared/IntelliSense/XamlCompletion.cs @@ -22,15 +22,22 @@ public XamlCompletion(Completion completion) completion.Description, GetImage(completion.Kind), completion.Kind.ToString(), - suffix: string.IsNullOrWhiteSpace(completion.Suffix) ? string.Empty : $"({completion.Suffix})") + suffix: string.IsNullOrWhiteSpace(completion.Suffix) ? string.Empty : $"({completion.Suffix})") { if (completion.RecommendedCursorOffset.HasValue) { CursorOffset = completion.InsertText.Length - completion.RecommendedCursorOffset.Value; } - + TriggerCompletion = completion.TriggerCompletionAfterInsert; Kind = completion.Kind; DeleteTextOffset = completion.DeleteTextOffset; + if (completion.Priority < 255) + { + this.AttributeIcons = new Microsoft.VisualStudio.Language.Intellisense.CompletionIcon2[] + { + new (KnownMonikers.OverlayProtected,"",""), + }; + } } public int? DeleteTextOffset { get; } @@ -41,7 +48,7 @@ public override string InsertionText { if (HasFlag(Kind, CompletionKind.Name) && !string.IsNullOrEmpty(Suffix)) { - return $"{Suffix.Substring(1,Suffix.Length-2)}#{base.InsertionText}"; + return $"{Suffix.Substring(1, Suffix.Length - 2)}#{base.InsertionText}"; } return base.InsertionText; } @@ -53,6 +60,8 @@ public override string InsertionText public CompletionKind Kind { get; } + public bool TriggerCompletion { get; } + public static IEnumerable Create( IEnumerable source) { @@ -100,7 +109,7 @@ private static void LoadImages() ThreadHelper.ThrowIfNotOnUIThread(); var capacity = Enum.GetValues(typeof(CompletionKind)).Cast().Max() + 1; - + s_images = new ImageMoniker[capacity]; s_images[(int)CompletionKind.Property] = KnownMonikers.Property; s_images[(int)CompletionKind.Event] = KnownMonikers.Event; diff --git a/AvaloniaVS.Shared/IntelliSense/XamlCompletionCommandHandler.cs b/AvaloniaVS.Shared/IntelliSense/XamlCompletionCommandHandler.cs index e23d2852..c55d87cc 100644 --- a/AvaloniaVS.Shared/IntelliSense/XamlCompletionCommandHandler.cs +++ b/AvaloniaVS.Shared/IntelliSense/XamlCompletionCommandHandler.cs @@ -333,7 +333,7 @@ private bool HandleSessionCompletion(char c) TriggerCompletion(); } } - else if (state != XmlParser.ParserState.StartElement) + else if (state != XmlParser.ParserState.StartElement || selected.TriggerCompletion) { TriggerCompletion(); } diff --git a/CompletionEngine/Avalonia.Ide.CompletionEngine/Completion/Completion.cs b/CompletionEngine/Avalonia.Ide.CompletionEngine/Completion/Completion.cs index c1c26151..74edf1b0 100644 --- a/CompletionEngine/Avalonia.Ide.CompletionEngine/Completion/Completion.cs +++ b/CompletionEngine/Avalonia.Ide.CompletionEngine/Completion/Completion.cs @@ -43,20 +43,23 @@ public record Completion(string DisplayText, CompletionKind Kind, int? RecommendedCursorOffset = null, string? Suffix = null, - int? DeleteTextOffset = null + int? DeleteTextOffset = null, + byte Priority = 255 ) { public override string ToString() => DisplayText; - public Completion(string insertText, CompletionKind kind, string? suffix = default) : - this(insertText, insertText, insertText, kind, Suffix: suffix) + public Completion(string insertText, CompletionKind kind, string? suffix = default, byte priority = 255) : + this(insertText, insertText, insertText, kind, Suffix: suffix, Priority: priority) { } - public Completion(string displayText, string insertText, CompletionKind kind, string? suffix = default) : - this(displayText, insertText, displayText, kind) + public Completion(string displayText, string insertText, CompletionKind kind, string? suffix = default, byte priority = 255) : + this(displayText, insertText, displayText, kind, Priority: priority) { } + + public bool TriggerCompletionAfterInsert { get; init; } } diff --git a/CompletionEngine/Avalonia.Ide.CompletionEngine/Completion/CompletionEngine.cs b/CompletionEngine/Avalonia.Ide.CompletionEngine/Completion/CompletionEngine.cs index 16332936..98c7da7c 100644 --- a/CompletionEngine/Avalonia.Ide.CompletionEngine/Completion/CompletionEngine.cs +++ b/CompletionEngine/Avalonia.Ide.CompletionEngine/Completion/CompletionEngine.cs @@ -244,7 +244,7 @@ private static Dictionary GetNamespaceAliases(string xml) var name = closingState.GetParentTagName(0); if (name == null) return null; - completions.Add(new Completion("/" + name + ">", CompletionKind.Class)); + completions.Add(new Completion("/" + name + ">", CompletionKind.Class, priority: 0)); } else if (tagName.Contains('.')) { @@ -260,7 +260,23 @@ private static Dictionary GetNamespaceAliases(string xml) } else { - completions.AddRange(_helper.FilterTypes(tagName).Select(kvp => + if (state.GetParentTagName(1) is string parentTag) + { + if (!state.IsInClosingTag) + { + completions.Add(new Completion("/" + parentTag + ">", CompletionKind.Class, priority: 0)); + } + if (parentTag.IndexOf('.') == -1) + { + completions.Add(new Completion(parentTag, $"{parentTag}.", CompletionKind.Class, priority: 1) + { + TriggerCompletionAfterInsert = true, + }); + } + } + + completions.AddRange(_helper.FilterTypes(tagName) + .Select(kvp => { if (kvp.Value.IsMarkupExtension) { @@ -327,7 +343,7 @@ private static Dictionary GetNamespaceAliases(string xml) if (targetType.IsAvaloniaObjectType) { - if (string.IsNullOrEmpty(attributeName) || "xmlns".StartsWith(attributeName,StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrEmpty(attributeName) || "xmlns".StartsWith(attributeName, StringComparison.OrdinalIgnoreCase)) { completions.Add(new("xmlns:", CompletionKind.Class)); } @@ -508,7 +524,8 @@ private static List SortCompletions(List completions) // Group the completions based on Kind, and sort the completions for each group return completions .GroupBy(i => i.Kind, (kind, compl) => - (Kind: kind, Completions: compl.OrderBy(j => j.DisplayText))) + (Kind: kind, Completions: compl + .OrderBy(j => j.Priority).ThenBy(j => j.DisplayText))) .OrderBy(i => GetCompletionPriority(i.Kind)) .SelectMany(i => i.Completions) .ToList(); diff --git a/tests/CompletionEngineTests/BasicTests.cs b/tests/CompletionEngineTests/BasicTests.cs index acbc9a9f..51c4f4e8 100644 --- a/tests/CompletionEngineTests/BasicTests.cs +++ b/tests/CompletionEngineTests/BasicTests.cs @@ -139,9 +139,9 @@ public void Completions_Should_Be_Sorted() { var compl = GetCompletionsFor("