@@ -7,6 +7,7 @@ package golang
7
7
import (
8
8
"bytes"
9
9
"context"
10
+ "encoding/json"
10
11
"fmt"
11
12
"go/ast"
12
13
"go/constant"
@@ -48,37 +49,47 @@ import (
48
49
// It is formatted in one of several formats as determined by the
49
50
// HoverKind setting.
50
51
type hoverResult struct {
51
- // synopsis is a single sentence synopsis of the symbol's documentation.
52
+ // The fields below are exported to define the JSON hover format.
53
+ // TODO(golang/go#70233): (re)remove support for JSON hover.
54
+
55
+ // Synopsis is a single sentence Synopsis of the symbol's documentation.
52
56
//
53
- // TODO(adonovan): in what syntax? It (usually) comes from doc.synopsis ,
57
+ // TODO(adonovan): in what syntax? It (usually) comes from doc.Synopsis ,
54
58
// which produces "Text" form, but it may be fed to
55
59
// DocCommentToMarkdown, which expects doc comment syntax.
56
- synopsis string
60
+ Synopsis string
57
61
58
- // fullDocumentation is the symbol's full documentation.
59
- fullDocumentation string
62
+ // FullDocumentation is the symbol's full documentation.
63
+ FullDocumentation string
60
64
61
- // signature is the symbol's signature .
62
- signature string
65
+ // Signature is the symbol's Signature .
66
+ Signature string
63
67
64
- // singleLine is a single line describing the symbol.
68
+ // SingleLine is a single line describing the symbol.
65
69
// This is recommended only for use in clients that show a single line for hover.
66
- singleLine string
70
+ SingleLine string
67
71
68
- // symbolName is the human-readable name to use for the symbol in links.
69
- symbolName string
72
+ // SymbolName is the human-readable name to use for the symbol in links.
73
+ SymbolName string
70
74
71
- // linkPath is the path of the package enclosing the given symbol,
75
+ // LinkPath is the path of the package enclosing the given symbol,
72
76
// with the module portion (if any) replaced by "module@version".
73
77
//
74
78
// For example: "github.com/google/go-github/[email protected] /github".
75
79
//
76
- // Use LinkTarget + "/" + linkPath + "#" + LinkAnchor to form a pkgsite URL.
77
- linkPath string
80
+ // Use LinkTarget + "/" + LinkPath + "#" + LinkAnchor to form a pkgsite URL.
81
+ LinkPath string
78
82
79
- // linkAnchor is the pkg.go.dev link anchor for the given symbol.
83
+ // LinkAnchor is the pkg.go.dev link anchor for the given symbol.
80
84
// For example, the "Node" part of "pkg.go.dev/go/ast#Node".
81
- linkAnchor string
85
+ LinkAnchor string
86
+
87
+ // New fields go below, and are unexported. The existing
88
+ // exported fields are underspecified and have already
89
+ // constrained our movements too much. A detailed JSON
90
+ // interface might be nice, but it needs a design and a
91
+ // precise specification.
92
+ // TODO(golang/go#70233): (re)deprecate the JSON hover output.
82
93
83
94
// typeDecl is the declaration syntax for a type,
84
95
// or "" for a non-type.
@@ -284,9 +295,9 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
284
295
typesinternal .SetVarKind (v , typesinternal .LocalVar )
285
296
signature := types .ObjectString (v , qual )
286
297
return * hoverRange , & hoverResult {
287
- signature : signature ,
288
- singleLine : signature ,
289
- symbolName : v .Name (),
298
+ Signature : signature ,
299
+ SingleLine : signature ,
300
+ SymbolName : v .Name (),
290
301
}, nil
291
302
}
292
303
@@ -615,13 +626,13 @@ func hover(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, pp pro
615
626
}
616
627
617
628
return * hoverRange , & hoverResult {
618
- synopsis : doc .Synopsis (docText ),
619
- fullDocumentation : docText ,
620
- singleLine : singleLineSignature ,
621
- symbolName : linkName ,
622
- signature : signature ,
623
- linkPath : linkPath ,
624
- linkAnchor : anchor ,
629
+ Synopsis : doc .Synopsis (docText ),
630
+ FullDocumentation : docText ,
631
+ SingleLine : singleLineSignature ,
632
+ SymbolName : linkName ,
633
+ Signature : signature ,
634
+ LinkPath : linkPath ,
635
+ LinkAnchor : anchor ,
625
636
typeDecl : typeDecl ,
626
637
methods : methods ,
627
638
promotedFields : fields ,
@@ -638,8 +649,8 @@ func hoverBuiltin(ctx context.Context, snapshot *cache.Snapshot, obj types.Objec
638
649
if obj .Name () == "Error" {
639
650
signature := obj .String ()
640
651
return & hoverResult {
641
- signature : signature ,
642
- singleLine : signature ,
652
+ Signature : signature ,
653
+ SingleLine : signature ,
643
654
// TODO(rfindley): these are better than the current behavior.
644
655
// SymbolName: "(error).Error",
645
656
// LinkPath: "builtin",
@@ -682,13 +693,13 @@ func hoverBuiltin(ctx context.Context, snapshot *cache.Snapshot, obj types.Objec
682
693
683
694
docText := comment .Text ()
684
695
return & hoverResult {
685
- synopsis : doc .Synopsis (docText ),
686
- fullDocumentation : docText ,
687
- signature : signature ,
688
- singleLine : obj .String (),
689
- symbolName : obj .Name (),
690
- linkPath : "builtin" ,
691
- linkAnchor : obj .Name (),
696
+ Synopsis : doc .Synopsis (docText ),
697
+ FullDocumentation : docText ,
698
+ Signature : signature ,
699
+ SingleLine : obj .String (),
700
+ SymbolName : obj .Name (),
701
+ LinkPath : "builtin" ,
702
+ LinkAnchor : obj .Name (),
692
703
}, nil
693
704
}
694
705
@@ -740,9 +751,9 @@ func hoverImport(ctx context.Context, snapshot *cache.Snapshot, pkg *cache.Packa
740
751
741
752
docText := comment .Text ()
742
753
return rng , & hoverResult {
743
- signature : "package " + string (impMetadata .Name ),
744
- synopsis : doc .Synopsis (docText ),
745
- fullDocumentation : docText ,
754
+ Signature : "package " + string (impMetadata .Name ),
755
+ Synopsis : doc .Synopsis (docText ),
756
+ FullDocumentation : docText ,
746
757
}, nil
747
758
}
748
759
@@ -798,9 +809,9 @@ func hoverPackageName(pkg *cache.Package, pgf *parsego.File) (protocol.Range, *h
798
809
}
799
810
800
811
return rng , & hoverResult {
801
- signature : "package " + string (pkg .Metadata ().Name ),
802
- synopsis : doc .Synopsis (docText ),
803
- fullDocumentation : docText ,
812
+ Signature : "package " + string (pkg .Metadata ().Name ),
813
+ Synopsis : doc .Synopsis (docText ),
814
+ FullDocumentation : docText ,
804
815
footer : footer ,
805
816
}, nil
806
817
}
@@ -926,8 +937,8 @@ func hoverLit(pgf *parsego.File, lit *ast.BasicLit, pos token.Pos) (protocol.Ran
926
937
}
927
938
hover := b .String ()
928
939
return rng , & hoverResult {
929
- synopsis : hover ,
930
- fullDocumentation : hover ,
940
+ Synopsis : hover ,
941
+ FullDocumentation : hover ,
931
942
}, nil
932
943
}
933
944
@@ -966,7 +977,7 @@ func hoverReturnStatement(pgf *parsego.File, path []ast.Node, ret *ast.ReturnStm
966
977
}
967
978
buf .WriteByte (')' )
968
979
return rng , & hoverResult {
969
- signature : buf .String (),
980
+ Signature : buf .String (),
970
981
}, nil
971
982
}
972
983
@@ -1005,9 +1016,9 @@ func hoverEmbed(fh file.Handle, rng protocol.Range, pattern string) (protocol.Ra
1005
1016
}
1006
1017
1007
1018
res := & hoverResult {
1008
- signature : fmt .Sprintf ("Embedding %q" , pattern ),
1009
- synopsis : s .String (),
1010
- fullDocumentation : s .String (),
1019
+ Signature : fmt .Sprintf ("Embedding %q" , pattern ),
1020
+ Synopsis : s .String (),
1021
+ FullDocumentation : s .String (),
1011
1022
}
1012
1023
return rng , res , nil
1013
1024
}
@@ -1242,10 +1253,17 @@ func formatHover(h *hoverResult, options *settings.Options, pkgURL func(path Pac
1242
1253
1243
1254
switch options .HoverKind {
1244
1255
case settings .SingleLine :
1245
- return h .singleLine , nil
1256
+ return h .SingleLine , nil
1246
1257
1247
1258
case settings .NoDocumentation :
1248
- return maybeFenced (h .signature ), nil
1259
+ return maybeFenced (h .Signature ), nil
1260
+
1261
+ case settings .Structured :
1262
+ b , err := json .Marshal (h )
1263
+ if err != nil {
1264
+ return "" , err
1265
+ }
1266
+ return string (b ), nil
1249
1267
1250
1268
case settings .SynopsisDocumentation , settings .FullDocumentation :
1251
1269
var sections [][]string // assembled below
@@ -1256,20 +1274,20 @@ func formatHover(h *hoverResult, options *settings.Options, pkgURL func(path Pac
1256
1274
// but not Signature, which is redundant (= TypeDecl + "\n" + Methods).
1257
1275
// For all other symbols, we display Signature;
1258
1276
// TypeDecl and Methods are empty.
1259
- // (Now that JSON is no more, we could rationalize this.)
1277
+ // TODO(golang/go#70233): When JSON is no more, we could rationalize this.
1260
1278
if h .typeDecl != "" {
1261
1279
sections = append (sections , []string {maybeFenced (h .typeDecl )})
1262
1280
} else {
1263
- sections = append (sections , []string {maybeFenced (h .signature )})
1281
+ sections = append (sections , []string {maybeFenced (h .Signature )})
1264
1282
}
1265
1283
1266
1284
// Doc section.
1267
1285
var doc string
1268
1286
switch options .HoverKind {
1269
1287
case settings .SynopsisDocumentation :
1270
- doc = h .synopsis
1288
+ doc = h .Synopsis
1271
1289
case settings .FullDocumentation :
1272
- doc = h .fullDocumentation
1290
+ doc = h .FullDocumentation
1273
1291
}
1274
1292
if options .PreferredContentFormat == protocol .Markdown {
1275
1293
doc = DocCommentToMarkdown (doc , options )
@@ -1392,34 +1410,34 @@ func StdSymbolOf(obj types.Object) *stdlib.Symbol {
1392
1410
1393
1411
// If pkgURL is non-nil, it should be used to generate doc links.
1394
1412
func formatLink (h * hoverResult , options * settings.Options , pkgURL func (path PackagePath , fragment string ) protocol.URI ) string {
1395
- if options .LinksInHover == settings .LinksInHover_None || h .linkPath == "" {
1413
+ if options .LinksInHover == settings .LinksInHover_None || h .LinkPath == "" {
1396
1414
return ""
1397
1415
}
1398
1416
var url protocol.URI
1399
1417
var caption string
1400
1418
if pkgURL != nil { // LinksInHover == "gopls"
1401
1419
// Discard optional module version portion.
1402
1420
// (Ideally the hoverResult would retain the structure...)
1403
- path := h .linkPath
1404
- if module , versionDir , ok := strings .Cut (h .linkPath , "@" ); ok {
1421
+ path := h .LinkPath
1422
+ if module , versionDir , ok := strings .Cut (h .LinkPath , "@" ); ok {
1405
1423
// "module@version/dir"
1406
1424
path = module
1407
1425
if _ , dir , ok := strings .Cut (versionDir , "/" ); ok {
1408
1426
path += "/" + dir
1409
1427
}
1410
1428
}
1411
- url = pkgURL (PackagePath (path ), h .linkAnchor )
1429
+ url = pkgURL (PackagePath (path ), h .LinkAnchor )
1412
1430
caption = "in gopls doc viewer"
1413
1431
} else {
1414
1432
if options .LinkTarget == "" {
1415
1433
return ""
1416
1434
}
1417
- url = cache .BuildLink (options .LinkTarget , h .linkPath , h .linkAnchor )
1435
+ url = cache .BuildLink (options .LinkTarget , h .LinkPath , h .LinkAnchor )
1418
1436
caption = "on " + options .LinkTarget
1419
1437
}
1420
1438
switch options .PreferredContentFormat {
1421
1439
case protocol .Markdown :
1422
- return fmt .Sprintf ("[`%s` %s](%s)" , h .symbolName , caption , url )
1440
+ return fmt .Sprintf ("[`%s` %s](%s)" , h .SymbolName , caption , url )
1423
1441
case protocol .PlainText :
1424
1442
return ""
1425
1443
default :
0 commit comments