internal/lsp: add support for hovering runes

Enable to hover runes found in basic literals in various forms.
When a rune is found, the hover message provides a summary composed of a
printable version (if it exists) of the rune, its codepoint and its name.

Behaviour varies slightly depending on the basic literal: rune literals
always display the summary when hovered, string literals only display it
when an escaped rune sequence is found to avoid providing unnecessary
information, and finally number literals only when expressed as a
hexadecimal number whose size ranges from one to eight bytes.

Fixes golang/go#38239

Change-Id: I024fdd5c511a45c7c285e200ce1eda0669a45491
Reviewed-on: https://go-review.googlesource.com/c/tools/+/321810
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
Trust: Rebecca Stambler <rstambler@golang.org>
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Jean-Hadrien Chabran 2021-04-30 21:34:57 +02:00 committed by Rebecca Stambler
parent 258ee27c37
commit cd7c003cd3
32 changed files with 491 additions and 198 deletions

1
go.mod
View File

@ -8,5 +8,6 @@ require (
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e
golang.org/x/text v0.3.6
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
)

3
go.sum
View File

@ -18,7 +18,10 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=

View File

@ -108,6 +108,10 @@ func (r *runner) AddImport(t *testing.T, uri span.URI, expectedImport string) {
//TODO: import addition not supported on command line
}
func (r *runner) Hover(t *testing.T, spn span.Span, info string) {
//TODO: hovering not supported on command line
}
func (r *runner) runGoplsCmd(t testing.TB, args ...string) (string, string) {
rStdout, wStdout, err := os.Pipe()
if err != nil {

View File

@ -718,7 +718,7 @@ func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) {
didSomething := false
if hover != nil {
didSomething = true
tag := fmt.Sprintf("%s-hover", d.Name)
tag := fmt.Sprintf("%s-hoverdef", d.Name)
expectHover := string(r.data.Golden(tag, d.Src.URI().Filename(), func() ([]byte, error) {
return []byte(hover.Contents.Value), nil
}))
@ -840,6 +840,43 @@ func (r *runner) Highlight(t *testing.T, src span.Span, locations []span.Span) {
}
}
func (r *runner) Hover(t *testing.T, src span.Span, text string) {
m, err := r.data.Mapper(src.URI())
if err != nil {
t.Fatal(err)
}
loc, err := m.Location(src)
if err != nil {
t.Fatalf("failed for %v", err)
}
tdpp := protocol.TextDocumentPositionParams{
TextDocument: protocol.TextDocumentIdentifier{URI: loc.URI},
Position: loc.Range.Start,
}
params := &protocol.HoverParams{
TextDocumentPositionParams: tdpp,
}
hover, err := r.server.Hover(r.ctx, params)
if err != nil {
t.Fatal(err)
}
if text == "" {
if hover != nil {
t.Errorf("want nil, got %v\n", hover)
}
} else {
if hover == nil {
t.Fatalf("want hover result to include %s, but got nil", text)
}
if got := hover.Contents.Value; got != text {
t.Errorf("want %v, got %v\n", text, got)
}
if want, got := loc.Range, hover.Range; want != got {
t.Errorf("want range %v, got %v instead", want, got)
}
}
}
func (r *runner) References(t *testing.T, src span.Span, itemList []span.Span) {
sm, err := r.data.Mapper(src.URI())
if err != nil {

View File

@ -14,9 +14,12 @@ import (
"go/format"
"go/token"
"go/types"
"strconv"
"strings"
"time"
"unicode/utf8"
"golang.org/x/text/unicode/runenames"
"golang.org/x/tools/internal/event"
"golang.org/x/tools/internal/lsp/protocol"
"golang.org/x/tools/internal/typeparams"
@ -66,6 +69,9 @@ type HoverInformation struct {
func Hover(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) (*protocol.Hover, error) {
ident, err := Identifier(ctx, snapshot, fh, position)
if err != nil {
if hover, innerErr := hoverRune(ctx, snapshot, fh, position); innerErr == nil {
return hover, nil
}
return nil, nil
}
h, err := HoverIdentifier(ctx, ident)
@ -93,6 +99,155 @@ func Hover(ctx context.Context, snapshot Snapshot, fh FileHandle, position proto
}, nil
}
func hoverRune(ctx context.Context, snapshot Snapshot, fh FileHandle, position protocol.Position) (*protocol.Hover, error) {
ctx, done := event.Start(ctx, "source.hoverRune")
defer done()
r, mrng, err := findRune(ctx, snapshot, fh, position)
if err != nil {
return nil, err
}
rng, err := mrng.Range()
if err != nil {
return nil, err
}
var desc string
runeName := runenames.Name(r)
if len(runeName) > 0 && runeName[0] == '<' {
// Check if the rune looks like an HTML tag. If so, trim the surrounding <>
// characters to work around https://github.com/microsoft/vscode/issues/124042.
runeName = strings.TrimRight(runeName[1:], ">")
}
if strconv.IsPrint(r) {
desc = fmt.Sprintf("'%s', U+%04X, %s", string(r), uint32(r), runeName)
} else {
desc = fmt.Sprintf("U+%04X, %s", uint32(r), runeName)
}
return &protocol.Hover{
Contents: protocol.MarkupContent{
Kind: snapshot.View().Options().PreferredContentFormat,
Value: desc,
},
Range: rng,
}, nil
}
// ErrNoRuneFound is the error returned when no rune is found at a particular position.
var ErrNoRuneFound = errors.New("no rune found")
// findRune returns rune information for a position in a file.
func findRune(ctx context.Context, snapshot Snapshot, fh FileHandle, pos protocol.Position) (rune, MappedRange, error) {
pkg, pgf, err := GetParsedFile(ctx, snapshot, fh, NarrowestPackage)
if err != nil {
return 0, MappedRange{}, err
}
spn, err := pgf.Mapper.PointSpan(pos)
if err != nil {
return 0, MappedRange{}, err
}
rng, err := spn.Range(pgf.Mapper.Converter)
if err != nil {
return 0, MappedRange{}, err
}
// Find the basic literal enclosing the given position, if there is one.
var lit *ast.BasicLit
var found bool
ast.Inspect(pgf.File, func(n ast.Node) bool {
if found {
return false
}
if n, ok := n.(*ast.BasicLit); ok && rng.Start >= n.Pos() && rng.Start <= n.End() {
lit = n
found = true
}
return !found
})
if !found {
return 0, MappedRange{}, ErrNoRuneFound
}
var r rune
var start, end token.Pos
switch lit.Kind {
case token.CHAR:
s, err := strconv.Unquote(lit.Value)
if err != nil {
// If the conversion fails, it's because of an invalid syntax, therefore
// there is no rune to be found.
return 0, MappedRange{}, ErrNoRuneFound
}
r, _ = utf8.DecodeRuneInString(s)
if r == utf8.RuneError {
return 0, MappedRange{}, fmt.Errorf("rune error")
}
start, end = lit.Pos(), lit.End()
case token.INT:
// It's an integer, scan only if it is a hex litteral whose bitsize in
// ranging from 8 to 32.
if !(strings.HasPrefix(lit.Value, "0x") && len(lit.Value[2:]) >= 2 && len(lit.Value[2:]) <= 8) {
return 0, MappedRange{}, ErrNoRuneFound
}
v, err := strconv.ParseUint(lit.Value[2:], 16, 32)
if err != nil {
return 0, MappedRange{}, err
}
r = rune(v)
if r == utf8.RuneError {
return 0, MappedRange{}, fmt.Errorf("rune error")
}
start, end = lit.Pos(), lit.End()
case token.STRING:
// It's a string, scan only if it contains a unicode escape sequence under or before the
// current cursor position.
var found bool
strMappedRng, err := posToMappedRange(snapshot, pkg, lit.Pos(), lit.End())
if err != nil {
return 0, MappedRange{}, err
}
strRng, err := strMappedRng.Range()
if err != nil {
return 0, MappedRange{}, err
}
offset := strRng.Start.Character
for i := pos.Character - offset; i > 0; i-- {
// Start at the cursor position and search backward for the beginning of a rune escape sequence.
rr, _ := utf8.DecodeRuneInString(lit.Value[i:])
if rr == utf8.RuneError {
return 0, MappedRange{}, fmt.Errorf("rune error")
}
if rr == '\\' {
// Got the beginning, decode it.
var tail string
r, _, tail, err = strconv.UnquoteChar(lit.Value[i:], '"')
if err != nil {
// If the conversion fails, it's because of an invalid syntax, therefore is no rune to be found.
return 0, MappedRange{}, ErrNoRuneFound
}
// Only the rune escape sequence part of the string has to be highlighted, recompute the range.
runeLen := len(lit.Value) - (int(i) + len(tail))
start = token.Pos(int(lit.Pos()) + int(i))
end = token.Pos(int(start) + runeLen)
found = true
break
}
}
if !found {
// No escape sequence found
return 0, MappedRange{}, ErrNoRuneFound
}
default:
return 0, MappedRange{}, ErrNoRuneFound
}
mappedRange, err := posToMappedRange(snapshot, pkg, start, end)
if err != nil {
return 0, MappedRange{}, err
}
return r, mappedRange, nil
}
func HoverIdentifier(ctx context.Context, i *IdentifierInfo) (*HoverInformation, error) {
ctx, done := event.Start(ctx, "source.Hover")
defer done()

View File

@ -576,12 +576,12 @@ func (r *runner) Definition(t *testing.T, spn span.Span, d tests.Definition) {
didSomething := false
if hover != "" {
didSomething = true
tag := fmt.Sprintf("%s-hover", d.Name)
tag := fmt.Sprintf("%s-hoverdef", d.Name)
expectHover := string(r.data.Golden(tag, d.Src.URI().Filename(), func() ([]byte, error) {
return []byte(hover), nil
}))
if hover != expectHover {
t.Errorf("hover for %s failed:\n%s", d.Src, tests.Diff(t, expectHover, hover))
t.Errorf("hoverdef for %s failed:\n%s", d.Src, tests.Diff(t, expectHover, hover))
}
}
if !d.OnlyHover {
@ -682,6 +682,37 @@ func (r *runner) Highlight(t *testing.T, src span.Span, locations []span.Span) {
}
}
func (r *runner) Hover(t *testing.T, src span.Span, text string) {
ctx := r.ctx
_, srcRng, err := spanToRange(r.data, src)
if err != nil {
t.Fatal(err)
}
fh, err := r.snapshot.GetFile(r.ctx, src.URI())
if err != nil {
t.Fatal(err)
}
hover, err := source.Hover(ctx, r.snapshot, fh, srcRng.Start)
if err != nil {
t.Errorf("hover failed for %s: %v", src.URI(), err)
}
if text == "" {
if hover != nil {
t.Errorf("want nil, got %v\n", hover)
}
} else {
if hover == nil {
t.Fatalf("want hover result to not be nil")
}
if got := hover.Contents.Value; got != text {
t.Errorf("want %v, got %v\n", got, text)
}
if want, got := srcRng, hover.Range; want != got {
t.Errorf("want range %v, got %v instead", want, got)
}
}
}
func (r *runner) References(t *testing.T, src span.Span, itemList []span.Span) {
ctx := r.ctx
_, srcRng, err := spanToRange(r.data, src)

View File

@ -10,4 +10,47 @@ func _() {
_ = 1. //@complete(".")
_ = 'a' //@complete("' ")
_ = 'a' //@hover("'a'", "'a', U+0061, LATIN SMALL LETTER A")
_ = 0x61 //@hover("0x61", "'a', U+0061, LATIN SMALL LETTER A")
_ = '\u2211' //@hover("'\\u2211'", "'∑', U+2211, N-ARY SUMMATION")
_ = 0x2211 //@hover("0x2211", "'∑', U+2211, N-ARY SUMMATION")
_ = "foo \u2211 bar" //@hover("\\u2211", "'∑', U+2211, N-ARY SUMMATION")
_ = '\a' //@hover("'\\a'", "U+0007, control")
_ = "foo \a bar" //@hover("\\a", "U+0007, control")
_ = '\U0001F30A' //@hover("'\\U0001F30A'", "'🌊', U+1F30A, WATER WAVE")
_ = 0x0001F30A //@hover("0x0001F30A", "'🌊', U+1F30A, WATER WAVE")
_ = "foo \U0001F30A bar" //@hover("\\U0001F30A", "'🌊', U+1F30A, WATER WAVE")
_ = '\x7E' //@hover("'\\x7E'", "'~', U+007E, TILDE")
_ = "foo \x7E bar" //@hover("\\x7E", "'~', U+007E, TILDE")
_ = "foo \a bar" //@hover("\\a", "U+0007, control")
_ = '\173' //@hover("'\\173'", "'{', U+007B, LEFT CURLY BRACKET")
_ = "foo \173 bar" //@hover("\\173", "'{', U+007B, LEFT CURLY BRACKET")
_ = "foo \173 bar \u2211 baz" //@hover("\\173", "'{', U+007B, LEFT CURLY BRACKET")
_ = "foo \173 bar \u2211 baz" //@hover("\\u2211", "'∑', U+2211, N-ARY SUMMATION")
_ = "foo\173bar\u2211baz" //@hover("\\173", "'{', U+007B, LEFT CURLY BRACKET")
_ = "foo\173bar\u2211baz" //@hover("\\u2211", "'∑', U+2211, N-ARY SUMMATION")
// search for runes in string only if there is an escaped sequence
_ = "hello" //@hover("\"hello\"", "")
// incorrect escaped rune sequences
_ = '\0' //@hover("'\\0'", "")
_ = '\u22111' //@hover("'\\u22111'", "")
_ = '\U00110000' //@hover("'\\U00110000'", "")
_ = '\u12e45'//@hover("'\\u12e45'", "")
_ = '\xa' //@hover("'\\xa'", "")
_ = 'aa' //@hover("'aa'", "")
// other basic lits
_ = 1 //@hover("1", "")
_ = 1.2 //@hover("1.2", "")
_ = 1.2i //@hover("1.2i", "")
_ = 0123 //@hover("0123", "")
_ = 0x1234567890 //@hover("0x1234567890", "")
}

View File

@ -22,7 +22,7 @@ func Example()
"description": "```go\nfunc Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/cgo?utm_source=gopls#Example)"
}
-- funccgoexample-hover --
-- funccgoexample-hoverdef --
```go
func Example()
```

View File

@ -22,7 +22,7 @@ func cgo.Example()
"description": "```go\nfunc cgo.Example()\n```\n\n[`cgo.Example` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/cgo?utm_source=gopls#Example)"
}
-- funccgoexample-hover --
-- funccgoexample-hoverdef --
```go
func cgo.Example()
```

View File

@ -1,5 +1,5 @@
// Package a is a package for testing go to definition.
package a //@mark(aPackage, "a "),hover("a ", aPackage)
package a //@mark(aPackage, "a "),hoverdef("a ", aPackage)
import (
"fmt"
@ -9,19 +9,19 @@ import (
var (
// x is a variable.
x string //@x,hover("x", x)
x string //@x,hoverdef("x", x)
)
// Constant block. When I hover on h, I should see this comment.
const (
// When I hover on g, I should see this comment.
g = 1 //@g,hover("g", g)
g = 1 //@g,hoverdef("g", g)
h = 2 //@h,hover("h", h)
h = 2 //@h,hoverdef("h", h)
)
// z is a variable too.
var z string //@z,hover("z", z)
var z string //@z,hoverdef("z", z)
type A string //@mark(AString, "A")
@ -33,14 +33,14 @@ func AStuff() { //@AStuff
var err error //@err
fmt.Printf("%v", err) //@godef("err", err)
var y string //@string,hover("string", string)
_ = make([]int, 0) //@make,hover("make", make)
var y string //@string,hoverdef("string", string)
_ = make([]int, 0) //@make,hoverdef("make", make)
var mu sync.Mutex
mu.Lock() //@Lock,hover("Lock", Lock)
mu.Lock() //@Lock,hoverdef("Lock", Lock)
var typ *types.Named //@mark(typesImport, "types"),hover("types", typesImport)
typ.Obj().Name() //@Name,hover("Name", Name)
var typ *types.Named //@mark(typesImport, "types"),hoverdef("types", typesImport)
typ.Obj().Name() //@Name,hoverdef("Name", Name)
}
type A struct {
@ -76,7 +76,7 @@ type J interface {
func _() {
// 1st type declaration block
type (
a struct { //@mark(declBlockA, "a"),hover("a", declBlockA)
a struct { //@mark(declBlockA, "a"),hoverdef("a", declBlockA)
x string
}
)
@ -84,21 +84,21 @@ func _() {
// 2nd type declaration block
type (
// b has a comment
b struct{} //@mark(declBlockB, "b"),hover("b", declBlockB)
b struct{} //@mark(declBlockB, "b"),hoverdef("b", declBlockB)
)
// 3rd type declaration block
type (
// c is a struct
c struct { //@mark(declBlockC, "c"),hover("c", declBlockC)
c struct { //@mark(declBlockC, "c"),hoverdef("c", declBlockC)
f string
}
d string //@mark(declBlockD, "d"),hover("d", declBlockD)
d string //@mark(declBlockD, "d"),hoverdef("d", declBlockD)
)
type (
e struct { //@mark(declBlockE, "e"),hover("e", declBlockE)
e struct { //@mark(declBlockE, "e"),hoverdef("e", declBlockE)
f float64
} // e has a comment
)

View File

@ -1,4 +1,4 @@
-- Lock-hover --
-- Lock-hoverdef --
```go
func (*sync.Mutex).Lock()
```
@ -6,7 +6,7 @@ func (*sync.Mutex).Lock()
[`(sync.Mutex).Lock` on pkg.go.dev](https://pkg.go.dev/sync?utm_source=gopls#Mutex.Lock)
Lock locks m\.
-- Name-hover --
-- Name-hoverdef --
```go
func (*types.object).Name() string
```
@ -38,7 +38,7 @@ func Random() int
"description": "```go\nfunc Random() int\n```\n\n[`a.Random` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Random)"
}
-- Random-hover --
-- Random-hoverdef --
```go
func Random() int
```
@ -68,15 +68,15 @@ func Random2(y int) int
"description": "```go\nfunc Random2(y int) int\n```\n\n[`a.Random2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Random2)"
}
-- Random2-hover --
-- Random2-hoverdef --
```go
func Random2(y int) int
```
[`a.Random2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Random2)
-- aPackage-hover --
-- aPackage-hoverdef --
Package a is a package for testing go to definition\.
-- declBlockA-hover --
-- declBlockA-hoverdef --
```go
type a struct {
x string
@ -84,13 +84,13 @@ type a struct {
```
1st type declaration block
-- declBlockB-hover --
-- declBlockB-hoverdef --
```go
type b struct{}
```
b has a comment
-- declBlockC-hover --
-- declBlockC-hoverdef --
```go
type c struct {
f string
@ -98,13 +98,13 @@ type c struct {
```
c is a struct
-- declBlockD-hover --
-- declBlockD-hoverdef --
```go
type d string
```
3rd type declaration block
-- declBlockE-hover --
-- declBlockE-hoverdef --
```go
type e struct {
f float64
@ -125,36 +125,36 @@ var err error
"start": {
"line": 33,
"column": 6,
"offset": 597
"offset": 612
},
"end": {
"line": 33,
"column": 9,
"offset": 600
"offset": 615
}
},
"description": "```go\nvar err error\n```\n\n\\@err"
}
-- err-hover --
-- err-hoverdef --
```go
var err error
```
\@err
-- g-hover --
-- g-hoverdef --
```go
const g untyped int = 1
```
When I hover on g, I should see this comment\.
-- h-hover --
-- h-hoverdef --
```go
const h untyped int = 2
```
Constant block\.
-- make-hover --
-- make-hoverdef --
```go
func(t Type, size ...IntegerType) Type
```
@ -162,23 +162,23 @@ func(t Type, size ...IntegerType) Type
[`make` on pkg.go.dev](https://pkg.go.dev/builtin?utm_source=gopls#make)
The make built\-in function allocates and initializes an object of type slice, map, or chan \(only\)\.
-- string-hover --
-- string-hoverdef --
```go
string
```
-- typesImport-hover --
-- typesImport-hoverdef --
```go
package types ("go/types")
```
[`types` on pkg.go.dev](https://pkg.go.dev/go/types?utm_source=gopls)
-- x-hover --
-- x-hoverdef --
```go
var x string
```
x is a variable\.
-- z-hover --
-- z-hoverdef --
```go
var z string
```

View File

@ -20,7 +20,7 @@ func TestA(t *testing.T)
"description": "```go\nfunc TestA(t *testing.T)\n```"
}
-- TestA-hover --
-- TestA-hoverdef --
```go
func TestA(t *testing.T)
```

View File

@ -20,7 +20,7 @@ func TestA2(t *testing.T)
"description": "```go\nfunc TestA2(t *testing.T)\n```"
}
-- TestA2-hover --
-- TestA2-hoverdef --
```go
func TestA2(t *testing.T)
```

View File

@ -1,4 +1,4 @@
package a //@mark(a, "a "),hover("a ", a)
package a //@mark(a, "a "),hoverdef("a ", a)
import "fmt"

View File

@ -13,18 +13,18 @@ field Member string
"start": {
"line": 6,
"column": 2,
"offset": 87
"offset": 90
},
"end": {
"line": 6,
"column": 8,
"offset": 93
"offset": 96
}
},
"description": "```go\nfield Member string\n```\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing.Member)\n\n\\@Member"
}
-- Member-hover --
-- Member-hoverdef --
```go
field Member string
```
@ -45,18 +45,18 @@ func (Thing).Method(i int) string
"start": {
"line": 15,
"column": 16,
"offset": 216
"offset": 219
},
"end": {
"line": 15,
"column": 22,
"offset": 222
"offset": 225
}
},
"description": "```go\nfunc (Thing).Method(i int) string\n```\n\n[`(a.Thing).Method` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing.Method)"
}
-- Method-hover --
-- Method-hoverdef --
```go
func (Thing).Method(i int) string
```
@ -77,18 +77,18 @@ var Other Thing
"start": {
"line": 9,
"column": 5,
"offset": 118
"offset": 121
},
"end": {
"line": 9,
"column": 10,
"offset": 123
"offset": 126
}
},
"description": "```go\nvar Other Thing\n```\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Other)\n\n\\@Other"
}
-- Other-hover --
-- Other-hoverdef --
```go
var Other Thing
```
@ -111,18 +111,18 @@ type Thing struct {
"start": {
"line": 5,
"column": 6,
"offset": 62
"offset": 65
},
"end": {
"line": 5,
"column": 11,
"offset": 67
"offset": 70
}
},
"description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing)"
}
-- Thing-hover --
-- Thing-hoverdef --
```go
type Thing struct {
Member string //@Member
@ -143,22 +143,22 @@ func Things(val []string) []Thing
"start": {
"line": 11,
"column": 6,
"offset": 145
"offset": 148
},
"end": {
"line": 11,
"column": 12,
"offset": 151
"offset": 154
}
},
"description": "```go\nfunc Things(val []string) []Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Things)"
}
-- Things-hover --
-- Things-hoverdef --
```go
func Things(val []string) []Thing
```
[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Things)
-- a-hover --
-- a-hoverdef --
Package a is a package for testing go to definition\.

View File

@ -7,9 +7,9 @@ func TypeStuff() { //@Stuff
switch y := interface{}(x).(type) { //@mark(switchY, "y"),godef("y", switchY)
case int: //@mark(intY, "int")
fmt.Printf("%v", y) //@hover("y", intY)
fmt.Printf("%v", y) //@hoverdef("y", intY)
case string: //@mark(stringY, "string")
fmt.Printf("%v", y) //@hover("y", stringY)
fmt.Printf("%v", y) //@hoverdef("y", stringY)
}
}

View File

@ -1,8 +1,8 @@
-- intY-hover --
-- intY-hoverdef --
```go
var y int
```
-- stringY-hover --
-- stringY-hoverdef --
```go
var y string
```
@ -28,7 +28,7 @@ var y interface{}
"description": "```go\nvar y interface{}\n```"
}
-- switchY-hover --
-- switchY-hoverdef --
```go
var y interface{}
```

View File

@ -3,4 +3,4 @@ package a
import "time"
// dur is a constant of type time.Duration.
const dur = 15*time.Minute + 10*time.Second + 350*time.Millisecond //@dur,hover("dur", dur)
const dur = 15*time.Minute + 10*time.Second + 350*time.Millisecond //@dur,hoverdef("dur", dur)

View File

@ -1,4 +1,4 @@
-- dur-hover --
-- dur-hoverdef --
```go
const dur time.Duration = 910350000000 // 15m10.35s
```

View File

@ -25,9 +25,9 @@ func _() {
}
var t s
_ = t.nested.number //@hover("number", nestedNumber)
_ = t.nested2[0].str //@hover("str", nestedString)
_ = t.x.x.x.x.x.m //@hover("m", nestedMap)
_ = t.nested.number //@hoverdef("number", nestedNumber)
_ = t.nested2[0].str //@hoverdef("str", nestedString)
_ = t.x.x.x.x.x.m //@hoverdef("m", nestedMap)
}
func _() {
@ -40,9 +40,9 @@ func _() {
c int //@mark(structC, "c")
}
}
_ = s.a //@hover("a", structA)
_ = s.b //@hover("b", structB)
_ = s.b.c //@hover("c", structC)
_ = s.a //@hoverdef("a", structA)
_ = s.b //@hoverdef("b", structB)
_ = s.b.c //@hoverdef("c", structC)
var arr []struct {
// d field
@ -53,9 +53,9 @@ func _() {
f int //@mark(arrF, "f")
}
}
_ = arr[0].d //@hover("d", arrD)
_ = arr[0].e //@hover("e", arrE)
_ = arr[0].e.f //@hover("f", arrF)
_ = arr[0].d //@hoverdef("d", arrD)
_ = arr[0].e //@hoverdef("e", arrE)
_ = arr[0].e.f //@hoverdef("f", arrF)
var complex []struct {
c <-chan map[string][]struct {
@ -68,16 +68,16 @@ func _() {
}
}
}
_ = (<-complex[0].c)["0"][0].h //@hover("h", complexH)
_ = (<-complex[0].c)["0"][0].i //@hover("i", complexI)
_ = (<-complex[0].c)["0"][0].i.j //@hover("j", complexJ)
_ = (<-complex[0].c)["0"][0].h //@hoverdef("h", complexH)
_ = (<-complex[0].c)["0"][0].i //@hoverdef("i", complexI)
_ = (<-complex[0].c)["0"][0].i.j //@hoverdef("j", complexJ)
var mapWithStructKey map[struct {
// X key field
x []string //@mark(mapStructKeyX, "x")
}]int
for k := range mapWithStructKey {
_ = k.x //@hover("x", mapStructKeyX)
_ = k.x //@hoverdef("x", mapStructKeyX)
}
var mapWithStructKeyAndValue map[struct {
@ -90,15 +90,15 @@ func _() {
for k, v := range mapWithStructKeyAndValue {
// TODO: we don't show docs for y field because both map key and value
// are structs. And in this case, we parse only map value
_ = k.y //@hover("y", mapStructKeyY)
_ = v.x //@hover("x", mapStructValueX)
_ = k.y //@hoverdef("y", mapStructKeyY)
_ = v.x //@hoverdef("x", mapStructValueX)
}
var i []map[string]interface {
// open method comment
open() error //@mark(openMethod, "open")
}
i[0]["1"].open() //@hover("open", openMethod)
i[0]["1"].open() //@hoverdef("open", openMethod)
}
func _() {
@ -106,7 +106,7 @@ func _() {
// test description
desc string //@mark(testDescription, "desc")
}{}
_ = test.desc //@hover("desc", testDescription)
_ = test.desc //@hoverdef("desc", testDescription)
for _, tt := range []struct {
// test input
@ -123,11 +123,11 @@ func _() {
}
}
}{} {
_ = tt.in //@hover("in", testInput)
_ = tt.in["0"][0].key //@hover("key", testInputKey)
_ = tt.in["0"][0].value //@hover("value", testInputValue)
_ = tt.in //@hoverdef("in", testInput)
_ = tt.in["0"][0].key //@hoverdef("key", testInputKey)
_ = tt.in["0"][0].value //@hoverdef("value", testInputValue)
_ = (<-tt.result.v).value //@hover("value", testResultValue)
_ = (<-tt.result.v).value //@hoverdef("value", testResultValue)
}
}
@ -142,6 +142,6 @@ func _() {
}
r := getPoints()
r[0].x //@hover("x", returnX)
r[0].y //@hover("y", returnY)
r[0].x //@hoverdef("x", returnX)
r[0].y //@hoverdef("y", returnY)
}

View File

@ -1,134 +1,134 @@
-- arrD-hover --
-- arrD-hoverdef --
```go
field d int
```
d field
-- arrE-hover --
-- arrE-hoverdef --
```go
field e struct{f int}
```
e nested struct
-- arrF-hover --
-- arrF-hoverdef --
```go
field f int
```
f field of nested struct
-- complexH-hover --
-- complexH-hoverdef --
```go
field h int
```
h field
-- complexI-hover --
-- complexI-hoverdef --
```go
field i struct{j int}
```
i nested struct
-- complexJ-hover --
-- complexJ-hoverdef --
```go
field j int
```
j field of nested struct
-- mapStructKeyX-hover --
-- mapStructKeyX-hoverdef --
```go
field x []string
```
X key field
-- mapStructKeyY-hover --
-- mapStructKeyY-hoverdef --
```go
field y string
```
-- mapStructValueX-hover --
-- mapStructValueX-hoverdef --
```go
field x string
```
X value field
-- nestedMap-hover --
-- nestedMap-hoverdef --
```go
field m map[string]float64
```
nested map
-- nestedNumber-hover --
-- nestedNumber-hoverdef --
```go
field number int64
```
nested number
-- nestedString-hover --
-- nestedString-hoverdef --
```go
field str string
```
nested string
-- openMethod-hover --
-- openMethod-hoverdef --
```go
func (interface).open() error
```
open method comment
-- returnX-hover --
-- returnX-hoverdef --
```go
field x int
```
X coord
-- returnY-hover --
-- returnY-hoverdef --
```go
field y int
```
Y coord
-- structA-hover --
-- structA-hoverdef --
```go
field a int
```
a field
-- structB-hover --
-- structB-hoverdef --
```go
field b struct{c int}
```
b nested struct
-- structC-hover --
-- structC-hoverdef --
```go
field c int
```
c field of nested struct
-- testDescription-hover --
-- testDescription-hoverdef --
```go
field desc string
```
test description
-- testInput-hover --
-- testInput-hoverdef --
```go
field in map[string][]struct{key string; value interface{}}
```
test input
-- testInputKey-hover --
-- testInputKey-hoverdef --
```go
field key string
```
test key
-- testInputValue-hover --
-- testInputValue-hoverdef --
```go
field value interface{}
```
test value
-- testResultValue-hover --
-- testResultValue-hoverdef --
```go
field value int
```

View File

@ -22,7 +22,7 @@ func (*Pos).Sum() int
"description": "```go\nfunc (*Pos).Sum() int\n```\n\n[`(a.Pos).Sum` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Pos.Sum)"
}
-- PosSum-hover --
-- PosSum-hoverdef --
```go
func (*Pos).Sum() int
```
@ -52,7 +52,7 @@ field x int
"description": "```go\nfield x int\n```\n\n\\@mark\\(PosX, \\\"x\\\"\\),mark\\(PosY, \\\"y\\\"\\)"
}
-- PosX-hover --
-- PosX-hoverdef --
```go
field x int
```
@ -80,7 +80,7 @@ var y int
"description": "```go\nvar y int\n```"
}
-- RandomParamY-hover --
-- RandomParamY-hoverdef --
```go
var y int
```
@ -106,7 +106,7 @@ field field string
"description": "```go\nfield field string\n```"
}
-- TypField-hover --
-- TypField-hoverdef --
```go
field field string
```

View File

@ -13,13 +13,13 @@ type Embed struct {
func _() {
e := Embed{}
e.Hi() //@hover("Hi", AHi)
e.B() //@hover("B", AB)
e.Field //@hover("Field", AField)
e.Field2 //@hover("Field2", AField2)
e.Hello() //@hover("Hello", AHello)
e.Hey() //@hover("Hey", AHey)
e.Goodbye() //@hover("Goodbye", AGoodbye)
e.Hi() //@hoverdef("Hi", AHi)
e.B() //@hoverdef("B", AB)
e.Field //@hoverdef("Field", AField)
e.Field2 //@hoverdef("Field2", AField2)
e.Hello() //@hoverdef("Hello", AHello)
e.Hey() //@hoverdef("Hey", AHey)
e.Goodbye() //@hoverdef("Goodbye", AGoodbye)
}
type aAlias = a.A //@mark(aAlias, "aAlias")

View File

@ -1,4 +1,4 @@
-- AB-hover --
-- AB-hoverdef --
```go
func (a.I).B()
```
@ -6,7 +6,7 @@ func (a.I).B()
[`(a.I).B` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#I.B)
\@mark\(AB, \"B\"\)
-- AField-hover --
-- AField-hoverdef --
```go
field Field int
```
@ -14,7 +14,7 @@ field Field int
[`(a.S).Field` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#S.Field)
\@mark\(AField, \"Field\"\)
-- AField2-hover --
-- AField2-hoverdef --
```go
field Field2 int
```
@ -22,7 +22,7 @@ field Field2 int
[`(a.R).Field2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#R.Field2)
\@mark\(AField2, \"Field2\"\)
-- AGoodbye-hover --
-- AGoodbye-hoverdef --
```go
func (a.H).Goodbye()
```
@ -30,7 +30,7 @@ func (a.H).Goodbye()
[`(a.H).Goodbye` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#H.Goodbye)
\@mark\(AGoodbye, \"Goodbye\"\)
-- AHello-hover --
-- AHello-hoverdef --
```go
func (a.J).Hello()
```
@ -38,13 +38,13 @@ func (a.J).Hello()
[`(a.J).Hello` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#J.Hello)
\@mark\(AHello, \"Hello\"\)
-- AHey-hover --
-- AHey-hoverdef --
```go
func (a.R).Hey()
```
[`(a.R).Hey` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#R.Hey)
-- AHi-hover --
-- AHi-hoverdef --
```go
func (a.A).Hi()
```
@ -74,7 +74,7 @@ package a ("golang.org/x/tools/internal/lsp/godef/a")
"description": "```go\npackage a (\"golang.org/x/tools/internal/lsp/godef/a\")\n```\n\n[`a` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls)"
}
-- AImport-hover --
-- AImport-hoverdef --
```go
package a ("golang.org/x/tools/internal/lsp/godef/a")
```
@ -95,18 +95,18 @@ type A string
"start": {
"line": 26,
"column": 6,
"offset": 452
"offset": 467
},
"end": {
"line": 26,
"column": 7,
"offset": 453
"offset": 468
}
},
"description": "```go\ntype A string\n```\n\n[`a.A` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#A)\n\n\\@mark\\(AString, \\\"A\\\"\\)"
}
-- AString-hover --
-- AString-hoverdef --
```go
type A string
```
@ -127,18 +127,18 @@ func a.AStuff()
"start": {
"line": 28,
"column": 6,
"offset": 489
"offset": 504
},
"end": {
"line": 28,
"column": 12,
"offset": 495
"offset": 510
}
},
"description": "```go\nfunc a.AStuff()\n```\n\n[`a.AStuff` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#AStuff)"
}
-- AStuff-hover --
-- AStuff-hoverdef --
```go
func a.AStuff()
```
@ -162,18 +162,18 @@ type S1 struct {
"start": {
"line": 27,
"column": 6,
"offset": 566
"offset": 587
},
"end": {
"line": 27,
"column": 8,
"offset": 568
"offset": 589
}
},
"description": "```go\ntype S1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2),mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", AString)\n\taAlias //@godef(\"a\", aAlias)\n}\n```\n\n[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1)"
}
-- S1-hover --
-- S1-hoverdef --
```go
type S1 struct {
F1 int //@mark(S1F1, "F1")
@ -199,18 +199,18 @@ field F1 int
"start": {
"line": 28,
"column": 2,
"offset": 585
"offset": 606
},
"end": {
"line": 28,
"column": 4,
"offset": 587
"offset": 608
}
},
"description": "```go\nfield F1 int\n```\n\n[`(b.S1).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1.F1)\n\n\\@mark\\(S1F1, \\\"F1\\\"\\)"
}
-- S1F1-hover --
-- S1F1-hoverdef --
```go
field F1 int
```
@ -233,18 +233,18 @@ field S2 S2
"start": {
"line": 29,
"column": 2,
"offset": 617
"offset": 638
},
"end": {
"line": 29,
"column": 4,
"offset": 619
"offset": 640
}
},
"description": "```go\nfield S2 S2\n```\n\n[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1.S2)\n\n\\@godef\\(\\\"S2\\\", S2\\),mark\\(S1S2, \\\"S2\\\"\\)"
}
-- S1S2-hover --
-- S1S2-hoverdef --
```go
field S2 S2
```
@ -269,18 +269,18 @@ type S2 struct {
"start": {
"line": 34,
"column": 6,
"offset": 741
"offset": 762
},
"end": {
"line": 34,
"column": 8,
"offset": 743
"offset": 764
}
},
"description": "```go\ntype S2 struct {\n\tF1 string //@mark(S2F1, \"F1\")\n\tF2 int //@mark(S2F2, \"F2\")\n\t*a.A //@godef(\"A\", AString),godef(\"a\",AImport)\n}\n```\n\n[`b.S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S2)"
}
-- S2-hover --
-- S2-hoverdef --
```go
type S2 struct {
F1 string //@mark(S2F1, "F1")
@ -305,18 +305,18 @@ field F1 string
"start": {
"line": 35,
"column": 2,
"offset": 760
"offset": 781
},
"end": {
"line": 35,
"column": 4,
"offset": 762
"offset": 783
}
},
"description": "```go\nfield F1 string\n```\n\n[`(b.S2).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S2.F1)\n\n\\@mark\\(S2F1, \\\"F1\\\"\\)"
}
-- S2F1-hover --
-- S2F1-hoverdef --
```go
field F1 string
```
@ -339,18 +339,18 @@ field F2 int
"start": {
"line": 36,
"column": 2,
"offset": 793
"offset": 814
},
"end": {
"line": 36,
"column": 4,
"offset": 795
"offset": 816
}
},
"description": "```go\nfield F2 int\n```\n\n[`(b.S2).F2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S2.F2)\n\n\\@mark\\(S2F2, \\\"F2\\\"\\)"
}
-- S2F2-hover --
-- S2F2-hoverdef --
```go
field F2 int
```
@ -371,18 +371,18 @@ type aAlias = a.A
"start": {
"line": 25,
"column": 6,
"offset": 521
"offset": 542
},
"end": {
"line": 25,
"column": 12,
"offset": 527
"offset": 548
}
},
"description": "```go\ntype aAlias = a.A\n```\n\n\\@mark\\(aAlias, \\\"aAlias\\\"\\)"
}
-- aAlias-hover --
-- aAlias-hoverdef --
```go
type aAlias = a.A
```
@ -403,18 +403,18 @@ const X untyped int = 0
"start": {
"line": 57,
"column": 7,
"offset": 1228
"offset": 1249
},
"end": {
"line": 57,
"column": 8,
"offset": 1229
"offset": 1250
}
},
"description": "```go\nconst X untyped int = 0\n```\n\n[`b.X` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#X)\n\n\\@mark\\(bX, \\\"X\\\"\\),godef\\(\\\"X\\\", bX\\)"
}
-- bX-hover --
-- bX-hoverdef --
```go
const X untyped int = 0
```
@ -446,7 +446,7 @@ package myFoo ("golang.org/x/tools/internal/lsp/foo")
"description": "```go\npackage myFoo (\"golang.org/x/tools/internal/lsp/foo\")\n```\n\n[`myFoo` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/foo?utm_source=gopls)"
}
-- myFoo-hover --
-- myFoo-hoverdef --
```go
package myFoo ("golang.org/x/tools/internal/lsp/foo")
```

View File

@ -16,18 +16,18 @@ type S1 struct {
"start": {
"line": 27,
"column": 6,
"offset": 566
"offset": 587
},
"end": {
"line": 27,
"column": 8,
"offset": 568
"offset": 589
}
},
"description": "```go\ntype S1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2),mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", AString)\n\taAlias //@godef(\"a\", aAlias)\n}\n```\n\n[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1)"
}
-- S1-hover --
-- S1-hoverdef --
```go
type S1 struct {
F1 int //@mark(S1F1, "F1")
@ -53,18 +53,18 @@ field F1 int
"start": {
"line": 28,
"column": 2,
"offset": 585
"offset": 606
},
"end": {
"line": 28,
"column": 4,
"offset": 587
"offset": 608
}
},
"description": "```go\nfield F1 int\n```\n\n[`(b.S1).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b?utm_source=gopls#S1.F1)\n\n\\@mark\\(S1F1, \\\"F1\\\"\\)"
}
-- S1F1-hover --
-- S1F1-hoverdef --
```go
field F1 int
```

View File

@ -22,10 +22,10 @@ godef(bFunc, Things)
func _() {
var x interface{} //@mark(eInterface, "interface{}")
switch x := x.(type) { //@hover("x", eInterface)
switch x := x.(type) { //@hoverdef("x", eInterface)
case string: //@mark(eString, "string")
fmt.Println(x) //@hover("x", eString)
fmt.Println(x) //@hoverdef("x", eString)
case int: //@mark(eInt, "int")
fmt.Println(x) //@hover("x", eInt)
fmt.Println(x) //@hoverdef("x", eInt)
}
}

View File

@ -13,18 +13,18 @@ field Member string
"start": {
"line": 6,
"column": 2,
"offset": 87
"offset": 90
},
"end": {
"line": 6,
"column": 8,
"offset": 93
"offset": 96
}
},
"description": "```go\nfield Member string\n```\n\n[`(a.Thing).Member` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing.Member)\n\n\\@Member"
}
-- Member-hover --
-- Member-hoverdef --
```go
field Member string
```
@ -47,18 +47,18 @@ var a.Other a.Thing
"start": {
"line": 9,
"column": 5,
"offset": 118
"offset": 121
},
"end": {
"line": 9,
"column": 10,
"offset": 123
"offset": 126
}
},
"description": "```go\nvar a.Other a.Thing\n```\n\n[`a.Other` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Other)\n\n\\@Other"
}
-- Other-hover --
-- Other-hoverdef --
```go
var a.Other a.Thing
```
@ -81,18 +81,18 @@ type Thing struct {
"start": {
"line": 5,
"column": 6,
"offset": 62
"offset": 65
},
"end": {
"line": 5,
"column": 11,
"offset": 67
"offset": 70
}
},
"description": "```go\ntype Thing struct {\n\tMember string //@Member\n}\n```\n\n[`a.Thing` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Thing)"
}
-- Thing-hover --
-- Thing-hoverdef --
```go
type Thing struct {
Member string //@Member
@ -113,32 +113,32 @@ func a.Things(val []string) []a.Thing
"start": {
"line": 11,
"column": 6,
"offset": 145
"offset": 148
},
"end": {
"line": 11,
"column": 12,
"offset": 151
"offset": 154
}
},
"description": "```go\nfunc a.Things(val []string) []a.Thing\n```\n\n[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Things)"
}
-- Things-hover --
-- Things-hoverdef --
```go
func a.Things(val []string) []a.Thing
```
[`a.Things` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#Things)
-- eInt-hover --
-- eInt-hoverdef --
```go
var x int
```
-- eInterface-hover --
-- eInterface-hoverdef --
```go
var x interface{}
```
-- eString-hover --
-- eString-hoverdef --
```go
var x string
```

View File

@ -4,7 +4,7 @@ import . "golang.org/x/tools/internal/lsp/godef/a"
func _() {
// variable of type a.A
var _ A //@mark(AVariable, "_"),hover("_", AVariable)
var _ A //@mark(AVariable, "_"),hoverdef("_", AVariable)
AStuff() //@hover("AStuff", AStuff)
AStuff() //@hoverdef("AStuff", AStuff)
}

View File

@ -1,10 +1,10 @@
-- AStuff-hover --
-- AStuff-hoverdef --
```go
func AStuff()
```
[`a.AStuff` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a?utm_source=gopls#AStuff)
-- AVariable-hover --
-- AVariable-hoverdef --
```go
var _ A
```

View File

@ -22,7 +22,7 @@ var myUnclosedIf string
"description": "```go\nvar myUnclosedIf string\n```\n\n\\@myUnclosedIf"
}
-- myUnclosedIf-hover --
-- myUnclosedIf-hoverdef --
```go
var myUnclosedIf string
```

View File

@ -1,20 +1,20 @@
-- argInfer-hover --
-- argInfer-hoverdef --
```go
func app(s []int, e int) []int // func[S₁ interface{~[]E₂}, E₂ interface{}](s S₁, e E₂) S₁
```
-- constrInf-hover --
-- constrInf-hoverdef --
```go
func app(s []int, e int) []int // func[S₁ interface{~[]E₂}, E₂ interface{}](s S₁, e E₂) S₁
```
-- constrInfer-hover --
-- constrInfer-hoverdef --
```go
func app(s []int, e int) []int // func[S₁ interface{~[]E₂}, E₂ interface{}](s S₁, e E₂) S₁
```
-- instance-hover --
-- instance-hoverdef --
```go
func app(s []int, e int) []int // func[S₁ interface{~[]E₂}, E₂ interface{}](s S₁, e E₂) S₁
```
-- partialInfer-hover --
-- partialInfer-hoverdef --
```go
func app(s []int, e int) []int // func[S₁ interface{~[]E₂}, E₂ interface{}](s S₁, e E₂) S₁
```

View File

@ -84,6 +84,7 @@ type WorkspaceSymbols map[WorkspaceSymbolsTestType]map[span.URI][]string
type Signatures map[span.Span]*protocol.SignatureHelp
type Links map[span.URI][]Link
type AddImport map[span.URI]string
type Hovers map[span.Span]string
type Data struct {
Config packages.Config
@ -119,6 +120,7 @@ type Data struct {
Signatures Signatures
Links Links
AddImport AddImport
Hovers Hovers
t testing.TB
fragments map[string]string
@ -161,6 +163,7 @@ type Tests interface {
SignatureHelp(*testing.T, span.Span, *protocol.SignatureHelp)
Link(*testing.T, span.URI, []Link)
AddImport(*testing.T, span.URI, string)
Hover(*testing.T, span.Span, string)
}
type Definition struct {
@ -309,6 +312,7 @@ func load(t testing.TB, mode string, dir string) *Data {
Signatures: make(Signatures),
Links: make(Links),
AddImport: make(AddImport),
Hovers: make(Hovers),
t: t,
dir: dir,
@ -459,7 +463,8 @@ func load(t testing.TB, mode string, dir string) *Data {
"godef": datum.collectDefinitions,
"implementations": datum.collectImplementations,
"typdef": datum.collectTypeDefinitions,
"hover": datum.collectHoverDefinitions,
"hoverdef": datum.collectHoverDefinitions,
"hover": datum.collectHovers,
"highlight": datum.collectHighlights,
"refs": datum.collectReferences,
"rename": datum.collectRenames,
@ -485,7 +490,7 @@ func load(t testing.TB, mode string, dir string) *Data {
// Collect names for the entries that require golden files.
if err := datum.Exported.Expect(map[string]interface{}{
"godef": datum.collectDefinitionNames,
"hover": datum.collectDefinitionNames,
"hoverdef": datum.collectDefinitionNames,
"workspacesymbol": datum.collectWorkspaceSymbols(WorkspaceSymbolsDefault),
"workspacesymbolfuzzy": datum.collectWorkspaceSymbols(WorkspaceSymbolsFuzzy),
"workspacesymbolcasesensitive": datum.collectWorkspaceSymbols(WorkspaceSymbolsCaseSensitive),
@ -730,6 +735,16 @@ func Run(t *testing.T, tests Tests, data *Data) {
}
})
t.Run("Hover", func(t *testing.T) {
t.Helper()
for pos, info := range data.Hovers {
t.Run(SpanName(pos), func(t *testing.T) {
t.Helper()
tests.Hover(t, pos, info)
})
}
})
t.Run("References", func(t *testing.T) {
t.Helper()
for src, itemList := range data.References {
@ -1222,6 +1237,10 @@ func (data *Data) collectHoverDefinitions(src, target span.Span) {
}
}
func (data *Data) collectHovers(src span.Span, expected string) {
data.Hovers[src] = expected
}
func (data *Data) collectTypeDefinitions(src, target span.Span) {
data.Definitions[src] = Definition{
Src: src,