Skip to content

Provide IntelliSense for ~/ asset paths in Razor components #84793

Description

@chsienki

Context

Razor components support opt-in compile-time ~/ asset-path expansion (dotnet/aspnetcore#68229): a literal like <img src="~/images/logo.png"> is rewritten to Assets["images/logo.png"] when the (element, attribute) pair is declared via [AcceptsAssetPath] or a component parameter is marked [AssetPath]. The compiler side lives under src/Razor/src/Compiler (ComponentTildePathPass, AcceptsAssetPathTagHelperProducer, PropertyMetadata.AcceptsAssetPath).

Today there is no IntelliSense for these paths. Inside an opted-in attribute value, ~/... is plain HTML attribute text to the tooling; nothing offers the set of available static web assets as completions.

Proposal

Provide completion for asset paths when the cursor is inside an opted-in location whose value begins with ~/, offering the project's available static web assets.

This splits into two halves:

1. Where to offer it (trigger) -- small, idiomatic

Razor tooling aggregates IRazorCompletionItemProvider implementations via RazorCompletionListProvider (e.g. DirectiveAttributeCompletionItemProvider). A new provider can reuse the exact opt-in metadata the compiler already reads:

  • the [AcceptsAssetPath] allowlist, surfaced as AssetPathMetadata tag-helper descriptors, and
  • [AssetPath] component parameters, surfaced as PropertyMetadata.AcceptsAssetPath.

Using that, the provider detects the cursor is inside an opted-in element/attribute or component parameter whose value starts with ~/ and contributes completion items. Under cohosting this lands in the cohost completion path (CohostDocumentCompletionEndpoint).

2. What to offer (the data) -- the real work

The available assets come from the static web assets manifest the SDK emits. Razor tooling currently has zero awareness of it (no manifest reading anywhere under src/Razor). This requires plumbing the project's static-web-asset keys into the language server -- an OOP/cohost service that reads the manifest and refreshes it on rebuild.

Effort / open questions

  • The completion provider itself is small (~a day).
  • The asset-source plumbing + freshness across rebuilds is the bulk of the work and the main open question (manifest location/format, how to keep it current, OOP surface).

Links

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions