Skip to content

Commit 65c0181

Browse files
committed
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 <[email protected]> Reviewed-by: Hyang-Ah Hana Kim <[email protected]> Reviewed-by: Suzy Mueller <[email protected]> Run-TryBot: Jamal Carvalho <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 9651276 commit 65c0181

File tree

5 files changed

+205
-2
lines changed

5 files changed

+205
-2
lines changed

internal/lsp/inlay_hint.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package lsp
6+
7+
import (
8+
"context"
9+
10+
"golang.org/x/tools/internal/lsp/protocol"
11+
"golang.org/x/tools/internal/lsp/source"
12+
)
13+
14+
func (s *Server) inlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
15+
snapshot, fh, ok, release, err := s.beginFileRequest(ctx, params.TextDocument.URI, source.Go)
16+
defer release()
17+
if !ok {
18+
return nil, err
19+
}
20+
return source.InlayHint(ctx, snapshot, fh, params.ViewPort)
21+
}

internal/lsp/server_gen.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ func (s *Server) Initialized(ctx context.Context, params *protocol.InitializedPa
160160
return s.initialized(ctx, params)
161161
}
162162

163-
func (s *Server) InlayHint(context.Context, *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
164-
return nil, notImplemented("InlayHint")
163+
func (s *Server) InlayHint(ctx context.Context, params *protocol.InlayHintParams) ([]protocol.InlayHint, error) {
164+
return s.inlayHint(ctx, params)
165165
}
166166

167167
func (s *Server) InlayHintRefresh(context.Context) error {

internal/lsp/source/inlay_hint.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Copyright 2022 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package source
6+
7+
import (
8+
"context"
9+
"fmt"
10+
"go/ast"
11+
"go/types"
12+
13+
"golang.org/x/tools/internal/event"
14+
"golang.org/x/tools/internal/lsp/lsppos"
15+
"golang.org/x/tools/internal/lsp/protocol"
16+
)
17+
18+
const (
19+
maxLabelLength = 28
20+
)
21+
22+
func InlayHint(ctx context.Context, snapshot Snapshot, fh FileHandle, _ protocol.Range) ([]protocol.InlayHint, error) {
23+
ctx, done := event.Start(ctx, "source.InlayHint")
24+
defer done()
25+
26+
pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
27+
if err != nil {
28+
return nil, fmt.Errorf("getting file for InlayHint: %w", err)
29+
}
30+
31+
tmap := lsppos.NewTokenMapper(pgf.Src, pgf.Tok)
32+
info := pkg.GetTypesInfo()
33+
34+
var hints []protocol.InlayHint
35+
ast.Inspect(pgf.File, func(node ast.Node) bool {
36+
switch n := node.(type) {
37+
case *ast.CallExpr:
38+
hints = append(hints, parameterNames(n, tmap, info)...)
39+
}
40+
return true
41+
})
42+
return hints, nil
43+
}
44+
45+
func parameterNames(node *ast.CallExpr, tmap *lsppos.TokenMapper, info *types.Info) []protocol.InlayHint {
46+
signature, ok := info.TypeOf(node.Fun).(*types.Signature)
47+
if !ok {
48+
return nil
49+
}
50+
51+
var hints []protocol.InlayHint
52+
for i, v := range node.Args {
53+
start, ok := tmap.Position(v.Pos())
54+
if !ok {
55+
continue
56+
}
57+
params := signature.Params()
58+
// When a function has variadic params, we skip args after
59+
// params.Len().
60+
if i > params.Len()-1 {
61+
break
62+
}
63+
value := params.At(i).Name()
64+
// param.Name is empty for built-ins like append
65+
if value == "" {
66+
continue
67+
}
68+
if signature.Variadic() && i == params.Len()-1 {
69+
value = value + "..."
70+
}
71+
hints = append(hints, protocol.InlayHint{
72+
Position: &start,
73+
Label: buildLabel(value + ":"),
74+
Kind: protocol.Parameter,
75+
PaddingRight: true,
76+
})
77+
}
78+
return hints
79+
}
80+
81+
func buildLabel(s string) []protocol.InlayHintLabelPart {
82+
label := protocol.InlayHintLabelPart{
83+
Value: s,
84+
}
85+
if len(s) > maxLabelLength {
86+
label.Value = s[:maxLabelLength] + "..."
87+
label.Tooltip = s
88+
}
89+
return []protocol.InlayHintLabelPart{label}
90+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package inlayHint //@inlayHint("package")
2+
3+
import "fmt"
4+
5+
func hello(name string) string {
6+
return "Hello " + name
7+
}
8+
9+
func helloWorld() string {
10+
return hello("World")
11+
}
12+
13+
type foo struct{}
14+
15+
func (*foo) bar(baz string, qux int) int {
16+
if baz != "" {
17+
return qux + 1
18+
}
19+
return qux
20+
}
21+
22+
func kase(foo int, bar bool, baz ...string) {
23+
fmt.Println(foo, bar, baz)
24+
}
25+
26+
func kipp(foo string, bar, baz string) {
27+
fmt.Println(foo, bar, baz)
28+
}
29+
30+
func plex(foo, bar string, baz string) {
31+
fmt.Println(foo, bar, baz)
32+
}
33+
34+
func tars(foo string, bar, baz string) {
35+
fmt.Println(foo, bar, baz)
36+
}
37+
38+
func foobar() {
39+
var x foo
40+
x.bar("", 1)
41+
kase(0, true, "c", "d", "e")
42+
kipp("a", "b", "c")
43+
plex("a", "b", "c")
44+
tars("a", "b", "c")
45+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
-- inlayHint --
2+
package inlayHint //@inlayHint("package")
3+
4+
import "fmt"
5+
6+
func hello(name string) string {
7+
return "Hello " + name
8+
}
9+
10+
func helloWorld() string {
11+
return hello(<name:>"World")
12+
}
13+
14+
type foo struct{}
15+
16+
func (*foo) bar(baz string, qux int) int {
17+
if baz != "" {
18+
return qux + 1
19+
}
20+
return qux
21+
}
22+
23+
func kase(foo int, bar bool, baz ...string) {
24+
fmt.Println(<a...:>foo, bar, baz)
25+
}
26+
27+
func kipp(foo string, bar, baz string) {
28+
fmt.Println(<a...:>foo, bar, baz)
29+
}
30+
31+
func plex(foo, bar string, baz string) {
32+
fmt.Println(<a...:>foo, bar, baz)
33+
}
34+
35+
func tars(foo string, bar, baz string) {
36+
fmt.Println(<a...:>foo, bar, baz)
37+
}
38+
39+
func foobar() {
40+
var x foo
41+
x.bar(<baz:>"", <qux:>1)
42+
kase(<foo:>0, <bar:>true, <baz...:>"c", "d", "e")
43+
kipp(<foo:>"a", <bar:>"b", <baz:>"c")
44+
plex(<foo:>"a", <bar:>"b", <baz:>"c")
45+
tars(<foo:>"a", <bar:>"b", <baz:>"c")
46+
}
47+

0 commit comments

Comments
 (0)