diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs index bebeef99665..0f91f0f59c0 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/AbstractRazorSemanticTokensInfoService.cs @@ -346,6 +346,19 @@ static bool TryWriteToken( { return false; } + + // If the previous range was from Razor and the current range is from C#, + // and the current range is contained within the previous range, skip it. + // This handles cases like fully qualified component names where Razor provides + // a single token but C# provides multiple tokens for the parts. + if (previousRange.FromRazor && + !currentRange.FromRazor && + previousRange.EndLine == currentRange.EndLine && + previousRange.StartCharacter <= currentRange.StartCharacter && + previousRange.EndCharacter >= currentRange.EndCharacter) + { + return false; + } } else { diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticRange.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticRange.cs index f7c6602112a..a699d477e02 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticRange.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/SemanticTokens/SemanticRange.cs @@ -70,6 +70,17 @@ public int CompareTo(SemanticRange other) return result; } + // If we have ranges with the same start position, we want a Razor produced token to win over a non-Razor produced token + // This is checked before comparing end positions to ensure Razor tokens that span multiple C# tokens are processed first + if (FromRazor && !other.FromRazor) + { + return -1; + } + else if (other.FromRazor && !FromRazor) + { + return 1; + } + result = EndLine.CompareTo(other.EndLine); if (result != 0) { @@ -82,16 +93,6 @@ public int CompareTo(SemanticRange other) return result; } - // If we have ranges that are the same, we want a Razor produced token to win over a non-Razor produced token - if (FromRazor && !other.FromRazor) - { - return -1; - } - else if (other.FromRazor && !FromRazor) - { - return 1; - } - return 0; } diff --git a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostSemanticTokensRangeEndpointTest.cs b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostSemanticTokensRangeEndpointTest.cs index 806d69b0e92..ba5266f1418 100644 --- a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostSemanticTokensRangeEndpointTest.cs +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Endpoints/Shared/CohostSemanticTokensRangeEndpointTest.cs @@ -94,6 +94,19 @@ @section MySection { await VerifySemanticTokensAsync(input, colorBackground, miscellaneousFile, fileKind: RazorFileKind.Legacy); } + [Theory] + [CombinatorialData] + public async Task FullyQualifiedComponent(bool colorBackground, bool miscellaneousFile) + { + var input = """ + @page "/" + + Hello + """; + + await VerifySemanticTokensAsync(input, colorBackground, miscellaneousFile); + } + [Theory] [CombinatorialData] public async Task Legacy_Compatibility(bool colorBackground, bool miscellaneousFile) diff --git a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent.txt b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent.txt new file mode 100644 index 00000000000..1d095c4e7a4 --- /dev/null +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent.txt @@ -0,0 +1,11 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [] ["/"] +2 0 1 markupTagDelimiter [] [<] +0 1 45 razorComponentElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] +0 6 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 45 razorComponentElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] diff --git a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent_misc_file.txt b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent_misc_file.txt new file mode 100644 index 00000000000..8d59eddd95f --- /dev/null +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent_misc_file.txt @@ -0,0 +1,11 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [] ["/"] +2 0 1 markupTagDelimiter [] [<] +0 1 45 markupElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] +0 6 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 45 markupElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] diff --git a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent_with_background.txt b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent_with_background.txt new file mode 100644 index 00000000000..eeae8ffea41 --- /dev/null +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent_with_background.txt @@ -0,0 +1,11 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [razorCode] ["/"] +2 0 1 markupTagDelimiter [] [<] +0 1 45 razorComponentElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] +0 6 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 45 razorComponentElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] diff --git a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent_with_background_misc_file.txt b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent_with_background_misc_file.txt new file mode 100644 index 00000000000..66fd299c73e --- /dev/null +++ b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles/SemanticTokens/FullyQualifiedComponent_with_background_misc_file.txt @@ -0,0 +1,11 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [razorCode] ["/"] +2 0 1 markupTagDelimiter [] [<] +0 1 45 markupElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] +0 6 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 45 markupElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] diff --git "a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent.txt" "b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent.txt" new file mode 100644 index 00000000000..1d095c4e7a4 --- /dev/null +++ "b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent.txt" @@ -0,0 +1,11 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [] ["/"] +2 0 1 markupTagDelimiter [] [<] +0 1 45 razorComponentElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] +0 6 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 45 razorComponentElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] diff --git "a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent_misc_file.txt" "b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent_misc_file.txt" new file mode 100644 index 00000000000..8d59eddd95f --- /dev/null +++ "b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent_misc_file.txt" @@ -0,0 +1,11 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [] ["/"] +2 0 1 markupTagDelimiter [] [<] +0 1 45 markupElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] +0 6 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 45 markupElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] diff --git "a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent_with_background.txt" "b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent_with_background.txt" new file mode 100644 index 00000000000..eeae8ffea41 --- /dev/null +++ "b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent_with_background.txt" @@ -0,0 +1,11 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [razorCode] ["/"] +2 0 1 markupTagDelimiter [] [<] +0 1 45 razorComponentElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] +0 6 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 45 razorComponentElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] diff --git "a/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent_with_background_misc_file.txt" "b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent_with_background_misc_file.txt" new file mode 100644 index 00000000000..66fd299c73e --- /dev/null +++ "b/src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/TestFiles\\SemanticTokens\\FullyQualifiedComponent_with_background_misc_file.txt" @@ -0,0 +1,11 @@ +Line Δ, Char Δ, Length, Type, Modifier(s), Text +0 0 1 razorTransition [] [@] +0 1 4 razorDirective [] [page] +0 5 3 string [razorCode] ["/"] +2 0 1 markupTagDelimiter [] [<] +0 1 45 markupElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>] +0 6 1 markupTagDelimiter [] [<] +0 1 1 markupTagDelimiter [] [/] +0 1 45 markupElement [] [Microsoft.AspNetCore.Components.Web.PageTitle] +0 45 1 markupTagDelimiter [] [>]