mirror of https://github.com/golang/go.git
internal/lsp: support textDocument/inlayHint for parameter names
This change implements support for textDocument/inlayHint and adds inlay hints for parameter names. For golang/go#52343. For golang/vscode-go#1631. Change-Id: I3f989838b86cef4fd2b4076cb6340010fff7c24c Reviewed-on: https://go-review.googlesource.com/c/tools/+/411094 gopls-CI: kokoro <noreply+kokoro@google.com> Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com> Reviewed-by: Suzy Mueller <suzmue@golang.org> Run-TryBot: Jamal Carvalho <jamal@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
9651276d64
commit
65c0181b23
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package lsp
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
"golang.org/x/tools/internal/lsp/source"
|
||||
)
|
||||
|
||||
func (s *Server) inlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
|
||||
snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
|
||||
defer release()
|
||||
if !ok {
|
||||
return nil, err
|
||||
}
|
||||
return source.InlayHint(ctx, snapshot, fh, params.ViewPort)
|
||||
}
|
||||
|
|
@ -160,8 +160,8 @@ func (s *Server) Initialized(ctx context.Context, params *protocol.InitializedPa
|
|||
return s.initialized(ctx, params)
|
||||
}
|
||||
|
||||
func (s *Server) InlayHint(context.Context, *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
|
||||
return nil, notImplemented("InlayHint")
|
||||
func (s *Server) InlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
|
||||
return s.inlayHint(ctx, params)
|
||||
}
|
||||
|
||||
func (s *Server) InlayHintRefresh(context.Context) error {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package source
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/internal/event"
|
||||
"golang.org/x/tools/internal/lsp/lsppos"
|
||||
"golang.org/x/tools/internal/lsp/protocol"
|
||||
)
|
||||
|
||||
const (
|
||||
maxLabelLength = 28
|
||||
)
|
||||
|
||||
func InlayHint(ctx context.Context, snapshot Snapshot, fh FileHandle, _ protocol.Range) ([]protocol.InlayHint, error) {
|
||||
ctx, done := event.Start(ctx, "source.InlayHint")
|
||||
defer done()
|
||||
|
||||
pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting file for InlayHint: %w", err)
|
||||
}
|
||||
|
||||
tmap := lsppos.NewTokenMapper(pgf.Src, pgf.Tok)
|
||||
info := pkg.GetTypesInfo()
|
||||
|
||||
var hints []protocol.InlayHint
|
||||
ast.Inspect(pgf.File, func(node ast.Node) bool {
|
||||
switch n := node.(type) {
|
||||
case *ast.CallExpr:
|
||||
hints = append(hints, parameterNames(n, tmap, info)...)
|
||||
}
|
||||
return true
|
||||
})
|
||||
return hints, nil
|
||||
}
|
||||
|
||||
func parameterNames(node *ast.CallExpr, tmap *lsppos.TokenMapper, info *types.Info) []protocol.InlayHint {
|
||||
signature, ok := info.TypeOf(node.Fun).(*types.Signature)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var hints []protocol.InlayHint
|
||||
for i, v := range node.Args {
|
||||
start, ok := tmap.Position(v.Pos())
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
params := signature.Params()
|
||||
// When a function has variadic params, we skip args after
|
||||
// params.Len().
|
||||
if i > params.Len()-1 {
|
||||
break
|
||||
}
|
||||
value := params.At(i).Name()
|
||||
// param.Name is empty for built-ins like append
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
if signature.Variadic() && i == params.Len()-1 {
|
||||
value = value + "..."
|
||||
}
|
||||
hints = append(hints, protocol.InlayHint{
|
||||
Position: &start,
|
||||
Label: buildLabel(value + ":"),
|
||||
Kind: protocol.Parameter,
|
||||
PaddingRight: true,
|
||||
})
|
||||
}
|
||||
return hints
|
||||
}
|
||||
|
||||
func buildLabel(s string) []protocol.InlayHintLabelPart {
|
||||
label := protocol.InlayHintLabelPart{
|
||||
Value: s,
|
||||
}
|
||||
if len(s) > maxLabelLength {
|
||||
label.Value = s[:maxLabelLength] + "..."
|
||||
label.Tooltip = s
|
||||
}
|
||||
return []protocol.InlayHintLabelPart{label}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package inlayHint //@inlayHint("package")
|
||||
|
||||
import "fmt"
|
||||
|
||||
func hello(name string) string {
|
||||
return "Hello " + name
|
||||
}
|
||||
|
||||
func helloWorld() string {
|
||||
return hello("World")
|
||||
}
|
||||
|
||||
type foo struct{}
|
||||
|
||||
func (*foo) bar(baz string, qux int) int {
|
||||
if baz != "" {
|
||||
return qux + 1
|
||||
}
|
||||
return qux
|
||||
}
|
||||
|
||||
func kase(foo int, bar bool, baz ...string) {
|
||||
fmt.Println(foo, bar, baz)
|
||||
}
|
||||
|
||||
func kipp(foo string, bar, baz string) {
|
||||
fmt.Println(foo, bar, baz)
|
||||
}
|
||||
|
||||
func plex(foo, bar string, baz string) {
|
||||
fmt.Println(foo, bar, baz)
|
||||
}
|
||||
|
||||
func tars(foo string, bar, baz string) {
|
||||
fmt.Println(foo, bar, baz)
|
||||
}
|
||||
|
||||
func foobar() {
|
||||
var x foo
|
||||
x.bar("", 1)
|
||||
kase(0, true, "c", "d", "e")
|
||||
kipp("a", "b", "c")
|
||||
plex("a", "b", "c")
|
||||
tars("a", "b", "c")
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
-- inlayHint --
|
||||
package inlayHint //@inlayHint("package")
|
||||
|
||||
import "fmt"
|
||||
|
||||
func hello(name string) string {
|
||||
return "Hello " + name
|
||||
}
|
||||
|
||||
func helloWorld() string {
|
||||
return hello(<name:>"World")
|
||||
}
|
||||
|
||||
type foo struct{}
|
||||
|
||||
func (*foo) bar(baz string, qux int) int {
|
||||
if baz != "" {
|
||||
return qux + 1
|
||||
}
|
||||
return qux
|
||||
}
|
||||
|
||||
func kase(foo int, bar bool, baz ...string) {
|
||||
fmt.Println(<a...:>foo, bar, baz)
|
||||
}
|
||||
|
||||
func kipp(foo string, bar, baz string) {
|
||||
fmt.Println(<a...:>foo, bar, baz)
|
||||
}
|
||||
|
||||
func plex(foo, bar string, baz string) {
|
||||
fmt.Println(<a...:>foo, bar, baz)
|
||||
}
|
||||
|
||||
func tars(foo string, bar, baz string) {
|
||||
fmt.Println(<a...:>foo, bar, baz)
|
||||
}
|
||||
|
||||
func foobar() {
|
||||
var x foo
|
||||
x.bar(<baz:>"", <qux:>1)
|
||||
kase(<foo:>0, <bar:>true, <baz...:>"c", "d", "e")
|
||||
kipp(<foo:>"a", <bar:>"b", <baz:>"c")
|
||||
plex(<foo:>"a", <bar:>"b", <baz:>"c")
|
||||
tars(<foo:>"a", <bar:>"b", <baz:>"c")
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue