Skip to content

Add expandable hover#3311

Open
jakebailey wants to merge 45 commits intomainfrom
jabaile/expand-hover
Open

Add expandable hover#3311
jakebailey wants to merge 45 commits intomainfrom
jabaile/expand-hover

Conversation

@jakebailey
Copy link
Copy Markdown
Member

@jakebailey jakebailey commented Apr 1, 2026

Closes #2457

This is a proposed VS Code feature. To make this work, we add the new API ontop of the LSP, then disable the LSP client's hover provider, in favor of one with the feature.

@jakebailey jakebailey requested a review from gabritto April 1, 2026 20:23
@jakebailey jakebailey marked this pull request as ready for review April 1, 2026 22:29
Copilot AI review requested due to automatic review settings April 1, 2026 22:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an “expandable hover” feature end-to-end: a proposed VS Code hover API that can request increased “verbosity”, an LSP extension (verbosityLevel on HoverParams + canIncreaseVerbosity on Hover), server plumbing to honor it, and fourslash coverage/baselines for the new hover behavior.

Changes:

  • Extend LSP hover request/response shapes to support verbosity (verbosityLevel) and server-provided expandability (canIncreaseVerbosity).
  • Add a VS Code extension hover provider that uses the proposed hover verbosity API and sends verbosityLevel over LSP (disabling the languageclient’s built-in hover).
  • Add fourslash harness support + many new baselines/tests for hover verbosity scenarios, plus conversion-script support for verify.baselineQuickInfo({...}).

Reviewed changes

Copilot reviewed 91 out of 93 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
internal/lsp/server.go Routes hover requests to verbose hover implementation when verbosityLevel is present.
internal/lsp/lsproto/lsp_generated.go Adds verbosityLevel to HoverParams, canIncreaseVerbosity to Hover, and a capabilities flag.
internal/lsp/lsproto/_generate/generate.mts Patches the LSP model so the generator emits the new hover fields/capabilities.
_extension/src/languageFeatures/hover.ts New VS Code hover provider that requests verbose hover via LSP and maps expand/decrease flags.
_extension/src/vscode.proposed.editorHoverVerbosityLevel.d.ts Declares the proposed VS Code API surface (VerboseHover, HoverContext, etc.).
_extension/src/client.ts Advertises hover verbosity capability + registers the custom hover provider; disables LSP hover via middleware.
_extension/package.json Enables the editorHoverVerbosityLevel proposal and bumps VS Code engine/types.
package-lock.json Updates VS Code typings version to match the engine bump.
internal/checker/printer.go Adds verbosity-aware type/signature/symbol-to-declaration stringification helpers.
internal/checker/nodebuilder.go Adds verbosity-aware nodebuilder entry points and symbol-declaration rendering helpers.
internal/checker/services.go Introduces Checker.IsLibType used to prevent expanding default-lib types.
internal/ls/completions.go Refactors completion item detail generation; threads hover quickinfo via the updated quickinfo helper signature.
internal/ls/string_completions.go Updates call into completion details helper after signature refactor.
internal/fourslash/fourslash.go Adds VerifyBaselineHoverWithVerbosity helper for producing multi-verbosity hover baselines.
internal/fourslash/baselineutil.go Uses stable sorting when inserting multiple tooltips at the same position.
internal/fourslash/_scripts/convertFourslash.mts Adds support for verify.baselineQuickInfo({...verbosity...}) conversion into Go tests.
internal/fourslash/_scripts/unparsedTests.txt Removes now-supported quickinfoVerbosity tests from the “unparsed” list.
internal/fourslash/_scripts/failingTests.txt Updates the list of failing tests (removals).
internal/fourslash/tests/quickinfoVerbosityNamespaceDefaultExport_test.go New manual fourslash test for namespace default export verbosity behavior.
internal/fourslash/tests/gen/quickinfoVerbosity1_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosity2_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosity3_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityClass1_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityClass2_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityConditionalType_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityEnum_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityFunction_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityImport_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityIndexedAccessType_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityIndexSignature_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityIndexType_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityInterface1_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityInterface2_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityIntersection1_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityJs_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityLibType_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityMappedType_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityNamespace_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityNamespaceDefaultExport_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityNoErrorTruncation1_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityObjectType1_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityRecursiveType_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityServer_test.go Generated hover verbosity test (server mode).
internal/fourslash/tests/gen/quickinfoVerbosityToplevelTruncation1_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityToplevelTruncation2_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityTruncation1_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityTruncation2_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityTuple_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityTypeof_test.go Generated hover verbosity test.
internal/fourslash/tests/gen/quickinfoVerbosityTypeParameter_test.go Generated hover verbosity test.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosity1.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosity2.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityConditionalType.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityFunction.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityIndexSignature.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityIndexType.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityIndexedAccessType.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityIntersection1.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityLibType.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityMappedType.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityNamespaceDefaultExport.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityNoErrorTruncation1.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityObjectType1.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityRecursiveType.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityServer.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityTruncation1.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityToplevelTruncation1.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityToplevelTruncation2.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityTypeof.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickinfoVerbosityTypeParameter.baseline New hover verbosity baseline.
testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsTypeParameterInFunction.baseline Updates baseline output for type parameter/parameter quickinfo display parts.
testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsTypeParameterInClass.baseline Updates baseline output for class type parameter/parameter quickinfo display parts.
testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsTypeParameterInTypeAlias.baseline Updates baseline output for type parameter quickinfo display parts.
testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsTypeParameterInFunctionLikeInTypeAlias.baseline Updates baseline output for type parameter quickinfo display parts.
testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsEnum1.baseline Updates enum quickinfo baseline (e.g. const enum rendering).
testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsEnum2.baseline Updates enum quickinfo baseline (e.g. const enum rendering).
testdata/baselines/reference/fourslash/quickInfo/quickInfoDisplayPartsEnum3.baseline Updates enum quickinfo baseline (e.g. const enum rendering).
testdata/baselines/reference/submodule/compiler/privateFieldsInClassExpressionDeclaration.js Updates compiler baseline output for private fields in .d.ts emit.
testdata/baselines/reference/submodule/compiler/privateFieldsInClassExpressionDeclaration.js.diff Updates compiler baseline diff for the same private field emit change.

@jakebailey
Copy link
Copy Markdown
Member Author

One icky thing is that symbolTableToDeclarationStatements is basically what used to power JS declaration emit, but now does not; everything here seems to be requiredish but the unported code is all JS stuff. Makes me wonder if this feature just needs a rethink now that we aren't doing JS in the same way?

@jakebailey jakebailey requested a review from gabritto April 6, 2026 20:32
levels = []int{0}
}
for _, level := range levels {
for i, level := range levels {
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 wonder if a better way to test this would be to just make the tests allow you to specify a maximum verbosity level, and then make fourslash check if every level from 0 to that can be expanded, and that it cannot be further expanded.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yeah, I just didn't want to make every test manual, so this was my workaround while debugging these. 😄

@jakebailey jakebailey requested a review from gabritto April 8, 2026 20:18
// canPossiblyExpandType returns true if it's possible the type or one of its components can be expanded.
// At maxExpansionDepth <= 0, no expansion will occur so we return false to allow type-node reuse.
// canPossiblyExpandType reports whether we are actively expanding types (depth < maxExpansionDepth),
// meaning type-node reuse should be skipped so typeToTypeNode can expand named types.
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.

Why do we need this function now? IIRC the difference between canPossiblyExpandType and shouldExpandType is that canPossiblyExpandType was meant to be called to see if we should avoid node reuse, but now we're not really avoiding node reuse anyways, so I don't quite get why not always use shouldExpandType.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We don't; it actually should have just been reduced to being a depth check. Refactored it again.

// as its structural form during hover expansion. Filters out lib types.
// When isAlias is true, checks whether t's alias symbol is from user code (not lib).
func (b *NodeBuilderImpl) isExpandableType(t *Type, isAlias bool) bool {
if isAlias {
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 can't really picture it in my head how this reflects the behavior of walking through a type and seeing if any of its parts are expandable. For instance, what if the type we're checking is an object literal type with a property whose type is an alias? How would that work?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Basically, it doesn't; this is only surface level, and the type traversal is in the caller during printing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Proposal: Prettified type display in hover output

3 participants