1// Copyright 2019 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package cmd 6 7import ( 8 "context" 9 "flag" 10 "fmt" 11 "sort" 12 13 "golang.org/x/tools/internal/lsp/protocol" 14 "golang.org/x/tools/internal/span" 15 "golang.org/x/tools/internal/tool" 16) 17 18// symbols implements the symbols verb for gopls 19type symbols struct { 20 app *Application 21} 22 23func (r *symbols) Name() string { return "symbols" } 24func (r *symbols) Usage() string { return "<file>" } 25func (r *symbols) ShortHelp() string { return "display selected file's symbols" } 26func (r *symbols) DetailedHelp(f *flag.FlagSet) { 27 fmt.Fprint(f.Output(), ` 28Example: 29 $ gopls symbols helper/helper.go 30`) 31 f.PrintDefaults() 32} 33func (r *symbols) Run(ctx context.Context, args ...string) error { 34 if len(args) != 1 { 35 return tool.CommandLineErrorf("symbols expects 1 argument (position)") 36 } 37 38 conn, err := r.app.connect(ctx) 39 if err != nil { 40 return err 41 } 42 defer conn.terminate(ctx) 43 44 from := span.Parse(args[0]) 45 p := protocol.DocumentSymbolParams{ 46 TextDocument: protocol.TextDocumentIdentifier{ 47 URI: protocol.URIFromSpanURI(from.URI()), 48 }, 49 } 50 51 symbols, err := conn.DocumentSymbol(ctx, &p) 52 if err != nil { 53 return err 54 } 55 for _, s := range symbols { 56 fmt.Println(symbolToString(s)) 57 // Sort children for consistency 58 sort.Slice(s.Children, func(i, j int) bool { 59 return s.Children[i].Name < s.Children[j].Name 60 }) 61 for _, c := range s.Children { 62 fmt.Println("\t" + symbolToString(c)) 63 } 64 } 65 66 return nil 67} 68 69func symbolToString(symbol protocol.DocumentSymbol) string { 70 r := symbol.SelectionRange 71 // convert ranges to user friendly 1-based positions 72 position := fmt.Sprintf("%v:%v-%v:%v", 73 r.Start.Line+1, 74 r.Start.Character+1, 75 r.End.Line+1, 76 r.End.Character+1, 77 ) 78 return fmt.Sprintf("%s %s %s", symbol.Name, symbol.Kind, position) 79} 80