mirror of
https://github.com/golang/go
synced 2024-11-18 16:54:43 -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:
parent
5a8dccf5b4
commit
1d95b17f1b
@ -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) {
|
||||
|
129
internal/lsp/source/symbols.go
Normal file
129
internal/lsp/source/symbols.go
Normal 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
48
internal/lsp/symbols.go
Normal 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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user