diff --git a/src/Analysis/Engine/Test/CompletionTests.cs b/src/Analysis/Engine/Test/CompletionTests.cs index b841af40e..18752d7bd 100644 --- a/src/Analysis/Engine/Test/CompletionTests.cs +++ b/src/Analysis/Engine/Test/CompletionTests.cs @@ -243,7 +243,8 @@ class oar(list): var completions = await server.SendCompletion(uri, 2, 8); completions.Should().HaveItem("append") - .Which.Should().HaveInsertText($"append(self, value):{Environment.NewLine} return super(oar, self).append(value)"); + .Which.Should().HaveInsertText($"append(self, value):{Environment.NewLine} return super(oar, self).append(value)") + .And.HaveInsertTextFormat(InsertTextFormat.PlainText); } [DataRow(PythonLanguageVersion.V36, "value")] @@ -259,7 +260,8 @@ class oar(list): var completions = await server.SendCompletion(uri, 2, 8); completions.Should().HaveItem("append") - .Which.Should().HaveInsertText($"append(self, {parameterName}):{Environment.NewLine} return super().append({parameterName})"); + .Which.Should().HaveInsertText($"append(self, {parameterName}):{Environment.NewLine} return super().append({parameterName})") + .And.HaveInsertTextFormat(InsertTextFormat.PlainText); } [ServerTestMethod(LatestAvailable2X = true), Priority(0)] @@ -417,7 +419,8 @@ public async Task AddBracketsEnabled(Server server, string code, int row, int ch var completion = await server.SendCompletion(uri, row, character); completion.Should().HaveItem(expectedLabel) - .Which.Should().HaveInsertText(expectedInsertText); + .Which.Should().HaveInsertText(expectedInsertText) + .And.HaveInsertTextFormat(InsertTextFormat.Snippet); } [DataRow(PythonLanguageMajorVersion.LatestV2, "foo(self):{0} return super(B, self).foo()")] @@ -438,7 +441,8 @@ class B(A): var completion = await server.SendCompletion(uri, 6, 9); completion.Should().HaveItem("foo") - .Which.Should().HaveInsertText(expectedInsertText); + .Which.Should().HaveInsertText(expectedInsertText) + .And.HaveInsertTextFormat(InsertTextFormat.PlainText); } [TestMethod, Priority(0)] @@ -499,7 +503,8 @@ public async Task Completion_PackageRelativeImport(Server server) { var completion = await server.SendCompletion(uri, 0, 22); completion.Should().HaveItem("right") - .Which.Should().HaveInsertText("right"); + .Which.Should().HaveInsertText("right") + .And.HaveInsertTextFormat(InsertTextFormat.PlainText); } [DataRow(true)] @@ -1008,7 +1013,7 @@ public async Task MultiPartDocument() { public async Task WithWhitespaceAroundDot() { using (var s = await CreateServerAsync()) { var u = await s.OpenDefaultDocumentAndGetUriAsync("import sys\nsys . version\n"); - await AssertCompletion(s, u, new[] { "argv" }, null, new SourceLocation(2, 7), + await AssertCompletion(s, u, new[] { "argv" }, null, new SourceLocation(2, 7), new CompletionContext { triggerCharacter = ".", triggerKind = CompletionTriggerKind.TriggerCharacter }); } } @@ -1029,7 +1034,7 @@ public async Task MarkupKindValid() { } } - private static async Task AssertCompletion(Server s, Uri uri, IReadOnlyCollection contains, IReadOnlyCollection excludes, Position? position = null, CompletionContext? context = null, Func cmpKey = null, string expr = null, Range? applicableSpan = null) { + private static async Task AssertCompletion(Server s, Uri uri, IReadOnlyCollection contains, IReadOnlyCollection excludes, Position? position = null, CompletionContext? context = null, Func cmpKey = null, string expr = null, Range? applicableSpan = null, InsertTextFormat? allFormat = InsertTextFormat.PlainText) { await s.WaitForCompleteAnalysisAsync(CancellationToken.None); var res = await s.Completion(new CompletionParams { textDocument = new TextDocumentIdentifier { uri = uri }, @@ -1040,10 +1045,14 @@ private static async Task AssertCompletion(Server s, Uri uri, IReadOnlyCollectio DumpDetails(res); cmpKey = cmpKey ?? (c => c.insertText); - var items = res.items?.Select(cmpKey).ToList() ?? new List(); + var items = res.items?.Select(i => (cmpKey(i), i.insertTextFormat)).ToList() ?? new List<(string, InsertTextFormat)>(); if (contains != null && contains.Any()) { - items.Should().Contain(contains); + items.Select(i => i.Item1).Should().Contain(contains); + + if (allFormat != null) { + items.Where(i => contains.Contains(i.Item1)).Select(i => i.Item2).Should().AllBeEquivalentTo(allFormat); + } } if (excludes != null && excludes.Any()) { @@ -1119,4 +1128,4 @@ await s.DidOpenTextDocument(new DidOpenTextDocumentParams { return uri; } } -} \ No newline at end of file +} diff --git a/src/Analysis/Engine/Test/FluentAssertions/CompletionItemAssertions.cs b/src/Analysis/Engine/Test/FluentAssertions/CompletionItemAssertions.cs index aedc3d2a3..4e9f3e3b8 100644 --- a/src/Analysis/Engine/Test/FluentAssertions/CompletionItemAssertions.cs +++ b/src/Analysis/Engine/Test/FluentAssertions/CompletionItemAssertions.cs @@ -40,6 +40,15 @@ public AndConstraint HaveInsertText(string insertText, return new AndConstraint(this); } + [CustomAssertion] + public AndConstraint HaveInsertTextFormat(InsertTextFormat insertTextFormat, string because = "", params object[] reasonArgs) { + Execute.Assertion.ForCondition(Subject.insertTextFormat == insertTextFormat) + .BecauseOf(because, reasonArgs) + .FailWith($"Expected '{Subject.label}' completion to have insert text format '{insertTextFormat}'{{reason}}, but it has '{Subject.insertTextFormat}'"); + + return new AndConstraint(this); + } + [CustomAssertion] public AndConstraint HaveDocumentation(string documentation, string because = "", params object[] reasonArgs) { Execute.Assertion.BecauseOf(because, reasonArgs) @@ -51,4 +60,4 @@ public AndConstraint HaveDocumentation(string document return new AndConstraint(this); } } -} \ No newline at end of file +} diff --git a/src/LanguageServer/Impl/Implementation/CompletionAnalysis.cs b/src/LanguageServer/Impl/Implementation/CompletionAnalysis.cs index 699d3126a..28e51ffcf 100644 --- a/src/LanguageServer/Impl/Implementation/CompletionAnalysis.cs +++ b/src/LanguageServer/Impl/Implementation/CompletionAnalysis.cs @@ -200,8 +200,8 @@ public IEnumerable GetCompletions() { return null; } - return addMetadataArg - ? GetCompletionsFromTopLevel().Append(MetadataArgCompletion) + return addMetadataArg + ? GetCompletionsFromTopLevel().Append(MetadataArgCompletion) : GetCompletionsFromTopLevel(); case ForStatement forStatement when TryGetCompletionsInForStatement(forStatement, out var result): @@ -269,7 +269,7 @@ private IEnumerable GetModules(string[] names, bool includeMembe return GetModules(); } - private IEnumerable GetModules() + private IEnumerable GetModules() => Analysis.ProjectState.GetModules().Select(ToCompletionItem); private IEnumerable GetModulesFromNode(DottedName name, bool includeMembers = false) => GetModules(GetNamesFromDottedName(name), includeMembers); @@ -410,6 +410,7 @@ private CompletionItem ToOverrideCompletionItem(IOverloadResult o, ClassDefiniti return new CompletionItem { label = o.Name, insertText = MakeOverrideCompletionString(indent, o, cd.Name), + insertTextFormat = InsertTextFormat.PlainText, kind = CompletionItemKind.Method }; } @@ -799,10 +800,11 @@ private CompletionItem ToCompletionItem(IMemberResult m) { var doc = _textBuilder.GetDocumentation(m.Values, string.Empty); var kind = ToCompletionItemKind(m.MemberType); - + var res = new CompletionItem { label = m.Name, insertText = completion, + insertTextFormat = InsertTextFormat.PlainText, documentation = string.IsNullOrWhiteSpace(doc) ? null : new MarkupContent { kind = _textBuilder.DisplayOptions.preferredFormat, value = doc @@ -825,6 +827,7 @@ private static CompletionItem ToCompletionItem(string text, PythonMemberType typ return new CompletionItem { label = label ?? text, insertText = text, + insertTextFormat = InsertTextFormat.PlainText, // Place regular items first, advanced entries last sortText = char.IsLetter(text, 0) ? "1" : "2", kind = ToCompletionItemKind(type), @@ -976,4 +979,4 @@ private IEnumerable ReadExpressionTokens(IEnumerable