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