1
0
mirror of https://github.com/golang/go synced 2024-11-18 19:34:41 -07:00

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:
Zac Bergquist 2019-03-18 16:43:08 -06:00 committed by Rebecca Stambler
parent 5a8dccf5b4
commit 1d95b17f1b
3 changed files with 185 additions and 2 deletions

View File

@ -125,6 +125,7 @@ func (s *server) Initialize(ctx context.Context, params *protocol.InitializePara
DefinitionProvider: true,
DocumentFormattingProvider: true,
DocumentRangeFormattingProvider: true,
DocumentSymbolProvider: true,
HoverProvider: true,
SignatureHelpProvider: &protocol.SignatureHelpOptions{
TriggerCharacters: []string{"(", ","},
@ -426,8 +427,13 @@ func (s *server) DocumentHighlight(context.Context, *protocol.TextDocumentPositi
return nil, notImplemented("DocumentHighlight")
}
func (s *server) DocumentSymbol(context.Context, *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
return nil, notImplemented("DocumentSymbol")
func (s *server) DocumentSymbol(ctx context.Context, params *protocol.DocumentSymbolParams) ([]protocol.DocumentSymbol, error) {
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) {

View File

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

48
internal/lsp/symbols.go Normal file
View File

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