-
Notifications
You must be signed in to change notification settings - Fork 0
/
pkgextra.go
162 lines (148 loc) · 4.53 KB
/
pkgextra.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
package main
import (
"go/ast"
"go/doc"
"log"
"path"
"aslevy.com/go-doc/internal/astutil"
"aslevy.com/go-doc/internal/godoc"
"aslevy.com/go-doc/internal/outfmt"
"aslevy.com/go-doc/internal/workdir"
"github.com/muesli/termenv"
)
// filterNodeDoc is called by Package.emit prior to rendering a node with
// [format.Node] in order to filter out unwanted documentation. The filtered
// doc is returned, if any.
//
// This prevents the node's docs from appearing redundantly as a comment above
// the rendered node, since they are shown as formatted text below the rendered
// node. This only affects [*ast.FuncDecl] and [*ast.GenDecl] nodes, otherwise
// it is a nop and doc is nil.
//
// In official go doc this is not necessary because the [doc.Package] is built
// without [doc.PreserveAST] unless the -src flag is given, in which case the
// comment is rendered as a comment, and should not be nilled out.
//
// However in this fork, the doc.Package is almost always built with
// doc.PreserveAST because it is the only way to get the comments with the
// `//syntax:` directives. Otherwise such directives are stripped from the
// comments collected by the doc.Package.
func filterNodeDoc(node any) (doc *ast.CommentGroup) {
if showSrc {
return
}
switch decl := node.(type) {
case *ast.FuncDecl:
doc = decl.Doc
decl.Doc = nil
decl.Body = nil
case *ast.GenDecl:
doc = decl.Doc
decl.Doc = nil
}
return
}
var subs = []workdir.Sub{{
Env: "GOROOT",
Path: buildCtx.GOROOT,
}, {
Env: "GOPATH",
Path: buildCtx.GOPATH,
}}
func (pkg *Package) emitLocation(node ast.Node) {
if godoc.NoLocation || short || showAll {
return
}
pos := pkg.fs.Position(node.Pos())
if pos.Filename != "" && pos.Line > 0 {
pkg.newlines(1)
pkg.Printf("// %s +%d\n", workdir.Rel(pos.Filename, subs...), pos.Line)
}
}
func (pkg *Package) flushImports() {
// Write the buffer up to the point where we might need to insert the
// import block.
_, err := pkg.writer.Write(pkg.buf.Next(pkg.endOfPkgClause))
if err != nil {
log.Fatal(err)
}
if godoc.NoImports {
return
}
// Write the import block.
if err := astutil.NewPackageResolver(pkg.fs, pkg.pkg).
BuildImports(pkg.pkgRefs, godoc.ShowStdlib).
Render(pkg.writer); err != nil {
log.Fatal(err)
}
}
const codeDelim = outfmt.CodeBlockDelim
func (pb *pkgBuffer) Code() {
if !outfmt.IsRichMarkdown() ||
pb.inCodeBlock {
return
}
pb.inCodeBlock = true
lang := "go"
if outfmt.NoSyntax {
lang = "text"
}
pb.Buffer.Write([]byte(codeDelim + lang + "\n"))
}
func (pb *pkgBuffer) Text() {
if !outfmt.IsRichMarkdown() ||
!pb.inCodeBlock {
return
}
pb.inCodeBlock = false
pb.Buffer.Write([]byte(codeDelim + "\n\n"))
}
func importPathLink(pkgPath string) string {
if outfmt.Format != outfmt.Term &&
outfmt.BaseURL != "" {
return pkgPath
}
link := path.Join(outfmt.BaseURL, pkgPath)
return termenv.Hyperlink(link, pkgPath)
}
func (pkg *Package) Doc() *doc.Package { return pkg.doc }
// OneLineNode returns a one-line summary of the given input node.
//
// If no non-empty valName is given, the summary will be of the first exported
// value in the node, if any exist, and otherwise the empty string.
//
// If a non-empty valName is given and the node is an *ast.GenDecl, the summary
// will be of the value (const or var) with that name. This allows completion
// to render one line summaries for values that don't come first in a value
// declaration.
//
// Only the first valName is considered.
func (pkg *Package) OneLineNode(node ast.Node, opts ...godoc.OneLineNodeOption) string {
return pkg.oneLineNode(node, opts...)
}
func (pkg *Package) FindTypeSpec(decl *ast.GenDecl, symbol string) *ast.TypeSpec {
return pkg.findTypeSpec(decl, symbol)
}
func (pkg *Package) IsTypedValue(value *doc.Value) bool { return pkg.typedValue[value] }
func (pkg *Package) IsConstructor(fnc *doc.Func) bool { return pkg.constructor[fnc] }
func (pkg *Package) oneLineFieldList(list *ast.FieldList, depth int, opts ...godoc.OneLineNodeOption) ([]string, bool) {
o := godoc.NewOneLineNodeOptions(opts...)
var params []string
var paramsLen int
needParens := len(list.List) > 1
for _, field := range list.List {
needParens = needParens || len(field.Names) > 0
var pkgRefs astutil.PackageReferences
if o.PkgRefs != nil {
pkgRefs = make(astutil.PackageReferences)
}
param := pkg.oneLineField(field, depth, godoc.WithOpts(opts...), godoc.WithPkgRefs(pkgRefs))
params = append(params, param)
paramsLen += len(param) + len(", ")
if paramsLen > punchedCardWidth {
break
}
o.PkgRefs.Merge(pkgRefs)
}
return params, needParens
}