diff --git a/StabilityMatrix.Avalonia/Behaviors/TextEditorCompletionBehavior.cs b/StabilityMatrix.Avalonia/Behaviors/TextEditorCompletionBehavior.cs index f3c5cf19..fd74aa21 100644 --- a/StabilityMatrix.Avalonia/Behaviors/TextEditorCompletionBehavior.cs +++ b/StabilityMatrix.Avalonia/Behaviors/TextEditorCompletionBehavior.cs @@ -98,46 +98,70 @@ public class TextEditorCompletionBehavior : Behavior private void TextArea_TextEntered(object? sender, TextInputEventArgs e) { - if (!IsEnabled || CompletionProvider?.IsLoaded != true || e.Text is not { } triggerText) + Logger.ConditionalTrace($"Text entered: {e.Text.ToRepr()}"); + + if (!IsEnabled || CompletionProvider?.IsLoaded != true) + { + Logger.ConditionalTrace("Skipping, not enabled or not loaded"); + return; + } + + if (e.Text is not { } triggerText) + { + Logger.ConditionalTrace("Skipping, null trigger text"); return; + } - if (triggerText.All(IsCompletionChar)) + if (!triggerText.All(IsCompletionChar)) { - // Create completion window if its not already created - if (completionWindow == null) + if (completionWindow is { } window) { - // Get the segment of the token the caret is currently in - if (GetCaretCompletionToken() is not { } completionRequest) - { - Logger.Trace("Token segment not found"); - return; - } + // Disallowed chars, close completion window if its open + Logger.ConditionalTrace( + $"Closing completion window: '{triggerText}' not a valid completion char" + ); + window.Close(); + completionWindow = null; + } + else + { + Logger.ConditionalTrace($"Skipping, invalid trigger text: {triggerText.ToRepr()}"); + } + return; + } + + // If window already open, skip since handled by completion window + // Unless this is an end char, where we'll open a new window + if (completionWindow != null && !triggerText.All(IsCompletionEndChar)) + { + Logger.ConditionalTrace("Skipping, completion window already open"); + return; + } - var tokenSegment = completionRequest.Segment; + // Get the segment of the token the caret is currently in + if (GetCaretCompletionToken() is not { } completionRequest) + { + Logger.Trace("Token segment not found"); + return; + } - var token = textEditor.Document.GetText(tokenSegment); - Logger.Trace("Using token {Token} ({@Segment})", token, tokenSegment); + var tokenSegment = completionRequest.Segment; - completionWindow = CreateCompletionWindow(textEditor.TextArea); - completionWindow.StartOffset = tokenSegment.Offset; - completionWindow.EndOffset = tokenSegment.EndOffset; + var token = textEditor.Document.GetText(tokenSegment); + Logger.Trace("Using token {Token} ({@Segment})", token, tokenSegment); - completionWindow.UpdateQuery(completionRequest); + completionWindow = CreateCompletionWindow(textEditor.TextArea); + completionWindow.StartOffset = tokenSegment.Offset; + completionWindow.EndOffset = tokenSegment.EndOffset; - completionWindow.Closed += delegate - { - completionWindow = null; - }; + completionWindow.UpdateQuery(completionRequest); - completionWindow.Show(); - } - } - else + completionWindow.Closed += delegate { - // Disallowed chars, close completion window if its open - Logger.Trace($"Closing completion window: '{triggerText}' not a valid completion char"); - completionWindow?.Close(); - } + completionWindow = null; + }; + + completionWindow.Show(); } /// @@ -154,6 +178,12 @@ public class TextEditorCompletionBehavior : Behavior return char.IsLetterOrDigit(c) || extraAllowedChars.Contains(c); } + private static bool IsCompletionEndChar(char c) + { + const string endChars = ":"; + return endChars.Contains(c); + } + /// /// Gets a segment of the token the caret is currently in for completions. /// Returns null if caret is not on a valid completion token (i.e. comments)