x/tools/internal/lsp: add support for document symbols
Updates golang/go#30915 Change-Id: I9a447f7748eb9894fb6f4072febec132b2ed91d7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/168338 Reviewed-by: Rebecca Stambler <rstambler@golang.org> Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
5a8dccf5b4
commit
1d95b17f1b
|
@ -125,6 +125,7 @@ func (s *server) Initialize(ctx context.Context, params *protocol.InitializePara
|
||||||
DefinitionProvider: true,
|
DefinitionProvider: true,
|
||||||
DocumentFormattingProvider: true,
|
DocumentFormattingProvider: true,
|
||||||
DocumentRangeFormattingProvider: true,
|
DocumentRangeFormattingProvider: true,
|
||||||
|
DocumentSymbolProvider: true,
|
||||||
HoverProvider: true,
|
HoverProvider: true,
|
||||||
SignatureHelpProvider: &protocol.SignatureHelpOptions{
|
SignatureHelpProvider: &protocol.SignatureHelpOptions{
|
||||||
TriggerCharacters: []string{"(", ","},
|
TriggerCharacters: []string{"(", ","},
|
||||||
|
@ -426,8 +427,13 @@ func (s *server) DocumentHighlight(context.Context, *protocol.TextDocumentPositi
|
||||||
return nil, notImplemented("DocumentHighlight")
|
return nil, notImplemented("DocumentHighlight")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) DocumentSymbol(context.Context, *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
|
func (s *server) DocumentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
|
||||||
return nil, notImplemented("DocumentSymbol")
|
f, m, err := newColumnMap(ctx, s.view, span.URI(params.TextDocument.URI))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
symbols := source.DocumentSymbols(ctx, f)
|
||||||
|
return toProtocolDocumentSymbols(m, symbols), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) CodeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
|
func (s *server) CodeAction(ctx context.Context, params *protocol.CodeActionParams) ([]protocol.CodeAction, error) {
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
// Copyright 2019 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 (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"go/ast"
|
||||||
|
"go/format"
|
||||||
|
"go/token"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/span"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SymbolKind int
|
||||||
|
|
||||||
|
const (
|
||||||
|
PackageSymbol SymbolKind = iota
|
||||||
|
StructSymbol
|
||||||
|
VariableSymbol
|
||||||
|
ConstantSymbol
|
||||||
|
FunctionSymbol
|
||||||
|
MethodSymbol
|
||||||
|
)
|
||||||
|
|
||||||
|
type Symbol struct {
|
||||||
|
Name string
|
||||||
|
Detail string
|
||||||
|
Span span.Span
|
||||||
|
Kind SymbolKind
|
||||||
|
Children []Symbol
|
||||||
|
}
|
||||||
|
|
||||||
|
func DocumentSymbols(ctx context.Context, f File) []Symbol {
|
||||||
|
var symbols []Symbol
|
||||||
|
fset := f.GetFileSet(ctx)
|
||||||
|
astFile := f.GetAST(ctx)
|
||||||
|
for _, decl := range astFile.Decls {
|
||||||
|
switch decl := decl.(type) {
|
||||||
|
case *ast.FuncDecl:
|
||||||
|
symbols = append(symbols, funcSymbol(decl, fset))
|
||||||
|
case *ast.GenDecl:
|
||||||
|
for _, spec := range decl.Specs {
|
||||||
|
switch spec := spec.(type) {
|
||||||
|
case *ast.ImportSpec:
|
||||||
|
symbols = append(symbols, importSymbol(spec, fset))
|
||||||
|
case *ast.TypeSpec:
|
||||||
|
symbols = append(symbols, typeSymbol(spec, fset))
|
||||||
|
case *ast.ValueSpec:
|
||||||
|
for _, name := range spec.Names {
|
||||||
|
symbols = append(symbols, varSymbol(decl, name, fset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return symbols
|
||||||
|
}
|
||||||
|
|
||||||
|
func funcSymbol(decl *ast.FuncDecl, fset *token.FileSet) Symbol {
|
||||||
|
s := Symbol{
|
||||||
|
Name: decl.Name.String(),
|
||||||
|
Kind: FunctionSymbol,
|
||||||
|
}
|
||||||
|
|
||||||
|
if decl.Recv != nil {
|
||||||
|
s.Kind = MethodSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
span, err := nodeSpan(decl, fset)
|
||||||
|
if err == nil {
|
||||||
|
s.Span = span
|
||||||
|
}
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
if err := format.Node(buf, fset, decl); err == nil {
|
||||||
|
s.Detail = buf.String()
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func importSymbol(spec *ast.ImportSpec, fset *token.FileSet) Symbol {
|
||||||
|
s := Symbol{
|
||||||
|
Name: spec.Path.Value,
|
||||||
|
Kind: PackageSymbol,
|
||||||
|
Detail: "import " + spec.Path.Value,
|
||||||
|
}
|
||||||
|
span, err := nodeSpan(spec, fset)
|
||||||
|
if err == nil {
|
||||||
|
s.Span = span
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func typeSymbol(spec *ast.TypeSpec, fset *token.FileSet) Symbol {
|
||||||
|
s := Symbol{
|
||||||
|
Name: spec.Name.String(),
|
||||||
|
Kind: StructSymbol,
|
||||||
|
}
|
||||||
|
span, err := nodeSpan(spec, fset)
|
||||||
|
if err == nil {
|
||||||
|
s.Span = span
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func varSymbol(decl *ast.GenDecl, name *ast.Ident, fset *token.FileSet) Symbol {
|
||||||
|
s := Symbol{
|
||||||
|
Name: name.Name,
|
||||||
|
Kind: VariableSymbol,
|
||||||
|
}
|
||||||
|
|
||||||
|
if decl.Tok == token.CONST {
|
||||||
|
s.Kind = ConstantSymbol
|
||||||
|
}
|
||||||
|
|
||||||
|
span, err := nodeSpan(name, fset)
|
||||||
|
if err == nil {
|
||||||
|
s.Span = span
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeSpan(n ast.Node, fset *token.FileSet) (span.Span, error) {
|
||||||
|
r := span.NewRange(fset, n.Pos(), n.End())
|
||||||
|
return r.Span()
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright 2019 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 (
|
||||||
|
"golang.org/x/tools/internal/lsp/source"
|
||||||
|
|
||||||
|
"golang.org/x/tools/internal/lsp/protocol"
|
||||||
|
)
|
||||||
|
|
||||||
|
func toProtocolDocumentSymbols(m *protocol.ColumnMapper, symbols []source.Symbol) []protocol.DocumentSymbol {
|
||||||
|
result := make([]protocol.DocumentSymbol, 0, len(symbols))
|
||||||
|
for _, s := range symbols {
|
||||||
|
ps := protocol.DocumentSymbol{
|
||||||
|
Name: s.Name,
|
||||||
|
Kind: toProtocolSymbolKind(s.Kind),
|
||||||
|
Detail: s.Detail,
|
||||||
|
Children: toProtocolDocumentSymbols(m, s.Children),
|
||||||
|
}
|
||||||
|
if r, err := m.Range(s.Span); err == nil {
|
||||||
|
ps.Range = r
|
||||||
|
ps.SelectionRange = r
|
||||||
|
}
|
||||||
|
result = append(result, ps)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func toProtocolSymbolKind(kind source.SymbolKind) protocol.SymbolKind {
|
||||||
|
switch kind {
|
||||||
|
case source.StructSymbol:
|
||||||
|
return protocol.Struct
|
||||||
|
case source.PackageSymbol:
|
||||||
|
return protocol.Package
|
||||||
|
case source.VariableSymbol:
|
||||||
|
return protocol.Variable
|
||||||
|
case source.ConstantSymbol:
|
||||||
|
return protocol.Constant
|
||||||
|
case source.FunctionSymbol:
|
||||||
|
return protocol.Function
|
||||||
|
case source.MethodSymbol:
|
||||||
|
return protocol.Method
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue