Skip to content

Fix semantic tokens for fully qualified component names#12334

Closed
Copilot wants to merge 2 commits intomainfrom
copilot/fix-fully-qualified-components
Closed

Fix semantic tokens for fully qualified component names#12334
Copilot wants to merge 2 commits intomainfrom
copilot/fix-fully-qualified-components

Conversation

Copy link
Contributor

Copilot AI commented Oct 15, 2025

Problem

Fully qualified component names were displaying with incorrect colorization in the editor. When using components like <Microsoft.AspNetCore.Components.Web.PageTitle>, the C# semantic tokens (namespace, operator, class) were showing through instead of being overridden by Razor's component element token:

image

Root Cause

The issue was in the SemanticRange.CompareTo sorting logic. When multiple semantic tokens started at the same position, the sort order was:

  1. Start line
  2. Start character
  3. End line
  4. End character ← Problem: Shorter tokens sorted first
  5. FromRazor flag ← Never reached when end positions differ

This caused shorter C# tokens (e.g., "Microsoft" at chars 1-10) to be sorted before the longer Razor token (chars 1-46), preventing the Razor token from overriding the C# tokens.

Solution

Modified SemanticRange.CompareTo: Moved the FromRazor check to occur immediately after comparing start positions, before comparing end positions. This ensures Razor tokens at the same start position always sort first, regardless of length.

Added containment filtering in TryWriteToken: Added logic to skip C# tokens that are fully contained within a Razor token on the same line, providing an additional safeguard.

Testing

Added comprehensive test coverage with the new FullyQualifiedComponent test that verifies:

  • Fully qualified component names display as single razorComponentElement tokens
  • Both component and non-component (miscellaneous file) scenarios work correctly
  • Background color variations work as expected

All existing semantic tokens tests continue to pass with no regressions.

Fixes #11480 (if applicable - replace with actual issue number)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • 2kmvsblobprodcus39.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • 2zrvsblobprodcus388.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • 7devsblobprodcus323.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • 7tjvsblobprodcus341.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • bcnvsblobprodcus378.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • frdvsblobprodcus327.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • ibzvsblobprodcus369.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • imzvsblobprodcus368.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • josvsblobprodcus372.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • kgfvsblobprodcus314.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • kh4vsblobprodcus325.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • kijvsblobprodcus387.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • l49vsblobprodcus358.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • mobile.events.data.microsoft.com
    • Triggering command: /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/razor/razor/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension.Test/Debug/net9.0/Microsoft.VisualStudioCode.RazorExtension.Test.runtimeconfig.json --depsfile /home/REDACTED/work/razor/razor/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension.Test/Debug/net9.0/Microsoft.VisualStudioCode.RazorExtension.Test.deps.json /home/REDACTED/work/razor/razor/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension.Test/Debug/net9.0/testhost.dll --port 46623 --endpoint 127.0.0.1:046623 --role client --parentprocessid 6323 --telemetryoptedin false (dns block)
    • Triggering command: /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/razor/razor/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension.Test/Debug/net9.0/Microsoft.VisualStudioCode.RazorExtension.Test.runtimeconfig.json --depsfile /home/REDACTED/work/razor/razor/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension.Test/Debug/net9.0/Microsoft.VisualStudioCode.RazorExtension.Test.deps.json /home/REDACTED/work/razor/razor/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension.Test/Debug/net9.0/testhost.dll --port 40259 --endpoint 127.0.0.1:040259 --role client --parentprocessid 6599 --telemetryoptedin false (dns block)
    • Triggering command: /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/razor/razor/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension.Test/Debug/net9.0/Microsoft.VisualStudioCode.RazorExtension.Test.runtimeconfig.json --depsfile /home/REDACTED/work/razor/razor/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension.Test/Debug/net9.0/Microsoft.VisualStudioCode.RazorExtension.Test.deps.json /home/REDACTED/work/razor/razor/artifacts/bin/Microsoft.VisualStudioCode.RazorExtension.Test/Debug/net9.0/testhost.dll --port 42535 --endpoint 127.0.0.1:042535 --role client --parentprocessid 11560 --telemetryoptedin false (dns block)
  • s4uvsblobprodcus326.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)
  • u3hvsblobprodcus371.vsblob.vsassets.io
    • Triggering command: dotnet build src/Razor/test/Microsoft.VisualStudioCode.RazorExtension.Test/Microsoft.VisualStudioCode.RazorExtension.Test.csproj (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Fully qualified components look bad</issue_title>
<issue_description>Presumably broken by my start tag mapping:

Image

Razor semantic tokens is supposed to override C# semantic tokens, but clearly that doesn't happen if there is a fully qualified component name. We probably don't have any test coverage for that.</issue_description>

<agent_instructions>New tests should be in CohostSemanticTokensRangeEndpointTest</agent_instructions>

Comments on the Issue (you are @copilot in this section)

Fixes #12330


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

- Modified SemanticRange.CompareTo to prioritize Razor tokens over C# tokens when they have the same start position
- Added containment check in TryWriteToken to filter out C# tokens that are fully contained within Razor tokens
- Added test case for fully qualified component names with baseline files
- Fixes issue where C# semantic tokens (namespace, operator, class) were showing through instead of being overridden by Razor component element tokens

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix fully qualified components rendering issue Fix semantic tokens for fully qualified component names Oct 15, 2025
Copilot AI requested a review from davidwengier October 15, 2025 00:59
davidwengier added a commit that referenced this pull request Oct 15, 2025
Fixes #12330

Our overlap logic only checked for overlaps at the start character, but
now C# ranges can be fully contained within a Razor range. Also, the
sort was wrong, because it only preferred Razor for a full overlap.

Also seeing what copilot comes up with in
#12334 just for fun :)
@davidwengier davidwengier deleted the copilot/fix-fully-qualified-components branch December 11, 2025 02:50
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.

Fully qualified components look bad

2 participants