@@ -22,6 +22,9 @@ package golang
22
22
// - add push notifications such as didChange -> reload.
23
23
// - there appears to be a maximum file size beyond which the
24
24
// "source.doc" code action is not offered. Remove that.
25
+ // - modify JS httpGET function to give a transient visual indication
26
+ // when clicking a source link that the editor is being navigated
27
+ // (in case it doesn't raise itself, like VS Code).
25
28
26
29
import (
27
30
"bytes"
@@ -33,6 +36,7 @@ import (
33
36
"go/token"
34
37
"go/types"
35
38
"html"
39
+ "log"
36
40
"path/filepath"
37
41
38
42
"golang.org/x/tools/gopls/internal/cache"
@@ -41,6 +45,7 @@ import (
41
45
"golang.org/x/tools/gopls/internal/util/bug"
42
46
"golang.org/x/tools/gopls/internal/util/safetoken"
43
47
"golang.org/x/tools/gopls/internal/util/slices"
48
+ "golang.org/x/tools/gopls/internal/util/typesutil"
44
49
"golang.org/x/tools/internal/typesinternal"
45
50
)
46
51
@@ -108,13 +113,72 @@ func RenderPackageDoc(pkg *cache.Package, posURL func(filename string, line, col
108
113
})
109
114
}
110
115
111
- // Ensure doc links (e.g. "[fmt.Println]") become valid links.
112
- docpkg .Printer ().DocLinkURL = func (link * comment.DocLink ) string {
113
- fragment := link .Name
114
- if link .Recv == "" {
115
- fragment = link .Recv + "." + link .Name
116
+ var docHTML func (comment string ) []byte
117
+ {
118
+ // Adapt doc comment parser and printer
119
+ // to our representation of Go packages
120
+ // so that doc links (e.g. "[fmt.Println]")
121
+ // become valid links.
122
+
123
+ printer := docpkg .Printer ()
124
+ printer .DocLinkURL = func (link * comment.DocLink ) string {
125
+ path := pkg .Metadata ().PkgPath
126
+ if link .ImportPath != "" {
127
+ path = PackagePath (link .ImportPath )
128
+ }
129
+ fragment := link .Name
130
+ if link .Recv != "" {
131
+ fragment = link .Recv + "." + link .Name
132
+ }
133
+ return pkgURL (path , fragment )
134
+ }
135
+ parser := docpkg .Parser ()
136
+ parser .LookupPackage = func (name string ) (importPath string , ok bool ) {
137
+ // Ambiguous: different files in the same
138
+ // package may have different import mappings,
139
+ // but the hook doesn't provide the file context.
140
+ // TODO(adonovan): conspire with docHTML to
141
+ // pass the doc comment's enclosing file through
142
+ // a shared variable, so that we can compute
143
+ // the correct per-file mapping.
144
+ //
145
+ // TODO(adonovan): check for PkgName.Name
146
+ // matches, but also check for
147
+ // PkgName.Imported.Namer matches, since some
148
+ // packages are typically imported under a
149
+ // non-default name (e.g. pathpkg "path") but
150
+ // may be referred to in doc links using their
151
+ // canonical name.
152
+ for _ , f := range pkg .Syntax () {
153
+ for _ , imp := range f .Imports {
154
+ pkgName , ok := typesutil .ImportedPkgName (pkg .TypesInfo (), imp )
155
+ if ok && pkgName .Name () == name {
156
+ return pkgName .Imported ().Path (), true
157
+ }
158
+ }
159
+ }
160
+ return "" , false
161
+ }
162
+ parser .LookupSym = func (recv , name string ) (ok bool ) {
163
+ defer func () {
164
+ log .Printf ("LookupSym %q %q = %t " , recv , name , ok )
165
+ }()
166
+ // package-level decl?
167
+ if recv == "" {
168
+ return pkg .Types ().Scope ().Lookup (name ) != nil
169
+ }
170
+
171
+ // method?
172
+ tname , ok := pkg .Types ().Scope ().Lookup (recv ).(* types.TypeName )
173
+ if ! ok {
174
+ return false
175
+ }
176
+ m , _ , _ := types .LookupFieldOrMethod (tname .Type (), true , pkg .Types (), name )
177
+ return is [* types.Func ](m )
178
+ }
179
+ docHTML = func (comment string ) []byte {
180
+ return printer .HTML (parser .Parse (comment ))
116
181
}
117
- return pkgURL (PackagePath (link .ImportPath ), fragment )
118
182
}
119
183
120
184
var buf bytes.Buffer
@@ -302,7 +366,7 @@ function httpGET(url) {
302
366
"https://pkg.go.dev/" + string (pkg .Types ().Path ()))
303
367
304
368
// package doc
305
- fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " , docpkg . HTML (docpkg .Doc ))
369
+ fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " , docHTML (docpkg .Doc ))
306
370
307
371
// symbol index
308
372
fmt .Fprintf (& buf , "<h2>Index</h2>\n " )
@@ -366,7 +430,7 @@ function httpGET(url) {
366
430
fmt .Fprintf (& buf , "<pre class='code'>%s</pre>\n " , nodeHTML (& decl2 ))
367
431
368
432
// comment (if any)
369
- fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " , docpkg . HTML (v .Doc ))
433
+ fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " , docHTML (v .Doc ))
370
434
}
371
435
}
372
436
fmt .Fprintf (& buf , "<h2 id='hdr-Constants'>Constants</h2>\n " )
@@ -397,7 +461,7 @@ function httpGET(url) {
397
461
nodeHTML (docfn .Decl .Type ))
398
462
399
463
// comment (if any)
400
- fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " , docpkg . HTML (docfn .Doc ))
464
+ fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " , docHTML (docfn .Doc ))
401
465
}
402
466
}
403
467
funcs (docpkg .Funcs )
@@ -417,7 +481,7 @@ function httpGET(url) {
417
481
fmt .Fprintf (& buf , "<pre class='code'>%s</pre>\n " , nodeHTML (& decl2 ))
418
482
419
483
// comment (if any)
420
- fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " , docpkg . HTML (doctype .Doc ))
484
+ fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " , docHTML (doctype .Doc ))
421
485
422
486
// subelements
423
487
values (doctype .Consts ) // constants of type T
@@ -437,7 +501,7 @@ function httpGET(url) {
437
501
438
502
// comment (if any)
439
503
fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " ,
440
- docpkg . HTML (docmethod .Doc ))
504
+ docHTML (docmethod .Doc ))
441
505
}
442
506
}
443
507
0 commit comments