Skip to content

Use document structure in breadcrumbs, sticky scroll, and outline in VSCode#81993

Merged
dibarbet merged 15 commits intomainfrom
copilot/fix-document-symbols-handler
Jan 21, 2026
Merged

Use document structure in breadcrumbs, sticky scroll, and outline in VSCode#81993
dibarbet merged 15 commits intomainfrom
copilot/fix-document-symbols-handler

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jan 13, 2026

The DocumentSymbolsHandler was using NavigationBarItemService which flattens the document hierarchy and excludes namespaces. This breaks VS Code's "Sticky Scroll" feature which requires proper hierarchical symbols.

Resolves dotnet/vscode-csharp#7985
Resolves dotnet/vscode-csharp#7762
Resolves dotnet/vscode-csharp#8880
Resolves dotnet/vscode-csharp#5278
Resolves dotnet/vscode-csharp#3519

New Behavior

image image

VS outline

image

VS sln explorer

image

Add DocumentSymbolsHandler.CSharpSyntaxWalker.cs that provides proper
hierarchical document symbols including namespaces for features like
VS Code's Sticky Scroll. The implementation uses only syntax analysis.

Update existing tests to expect the new namespace hierarchy.

Co-authored-by: dibarbet <5749229+dibarbet@users.noreply.github.com>
Copilot AI and others added 2 commits January 13, 2026 20:15
Add tests for:
- Nested namespace hierarchies
- Classes without namespaces
- Nested types (e.g., nested enums in classes)

Co-authored-by: dibarbet <5749229+dibarbet@users.noreply.github.com>
Co-authored-by: dibarbet <5749229+dibarbet@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix DocumentSymbols handler to use CSharpSyntaxWalker Use CSharpSyntaxWalker for hierarchical document symbols to support VS Code Sticky Scroll Jan 13, 2026
Copilot AI requested a review from dibarbet January 13, 2026 20:26
@dibarbet dibarbet changed the title Use CSharpSyntaxWalker for hierarchical document symbols to support VS Code Sticky Scroll Use document structure in breadcrumbs, sticky scroll, and outline in VSCode Jan 14, 2026
@dibarbet dibarbet marked this pull request as ready for review January 14, 2026 19:51
@dibarbet dibarbet requested a review from a team as a code owner January 14, 2026 19:51
@dibarbet dibarbet marked this pull request as draft January 16, 2026 02:02
Comment thread src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs Outdated
TEnumDeclarationSyntax,
TTypeDeclarationSyntax>
TTypeDeclarationSyntax,
TMemberStatement>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

glad you could reuse this type.

does this mean SolutionExplorer is changing as well?

Copy link
Copy Markdown
Member

@dibarbet dibarbet Jan 16, 2026

Choose a reason for hiding this comment

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

A little bit - it will now show local functions as well. I just added namespace support, but I made that optional and so the sln explorer will not show namespace nodes (only in the doc outline window).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

that seems fine :)

=> typeDeclaration.Members;

protected override bool TryAddNamespace(
DocumentId documentId, MemberDeclarationSyntax member, ArrayBuilder<SymbolTreeItemData> items, StringBuilder nameBuilder)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

fwiw, havin this return a boolean doesn't actually seem that helpful. i would personally remove.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it needs to return a boolean here because a member could be a type declaration or a namespace. The caller observes the return - and if false tries to add the member as a type.

I suppose technically that check could be extracted out of this method and into the caller - is that the change you'd like me to make?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

my thought was that the caller just tries both blindly. only one of the callees at most will handle the call, so it's fine.

(but i may be not understanding properly why it's important to skip the other callee if the first succeeds. it is almost 5am here) :)


var text = await document.GetValueTextAsync(cancellationToken).ConfigureAwait(false);

if (useHierarchicalSymbols)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

when do we not do this now?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Technically it is a client capability, so any client could set this. But the only client we have that sets this is VS LiveShare, where document symbols power the navbar. The navbar doesn't support deep nesting so makes sense to continue using the navbar service there.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We may want to add a comment here explaining that.

Comment thread src/LanguageServer/Protocol/Handler/Symbols/DocumentSymbolsHandler.cs Outdated
@dibarbet dibarbet marked this pull request as ready for review January 16, 2026 03:26
// Get the full span from the declaration node and the selection span from the navigation token
var fullSpan = itemSyntax.DeclarationNode.Span;
// If we're in the middle of typing, the navigation token (typically identifier) may be missing and this will be a SyntaxKind.None (0)
var selectionSpan = itemSyntax.NavigationToken.RawKind == 0 ? itemSyntax.DeclarationNode.Span : itemSyntax.NavigationToken.Span;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Would the span also be empty in that case? Is it easier to just do something like

Suggested change
var selectionSpan = itemSyntax.NavigationToken.RawKind == 0 ? itemSyntax.DeclarationNode.Span : itemSyntax.NavigationToken.Span;
var selectionSpan = itemSyntax.NavigationToken.Span.Length == 0 ? itemSyntax.DeclarationNode.Span : itemSyntax.NavigationToken.Span;

Just in case the parser ever gives us an empty but identified token?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the span is empty, but I also wasn't sure if we might ever get a valid token with no span. If that can't happen then happy to go with the length check

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I def think you can get empty identifier tokens. They will just have length 0, but a normal kind.

@dibarbet dibarbet merged commit b72210c into main Jan 21, 2026
25 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jan 21, 2026
@PavelCibulka
Copy link
Copy Markdown

This looks great. Are we also going to be able to see regions in C# outlines?
dotnet/vscode-csharp#5280 (comment)

@davidwengier davidwengier modified the milestones: Next, 18.4 Jan 27, 2026
davidwengier added a commit to dotnet/razor that referenced this pull request Feb 2, 2026
Responding to changes in Roslyn in dotnet/roslyn#81993
davidwengier added a commit to davidwengier/razor that referenced this pull request Feb 19, 2026
Responding to changes in Roslyn in dotnet/roslyn#81993
davidwengier added a commit to davidwengier/razor that referenced this pull request Feb 20, 2026
Responding to changes in Roslyn in dotnet/roslyn#81993
jjonescz added a commit to dotnet/razor that referenced this pull request Mar 31, 2026
* Update post 18.4 snap

* Fix indentation following self closing tag with lambda attribute

* Change insertionCreateDraftPR to false

* Upgrade dotnet version to 10.0.102

* Update dependencies from https://github.com/dotnet/arcade build 20260130.4
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26066.3 -> To Version 10.0.0-beta.26080.4

* Initial plan

* Add html.autoClosingTags setting support in VS Code Cohosting

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Fix: Use snake_case for html.auto_closing_tags setting name

Changed from html.autoClosingTags to html.auto_closing_tags to match VS Code's
snake_case naming convention. Added comment explaining the naming pattern for
future setting additions.

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Update to net10.0 and packages to .NET 10

* Update docs

* Use net10 for tests

* Remove unnecessary code block

* Fix CA warning

* Fix document symbol tests

Responding to changes in Roslyn in dotnet/roslyn#81993

* Fix settings.json for this repo

* Create integration test project, and services for installing and running VS Code

* Add formatting tests and services

* Add go to def and FAR tests and services

* Add diagnostics tests and services

* Add completion tests and services

* Add hover tests and services

* Add code action tests and services

* Add some docs

* Use Playwright locator API

* Move method to services

* Remove a few delays

* Remove unused methods

* Simplify selector

* Simplify get problems code

* Various test fixes

* Fix select word

* Improve TestServices access

* Misc bits of PR feedback

* Revamp special key handling

* Don't assume source mappings are in order of their original spans

* Improve the "next" C# position logic

* Move First to after Count

* Consolidate all timeout waits to a helper method

* PR feedback

* PR Feedback

* Use Razor.slnx by default, and remove old setting

* Add some follow up tests

* Dont run in CI

* Create specific syntax node type for using directives

* Parse using directives as using directives

* Update code that deals with using directives to handle the new type, simplifying a bunch of it

* Add a strongly typed property for the directive body, to simplify code

This has always annoyed that we had to cast this, so thought I'd twaek it while we're here.

* Fix semantic tokens

* Clean up a few other spots I missed earlier

* Update compiler test baselines

* Use the VS2022 release image in CI

* [main] Update dependencies from dotnet/arcade (#12748)

* Update dependencies from https://github.com/dotnet/arcade build 20260204.6
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26080.4 -> To Version 10.0.0-beta.26104.6

* Update dependencies from https://github.com/dotnet/arcade build 20260206.4
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26080.4 -> To Version 10.0.0-beta.26106.4

* Update dependencies from https://github.com/dotnet/arcade build 20260210.1
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26080.4 -> To Version 10.0.0-beta.26110.1

---------

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>

* Handle when formatters insert entirely blank lines between original lines

* Consume original and formatter lines to correctly handle VS Code moving attributes around in various ways.

* Simplify and extract to separate methods (with annoyingly long parameter lists)

* Reduce string allocations in ParseUsingDeclaration by replacing LINQ + Concat(this WorkspaceEdit, WorkspaceEdit?) with StringBuilder loop

* Use pooled StringBuilders as per feedback

* remove unused using

* Modify RazorCSharpDocument to keep SourceMappings sorted by both original and generated document positions (#12772)

* Modify RazorCSharpDocument to keep sourcemappings sorted by both Original and Generated document indices

This class previously just kept an array that was sorted by generated positions. Many callers would benefit instead from an array sorted by original (html) posititions. This allows many loops to short-circuit once they've moved beyond any mappings that could be of interest to them.

This also renamed the original array to indicate it's sorted by generated positions, and to validate that upon it's input, as some callers were assuming that. By renaming this variable, it will hopefully make callers

1) Aware that the input is sorted and may be short-circuited or binary searched
2) Aware what it is sorted by (eg: formatting had some code that was assuming the array was sorted by original position)

* Be more resilient to bad input

* Use Debug.Fail

* Fix test to do different validation in debug/release

* Initial plan

* Add UTF-8 string literal support and comprehensive tests

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Address code review: Fix length check for UTF-8 string validation

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Fix length check: Use expectedPostfix.Length + 2 for proper UTF-8 validation

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Improve comments in IsStringProperlyTerminated for clarity

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Use a non-capturing group so as not to break things

* Address PR feedback: Add UTF-8 raw string literal tests and fix .cshtml test file

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Fix RazorFormattingPass when multiple markup blocks are on the same line

* Don't crash if we produce bad data in document generation

* Add obsolete attribute tests

* Add new helper methods and simplify code

* Futile update to copilot instructions

* PR Feedback

* Add theme info for leading whitespace to a comment (#12791)

* Initial plan

* Fix formatting for void tag helpers by moving IsVoidElement to base class and fixing CSharpDocumentGenerator and FormattingVisitor

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Revert changes to FormattingVisitor.cs

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Revert changes to LanguageServer HtmlFormattingTest.cs

Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>

* Pass fromPaste through to OOP

* Make tests fail when an error is logged, just like in VS

* Add failing test

* Swallow exceptions during format on paste

* Fix workitem attribute

* Create failing test

* Ensure Roslyn knows we're emitting expressions, so it doesn't get confused

* Create test to demonstrate the bug is fixed

* Make it easier to diagnose test failures due to Web Tools formatting

* Use the Roslyn tokenizer in tests

* Fix test

* Format (or don't!) pre tags like textarea tags

* Emit initial whitespace to stop multiline if statements migrating right

* Fix `@@` escape handling in component attribute values (#12754)

* Initial plan

* Fix @@ escape handling in component attribute values

The issue was that @@ escape sequences were being parsed correctly
but then treated as "complex content" during code generation, causing
them to fail when used in component attributes.

The fix modifies the VisitAttributeValue method to extract the literal
@ token from the escaped @@ pattern and merge it with the rest of the
attribute value as a simple string, rather than creating separate HTML
content nodes.

This allows component attributes to accept literal @ characters using
the @@ escape syntax, e.g. <Weather Value="@@currentCount" /> now
correctly passes the string "@currentCount" to the component.

Co-authored-by: chsienki <16246502+chsienki@users.noreply.github.com>

* Update test baselines after @@ escape fix

The fix for @@ escape handling changed how source positions are
tracked for escaped @ tokens in attribute values. The ComplexTagHelpers
test baselines needed to be updated to reflect the new positions.

Co-authored-by: chsienki <16246502+chsienki@users.noreply.github.com>

* Address code review feedback - formatting improvements

Co-authored-by: chsienki <16246502+chsienki@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: chsienki <16246502+chsienki@users.noreply.github.com>

* Apply suggestion from @davidwengier

Co-authored-by: David Wengier <david.wengier@microsoft.com>

* Update vsBranch and insertionTitlePrefix values

* [release/insiders] Update dependencies from dotnet/arcade (#12829)

* Update dependencies from https://github.com/dotnet/arcade build 20260223.2
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26110.1 -> To Version 10.0.0-beta.26123.2

* update package versions

* Update dependencies from https://github.com/dotnet/arcade build 20260302.1
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26110.1 -> To Version 10.0.0-beta.26152.1

* Update dependencies from https://github.com/dotnet/arcade build 20260303.3
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26110.1 -> To Version 10.0.0-beta.26153.3

* Update dependencies from https://github.com/dotnet/arcade build 20260309.1
On relative base path root
Microsoft.DotNet.Arcade.Sdk From Version 10.0.0-beta.26110.1 -> To Version 10.0.0-beta.26159.1

* Fixup versions

---------

Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Ankita Khera <ankitakhera@microsoft.com>
Co-authored-by: Jan Jones <janjones@microsoft.com>

* Update dependencies from https://github.com/dotnet/arcade build 20260310.1 (#12889)

[release/insiders] Update dependencies from dotnet/arcade

* Update dependencies from https://github.com/dotnet/arcade build 20260314.1 (#12900)

[release/insiders] Update dependencies from dotnet/arcade

* Update dependencies from https://github.com/dotnet/arcade build 20260318.1 (#12925)

[release/insiders] Update dependencies from dotnet/arcade

* Update dependencies from https://github.com/dotnet/arcade build 20260327.7 (#12967)

[release/insiders] Update dependencies from dotnet/arcade

* Update PublishData.json for release/stable

---------

Co-authored-by: David Wengier <david.wengier@microsoft.com>
Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: davidwengier <754264+davidwengier@users.noreply.github.com>
Co-authored-by: Joey Robichaud <joseph.robichaud@microsoft.com>
Co-authored-by: dotnet-maestro[bot] <42748379+dotnet-maestro[bot]@users.noreply.github.com>
Co-authored-by: Naresh Joshi <Naresh.Joshi@microsoft.com>
Co-authored-by: Todd Grunke <toddgrun@microsoft.com>
Co-authored-by: chsienki <16246502+chsienki@users.noreply.github.com>
Co-authored-by: Ankita Khera <ankitakhera@microsoft.com>
Co-authored-by: Ankita Khera <40616383+akhera99@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

7 participants