Giant blob of minor changes
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / golang.org / x / tools@v0.0.0-20201028153306-37f0764111ff / godoc / linkify.go
diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/godoc/linkify.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201028153306-37f0764111ff/godoc/linkify.go
new file mode 100644 (file)
index 0000000..e4add22
--- /dev/null
@@ -0,0 +1,195 @@
+// Copyright 2013 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.
+
+// This file implements LinkifyText which introduces
+// links for identifiers pointing to their declarations.
+// The approach does not cover all cases because godoc
+// doesn't have complete type information, but it's
+// reasonably good for browsing.
+
+package godoc
+
+import (
+       "fmt"
+       "go/ast"
+       "go/doc"
+       "go/token"
+       "io"
+       "strconv"
+)
+
+// LinkifyText HTML-escapes source text and writes it to w.
+// Identifiers that are in a "use" position (i.e., that are
+// not being declared), are wrapped with HTML links pointing
+// to the respective declaration, if possible. Comments are
+// formatted the same way as with FormatText.
+//
+func LinkifyText(w io.Writer, text []byte, n ast.Node) {
+       links := linksFor(n)
+
+       i := 0     // links index
+       prev := "" // prev HTML tag
+       linkWriter := func(w io.Writer, _ int, start bool) {
+               // end tag
+               if !start {
+                       if prev != "" {
+                               fmt.Fprintf(w, `</%s>`, prev)
+                               prev = ""
+                       }
+                       return
+               }
+
+               // start tag
+               prev = ""
+               if i < len(links) {
+                       switch info := links[i]; {
+                       case info.path != "" && info.name == "":
+                               // package path
+                               fmt.Fprintf(w, `<a href="/pkg/%s/">`, info.path)
+                               prev = "a"
+                       case info.path != "" && info.name != "":
+                               // qualified identifier
+                               fmt.Fprintf(w, `<a href="/pkg/%s/#%s">`, info.path, info.name)
+                               prev = "a"
+                       case info.path == "" && info.name != "":
+                               // local identifier
+                               if info.isVal {
+                                       fmt.Fprintf(w, `<span id="%s">`, info.name)
+                                       prev = "span"
+                               } else if ast.IsExported(info.name) {
+                                       fmt.Fprintf(w, `<a href="#%s">`, info.name)
+                                       prev = "a"
+                               }
+                       }
+                       i++
+               }
+       }
+
+       idents := tokenSelection(text, token.IDENT)
+       comments := tokenSelection(text, token.COMMENT)
+       FormatSelections(w, text, linkWriter, idents, selectionTag, comments)
+}
+
+// A link describes the (HTML) link information for an identifier.
+// The zero value of a link represents "no link".
+//
+type link struct {
+       path, name string // package path, identifier name
+       isVal      bool   // identifier is defined in a const or var declaration
+}
+
+// linksFor returns the list of links for the identifiers used
+// by node in the same order as they appear in the source.
+//
+func linksFor(node ast.Node) (links []link) {
+       // linkMap tracks link information for each ast.Ident node. Entries may
+       // be created out of source order (for example, when we visit a parent
+       // definition node). These links are appended to the returned slice when
+       // their ast.Ident nodes are visited.
+       linkMap := make(map[*ast.Ident]link)
+
+       ast.Inspect(node, func(node ast.Node) bool {
+               switch n := node.(type) {
+               case *ast.Field:
+                       for _, n := range n.Names {
+                               linkMap[n] = link{}
+                       }
+               case *ast.ImportSpec:
+                       if name := n.Name; name != nil {
+                               linkMap[name] = link{}
+                       }
+               case *ast.ValueSpec:
+                       for _, n := range n.Names {
+                               linkMap[n] = link{name: n.Name, isVal: true}
+                       }
+               case *ast.FuncDecl:
+                       linkMap[n.Name] = link{}
+               case *ast.TypeSpec:
+                       linkMap[n.Name] = link{}
+               case *ast.AssignStmt:
+                       // Short variable declarations only show up if we apply
+                       // this code to all source code (as opposed to exported
+                       // declarations only).
+                       if n.Tok == token.DEFINE {
+                               // Some of the lhs variables may be re-declared,
+                               // so technically they are not defs. We don't
+                               // care for now.
+                               for _, x := range n.Lhs {
+                                       // Each lhs expression should be an
+                                       // ident, but we are conservative and check.
+                                       if n, _ := x.(*ast.Ident); n != nil {
+                                               linkMap[n] = link{isVal: true}
+                                       }
+                               }
+                       }
+               case *ast.SelectorExpr:
+                       // Detect qualified identifiers of the form pkg.ident.
+                       // If anything fails we return true and collect individual
+                       // identifiers instead.
+                       if x, _ := n.X.(*ast.Ident); x != nil {
+                               // Create links only if x is a qualified identifier.
+                               if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg {
+                                       if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil {
+                                               // spec.Path.Value is the import path
+                                               if path, err := strconv.Unquote(spec.Path.Value); err == nil {
+                                                       // Register two links, one for the package
+                                                       // and one for the qualified identifier.
+                                                       linkMap[x] = link{path: path}
+                                                       linkMap[n.Sel] = link{path: path, name: n.Sel.Name}
+                                               }
+                                       }
+                               }
+                       }
+               case *ast.CompositeLit:
+                       // Detect field names within composite literals. These links should
+                       // be prefixed by the type name.
+                       fieldPath := ""
+                       prefix := ""
+                       switch typ := n.Type.(type) {
+                       case *ast.Ident:
+                               prefix = typ.Name + "."
+                       case *ast.SelectorExpr:
+                               if x, _ := typ.X.(*ast.Ident); x != nil {
+                                       // Create links only if x is a qualified identifier.
+                                       if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg {
+                                               if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil {
+                                                       // spec.Path.Value is the import path
+                                                       if path, err := strconv.Unquote(spec.Path.Value); err == nil {
+                                                               // Register two links, one for the package
+                                                               // and one for the qualified identifier.
+                                                               linkMap[x] = link{path: path}
+                                                               linkMap[typ.Sel] = link{path: path, name: typ.Sel.Name}
+                                                               fieldPath = path
+                                                               prefix = typ.Sel.Name + "."
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       for _, e := range n.Elts {
+                               if kv, ok := e.(*ast.KeyValueExpr); ok {
+                                       if k, ok := kv.Key.(*ast.Ident); ok {
+                                               // Note: there is some syntactic ambiguity here. We cannot determine
+                                               // if this is a struct literal or a map literal without type
+                                               // information. We assume struct literal.
+                                               name := prefix + k.Name
+                                               linkMap[k] = link{path: fieldPath, name: name}
+                                       }
+                               }
+                       }
+               case *ast.Ident:
+                       if l, ok := linkMap[n]; ok {
+                               links = append(links, l)
+                       } else {
+                               l := link{name: n.Name}
+                               if n.Obj == nil && doc.IsPredeclared(n.Name) {
+                                       l.path = builtinPkgPath
+                               }
+                               links = append(links, l)
+                       }
+               }
+               return true
+       })
+       return
+}