1
0
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:
Ian Cottrell 2019-04-24 11:33:45 -04:00
parent 9cb3dcf692
commit 3b6f9c0030
7 changed files with 130 additions and 2 deletions

View File

@ -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 {

View File

@ -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
View 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
}

View File

@ -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 {

View File

@ -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
View 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
)

View File

@ -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,
})
}