feat(language-service): add Document Symbols support for Angular templates#66690
Conversation
| // Get the navigation tree from TypeScript's language service. | ||
| // This includes classes, functions, variables, and for Angular files, | ||
| // also includes template symbols via the Angular language service. | ||
| const navigationTree = languageService.getNavigationTree(scriptInfo.fileName); |
There was a problem hiding this comment.
Should this only happen for TS files? What do we do about symbols for external templates (html files)
There was a problem hiding this comment.
I've refactored the code to make the two paths clearer:
// For HTML template files, we only need Angular template symbols (no TS symbols)
if (isHtmlFile) {
// Returns template symbols at root level
return convertTemplateSymbols(templateSymbols, scriptInfo);
}
// For TypeScript files, get navigation tree + merge template symbols into classes
// ... TS symbols with (template) node nested under classTest at ivy_spec.ts:411 verifies external HTML templates work.
There was a problem hiding this comment.
I see in the screenshots that the document symbols are separated by the provider. In that case, should we even include the TS document symbols in TS files?
There was a problem hiding this comment.
hmm, yes it is duplicating some positions, but so is html template one doing - should it also skip positions handled by native html? or make it configurable mayby?
There was a problem hiding this comment.
For typescript, I think we should only include the parents of the inline template but should not provide other things from typescript (e.g. ngOnInit random various functions in the file, etc). For HTML, we can leave it as-is to keep it consistent for inline and external templates.
| args.push('--suppressAngularDiagnosticCodes', suppressAngularDiagnosticCodes); | ||
| } | ||
|
|
||
| const documentSymbolsEnabled = config.get<boolean>('angular.documentSymbols.enabled', true); |
There was a problem hiding this comment.
We use middleware above to prevent the angular language server from processing files in projects that don't use Angular. Since the extension activates on all html and ts files, this is relatively important.
There was a problem hiding this comment.
Thx for the hint! Added the provideDocumentSymbols middleware with isInAngularProject guard.
9b9c431 to
9e2edd7
Compare
8b102aa to
a0de8d6
Compare
This commit adds infrastructure for features to request configuration from the VS Code client using the LSP workspace/configuration protocol. This is the preferred approach over CLI arguments because: 1. Configuration changes take effect immediately without restarting 2. Supports per-workspace and per-folder configuration 3. VS Code automatically merges settings from different scopes: - Default settings - User settings (global) - Workspace settings - Workspace folder settings - Language-specific settings The new utilities include: - getWorkspaceConfiguration: Request multiple config sections at once - getConfigurationSection: Convenience wrapper for single sections - flattenConfiguration: Flatten nested config to dot-notation keys This infrastructure will be used by: - Inlay hints feature (PR angular#66731) - Document symbols feature (PR angular#66690)
a0de8d6 to
4b96714
Compare
🔗 Dependency UpdateThis PR now depends on #66734 (feat(language-server): add shared workspace/configuration utilities). Changes in this update:
Merge Order:
The PR has been rebased onto the |
4b96714 to
6fabcea
Compare
Update: Hybrid Approach ImplementedFollowing @atscott's feedback, I've implemented the hybrid approach (Option 1 + 2 from the analysis): Changes:
Default behavior (new):With
|
6fabcea to
e57626d
Compare
sorry, that’s not really what I asked. Please remove all typescript symbols outside of the ancestors of the template property |
| * ); | ||
| * ``` | ||
| */ | ||
| export async function getConfigurationSection<T = unknown>( |
There was a problem hiding this comment.
I don't see this used anywhere
e57626d to
c9b1442
Compare
c9b1442 to
5ca4d1d
Compare
5ca4d1d to
ac699af
Compare
|
I'm leaving out inlay styles support: |
975ac56 to
8ac4109
Compare
| /** | ||
| * Gets the expression text for a template attribute by name. | ||
| */ | ||
| private getTemplateAttrExpression(template: TmplAstTemplate, attrName: string): string { |
There was a problem hiding this comment.
looks like this isn't used anywhere
|
|
||
| const keyedBound = boundAttrs.find( | ||
| (attr) => | ||
| attr.name.toLowerCase().startsWith(directiveNameLower) && |
There was a problem hiding this comment.
This seems suspicous. it might be safer to strictly verify the binding property matches the expected microsyntax key format.
|
|
||
| let name: string; | ||
| let kind: ts.ScriptElementKind; | ||
| let lspKind: AngularSymbolKind | undefined; |
There was a problem hiding this comment.
this looks like it's always undefined
There was a problem hiding this comment.
If the intent is for components to have the Class icon to differentiate them from HTML elements, it's better to make this explicit. Consider adding Class = 5 to the AngularSymbolKind enum and explicitly setting lspKind: AngularSymbolKind.Class.
Alternatively, if components should be grouped visually with standard HTML elements in the Outline view, you should explicitly set lspKind: AngularSymbolKind.Object for them as well.
|
Overall, this is looking good. Can you also add a note in the commit message of the document symbol one for "resolves #65488" |
871e886 to
c84dc34
Compare
atscott
left a comment
There was a problem hiding this comment.
AGENT: I have completed a thorough review of this PR. The implementation of document symbols using the new AngularSymbolKind is correct and provides excellent structural representation for Angular templates. The approach of nesting template symbols within the component class is the best path forward given VS Code's Outline behavior with multiple providers. The logic for identifying structural directives and variables is solid, and the integration tests provide great coverage. Great work!
|
Please rebase the PR but this otherwise LGTM |
c84dc34 to
b4a3f73
Compare
@atscott sorry for the delay. Thank You for dedicating Your time! |
b4a3f73 to
4fa07c1
Compare
|
last push cleaned up how changes were divided between commits |
4fa07c1 to
941b308
Compare
|
lint fixed |
There was a problem hiding this comment.
Great work adding Document Symbol support for Angular templates! The implementation nicely addresses the previous feedback.
I reviewed the changes against the existing comments:
- External HTML template files are now properly handled.
- The special handling for
router-outlethas been removed. - For TypeScript files, the filter logic correctly hides generic TypeScript properties and functions from the Angular LS output, leaving only the component structure and its nested template symbols (avoiding clutter with duplicate TS symbols).
- Extracting microsyntax let/as keys is now robust and backed by solid test cases.
One minor nit in packages/language-service/src/document_symbols.ts:
TmplAstBoundEventandParseSourceSpanare imported at the top of the file but are unused.- Around line 144, the
DocumentSymbolsOptionsgets imported and re-exported redundantly, which could be collapsed:
import {AngularSymbolKind, DocumentSymbolsOptions, TemplateDocumentSymbol} from '../api';
export {AngularSymbolKind, DocumentSymbolsOptions, TemplateDocumentSymbol};Aside from those small details, this looks fantastic and is ready to go!
Edit: You can ignore this. I was doing a final agent review pass.
941b308 to
523a732
Compare
Fixed before realized not needed to do it :) Thank You again for your work put into this PR as well! Looking forward to merge next one :) |
523a732 to
9c1e935
Compare
|
commit messages now adhere to a minimum length |
…lates Add DocumentSymbol provider for Angular templates, surfacing structural elements like components, directives, control flow blocks, and template variables in the VS Code Outline and breadcrumbs. resolves angular#65488
9c1e935 to
ba920ff
Compare
|
This PR was merged into the repository. The changes were merged into the following branches:
|
|
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |



PR: feat(language-service): add Document Symbols support for Angular templates
Description
Adds comprehensive Document Symbols support for Angular templates, enabling the Outline panel, breadcrumbs navigation, and "Go to Symbol" (Cmd+Shift+O / Ctrl+Shift+O) features to work with Angular template syntax.
Features
Block Syntax Support
@if,@else,@else ifwith expression and alias display@forwith track expression and context variables@switch,@case,@defaultblocks@defer,@placeholder,@loading,@errorblocks with triggers@letdeclarationsStructural Directive Support
*ngIf,*ngFor,*ngSwitch,*ngSwitchCase,*ngSwitchDefault*ngTemplateOutlet,*ngComponentOutlet,*ngPlural,*ngPluralCaseTemplate File Support
(template)node in component classtemplateUrl)Multi-Component Support
Variables and References
let item)#ref)let i = $index)as alias)SymbolKind Mappings
@if,@else,@switch,@case@for,@empty@defer,@placeholder,@loading,@errorConfiguration
angular.documentSymbols.enabled(default:true)Enables Angular-specific document symbols.
angular.documentSymbols.showImplicitForVariables(default:false)Shows all implicit
@forloop variables ($index,$count,$first,$last,$even,$odd).Example
Template:
@for (item of items; track item.id; let i = $index) { @if (item.visible; as isVisible) { <div #container (click)="onClick()"> {{ item.name }} </div> } }Outline:
Breaking Changes
None
Related Issues
Closes #66691
AI Disclosure
This PR was developed using Claude Opus 4.6 and GPT 5.3 Max AI assistants under human orchestration and review by @kbrilla.