@@ -6,6 +6,7 @@ package golang
6
6
7
7
import (
8
8
"bytes"
9
+ "cmp"
9
10
"context"
10
11
"go/ast"
11
12
"go/token"
@@ -20,14 +21,8 @@ import (
20
21
"golang.org/x/tools/gopls/internal/util/safetoken"
21
22
)
22
23
23
- // FoldingRangeInfo holds range and kind info of folding for an ast.Node
24
- type FoldingRangeInfo struct {
25
- Range protocol.Range
26
- Kind protocol.FoldingRangeKind
27
- }
28
-
29
24
// FoldingRange gets all of the folding range for f.
30
- func FoldingRange (ctx context.Context , snapshot * cache.Snapshot , fh file.Handle , lineFoldingOnly bool ) (ranges [] * FoldingRangeInfo , err error ) {
25
+ func FoldingRange (ctx context.Context , snapshot * cache.Snapshot , fh file.Handle , lineFoldingOnly bool ) ([]protocol. FoldingRange , error ) {
31
26
// TODO(suzmue): consider limiting the number of folding ranges returned, and
32
27
// implement a way to prioritize folding ranges in that case.
33
28
pgf , err := snapshot .ParseGo (ctx , fh , parsego .Full )
@@ -48,27 +43,29 @@ func FoldingRange(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle,
48
43
}
49
44
50
45
// Get folding ranges for comments separately as they are not walked by ast.Inspect.
51
- ranges = append ( ranges , commentsFoldingRange (pgf ) ... )
46
+ ranges := commentsFoldingRange (pgf )
52
47
53
- visit := func ( n ast. Node ) bool {
54
- rng := foldingRangeFunc (pgf , n , lineFoldingOnly )
55
- if rng != nil {
48
+ // Walk the ast and collect folding ranges.
49
+ ast . Inspect (pgf . File , func ( n ast. Node ) bool {
50
+ if rng , ok := foldingRangeFunc ( pgf , n , lineFoldingOnly ); ok {
56
51
ranges = append (ranges , rng )
57
52
}
58
53
return true
59
- }
60
- // Walk the ast and collect folding ranges.
61
- ast .Inspect (pgf .File , visit )
54
+ })
62
55
63
- slices .SortFunc (ranges , func (x , y * FoldingRangeInfo ) int {
64
- return protocol .CompareRange (x .Range , y .Range )
56
+ // Sort by start position.
57
+ slices .SortFunc (ranges , func (x , y protocol.FoldingRange ) int {
58
+ if d := cmp .Compare (x .StartLine , y .StartLine ); d != 0 {
59
+ return d
60
+ }
61
+ return cmp .Compare (x .StartCharacter , y .StartCharacter )
65
62
})
66
63
67
64
return ranges , nil
68
65
}
69
66
70
67
// foldingRangeFunc calculates the line folding range for ast.Node n
71
- func foldingRangeFunc (pgf * parsego.File , n ast.Node , lineFoldingOnly bool ) * FoldingRangeInfo {
68
+ func foldingRangeFunc (pgf * parsego.File , n ast.Node , lineFoldingOnly bool ) (protocol. FoldingRange , bool ) {
72
69
// TODO(suzmue): include trailing empty lines before the closing
73
70
// parenthesis/brace.
74
71
var kind protocol.FoldingRangeKind
@@ -109,25 +106,22 @@ func foldingRangeFunc(pgf *parsego.File, n ast.Node, lineFoldingOnly bool) *Fold
109
106
110
107
// Check that folding positions are valid.
111
108
if ! start .IsValid () || ! end .IsValid () {
112
- return nil
109
+ return protocol. FoldingRange {}, false
113
110
}
114
111
if start == end {
115
112
// Nothing to fold.
116
- return nil
113
+ return protocol. FoldingRange {}, false
117
114
}
118
115
// in line folding mode, do not fold if the start and end lines are the same.
119
116
if lineFoldingOnly && safetoken .Line (pgf .Tok , start ) == safetoken .Line (pgf .Tok , end ) {
120
- return nil
117
+ return protocol. FoldingRange {}, false
121
118
}
122
119
rng , err := pgf .PosRange (start , end )
123
120
if err != nil {
124
121
bug .Reportf ("failed to create range: %s" , err ) // can't happen
125
- return nil
126
- }
127
- return & FoldingRangeInfo {
128
- Range : rng ,
129
- Kind : kind ,
122
+ return protocol.FoldingRange {}, false
130
123
}
124
+ return foldingRange (kind , rng ), true
131
125
}
132
126
133
127
// getLineFoldingRange returns the folding range for nodes with parentheses/braces/brackets
@@ -196,7 +190,7 @@ func getLineFoldingRange(pgf *parsego.File, open, close token.Pos, lineFoldingOn
196
190
// commentsFoldingRange returns the folding ranges for all comment blocks in file.
197
191
// The folding range starts at the end of the first line of the comment block, and ends at the end of the
198
192
// comment block and has kind protocol.Comment.
199
- func commentsFoldingRange (pgf * parsego.File ) (comments []* FoldingRangeInfo ) {
193
+ func commentsFoldingRange (pgf * parsego.File ) (comments []protocol. FoldingRange ) {
200
194
tokFile := pgf .Tok
201
195
for _ , commentGrp := range pgf .File .Comments {
202
196
startGrpLine , endGrpLine := safetoken .Line (tokFile , commentGrp .Pos ()), safetoken .Line (tokFile , commentGrp .End ())
@@ -218,11 +212,19 @@ func commentsFoldingRange(pgf *parsego.File) (comments []*FoldingRangeInfo) {
218
212
bug .Reportf ("failed to create mapped range: %s" , err ) // can't happen
219
213
continue
220
214
}
221
- comments = append (comments , & FoldingRangeInfo {
222
- // Fold from the end of the first line comment to the end of the comment block.
223
- Range : rng ,
224
- Kind : protocol .Comment ,
225
- })
215
+ // Fold from the end of the first line comment to the end of the comment block.
216
+ comments = append (comments , foldingRange (protocol .Comment , rng ))
226
217
}
227
218
return comments
228
219
}
220
+
221
+ func foldingRange (kind protocol.FoldingRangeKind , rng protocol.Range ) protocol.FoldingRange {
222
+ return protocol.FoldingRange {
223
+ // I have no idea why LSP doesn't use a protocol.Range here.
224
+ StartLine : rng .Start .Line ,
225
+ StartCharacter : rng .Start .Character ,
226
+ EndLine : rng .End .Line ,
227
+ EndCharacter : rng .End .Character ,
228
+ Kind : string (kind ),
229
+ }
230
+ }
0 commit comments