Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix completion in an empty document #11344

Merged
merged 1 commit into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT license. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading;
Expand Down Expand Up @@ -47,6 +48,17 @@ public static DocumentPositionInfo GetPositionInfo(
int hostDocumentIndex)
{
var sourceText = codeDocument.Source.Text;

if (sourceText.Length == 0)
{
Debug.Assert(hostDocumentIndex == 0);

// Special case for empty documents, to just force Html. When there is no content, then there are no source mappings,
// so the map call below fails, and we would default to Razor. This is fine for most cases, but empty documents are a
// special case where Html provides much better results when users first start typing.
return new DocumentPositionInfo(RazorLanguageKind.Html, new Position(0, 0), hostDocumentIndex);
Copy link
Contributor

@alexgav alexgav Jan 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the comment! :) #Resolved

}

var position = sourceText.GetPosition(hostDocumentIndex);

var languageKind = codeDocument.GetLanguageKind(hostDocumentIndex, rightAssociative: false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,59 @@ The end.
snippetLabels: ["snippet1", "snippet2"]);
}

[Fact]
public async Task HtmlSnippetsCompletion_EmptyDocument()
{
await VerifyCompletionListAsync(
input: """
$$
""",
completionContext: new RoslynVSInternalCompletionContext()
{
InvokeKind = RoslynVSInternalCompletionInvokeKind.Explicit,
TriggerCharacter = null,
TriggerKind = RoslynCompletionTriggerKind.Invoked
},
expectedItemLabels: ["snippet1", "snippet2"],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an unfortunate behavior change/regression in empty HTML document in HTML LSP editor. It no longer shows tags (as non-LSP editor and thus legacy Razor editor used to). E.g. legacy HTML

image

but no completion at all in LSP HTML editor (since there aren't any snippets). By extension that affects Razor as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues with changes in this PR though, thank you for fixing this case!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same conversation as #11343 (comment) really.

This PR isn't introducing any regression or change in behaviour. We don't show Html elements or components when completion is invoked on an empty line, as the completion items don't have the < in them, so they wouldn't produce valid code. This PR just makes the experience the same whether the document is empty or not.

snippetLabels: ["snippet1", "snippet2"]);
}

[Fact]
public async Task HtmlSnippetsCompletion_WhitespaceOnlyDocument1()
{
await VerifyCompletionListAsync(
input: """

$$
""",
completionContext: new RoslynVSInternalCompletionContext()
{
InvokeKind = RoslynVSInternalCompletionInvokeKind.Explicit,
TriggerCharacter = null,
TriggerKind = RoslynCompletionTriggerKind.Invoked
},
expectedItemLabels: ["snippet1", "snippet2"],
snippetLabels: ["snippet1", "snippet2"]);
}

[Fact]
public async Task HtmlSnippetsCompletion_WhitespaceOnlyDocument2()
{
await VerifyCompletionListAsync(
input: """
$$

""",
completionContext: new RoslynVSInternalCompletionContext()
{
InvokeKind = RoslynVSInternalCompletionInvokeKind.Explicit,
TriggerCharacter = null,
TriggerKind = RoslynCompletionTriggerKind.Invoked
},
expectedItemLabels: ["snippet1", "snippet2"],
snippetLabels: ["snippet1", "snippet2"]);
}

[Fact]
public async Task HtmlSnippetsCompletion_NotInStartTag()
{
Expand Down
Loading