-
Notifications
You must be signed in to change notification settings - Fork 745
Implement support for Code Lenses #2145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+1,840
−74
Merged
Changes from 8 commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
42ca92a
Implement support for `IncludeDeclaration` in find-all-references.
DanielRosenwasser 6a1bab5
Added some configuration to go-to-implementation.
DanielRosenwasser 145868f
Just hoist argument into variable.
DanielRosenwasser ec58571
Implemented CodeLens.
DanielRosenwasser ddb7ef6
Set `IncludeDeclaration` for all tests.
DanielRosenwasser 3ca859c
Merge remote-tracking branch 'origin/main' into codeLenss
DanielRosenwasser 477863e
Added custom `CodeLensData` types to `generate.mts` .
DanielRosenwasser 0596214
Use a handshake for the CodeLens command name, and use an appropriate…
DanielRosenwasser b140229
Merge remote-tracking branch 'origin/main' into codeLenss
DanielRosenwasser f3cc278
Adapt code to changes from merge.
DanielRosenwasser 0349935
Accept baselines.
DanielRosenwasser ed72b96
Add testing for Code Lens (`VerifyBaselineCodeLensForActiveFile`).
DanielRosenwasser 5e9aca3
Update baselines.
DanielRosenwasser 5e32b67
Request codelenses across all files.
DanielRosenwasser c6ee5d8
Update baselines.
DanielRosenwasser 6ecdca4
Merge remote-tracking branch 'origin/main' into codeLenss
DanielRosenwasser 5625539
Localize titles for lenses.
DanielRosenwasser 494b5f7
Format.
DanielRosenwasser 42d5741
Force ordering of file iteration.
DanielRosenwasser 704cae6
Drive-by fix.
DanielRosenwasser 188f9c7
Update baselines.
DanielRosenwasser c69f55a
Add test for overloads.
DanielRosenwasser a2d62fb
Update baselines.
DanielRosenwasser 901d199
Only print on the first-ish overload.
DanielRosenwasser 5714e7a
Update baselines.
DanielRosenwasser 3595713
Add codelens test for function expressions.
DanielRosenwasser 2f270fe
Update baselines.
DanielRosenwasser 37bb977
Don't provide code lenses on any types of function expressions.
DanielRosenwasser 0947f73
Update baselines.
DanielRosenwasser c4e242b
Rename test.
DanielRosenwasser d202d83
Add an actual usage inside/outside the function expression to show wh…
DanielRosenwasser 0b91cbb
Update baselines.
DanielRosenwasser d050804
Add explicit test for toggling `showOnAllFunctions` for references co…
DanielRosenwasser 37b63d8
Update baselines.
DanielRosenwasser 959b5db
Add test for `showOnInterfaceMethods`.
DanielRosenwasser 73d11c4
Update baselines.
DanielRosenwasser e2ff436
Switch towards using sub-tests.
DanielRosenwasser c504544
Update baselines.
DanielRosenwasser 46164b3
Add test for `showOnAllClassMethods`.
DanielRosenwasser 3a58afc
Update baselines.
DanielRosenwasser 4357078
Clarify comment.
DanielRosenwasser 73af385
Update stale baselines from before test was modified
DanielRosenwasser 0113665
Drive-by fix.
DanielRosenwasser 580a3d0
Use the JSON-round-tripping trick for code lens arguments in tests.
DanielRosenwasser 727957b
Fix lint issues.
DanielRosenwasser e11739a
Merge remote-tracking branch 'origin/main' into codeLenss
DanielRosenwasser d6396a1
Add early bailout for stale `codeLens/resolve`s.
DanielRosenwasser ff9d7fb
Fix comment and document follow-up.
DanielRosenwasser 00436de
Back out change to avoid issues with upcoming PR.
DanielRosenwasser bed760c
Merge remote-tracking branch 'origin/main' into codeLenss
DanielRosenwasser 766a5b4
Update const name.
DanielRosenwasser 1fc1f2b
Merge remote-tracking branch 'origin' into codeLenss
DanielRosenwasser File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| package ls | ||
|
|
||
| import ( | ||
| "context" | ||
|
|
||
| "github.com/microsoft/typescript-go/internal/ast" | ||
| "github.com/microsoft/typescript-go/internal/core" | ||
| "github.com/microsoft/typescript-go/internal/diagnostics" | ||
| "github.com/microsoft/typescript-go/internal/ls/lsutil" | ||
| "github.com/microsoft/typescript-go/internal/lsp/lsproto" | ||
| "github.com/microsoft/typescript-go/internal/scanner" | ||
| ) | ||
|
|
||
| func (l *LanguageService) ProvideCodeLenses(ctx context.Context, documentURI lsproto.DocumentUri) (lsproto.CodeLensResponse, error) { | ||
| _, file := l.getProgramAndFile(documentURI) | ||
|
|
||
| userPrefs := l.UserPreferences() | ||
| if !userPrefs.ReferencesCodeLensEnabled && !userPrefs.ImplementationsCodeLensEnabled { | ||
| return lsproto.CodeLensResponse{}, nil | ||
| } | ||
|
|
||
| var lenses []*lsproto.CodeLens | ||
| var visit func(node *ast.Node) bool | ||
| visit = func(node *ast.Node) bool { | ||
| if ctx.Err() != nil { | ||
| return true | ||
| } | ||
|
|
||
| if userPrefs.ReferencesCodeLensEnabled && isValidReferenceLensNode(node, userPrefs) { | ||
| lenses = append(lenses, l.newCodeLensForNode(documentURI, file, node, lsproto.CodeLensKindReferences)) | ||
| } | ||
|
|
||
| if userPrefs.ImplementationsCodeLensEnabled && isValidImplementationsCodeLensNode(node, userPrefs) { | ||
| lenses = append(lenses, l.newCodeLensForNode(documentURI, file, node, lsproto.CodeLensKindImplementations)) | ||
| } | ||
|
|
||
| node.ForEachChild(visit) | ||
| return false | ||
| } | ||
|
|
||
| visit(file.AsNode()) | ||
|
|
||
| return lsproto.CodeLensResponse{ | ||
| CodeLenses: &lenses, | ||
| }, nil | ||
| } | ||
|
|
||
| func (l *LanguageService) ResolveCodeLens(ctx context.Context, codeLens *lsproto.CodeLens, showLocationsCommandName *string) (*lsproto.CodeLens, error) { | ||
| uri := codeLens.Data.Uri | ||
| textDoc := lsproto.TextDocumentIdentifier{ | ||
| Uri: uri, | ||
| } | ||
|
|
||
| var locs []lsproto.Location | ||
| var lensTitle string | ||
| switch codeLens.Data.Kind { | ||
| case lsproto.CodeLensKindReferences: | ||
| references, err := l.ProvideReferences(ctx, &lsproto.ReferenceParams{ | ||
| TextDocument: textDoc, | ||
| Position: codeLens.Range.Start, | ||
| Context: &lsproto.ReferenceContext{ | ||
| // Don't include the declaration in the references count. | ||
| IncludeDeclaration: false, | ||
| }, | ||
| }) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if references.Locations != nil { | ||
| locs = *references.Locations | ||
| } | ||
|
|
||
| if len(locs) == 1 { | ||
| lensTitle = diagnostics.X_1_reference.Message() | ||
| } else { | ||
| lensTitle = diagnostics.X_0_references.Format(len(locs)) | ||
| } | ||
| case lsproto.CodeLensKindImplementations: | ||
| // "Force" link support to be false so that we only get `Locations` back, | ||
| // and don't include the "current" node in the results. | ||
| findImplsOptions := provideImplementationsOpts{ | ||
| requireLocationsResult: true, | ||
| dropOriginNodes: true, | ||
| } | ||
| implementations, err := l.provideImplementationsEx(ctx, &lsproto.ImplementationParams{ | ||
| TextDocument: textDoc, | ||
| Position: codeLens.Range.Start, | ||
| }, findImplsOptions) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| if implementations.Locations != nil { | ||
| locs = *implementations.Locations | ||
| } | ||
|
|
||
| if len(locs) == 1 { | ||
| lensTitle = diagnostics.X_1_implementation.Message() | ||
| } else { | ||
| lensTitle = diagnostics.X_0_implementations.Format(len(locs)) | ||
| } | ||
| } | ||
|
|
||
| cmd := &lsproto.Command{ | ||
| Title: lensTitle, | ||
| } | ||
| if len(locs) > 0 && showLocationsCommandName != nil { | ||
| cmd.Command = *showLocationsCommandName | ||
| cmd.Arguments = &[]any{ | ||
| uri, | ||
| codeLens.Range.Start, | ||
| locs, | ||
| } | ||
| } | ||
|
|
||
| codeLens.Command = cmd | ||
| return codeLens, nil | ||
| } | ||
|
|
||
| func (l *LanguageService) newCodeLensForNode(fileUri lsproto.DocumentUri, file *ast.SourceFile, node *ast.Node, kind lsproto.CodeLensKind) *lsproto.CodeLens { | ||
| nodeForRange := node | ||
| nodeName := node.Name() | ||
| if nodeName != nil { | ||
| nodeForRange = nodeName | ||
| } | ||
| pos := scanner.SkipTrivia(file.Text(), nodeForRange.Pos()) | ||
|
|
||
| return &lsproto.CodeLens{ | ||
| Range: lsproto.Range{ | ||
| Start: l.converters.PositionToLineAndCharacter(file, core.TextPos(pos)), | ||
| End: l.converters.PositionToLineAndCharacter(file, core.TextPos(node.End())), | ||
| }, | ||
| Data: &lsproto.CodeLensData{ | ||
| Kind: kind, | ||
| Uri: fileUri, | ||
| }, | ||
| } | ||
| } | ||
|
|
||
| func isValidImplementationsCodeLensNode(node *ast.Node, userPrefs *lsutil.UserPreferences) bool { | ||
| switch node.Kind { | ||
| // Always show on interfaces | ||
| case ast.KindInterfaceDeclaration: | ||
| // TODO: ast.KindTypeAliasDeclaration? | ||
| return true | ||
|
|
||
| // If configured, show on interface methods | ||
| case ast.KindMethodSignature: | ||
| return userPrefs.ImplementationsCodeLensShowOnInterfaceMethods && node.Parent.Kind == ast.KindInterfaceDeclaration | ||
|
|
||
| // If configured, show on all class methods - but not private ones. | ||
| case ast.KindMethodDeclaration: | ||
| if userPrefs.ImplementationsCodeLensShowOnAllClassMethods && node.Parent.Kind == ast.KindClassDeclaration { | ||
| return !ast.HasModifier(node, ast.ModifierFlagsPrivate) && node.Name().Kind != ast.KindPrivateIdentifier | ||
| } | ||
| fallthrough | ||
|
|
||
| // Always show on abstract classes/properties/methods | ||
| case ast.KindClassDeclaration, ast.KindConstructor, | ||
| ast.KindGetAccessor, ast.KindSetAccessor, ast.KindPropertyDeclaration: | ||
| return ast.HasModifier(node, ast.ModifierFlagsAbstract) | ||
| } | ||
|
|
||
| return false | ||
| } | ||
|
|
||
| func isValidReferenceLensNode(node *ast.Node, userPrefs *lsutil.UserPreferences) bool { | ||
| switch node.Kind { | ||
| case ast.KindFunctionDeclaration, ast.KindFunctionExpression: | ||
| if userPrefs.ReferencesCodeLensShowOnAllFunctions { | ||
| return true | ||
| } | ||
| fallthrough | ||
|
|
||
| case ast.KindVariableDeclaration: | ||
| return ast.GetCombinedModifierFlags(node)&ast.ModifierFlagsExport != 0 | ||
|
|
||
| case ast.KindClassDeclaration, ast.KindInterfaceDeclaration, ast.KindTypeAliasDeclaration, ast.KindEnumDeclaration, ast.KindEnumMember: | ||
| return true | ||
|
|
||
| case ast.KindMethodDeclaration, ast.KindMethodSignature, ast.KindConstructor, | ||
| ast.KindGetAccessor, ast.KindSetAccessor, | ||
| ast.KindPropertyDeclaration, ast.KindPropertySignature: | ||
| // Don't show if child and parent have same start | ||
| // For https://github.com/microsoft/vscode/issues/90396 | ||
| // !!! | ||
|
|
||
| switch node.Parent.Kind { | ||
| case ast.KindClassDeclaration, ast.KindInterfaceDeclaration, ast.KindTypeLiteral: | ||
| return true | ||
| } | ||
| } | ||
|
|
||
| return false | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.