Skip to content

Conversation

@ToddGrun
Copy link
Contributor

@ToddGrun ToddGrun commented Nov 22, 2025

Add the csharp razor keywords to show up in completion after typing an '@'

Should fix #6927 and part of #12483

From David's analysis, which I didn't stray too far away from:

When Roslyn introduced semantic snippets, it broke Razor because it wouldn't offer the if snippet outside of a code block. This is because until you actually write code after an @ in Razor, the compiler doesn't know if it should go in the class, or the render method. Roslyn is "smart" enough not to show if as a completion option if you're at the class level, and of course as soon as you do type @if the Razor compiler is smart enough to put that in the render method, and everyone is happy. Except the user who was just trying to type :)

So as a consequence, we turned off semantic snippets for Razor files, as a temporary workaround. 3 years later is still temporary, right? Anyway, that "turn off for Razor files" is probably broken for cohosting, so we're back in this position. So the plan, in #6927, is for us to add back our own snippets for @ if (and maybe @ for, @ foreach etc.) to this list and then I think we might be good.

Will add more details after verifying this is the desired approach
@ToddGrun ToddGrun marked this pull request as ready for review November 22, 2025 17:43
@ToddGrun ToddGrun requested a review from a team as a code owner November 22, 2025 17:43
Copy link
Member

@davidwengier davidwengier left a comment

Choose a reason for hiding this comment

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

LGTM, though I think its either worth manually testing without cohosting to ensure there aren't duplicate items, or just remove the class from the non-cohosting DI container just in case.

services.AddSingleton<CompletionItemResolver, DelegatedCompletionItemResolver>();
services.AddSingleton<ITagHelperCompletionService, TagHelperCompletionService>();
services.AddSingleton<IRazorCompletionFactsService, LspRazorCompletionFactsService>();
services.AddSingleton<IRazorCompletionItemProvider, CSharpRazorKeywordCompletionItemProvider>();
Copy link
Member

Choose a reason for hiding this comment

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

If my hypothesis is correct, and this issue is caused by semantic tokens, then I think putting this in the non-cohosting editor would actually result in doubling up of completion items for these, as Roslyn will add them as well, so I think perhaps this line is not desirable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Can I have you try out cohosting off and see if you see the keywords in completion after typing just '@'? (I'm not seeing it without my changes)

Copy link
Member

Choose a reason for hiding this comment

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

Well now I'm really confused. Using Version: 18.3.0 Insiders [11220.113.main]

Without cohosting:
image

With cohosting:
image

Copy link
Member

Choose a reason for hiding this comment

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

If I remember I'll pull this branch down tomorrow and see what I get with these changes

Copy link
Contributor Author

@ToddGrun ToddGrun Nov 23, 2025

Choose a reason for hiding this comment

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

Huh, behavior seems to vary across more axes than I tested. I'll do a more comprehensive run through of with/without my changes, at various locations, forced completion versus typed trigger, cohosting on/off and report back probably early tomorrow.

@ToddGrun
Copy link
Contributor Author

@davidwengier -- Verified no duplicate items when I tested with cohosting off. Might be nice to get verification from you since this doesn't fit your mental model.


In reply to: 3497021163

@davidwengier
Copy link
Member

Checked out the branch, and yeah I don't see duplicates, but if I type fast, I can still repro the original problem, so I think my guess about semantic tokens is probably wrong.

It took a couple of attempts typing @if quickly, and backspacing, but I cause this state:
image

Basically the same as Peter says in #12483 (comment).

Having said that, this PR doesn't seem to actively cause problems, so I think it's still fine to merge, just shouldn't be marked as fixing those issues.

@ToddGrun
Copy link
Contributor Author

I've tried a couple dozen times and for the life of me I cannot repro not having "if" in the completion with this change, even with a debugger attached to change the timing. Did you type the full "@if" quickly, or just the "if" part?


In reply to: 3568493906

@ToddGrun
Copy link
Contributor Author

Ooh, if I bring up completion inside a tag's contents, I'm reproducing. Will debug later this morning.


In reply to: 3571458047

…as that has some filtering going on that we don't want for razor csharp keyword completion
@ToddGrun
Copy link
Contributor Author

Commit 3 should fix the issue where keywords weren't being suggested in a non-toplevel context. But I still can't reproduce "if" not showing up in the completion list.


In reply to: 3571481513

@davidwengier
Copy link
Member

I've tried a couple dozen times and for the life of me I cannot repro not having "if" in the completion with this change, even with a debugger attached to change the timing. Did you type the full @if quickly, or just the "if" part?

In the picture I put in yesterday, I just typed @if quickly and stopped. Sometimes if was in the list, in which case I backspaced and tried again, and sometimes it wasn't, in which case I took the screenshot. If I type @if (including the trailing space) then I either get @if or @IFileHttpResult in the doc, but the completion list never shows since I'm typing fast enough.

}

[Fact]
public void ShouldProvideCompletions_ReturnsTrueForSimpleImplicitExpressions_WhenInvoked()
Copy link
Member

Choose a reason for hiding this comment

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

Not suggesting this is worth changing in this PR, but I'm curious others' opinions.

I personally prefer the "integration test" style of tests, where we have a Razor document, and run the whole completion system, and verify that an item is or isn't present, over this direct unit testing. Am I alone in this?

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 actually prefer the integration test style too, but I just followed what DirectiveCompletionItemProvider did for it's testing, as a lot of the code in this PR was copied over from it.

@ToddGrun ToddGrun merged commit c1e400a into dotnet:main Nov 24, 2025
11 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Nov 24, 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.

Roslyn semantic snippets don't know to show if for @i etc.

3 participants