@@ -39,85 +39,39 @@ internal static class TokenOperations
39
39
/// <summary>
40
40
/// Extracts all of the unique foldable regions in a script given the list tokens
41
41
/// </summary>
42
- internal static FoldingReference [ ] FoldableRegions (
43
- Token [ ] tokens ,
44
- bool ShowLastLine )
42
+ internal static FoldingReferenceList FoldableRegions (
43
+ Token [ ] tokens )
45
44
{
46
- List < FoldingReference > foldableRegions = new List < FoldingReference > ( ) ;
45
+ var refList = new FoldingReferenceList ( ) ;
47
46
48
47
// Find matching braces { -> }
49
48
// Find matching hashes @{ -> }
50
- foldableRegions . AddRange (
51
- MatchTokenElements ( tokens , s_openingBraces , TokenKind . RCurly , RegionKindNone )
52
- ) ;
49
+ MatchTokenElements ( tokens , s_openingBraces , TokenKind . RCurly , RegionKindNone , ref refList ) ;
53
50
54
51
// Find matching parentheses ( -> )
55
52
// Find matching array literals @( -> )
56
53
// Find matching subexpressions $( -> )
57
- foldableRegions . AddRange (
58
- MatchTokenElements ( tokens , s_openingParens , TokenKind . RParen , RegionKindNone )
59
- ) ;
54
+ MatchTokenElements ( tokens , s_openingParens , TokenKind . RParen , RegionKindNone , ref refList ) ;
60
55
61
56
// Find contiguous here strings @' -> '@
62
- foldableRegions . AddRange (
63
- MatchTokenElement ( tokens , TokenKind . HereStringLiteral , RegionKindNone )
64
- ) ;
57
+ MatchTokenElement ( tokens , TokenKind . HereStringLiteral , RegionKindNone , ref refList ) ;
65
58
66
59
// Find unopinionated variable names ${ \n \n }
67
- foldableRegions . AddRange (
68
- MatchTokenElement ( tokens , TokenKind . Variable , RegionKindNone )
69
- ) ;
60
+ MatchTokenElement ( tokens , TokenKind . Variable , RegionKindNone , ref refList ) ;
70
61
71
62
// Find contiguous here strings @" -> "@
72
- foldableRegions . AddRange (
73
- MatchTokenElement ( tokens , TokenKind . HereStringExpandable , RegionKindNone )
74
- ) ;
63
+ MatchTokenElement ( tokens , TokenKind . HereStringExpandable , RegionKindNone , ref refList ) ;
75
64
76
65
// Find matching comment regions #region -> #endregion
77
- foldableRegions . AddRange (
78
- MatchCustomCommentRegionTokenElements ( tokens , RegionKindRegion )
79
- ) ;
66
+ MatchCustomCommentRegionTokenElements ( tokens , RegionKindRegion , ref refList ) ;
80
67
81
68
// Find blocks of line comments # comment1\n# comment2\n...
82
- foldableRegions . AddRange (
83
- MatchBlockCommentTokenElement ( tokens , RegionKindComment )
84
- ) ;
69
+ MatchBlockCommentTokenElement ( tokens , RegionKindComment , ref refList ) ;
85
70
86
71
// Find comments regions <# -> #>
87
- foldableRegions . AddRange (
88
- MatchTokenElement ( tokens , TokenKind . Comment , RegionKindComment )
89
- ) ;
90
-
91
- // Remove any null entries. Nulls appear if the folding reference is invalid
92
- // or missing
93
- foldableRegions . RemoveAll ( item => item == null ) ;
94
-
95
- // Sort the FoldingReferences, starting at the top of the document,
96
- // and ensure that, in the case of multiple ranges starting the same line,
97
- // that the largest range (i.e. most number of lines spanned) is sorted
98
- // first. This is needed to detect duplicate regions. The first in the list
99
- // will be used and subsequent duplicates ignored.
100
- foldableRegions . Sort ( ) ;
101
-
102
- // It's possible to have duplicate or overlapping ranges, that is, regions which have the same starting
103
- // line number as the previous region. Therefore only emit ranges which have a different starting line
104
- // than the previous range.
105
- foldableRegions . RemoveAll ( ( FoldingReference item ) => {
106
- // Note - I'm not happy with searching here, but as the RemoveAll
107
- // doesn't expose the index in the List, we need to calculate it. Fortunately the
108
- // list is sorted at this point, so we can use BinarySearch.
109
- int index = foldableRegions . BinarySearch ( item ) ;
110
- if ( index == 0 ) { return false ; }
111
- return ( item . StartLine == foldableRegions [ index - 1 ] . StartLine ) ;
112
- } ) ;
113
-
114
- // Some editors have different folding UI, sometimes the lastline should be displayed
115
- // If we do want to show the last line, just change the region to be one line less
116
- if ( ShowLastLine ) {
117
- foldableRegions . ForEach ( item => { item . EndLine -- ; } ) ;
118
- }
72
+ MatchTokenElement ( tokens , TokenKind . Comment , RegionKindComment , ref refList ) ;
119
73
120
- return foldableRegions . ToArray ( ) ;
74
+ return refList ;
121
75
}
122
76
123
77
/// <summary>
@@ -163,42 +117,40 @@ static private FoldingReference CreateFoldingReference(
163
117
/// <summary>
164
118
/// Given an array of tokens, find matching regions which start (array of tokens) and end with a different TokenKind
165
119
/// </summary>
166
- static private List < FoldingReference > MatchTokenElements (
120
+ static private void MatchTokenElements (
167
121
Token [ ] tokens ,
168
122
TokenKind [ ] startTokenKind ,
169
123
TokenKind endTokenKind ,
170
- string matchKind )
124
+ string matchKind ,
125
+ ref FoldingReferenceList refList )
171
126
{
172
- List < FoldingReference > result = new List < FoldingReference > ( ) ;
173
127
Stack < Token > tokenStack = new Stack < Token > ( ) ;
174
128
foreach ( Token token in tokens )
175
129
{
176
130
if ( Array . IndexOf ( startTokenKind , token . Kind ) != - 1 ) {
177
131
tokenStack . Push ( token ) ;
178
132
}
179
133
if ( ( tokenStack . Count > 0 ) && ( token . Kind == endTokenKind ) ) {
180
- result . Add ( CreateFoldingReference ( tokenStack . Pop ( ) , token , matchKind ) ) ;
134
+ refList . SafeAdd ( CreateFoldingReference ( tokenStack . Pop ( ) , token , matchKind ) ) ;
181
135
}
182
136
}
183
- return result ;
184
137
}
185
138
186
139
/// <summary>
187
140
/// Given an array of token, finds a specific token
188
141
/// </summary>
189
- static private List < FoldingReference > MatchTokenElement (
142
+ static private void MatchTokenElement (
190
143
Token [ ] tokens ,
191
144
TokenKind tokenKind ,
192
- string matchKind )
145
+ string matchKind ,
146
+ ref FoldingReferenceList refList )
193
147
{
194
- List < FoldingReference > result = new List < FoldingReference > ( ) ;
195
148
foreach ( Token token in tokens )
196
149
{
197
150
if ( ( token . Kind == tokenKind ) && ( token . Extent . StartLineNumber != token . Extent . EndLineNumber ) ) {
198
- result . Add ( CreateFoldingReference ( token , token , matchKind ) ) ;
151
+ refList . SafeAdd ( CreateFoldingReference ( token , token , matchKind ) ) ;
199
152
}
200
153
}
201
- return result ;
202
154
}
203
155
204
156
/// <summary>
@@ -230,11 +182,11 @@ static private bool IsBlockComment(int index, Token[] tokens) {
230
182
/// classed as comments. To workaround this we search for valid block comments (See IsBlockCmment)
231
183
/// and then determine contiguous line numbers from there
232
184
/// </summary>
233
- static private List < FoldingReference > MatchBlockCommentTokenElement (
185
+ static private void MatchBlockCommentTokenElement (
234
186
Token [ ] tokens ,
235
- string matchKind )
187
+ string matchKind ,
188
+ ref FoldingReferenceList refList )
236
189
{
237
- List < FoldingReference > result = new List < FoldingReference > ( ) ;
238
190
Token startToken = null ;
239
191
int nextLine = - 1 ;
240
192
for ( int index = 0 ; index < tokens . Length ; index ++ )
@@ -243,7 +195,7 @@ static private List<FoldingReference> MatchBlockCommentTokenElement(
243
195
if ( IsBlockComment ( index , tokens ) && s_nonRegionLineCommentRegex . IsMatch ( thisToken . Text ) ) {
244
196
int thisLine = thisToken . Extent . StartLineNumber - 1 ;
245
197
if ( ( startToken != null ) && ( thisLine != nextLine ) ) {
246
- result . Add ( CreateFoldingReference ( startToken , nextLine - 1 , matchKind ) ) ;
198
+ refList . SafeAdd ( CreateFoldingReference ( startToken , nextLine - 1 , matchKind ) ) ;
247
199
startToken = thisToken ;
248
200
}
249
201
if ( startToken == null ) { startToken = thisToken ; }
@@ -253,27 +205,26 @@ static private List<FoldingReference> MatchBlockCommentTokenElement(
253
205
// If we exit the token array and we're still processing comment lines, then the
254
206
// comment block simply ends at the end of document
255
207
if ( startToken != null ) {
256
- result . Add ( CreateFoldingReference ( startToken , nextLine - 1 , matchKind ) ) ;
208
+ refList . SafeAdd ( CreateFoldingReference ( startToken , nextLine - 1 , matchKind ) ) ;
257
209
}
258
- return result ;
259
210
}
260
211
261
212
/// <summary>
262
213
/// Given a list of tokens, find the tokens that are comments and
263
214
/// the comment text is either `# region` or `# endregion`, and then use a stack to determine
264
215
/// the ranges they span
265
216
/// </summary>
266
- static private List < FoldingReference > MatchCustomCommentRegionTokenElements (
217
+ static private void MatchCustomCommentRegionTokenElements (
267
218
Token [ ] tokens ,
268
- string matchKind )
219
+ string matchKind ,
220
+ ref FoldingReferenceList refList )
269
221
{
270
222
// These regular expressions are used to match lines which mark the start and end of region comment in a PowerShell
271
223
// script. They are based on the defaults in the VS Code Language Configuration at;
272
224
// https://github.com/Microsoft/vscode/blob/64186b0a26/extensions/powershell/language-configuration.json#L26-L31
273
225
string startRegionText = @"^\s*#region\b" ;
274
226
string endRegionText = @"^\s*#endregion\b" ;
275
227
276
- List < FoldingReference > result = new List < FoldingReference > ( ) ;
277
228
Stack < Token > tokenStack = new Stack < Token > ( ) ;
278
229
for ( int index = 0 ; index < tokens . Length ; index ++ )
279
230
{
@@ -283,11 +234,10 @@ static private List<FoldingReference> MatchCustomCommentRegionTokenElements(
283
234
tokenStack . Push ( token ) ;
284
235
}
285
236
if ( ( tokenStack . Count > 0 ) && ( Regex . IsMatch ( token . Text , endRegionText , RegexOptions . IgnoreCase ) ) ) {
286
- result . Add ( CreateFoldingReference ( tokenStack . Pop ( ) , token , matchKind ) ) ;
237
+ refList . SafeAdd ( CreateFoldingReference ( tokenStack . Pop ( ) , token , matchKind ) ) ;
287
238
}
288
239
}
289
240
}
290
- return result ;
291
241
}
292
242
}
293
243
}
0 commit comments