@@ -25,6 +25,9 @@ package golang
25
25
// - modify JS httpGET function to give a transient visual indication
26
26
// when clicking a source link that the editor is being navigated
27
27
// (in case it doesn't raise itself, like VS Code).
28
+ // - move this into a new package, golang/pkgdoc, and then
29
+ // split out the various helpers without fear of polluting
30
+ // the golang package namespace.
28
31
29
32
import (
30
33
"bytes"
@@ -263,7 +266,11 @@ window.onload = () => {
263
266
if i > 0 {
264
267
buf .WriteString (", " )
265
268
}
266
- buf .WriteString (sig .Params ().At (i ).Name ())
269
+ name := sig .Params ().At (i ).Name ()
270
+ if name == "" {
271
+ name = "_"
272
+ }
273
+ buf .WriteString (name )
267
274
}
268
275
buf .WriteByte (')' )
269
276
label = buf .String ()
@@ -439,12 +446,62 @@ window.onload = () => {
439
446
return escape (buf .String ())
440
447
}
441
448
442
- // pkgRelative qualifies types by package name alone
443
- pkgRelative := func (other * types.Package ) string {
444
- if pkg .Types () == other {
445
- return "" // same package; unqualified
449
+ // fnString is like fn.String() except that it:
450
+ // - shows the receiver name;
451
+ // - uses space "(T) M()" not dot "(T).M()" after receiver;
452
+ // - doesn't bother with the special case for interface receivers
453
+ // since it is unreachable for the methods in go/doc.
454
+ // - elides parameters after the first three: f(a, b, c, ...).
455
+ fnString := func (fn * types.Func ) string {
456
+ // pkgRelative qualifies types by package name alone
457
+ pkgRelative := func (other * types.Package ) string {
458
+ if pkg .Types () == other {
459
+ return "" // same package; unqualified
460
+ }
461
+ return other .Name ()
462
+ }
463
+
464
+ sig := fn .Type ().(* types.Signature )
465
+
466
+ // Emit "func (recv T) F".
467
+ var buf bytes.Buffer
468
+ buf .WriteString ("func " )
469
+ if recv := sig .Recv (); recv != nil {
470
+ buf .WriteByte ('(' )
471
+ if recv .Name () != "" {
472
+ buf .WriteString (recv .Name ())
473
+ buf .WriteByte (' ' )
474
+ }
475
+ types .WriteType (& buf , recv .Type (), pkgRelative )
476
+ buf .WriteByte (')' )
477
+ buf .WriteByte (' ' ) // (ObjectString uses a '.' here)
478
+ } else if pkg := fn .Pkg (); pkg != nil {
479
+ if s := pkgRelative (pkg ); s != "" {
480
+ buf .WriteString (s )
481
+ buf .WriteByte ('.' )
482
+ }
446
483
}
447
- return other .Name ()
484
+ buf .WriteString (fn .Name ())
485
+
486
+ // Emit signature.
487
+ //
488
+ // Elide parameters after the third one.
489
+ // WriteSignature is too complex to fork, so we replace
490
+ // parameters 4+ with "invalid type", format,
491
+ // then post-process the string.
492
+ if sig .Params ().Len () > 3 {
493
+ sig = types .NewSignatureType (
494
+ sig .Recv (),
495
+ typesSeqToSlice [* types.TypeParam ](sig .RecvTypeParams ()),
496
+ typesSeqToSlice [* types.TypeParam ](sig .TypeParams ()),
497
+ types .NewTuple (append (
498
+ typesSeqToSlice [* types.Var ](sig .Params ())[:3 ],
499
+ types .NewVar (0 , nil , "" , types .Typ [types .Invalid ]))... ),
500
+ sig .Results (),
501
+ sig .Variadic ())
502
+ }
503
+ types .WriteSignature (& buf , sig , pkgRelative )
504
+ return strings .ReplaceAll (buf .String (), ", invalid type)" , ", ...)" )
448
505
}
449
506
450
507
fmt .Fprintf (& buf , "<main>\n " )
@@ -473,10 +530,8 @@ window.onload = () => {
473
530
}
474
531
for _ , fn := range docpkg .Funcs {
475
532
obj := scope .Lookup (fn .Name ).(* types.Func )
476
- // TODO(adonovan): show only 3 parameters; elide 4+. Ditto for methods.
477
533
fmt .Fprintf (& buf , "<li><a href='#%s'>%s</a></li>\n " ,
478
- obj .Name (),
479
- escape (types .ObjectString (obj , pkgRelative )))
534
+ obj .Name (), escape (fnString (obj )))
480
535
}
481
536
for _ , doctype := range docpkg .Types {
482
537
tname := scope .Lookup (doctype .Name ).(* types.TypeName )
@@ -490,19 +545,15 @@ window.onload = () => {
490
545
for _ , docfn := range doctype .Funcs {
491
546
obj := scope .Lookup (docfn .Name ).(* types.Func )
492
547
fmt .Fprintf (& buf , "<li><a href='#%s'>%s</a></li>\n " ,
493
- docfn .Name ,
494
- escape (types .ObjectString (obj , pkgRelative )))
548
+ docfn .Name , escape (fnString (obj )))
495
549
}
496
550
// methods
497
551
for _ , docmethod := range doctype .Methods {
498
552
method , _ , _ := types .LookupFieldOrMethod (tname .Type (), true , tname .Pkg (), docmethod .Name )
499
- // TODO(adonovan): style: change the . into a space in
500
- // ObjectString's "func (T).M()", and hide unexported
501
- // embedded types.
502
553
fmt .Fprintf (& buf , "<li><a href='#%s.%s'>%s</a></li>\n " ,
503
554
doctype .Name ,
504
555
docmethod .Name ,
505
- escape (types . ObjectString (method , pkgRelative )))
556
+ escape (fnString (method .( * types. Func ) )))
506
557
}
507
558
fmt .Fprintf (& buf , "</ul>\n " )
508
559
}
@@ -613,6 +664,22 @@ window.onload = () => {
613
664
return buf .Bytes (), nil
614
665
}
615
666
667
+ // typesSeq abstracts various go/types sequence types:
668
+ // MethodSet, Tuple, TypeParamList, TypeList.
669
+ // TODO(adonovan): replace with go1.23 iterators.
670
+ type typesSeq [T any ] interface {
671
+ Len () int
672
+ At (int ) T
673
+ }
674
+
675
+ func typesSeqToSlice [T any ](seq typesSeq [T ]) []T {
676
+ slice := make ([]T , seq .Len ())
677
+ for i := range slice {
678
+ slice [i ] = seq .At (i )
679
+ }
680
+ return slice
681
+ }
682
+
616
683
// (partly taken from pkgsite's typography.css)
617
684
const pkgDocStyle = `
618
685
body {
0 commit comments