Object Browser / Class View: no way for a non-Roslyn language (F#) to draw its own project glyph
- Dominant language
- C#
- Stars
- 20.7k
- Forks
- 4.3k
- PR merge metrics
- PR metrics pending
Description
## Summary
I am adding Object Browser and Class View support to F# ([dotnet/fsharp#3512](https://github.com/dotnet/fsharp/issues/3512)), implementing `IVsSimpleLibrary2` / `IVsSimpleObjectList2` directly and modelling it on Roslyn's `src/VisualStudio/Core/Def/Library/**`.
Everything transfers except the project node's icon: there is no F# glyph reachable from that surface, so an F# project can only be drawn with another language's icon.
Filing here rather than on Developer Community because Roslyn owns the only managed implementation of this surface and the `Glyph` → image mapping around it; if the right fix lives in the VS SDK instead, I would appreciate a redirect.
## Why the icon cannot be supplied
`IVsSimpleObjectList2.GetDisplayData` communicates the icon as `VSTREEDISPLAYDATA.Image`, a `ushort` index into an image list. Roslyn deliberately passes `hImageList = 0` so the shell uses its default list ([`AbstractObjectList.GetDisplayData`](https://github.com/dotnet/roslyn/blob/main/src/VisualStudio/Core/Def/Library/AbstractObjectList.cs), *"allows the object browser to use the default image list with no DPI issues"*), and `ObjectListItem.GlyphIndex` is computed from `StandardGlyphGroup` + `StandardGlyphItem`.
That table has project glyphs for C#, VB, C++ and J#:
```
GlyphVBProject = 0xC2
GlyphCoolProject = 0xC4
GlyphCppProject = 0xC7
GlyphJSharpProject = 0xD3
```
but none for F# — `StandardGlyphGroup` lives in `Microsoft.VisualStudio.Language.Intellisense` and predates the language. I also checked `KnownMonikers` in `Microsoft.VisualStudio.ImageCatalog`: it has no `FSharp*` entry either, and there is no moniker → `HIMAGELIST` bridge in the SDK (`IVsUIShell5/6.CreateThemedImageList` only themes a list that already exists).
So `ProjectListItem`'s equivalent for F# has to choose between the C# icon and a generic one. Roslyn hits the same wall from the other side — `GlyphExtensions.GetStandardGlyphGroup` can map `Glyph.CSharpProject`/`Glyph.BasicProject`, and there is nothing it could map an F# project to.
## What I did instead
For project nodes I read the icon the project's own hierarchy already publishes to Solution Explorer, and hand the shell that image list rather than the default one:
```fsharp
hierarchy.GetProperty(VSITEMID_ROOT, __VSHPROPID.VSHPROPID_IconImgList, &imageList)
hierarchy.GetProperty(VSITEMID_ROOT, __VSHPROPID.VSHPROPID_IconIndex, &index)
// -> VSTREEDISPLAYDATA.hImageList / .Image
```
This works and is themed and DPI-correct, because the icon comes from the project system. It is a workaround though: it only covers nodes that map to an `IVsHierarchy`, and it opts out of the default-image-list guarantee the comment in `AbstractObjectList` is protecting.
## What would help
Either of these, in preference order:
1. **Expose the Object Browser / Class View library infrastructure through `Microsoft.CodeAnalysis.ExternalAccess.FSharp`.** `AbstractObjectBrowserLibraryManager`, `AbstractObjectList`, `ObjectListItem`, `NavInfoFactory` and friends are all `internal`, so a non-Roslyn language reimplements the entire COM surface — roughly 1.5k lines of `IVsSimpleObjectList2` plumbing that is not language-specific in any way. Sharing it would carry the glyph handling along with everything else, and is the same shape as the seam proposed in #85089.
2. **Add F# entries to the glyph path** — an `FSharpProject` moniker in the image catalog and a corresponding `Glyph`/`StandardGlyphGroup` value — so the default image list can represent an F# project at all.
Happy to do the work on either side; mainly looking for a decision on which direction is acceptable before writing PRs.
cc @tmat @davidwengier @vzarytovskii @T-Gro
Contributor guide
Research direction
Start by reading Roslyn's src/VisualStudio/Core/Def/Library/AbstractObjectList.cs, ObjectListItem, GlyphExtensions.GetStandardGlyphGroup, and the Microsoft.CodeAnalysis.ExternalAccess.FSharp seam proposed in #85089. Compare the two requested directions—shared library infrastructure or F# glyph entries—and seek a maintainer decision before implementation; done means one accepted path is specified well enough for a PR.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- developer-experience, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100