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 at end of document #11343

Merged
merged 11 commits into from
Jan 2, 2025

Conversation

davidwengier
Copy link
Contributor

Fixes element completion at the end of a document.
Also closes #4622 by adding a test to prove it doesn't repro.

@davidwengier davidwengier requested a review from a team as a code owner January 2, 2025 00:12
absoluteIndex > 0)
{
// If we're at the end of the file, we check if the previous token is an open angle (ie, we're in <$$[EOF])
// because even though the tree won't match our expectations for an incomplete start tag, thats what it is.
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to modify RazorSyntaxFacts.IsAnyStarTag instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Even if we did that, it wouldn't solve the issue for this because the final check in this method checks the span of the start tag, and that span doesn't include the end of file. Unless the compiler changes the shape of the Razor syntax tree I think this is always going to need some kind of special-casing.

}
snippetCompletionItemProvider.SnippetCache.Update(SnippetLanguage.Html, [
new SnippetInfo("snippet1", "snippet1", "snippet1", string.Empty, SnippetLanguage.Html),
new SnippetInfo("snippet2", "snippet2", "snippet2", string.Empty, SnippetLanguage.Html)]);
Copy link
Contributor

Choose a reason for hiding this comment

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

I really don't like this actually. It's not at all clear not whey the test is specifying that "snippet1" and "snippet2" are not expected. Also we are hardcoding setup in Verify method.

I wouldn't have a problem with some sort of a common setup instead, but this looks wrong to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

All of our test setup is in this Verify method, and this change is simply making snippets part of the common setup. IMO tests should state the inputs, and expected outputs, and only do set up if there is something special they need. In a real user scenario there are snippets that are installed by default, therefore having snippets present by default in tests makes sense to me. If there was a test that specifically wanted to cover a scenario where there are no snippets, that should be the exception not the rule.

I've updated the tests to use a shared constant for each snippet, so there is no "magic string" effect in the tests, does that help?

Copy link
Contributor

Choose a reason for hiding this comment

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

Thank you, that does make it easier to reason about it IMHO - I may have even made the snippet label collection private static readonly field.

I guess a logical question would be - should be we do the same thing with HTML labels then? (Not asking you to do either change in this PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, probably. If we assume that any time Html is asked for completion items it will return "div" and "a", then a test that doesn't specify delegatedItemLabels could be passing by accident because it assumes that the delegated server wasn't called, but in actual fact there just wasn't a test setup for it.

Probably should have all tests explicitly verify whether they expect Html completion, C# completion, tag helper completion and/or snippet completion, and verify the presence/lack of items every time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I ended up reverting this change, as it was actually hiding a bug. I added it initially because I was annoyed at a test failing because the "Update" method on the snippet provider happened to not be called, and I thought it was a test setup issue, but turns out that actually signifies a product bug and should have failed the test, just ideally in a better way. I'm fixing that now by adding dummy delegated and snippet items that should never appear as results, and failing the test if they do.

@@ -292,7 +292,7 @@ await _provider.GetCompletionListAsync(

[Theory]
[InlineData("$$", true)]
[InlineData("<$$", true)]
[InlineData("<$$", false)]
[InlineData(">$$", true)]
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a behavior change from the legacy editor. Legacy editor would've included snippets here. If we are trying to reduce friction while removing legacy editor, this might be a somewhat important scenario. E.g. previously (in legacy) you could type in "<" to invoke html completion, scroll or type more to select snippet, and tab to complete snippet. With this change snippets will be absent (and possibly they should've been present in more cases).

I want to make sure we realize there is a behavior change here that affects end users and are fine with it if we are to go through with this change.

Copy link
Contributor

Choose a reason for hiding this comment

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

Legacy:

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This PR is not introducing that behaviour change, it was introduced when we added snippets. We don't show snippets when bringing up completion inside a tag, legacy does. This PR doesn't change that, it just makes our experience the same whether typing at the end of a document or in the middle.

Copy link
Contributor

Choose a reason for hiding this comment

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

In that case we probably should've had a test case like <$$ <div></div> to illustrate that. This was before my time as active contributor, I assume we discussed this behavior difference and are fine with it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't remember specifically but given LSP snippets and legacy snippets work in a fundamentally different way, I don't think it could have happened any other way. I think of it more like "show a subset of snippets as completion items", rather than "support snippets in Razor". If we were to show snippets inside elements in the LSP editor the user would end up with two <s at the start of their tag, as the snippet includes one.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah, there is special code in the legacy HTML to see if there is an "<" in front of snippet shortcut. I guess we can leave it as is unless there are user complaints (especially since we already shipped it like this and haven't heard any complaints AFAIK). @danroth27 and @leslierichardson95 FYI.

@davidwengier davidwengier enabled auto-merge January 2, 2025 05:39
@davidwengier davidwengier merged commit d52a45b into dotnet:main Jan 2, 2025
11 of 12 checks passed
@davidwengier davidwengier deleted the CompletionAtEndOfDocument branch January 2, 2025 06:23
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jan 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Component attributes at end of file do not receive HTML completion suggestions
2 participants