@@ -38,6 +38,7 @@ import (
38
38
"html"
39
39
"log"
40
40
"path/filepath"
41
+ "strings"
41
42
42
43
"golang.org/x/tools/gopls/internal/cache"
43
44
"golang.org/x/tools/gopls/internal/protocol"
@@ -181,6 +182,8 @@ func RenderPackageDoc(pkg *cache.Package, posURL func(filename string, line, col
181
182
}
182
183
}
183
184
185
+ scope := pkg .Types ().Scope ()
186
+
184
187
var buf bytes.Buffer
185
188
buf .WriteString (`<!DOCTYPE html>
186
189
<html>
@@ -196,6 +199,13 @@ function httpGET(url) {
196
199
return false; // disable usual <a href=...> behavior
197
200
}
198
201
202
+ window.onload = () => {
203
+ // Hook up the navigation selector.
204
+ document.getElementById('hdr-Selector').onchange = (e) => {
205
+ window.location.href = e.target.value;
206
+ };
207
+ };
208
+
199
209
// Start a GET /hang request. If it ever completes, the server
200
210
// has disconnected. Show a banner in that case.
201
211
{
@@ -209,9 +219,85 @@ function httpGET(url) {
209
219
</script>
210
220
</head>
211
221
<body>
222
+ <header>
212
223
<div id='disconnected'>Gopls server has terminated. Page is inactive.</div>
224
+ <select id='hdr-Selector'>
225
+ <optgroup label="Documentation">
226
+ <option label="Overview" value="#hdr-Overview"/>
227
+ <option label="Index" value="#hdr-Index"/>
228
+ <option label="Constants" value="#hdr-Constants"/>
229
+ <option label="Variables" value="#hdr-Variables"/>
230
+ <option label="Functions" value="#hdr-Functions"/>
231
+ <option label="Types" value="#hdr-Types"/>
232
+ <option label="Source Files" value="#hdr-SourceFiles"/>
233
+ </optgroup>
213
234
` )
214
235
236
+ // -- header select element --
237
+
238
+ // option emits an <option> for the specified symbol.
239
+ option := func (obj types.Object ) {
240
+ // Render functions/methods as "(recv) Method(p1, ..., pN)".
241
+ fragment := obj .Name ()
242
+
243
+ // format parameter names (p1, ..., pN)
244
+ label := obj .Name () // for a type
245
+ if fn , ok := obj .(* types.Func ); ok {
246
+ var buf strings.Builder
247
+ sig := fn .Type ().(* types.Signature )
248
+ if sig .Recv () != nil {
249
+ _ , named := typesinternal .ReceiverNamed (sig .Recv ())
250
+ fmt .Fprintf (& buf , "(%s) " , sig .Recv ().Name ())
251
+ fragment = named .Obj ().Name () + "." + fn .Name ()
252
+ }
253
+ fmt .Fprintf (& buf , "%s(" , fn .Name ())
254
+ for i := 0 ; i < sig .Params ().Len (); i ++ {
255
+ if i > 0 {
256
+ buf .WriteString (", " )
257
+ }
258
+ buf .WriteString (sig .Params ().At (i ).Name ())
259
+ }
260
+ buf .WriteByte (')' )
261
+ label = buf .String ()
262
+ }
263
+
264
+ fmt .Fprintf (& buf , " <option label='%s' value='#%s'/>\n " , label , fragment )
265
+ }
266
+
267
+ // index of functions
268
+ fmt .Fprintf (& buf , "<optgroup label='Functions'>\n " )
269
+ for _ , fn := range docpkg .Funcs {
270
+ option (scope .Lookup (fn .Name ))
271
+ }
272
+ fmt .Fprintf (& buf , "</optgroup>\n " )
273
+
274
+ // index of types
275
+ fmt .Fprintf (& buf , "<optgroup label='Types'>\n " )
276
+ for _ , doctype := range docpkg .Types {
277
+ option (scope .Lookup (doctype .Name ))
278
+ }
279
+ fmt .Fprintf (& buf , "</optgroup>\n " )
280
+
281
+ // index of constructors and methods of each type
282
+ for _ , doctype := range docpkg .Types {
283
+ tname := scope .Lookup (doctype .Name ).(* types.TypeName )
284
+ if len (doctype .Funcs )+ len (doctype .Methods ) > 0 {
285
+ fmt .Fprintf (& buf , "<optgroup label='type %s'>\n " , doctype .Name )
286
+ for _ , docfn := range doctype .Funcs {
287
+ option (scope .Lookup (docfn .Name ))
288
+ }
289
+ for _ , docmethod := range doctype .Methods {
290
+ method , _ , _ := types .LookupFieldOrMethod (tname .Type (), true , tname .Pkg (), docmethod .Name )
291
+ option (method )
292
+ }
293
+ fmt .Fprintf (& buf , "</optgroup>\n " )
294
+ }
295
+ }
296
+ fmt .Fprintf (& buf , "</select>\n " )
297
+ fmt .Fprintf (& buf , "</header>\n " )
298
+
299
+ // -- main element --
300
+
215
301
escape := html .EscapeString
216
302
217
303
// sourceLink returns HTML for a link to open a file in the client editor.
@@ -355,8 +441,10 @@ function httpGET(url) {
355
441
return other .Name ()
356
442
}
357
443
444
+ fmt .Fprintf (& buf , "<main>\n " )
445
+
358
446
// package name
359
- fmt .Fprintf (& buf , "<h1>Package %s</h1>\n " , pkg .Types ().Name ())
447
+ fmt .Fprintf (& buf , "<h1 id='hdr-Overview' >Package %s</h1>\n " , pkg .Types ().Name ())
360
448
361
449
// import path
362
450
fmt .Fprintf (& buf , "<pre class='code'>import %q</pre>\n " , pkg .Types ().Path ())
@@ -369,15 +457,14 @@ function httpGET(url) {
369
457
fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " , docHTML (docpkg .Doc ))
370
458
371
459
// symbol index
372
- fmt .Fprintf (& buf , "<h2>Index</h2>\n " )
460
+ fmt .Fprintf (& buf , "<h2 id='hdr-Index' >Index</h2>\n " )
373
461
fmt .Fprintf (& buf , "<ul>\n " )
374
462
if len (docpkg .Consts ) > 0 {
375
463
fmt .Fprintf (& buf , "<li><a href='#hdr-Constants'>Constants</a></li>\n " )
376
464
}
377
465
if len (docpkg .Vars ) > 0 {
378
466
fmt .Fprintf (& buf , "<li><a href='#hdr-Variables'>Variables</a></li>\n " )
379
467
}
380
- scope := pkg .Types ().Scope ()
381
468
for _ , fn := range docpkg .Funcs {
382
469
obj := scope .Lookup (fn .Name ).(* types.Func )
383
470
fmt .Fprintf (& buf , "<li><a href='#%s'>%s</a></li>\n " ,
@@ -447,7 +534,7 @@ function httpGET(url) {
447
534
}
448
535
449
536
// package-level functions
450
- fmt .Fprintf (& buf , "<h2>Functions</h2>\n " )
537
+ fmt .Fprintf (& buf , "<h2 id='hdr-Functions' >Functions</h2>\n " )
451
538
// funcs emits a list of package-level functions,
452
539
// possibly organized beneath the type they construct.
453
540
funcs := func (funcs []* doc.Func ) {
@@ -467,7 +554,7 @@ function httpGET(url) {
467
554
funcs (docpkg .Funcs )
468
555
469
556
// types and their subelements
470
- fmt .Fprintf (& buf , "<h2>Types</h2>\n " )
557
+ fmt .Fprintf (& buf , "<h2 id='hdr-Types' >Types</h2>\n " )
471
558
for _ , doctype := range docpkg .Types {
472
559
tname := scope .Lookup (doctype .Name ).(* types.TypeName )
473
560
@@ -506,12 +593,16 @@ function httpGET(url) {
506
593
}
507
594
508
595
// source files
509
- fmt .Fprintf (& buf , "<h2>Source files</h2>\n " )
596
+ fmt .Fprintf (& buf , "<h2 id='hdr-SourceFiles' >Source files</h2>\n " )
510
597
for _ , filename := range docpkg .Filenames {
511
598
fmt .Fprintf (& buf , "<div class='comment'>%s</div>\n " ,
512
599
sourceLink (filepath .Base (filename ), posURL (filename , 1 , 1 )))
513
600
}
514
601
602
+ fmt .Fprintf (& buf , "</main>\n " )
603
+ fmt .Fprintf (& buf , "</body>\n " )
604
+ fmt .Fprintf (& buf , "</html>\n " )
605
+
515
606
return buf .Bytes (), nil
516
607
}
517
608
@@ -621,6 +712,21 @@ a:hover > * {
621
712
622
713
#pkgsite { height: 1.5em; }
623
714
715
+ header {
716
+ position: sticky;
717
+ top: 0;
718
+ left: 0;
719
+ width: 100%;
720
+ padding: 0.3em;
721
+ }
722
+
723
+ #hdr-Selector {
724
+ margin-right: 0.3em;
725
+ float: right;
726
+ min-width: 25em;
727
+ padding: 0.3em;
728
+ }
729
+
624
730
#disconnected {
625
731
position: fixed;
626
732
top: 1em;
0 commit comments