Outline model (aka `DocumentSymbolProvider`) doesn't reflect actual document hierarchy, which breaks "Sticky Scroll"
Expected behavior
C# documents support VS Code's "Sticky Scroll" feature when configured with the default settings ("editor.stickyScroll.defaultModel": "outlineModel").
Actual behavior
The C# extension's outline model (provided by DocumentSymbolProvider) flattens the document hierarchy and excludes critical symbols like namespaces, which breaks the "Sticky Scroll" behavior.
Additional context
This issue can be partially worked around by changing editor.stickyScroll.defaultModel to foldingProviderModel for C# projects, but this is an imperfect solution that produces its own set of problems.
Steps to reproduce
Setup a C# project with this example document:
namespace Example
{
public class Foo
{
int m_Lorem = 0;
int m_Ipsum = 1;
public enum Bar
{
None = 0,
One = 1,
Two = 2,
Three = 3,
}
Bar Dolor { get; set; } = Bar.None;
public Foo(int lorem, int ipsum, Bar dolor)
{
m_Lorem = lorem;
m_Ipsum = ipsum;
Dolor = dolor;
}
public void SwapLipsum()
{
(m_Ipsum, m_Lorem) = (m_Lorem, m_Ipsum);
}
public int Sum() => m_Lorem + m_Ipsum + (int)Dolor;
public static Foo operator++(Foo foo)
{
++foo.m_Lorem;
++foo.m_Ipsum;
foo.Dolor = (Bar)(((int)foo.Dolor + 1) % 4);
return foo;
}
}
}
Compare/contrast the Outline view and sticky-scroll behavior of the C# document above with this (roughly) equivalent TypeScript document:
namespace Example {
export class Foo {
private lorem = 0;
private ipsum = 1;
// Super contrived example because TypeScript doesn't do enums nested in classes
static readonly Bar = class {
static readonly None = 0;
static readonly One = 1;
static readonly Two = 2;
static readonly Three = 3;
}
private _dolor: 0|1|2|3 = Foo.Bar.None;
get dolor() { return this._dolor; }
set dolor(value) { this._dolor = value; }
constructor (lorem: number, ipsum: number, dolor: 0|1|2|3) {
this.lorem = lorem;
this.ipsum = ipsum;
this.dolor = dolor;
}
swapLipsum(): void {
[this.ipsum, this.lorem] = [this.lorem, this.ipsum];
}
sum = () => this.lorem + this.ipsum + this.dolor;
inc(): Foo {
let result = new Foo(this.lorem, this.ipsum, this.dolor);
++result.lorem;
++result.ipsum;
result.dolor = ((result.dolor + 1) % 4) as 0|1|2|3;
return result;
}
}
}
Screenshots
Environment data
dotnet --info output:
.NET SDK:
Version: 9.0.100
Commit: 59db016f11
Workload version: 9.0.100-manifests.4a280210
MSBuild version: 17.12.7+5b8665660
Runtime Environment:
OS Name: Windows
OS Version: 10.0.22631
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\9.0.100\
.NET workloads installed:
There are no installed workloads to display.
Configured to use loose manifests when installing new manifests.
Host:
Version: 9.0.0
Architecture: x64
Commit: 9d5a6a9aa4
.NET SDKs installed:
3.1.426 [C:\Program Files\dotnet\sdk]
9.0.100 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.11 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.36 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 9.0.0 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Other architectures found:
x86 [C:\Program Files (x86)\dotnet]
registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]
Environment variables:
Not set
global.json file:
Not found
VS Code version: 1.97.1 C# Extension version: 2.63.32
OmniSharp log
N/A
thanks for the detailed report. Definitely should update our document symbols handler to play nicer here.