mirror of
https://github.com/golang/go
synced 2024-11-18 13:24:39 -07:00
internal/lsp: add document link handling for import paths to godoc
Change-Id: Ib2eef50047dfcc64110c264e77d648f959613b88 Reviewed-on: https://go-review.googlesource.com/c/tools/+/173698 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
This commit is contained in:
parent
9cb3dcf692
commit
3b6f9c0030
@ -57,6 +57,10 @@ func (r *runner) Signature(t *testing.T, data tests.Signatures) {
|
|||||||
//TODO: add command line signature tests when it works
|
//TODO: add command line signature tests when it works
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *runner) Link(t *testing.T, data tests.Links) {
|
||||||
|
//TODO: add command line link tests when it works
|
||||||
|
}
|
||||||
|
|
||||||
func captureStdOut(t testing.TB, f func()) string {
|
func captureStdOut(t testing.TB, f func()) string {
|
||||||
r, out, err := os.Pipe()
|
r, out, err := os.Pipe()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -84,6 +84,7 @@ func (s *Server) initialize(ctx context.Context, params *protocol.InitializePara
|
|||||||
DocumentSymbolProvider: true,
|
DocumentSymbolProvider: true,
|
||||||
HoverProvider: true,
|
HoverProvider: true,
|
||||||
DocumentHighlightProvider: true,
|
DocumentHighlightProvider: true,
|
||||||
|
DocumentLinkProvider: &protocol.DocumentLinkOptions{},
|
||||||
SignatureHelpProvider: &protocol.SignatureHelpOptions{
|
SignatureHelpProvider: &protocol.SignatureHelpOptions{
|
||||||
TriggerCharacters: []string{"(", ","},
|
TriggerCharacters: []string{"(", ","},
|
||||||
},
|
},
|
||||||
|
45
internal/lsp/link.go
Normal file
45
internal/lsp/link.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright 2018 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"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
|
"golang.org/x/tools/internal/span"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s *Server) documentLink(ctx context.Context, params *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) {
|
||||||
|
uri := span.NewURI(params.TextDocument.URI)
|
||||||
|
view := s.findView(ctx, uri)
|
||||||
|
f, m, err := newColumnMap(ctx, view, uri)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// find the import block
|
||||||
|
ast := f.GetAST(ctx)
|
||||||
|
var result []protocol.DocumentLink
|
||||||
|
for _, imp := range ast.Imports {
|
||||||
|
spn, err := span.NewRange(f.GetFileSet(ctx), imp.Pos(), imp.End()).Span()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
rng, err := m.Range(spn)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
target, err := strconv.Unquote(imp.Path.Value)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
target = "https://godoc.org/" + target
|
||||||
|
result = append(result, protocol.DocumentLink{
|
||||||
|
Range: rng,
|
||||||
|
Target: target,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
@ -536,6 +536,41 @@ func diffSignatures(spn span.Span, want source.SignatureInformation, got *protoc
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *runner) Link(t *testing.T, data tests.Links) {
|
||||||
|
for uri, wantLinks := range data {
|
||||||
|
m := r.mapper(uri)
|
||||||
|
gotLinks, err := r.server.DocumentLink(context.Background(), &protocol.DocumentLinkParams{
|
||||||
|
TextDocument: protocol.TextDocumentIdentifier{
|
||||||
|
URI: protocol.NewURI(uri),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
links := make(map[span.Span]string, len(wantLinks))
|
||||||
|
for _, link := range wantLinks {
|
||||||
|
links[link.Src] = link.Target
|
||||||
|
}
|
||||||
|
for _, link := range gotLinks {
|
||||||
|
spn, err := m.RangeSpan(link.Range)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if target, ok := links[spn]; ok {
|
||||||
|
delete(links, spn)
|
||||||
|
if target != link.Target {
|
||||||
|
t.Errorf("for %v want %v, got %v\n", spn, link.Target, target)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
t.Errorf("unexpected link %v:%v\n", spn, link.Target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for spn, target := range links {
|
||||||
|
t.Errorf("missing link %v:%v\n", spn, target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *runner) mapper(uri span.URI) *protocol.ColumnMapper {
|
func (r *runner) mapper(uri span.URI) *protocol.ColumnMapper {
|
||||||
fname, err := uri.Filename()
|
fname, err := uri.Filename()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -210,8 +210,8 @@ func (s *Server) ResolveCodeLens(context.Context, *protocol.CodeLens) (*protocol
|
|||||||
return nil, notImplemented("ResolveCodeLens")
|
return nil, notImplemented("ResolveCodeLens")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) DocumentLink(context.Context, *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) {
|
func (s *Server) DocumentLink(ctx context.Context, params *protocol.DocumentLinkParams) ([]protocol.DocumentLink, error) {
|
||||||
return nil, nil // ignore
|
return s.documentLink(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) ResolveDocumentLink(context.Context, *protocol.DocumentLink) (*protocol.DocumentLink, error) {
|
func (s *Server) ResolveDocumentLink(context.Context, *protocol.DocumentLink) (*protocol.DocumentLink, error) {
|
||||||
|
12
internal/lsp/testdata/links/links.go
vendored
Normal file
12
internal/lsp/testdata/links/links.go
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package links
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt" //@link(re`".*"`,"https://godoc.org/fmt")
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/lsp/foo" //@link(re`".*"`,"https://godoc.org/golang.org/x/tools/internal/lsp/foo")
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ fmt.Formatter
|
||||||
|
_ foo.StructFoo
|
||||||
|
)
|
@ -36,6 +36,7 @@ const (
|
|||||||
ExpectedSymbolsCount = 1
|
ExpectedSymbolsCount = 1
|
||||||
ExpectedSignaturesCount = 19
|
ExpectedSignaturesCount = 19
|
||||||
ExpectedCompletionSnippetCount = 9
|
ExpectedCompletionSnippetCount = 9
|
||||||
|
ExpectedLinksCount = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -57,6 +58,7 @@ type Highlights map[string][]span.Span
|
|||||||
type Symbols map[span.URI][]source.Symbol
|
type Symbols map[span.URI][]source.Symbol
|
||||||
type SymbolsChildren map[string][]source.Symbol
|
type SymbolsChildren map[string][]source.Symbol
|
||||||
type Signatures map[span.Span]source.SignatureInformation
|
type Signatures map[span.Span]source.SignatureInformation
|
||||||
|
type Links map[span.URI][]Link
|
||||||
|
|
||||||
type Data struct {
|
type Data struct {
|
||||||
Config packages.Config
|
Config packages.Config
|
||||||
@ -71,6 +73,7 @@ type Data struct {
|
|||||||
Symbols Symbols
|
Symbols Symbols
|
||||||
symbolsChildren SymbolsChildren
|
symbolsChildren SymbolsChildren
|
||||||
Signatures Signatures
|
Signatures Signatures
|
||||||
|
Links Links
|
||||||
|
|
||||||
t testing.TB
|
t testing.TB
|
||||||
fragments map[string]string
|
fragments map[string]string
|
||||||
@ -85,6 +88,7 @@ type Tests interface {
|
|||||||
Highlight(*testing.T, Highlights)
|
Highlight(*testing.T, Highlights)
|
||||||
Symbol(*testing.T, Symbols)
|
Symbol(*testing.T, Symbols)
|
||||||
Signature(*testing.T, Signatures)
|
Signature(*testing.T, Signatures)
|
||||||
|
Link(*testing.T, Links)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Definition struct {
|
type Definition struct {
|
||||||
@ -101,6 +105,11 @@ type CompletionSnippet struct {
|
|||||||
PlaceholderSnippet string
|
PlaceholderSnippet string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Link struct {
|
||||||
|
Src span.Span
|
||||||
|
Target string
|
||||||
|
}
|
||||||
|
|
||||||
func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@ -114,6 +123,7 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
|||||||
Symbols: make(Symbols),
|
Symbols: make(Symbols),
|
||||||
symbolsChildren: make(SymbolsChildren),
|
symbolsChildren: make(SymbolsChildren),
|
||||||
Signatures: make(Signatures),
|
Signatures: make(Signatures),
|
||||||
|
Links: make(Links),
|
||||||
|
|
||||||
t: t,
|
t: t,
|
||||||
dir: dir,
|
dir: dir,
|
||||||
@ -180,6 +190,7 @@ func Load(t testing.TB, exporter packagestest.Exporter, dir string) *Data {
|
|||||||
"symbol": data.collectSymbols,
|
"symbol": data.collectSymbols,
|
||||||
"signature": data.collectSignatures,
|
"signature": data.collectSignatures,
|
||||||
"snippet": data.collectCompletionSnippets,
|
"snippet": data.collectCompletionSnippets,
|
||||||
|
"link": data.collectLinks,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@ -264,6 +275,18 @@ func Run(t *testing.T, tests Tests, data *Data) {
|
|||||||
}
|
}
|
||||||
tests.Signature(t, data.Signatures)
|
tests.Signature(t, data.Signatures)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Links", func(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
linksCount := 0
|
||||||
|
for _, want := range data.Links {
|
||||||
|
linksCount += len(want)
|
||||||
|
}
|
||||||
|
if linksCount != ExpectedLinksCount {
|
||||||
|
t.Errorf("got %v links expected %v", linksCount, ExpectedLinksCount)
|
||||||
|
}
|
||||||
|
tests.Link(t, data.Links)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (data *Data) Golden(tag string, target string, update func(golden string) error) []byte {
|
func (data *Data) Golden(tag string, target string, update func(golden string) error) []byte {
|
||||||
@ -379,3 +402,11 @@ func (data *Data) collectCompletionSnippets(spn span.Span, item token.Pos, plain
|
|||||||
PlaceholderSnippet: placeholder,
|
PlaceholderSnippet: placeholder,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (data *Data) collectLinks(spn span.Span, link string) {
|
||||||
|
uri := spn.URI()
|
||||||
|
data.Links[uri] = append(data.Links[uri], Link{
|
||||||
|
Src: spn,
|
||||||
|
Target: link,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user