github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/internal/lsp/cmd/symbols.go (about) 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 5 package cmd 6 7 import ( 8 "context" 9 "encoding/json" 10 "flag" 11 "fmt" 12 "sort" 13 14 "github.com/powerman/golang-tools/internal/lsp/protocol" 15 "github.com/powerman/golang-tools/internal/span" 16 "github.com/powerman/golang-tools/internal/tool" 17 ) 18 19 // symbols implements the symbols verb for gopls 20 type symbols struct { 21 app *Application 22 } 23 24 func (r *symbols) Name() string { return "symbols" } 25 func (r *symbols) Parent() string { return r.app.Name() } 26 func (r *symbols) Usage() string { return "<file>" } 27 func (r *symbols) ShortHelp() string { return "display selected file's symbols" } 28 func (r *symbols) DetailedHelp(f *flag.FlagSet) { 29 fmt.Fprint(f.Output(), ` 30 Example: 31 $ gopls symbols helper/helper.go 32 `) 33 printFlagDefaults(f) 34 } 35 func (r *symbols) Run(ctx context.Context, args ...string) error { 36 if len(args) != 1 { 37 return tool.CommandLineErrorf("symbols expects 1 argument (position)") 38 } 39 40 conn, err := r.app.connect(ctx) 41 if err != nil { 42 return err 43 } 44 defer conn.terminate(ctx) 45 46 from := span.Parse(args[0]) 47 p := protocol.DocumentSymbolParams{ 48 TextDocument: protocol.TextDocumentIdentifier{ 49 URI: protocol.URIFromSpanURI(from.URI()), 50 }, 51 } 52 symbols, err := conn.DocumentSymbol(ctx, &p) 53 if err != nil { 54 return err 55 } 56 for _, s := range symbols { 57 if m, ok := s.(map[string]interface{}); ok { 58 s, err = mapToSymbol(m) 59 if err != nil { 60 return err 61 } 62 } 63 switch t := s.(type) { 64 case protocol.DocumentSymbol: 65 printDocumentSymbol(t) 66 case protocol.SymbolInformation: 67 printSymbolInformation(t) 68 } 69 } 70 return nil 71 } 72 73 func mapToSymbol(m map[string]interface{}) (interface{}, error) { 74 b, err := json.Marshal(m) 75 if err != nil { 76 return nil, err 77 } 78 79 if _, ok := m["selectionRange"]; ok { 80 var s protocol.DocumentSymbol 81 if err := json.Unmarshal(b, &s); err != nil { 82 return nil, err 83 } 84 return s, nil 85 } 86 87 var s protocol.SymbolInformation 88 if err := json.Unmarshal(b, &s); err != nil { 89 return nil, err 90 } 91 return s, nil 92 } 93 94 func printDocumentSymbol(s protocol.DocumentSymbol) { 95 fmt.Printf("%s %s %s\n", s.Name, s.Kind, positionToString(s.SelectionRange)) 96 // Sort children for consistency 97 sort.Slice(s.Children, func(i, j int) bool { 98 return s.Children[i].Name < s.Children[j].Name 99 }) 100 for _, c := range s.Children { 101 fmt.Printf("\t%s %s %s\n", c.Name, c.Kind, positionToString(c.SelectionRange)) 102 } 103 } 104 105 func printSymbolInformation(s protocol.SymbolInformation) { 106 fmt.Printf("%s %s %s\n", s.Name, s.Kind, positionToString(s.Location.Range)) 107 } 108 109 func positionToString(r protocol.Range) string { 110 return fmt.Sprintf("%v:%v-%v:%v", 111 r.Start.Line+1, 112 r.Start.Character+1, 113 r.End.Line+1, 114 r.End.Character+1, 115 ) 116 }