.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.1.1-0.20210319172145-bda8f5cee399 / internal / lsp / debug / info.go
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 debug exports debug information for gopls.
6 package debug
7
8 import (
9         "context"
10         "fmt"
11         "io"
12         "reflect"
13         "runtime/debug"
14         "sort"
15         "strings"
16
17         "golang.org/x/tools/internal/lsp/source"
18 )
19
20 type PrintMode int
21
22 const (
23         PlainText = PrintMode(iota)
24         Markdown
25         HTML
26 )
27
28 // Version is a manually-updated mechanism for tracking versions.
29 const Version = "v0.6.9"
30
31 // ServerVersion is the format used by gopls to report its version to the
32 // client. This format is structured so that the client can parse it easily.
33 type ServerVersion struct {
34         Module
35         Deps []*Module `json:"deps,omitempty"`
36 }
37
38 type Module struct {
39         ModuleVersion
40         Replace *ModuleVersion `json:"replace,omitempty"`
41 }
42
43 type ModuleVersion struct {
44         Path    string `json:"path,omitempty"`
45         Version string `json:"version,omitempty"`
46         Sum     string `json:"sum,omitempty"`
47 }
48
49 // VersionInfo returns the build info for the gopls process. If it was not
50 // built in module mode, we return a GOPATH-specific message with the
51 // hardcoded version.
52 func VersionInfo() *ServerVersion {
53         if info, ok := debug.ReadBuildInfo(); ok {
54                 return getVersion(info)
55         }
56         path := "gopls, built in GOPATH mode"
57         return &ServerVersion{
58                 Module: Module{
59                         ModuleVersion: ModuleVersion{
60                                 Path:    path,
61                                 Version: Version,
62                         },
63                 },
64         }
65 }
66
67 func getVersion(info *debug.BuildInfo) *ServerVersion {
68         serverVersion := ServerVersion{
69                 Module: Module{
70                         ModuleVersion: ModuleVersion{
71                                 Path:    info.Main.Path,
72                                 Version: info.Main.Version,
73                                 Sum:     info.Main.Sum,
74                         },
75                 },
76         }
77         for _, d := range info.Deps {
78                 m := &Module{
79                         ModuleVersion: ModuleVersion{
80                                 Path:    d.Path,
81                                 Version: d.Version,
82                                 Sum:     d.Sum,
83                         },
84                 }
85                 if d.Replace != nil {
86                         m.Replace = &ModuleVersion{
87                                 Path:    d.Replace.Path,
88                                 Version: d.Replace.Version,
89                         }
90                 }
91                 serverVersion.Deps = append(serverVersion.Deps, m)
92         }
93         return &serverVersion
94 }
95
96 // PrintServerInfo writes HTML debug info to w for the Instance.
97 func (i *Instance) PrintServerInfo(ctx context.Context, w io.Writer) {
98         section(w, HTML, "Server Instance", func() {
99                 fmt.Fprintf(w, "Start time: %v\n", i.StartTime)
100                 fmt.Fprintf(w, "LogFile: %s\n", i.Logfile)
101                 fmt.Fprintf(w, "Working directory: %s\n", i.Workdir)
102                 fmt.Fprintf(w, "Address: %s\n", i.ServerAddress)
103                 fmt.Fprintf(w, "Debug address: %s\n", i.DebugAddress)
104         })
105         PrintVersionInfo(ctx, w, true, HTML)
106         section(w, HTML, "Command Line", func() {
107                 fmt.Fprintf(w, "<a href=/debug/pprof/cmdline>cmdline</a>")
108         })
109 }
110
111 // PrintVersionInfo writes version information to w, using the output format
112 // specified by mode. verbose controls whether additional information is
113 // written, including section headers.
114 func PrintVersionInfo(ctx context.Context, w io.Writer, verbose bool, mode PrintMode) {
115         info := VersionInfo()
116         if !verbose {
117                 printBuildInfo(w, info, false, mode)
118                 return
119         }
120         section(w, mode, "Build info", func() {
121                 printBuildInfo(w, info, true, mode)
122         })
123 }
124
125 func section(w io.Writer, mode PrintMode, title string, body func()) {
126         switch mode {
127         case PlainText:
128                 fmt.Fprintln(w, title)
129                 fmt.Fprintln(w, strings.Repeat("-", len(title)))
130                 body()
131         case Markdown:
132                 fmt.Fprintf(w, "#### %s\n\n```\n", title)
133                 body()
134                 fmt.Fprintf(w, "```\n")
135         case HTML:
136                 fmt.Fprintf(w, "<h3>%s</h3>\n<pre>\n", title)
137                 body()
138                 fmt.Fprint(w, "</pre>\n")
139         }
140 }
141
142 func printBuildInfo(w io.Writer, info *ServerVersion, verbose bool, mode PrintMode) {
143         fmt.Fprintf(w, "%v %v\n", info.Path, Version)
144         printModuleInfo(w, &info.Module, mode)
145         if !verbose {
146                 return
147         }
148         for _, dep := range info.Deps {
149                 printModuleInfo(w, dep, mode)
150         }
151 }
152
153 func printModuleInfo(w io.Writer, m *Module, mode PrintMode) {
154         fmt.Fprintf(w, "    %s@%s", m.Path, m.Version)
155         if m.Sum != "" {
156                 fmt.Fprintf(w, " %s", m.Sum)
157         }
158         if m.Replace != nil {
159                 fmt.Fprintf(w, " => %v", m.Replace.Path)
160         }
161         fmt.Fprintf(w, "\n")
162 }
163
164 type field struct {
165         index []int
166 }
167
168 var fields []field
169
170 // find all the options. The presumption is that the Options are nested structs
171 // and that pointers don't need to be dereferenced
172 func swalk(t reflect.Type, ix []int, indent string) {
173         switch t.Kind() {
174         case reflect.Struct:
175                 for i := 0; i < t.NumField(); i++ {
176                         fld := t.Field(i)
177                         ixx := append(append([]int{}, ix...), i)
178                         swalk(fld.Type, ixx, indent+". ")
179                 }
180         default:
181                 // everything is either a struct or a field (that's an assumption about Options)
182                 fields = append(fields, field{ix})
183         }
184 }
185
186 func showOptions(o *source.Options) []string {
187         // non-breaking spaces for indenting current and defaults when they are on a separate line
188         const indent = "\u00a0\u00a0\u00a0\u00a0\u00a0"
189         var ans strings.Builder
190         t := reflect.TypeOf(*o)
191         swalk(t, []int{}, "")
192         v := reflect.ValueOf(*o)
193         do := reflect.ValueOf(*source.DefaultOptions())
194         for _, f := range fields {
195                 val := v.FieldByIndex(f.index)
196                 def := do.FieldByIndex(f.index)
197                 tx := t.FieldByIndex(f.index)
198                 prefix := fmt.Sprintf("%s (type is %s): ", tx.Name, tx.Type)
199                 is := strVal(val)
200                 was := strVal(def)
201                 if len(is) < 30 && len(was) < 30 {
202                         fmt.Fprintf(&ans, "%s current:%s, default:%s\n", prefix, is, was)
203                 } else {
204                         fmt.Fprintf(&ans, "%s\n%scurrent:%s\n%sdefault:%s\n", prefix, indent, is, indent, was)
205                 }
206         }
207         return strings.Split(ans.String(), "\n")
208 }
209 func strVal(val reflect.Value) string {
210         switch val.Kind() {
211         case reflect.Bool:
212                 return fmt.Sprintf("%v", val.Interface())
213         case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
214                 return fmt.Sprintf("%v", val.Interface())
215         case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
216                 return fmt.Sprintf("%v", val.Interface())
217         case reflect.Uintptr, reflect.UnsafePointer:
218                 return fmt.Sprintf("0x%x", val.Pointer())
219         case reflect.Complex64, reflect.Complex128:
220                 return fmt.Sprintf("%v", val.Complex())
221         case reflect.Array, reflect.Slice:
222                 ans := []string{}
223                 for i := 0; i < val.Len(); i++ {
224                         ans = append(ans, strVal(val.Index(i)))
225                 }
226                 sort.Strings(ans)
227                 return fmt.Sprintf("%v", ans)
228         case reflect.Chan, reflect.Func, reflect.Ptr:
229                 return val.Kind().String()
230         case reflect.Struct:
231                 var x source.Analyzer
232                 if val.Type() != reflect.TypeOf(x) {
233                         return val.Kind().String()
234                 }
235                 // this is sort of ugly, but usable
236                 str := val.FieldByName("Analyzer").Elem().FieldByName("Doc").String()
237                 ix := strings.Index(str, "\n")
238                 if ix == -1 {
239                         ix = len(str)
240                 }
241                 return str[:ix]
242         case reflect.String:
243                 return fmt.Sprintf("%q", val.Interface())
244         case reflect.Map:
245                 ans := []string{}
246                 iter := val.MapRange()
247                 for iter.Next() {
248                         k := iter.Key()
249                         v := iter.Value()
250                         ans = append(ans, fmt.Sprintf("%s:%s, ", strVal(k), strVal(v)))
251                 }
252                 sort.Strings(ans)
253                 return fmt.Sprintf("%v", ans)
254         }
255         return fmt.Sprintf("??%s??", val.Type())
256 }