Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cd19f84

Browse files
(GH-1336) Add syntax folding for comments
This commit adds syntax aware folding for comment regions * Contiguous blocks of line comments `# ....` * Function defintion blocks `<# ... #>` * Region bound comments `# region ... # endregion`
1 parent 57bd4c7 commit cd19f84

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

‎src/features/Folding.ts‎

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,114 @@ export class FoldingProvider implements vscode.FoldingRangeProvider {
207207
return result;
208208
}
209209

210+
// Given a zero based offset, find the line text preceeding it in the document
211+
private preceedingText(offset: number,
212+
document: vscode.TextDocument): string {
213+
const endPos = document.positionAt(offset);
214+
const startPos = endPos.translate(0, -endPos.character);
215+
216+
return document.getText(new vscode.Range(startPos, endPos));
217+
}
218+
219+
// Given a zero based offset, return the line number in the document
220+
private lineAtOffest(offset: number,
221+
document: vscode.TextDocument): number {
222+
return document.positionAt(offset).line;
223+
}
224+
225+
// Finding blocks of comment tokens is more complicated as the newline characters are not
226+
// classed as comments. To workaround this we search for the comment character `#` scope name
227+
// "punctuation.definition.comment.powershell" and then determine contiguous line numbers from there
228+
private matchBlockCommentScopeElements(tokens,
229+
document: vscode.TextDocument) {
230+
const result = [];
231+
232+
const emptyLine = new RegExp("^[\\s]+$");
233+
234+
let startLine: number = -1;
235+
let nextLine: number = -1;
236+
237+
tokens.forEach((token, index) => {
238+
if (token.scopes.includes("punctuation.definition.comment.powershell")) {
239+
// The punctuation.definition.comment.powershell token matches new-line comments
240+
// and inline comments e.g. `$x = 'foo' # inline comment`. We are only interested
241+
// in comments which begin the line i.e. no preceeding text
242+
if (emptyLine.test(this.preceedingText(token.startIndex, document))) {
243+
const lineNum = this.lineAtOffest(token.startIndex, document);
244+
// A simple pattern for keeping track of contiguous numbers in a known
245+
// sorted array
246+
if (startLine === -1) {
247+
startLine = lineNum;
248+
nextLine = lineNum + 1;
249+
} else {
250+
if (lineNum === nextLine) {
251+
nextLine = lineNum + 1;
252+
} else {
253+
result.push(new MatchedToken(null,
254+
null,
255+
startLine,
256+
nextLine - 1,
257+
MatchType.Comment,
258+
document));
259+
startLine = lineNum;
260+
nextLine = lineNum + 1;
261+
}
262+
}
263+
}
264+
}
265+
});
266+
267+
// If we exist the token array and we're still processing comment lines, then the
268+
// comment block simply ends at the end of document
269+
if (startLine !== -1) {
270+
result.push(new MatchedToken(null, null, startLine, nextLine - 1, MatchType.Comment, document));
271+
}
272+
273+
return result;
274+
}
275+
276+
// Given a zero based offset, find the line text after it in the document
277+
private subsequentText(offset: number,
278+
document: vscode.TextDocument): string {
279+
const startPos = document.positionAt(offset);
280+
// We don't know how long the line is so just return a really long one.
281+
const endPos = startPos.translate(0, 1000);
282+
return document.getText(new vscode.Range(startPos, endPos));
283+
}
284+
285+
// Create a new token object with an appended scopeName
286+
private addTokenScope(token,
287+
scopeName: string) {
288+
// Only a shallow clone is required
289+
const tokenClone = Object.assign({}, token);
290+
tokenClone.scopes.push(scopeName);
291+
return tokenClone;
292+
}
293+
294+
// Given a list of grammar tokens, find the tokens that are comments and
295+
// the comment text is either `# region` or `# endregion`. Return a new list of tokens
296+
// with custom scope names added, "custom.start.region" and "custom.end.region" respectively
297+
private extractRegionScopeElements(tokens,
298+
document: vscode.TextDocument) {
299+
const result = [];
300+
301+
const emptyLine = new RegExp("^[\\s]+$");
302+
const startRegionText = new RegExp("^#\\s*region\\b");
303+
const endRegionText = new RegExp("^#\\s*endregion\\b");
304+
305+
tokens.forEach( (token, index) => {
306+
if (token.scopes.includes("punctuation.definition.comment.powershell")) {
307+
if (emptyLine.test(this.preceedingText(token.startIndex, document))) {
308+
const commentText = this.subsequentText(token.startIndex, document);
309+
310+
if (startRegionText.test(commentText)) { result.push(this.addTokenScope(token, "custom.start.region")); }
311+
if (endRegionText.test(commentText)) { result.push(this.addTokenScope(token, "custom.end.region")); }
312+
}
313+
}
314+
});
315+
return result;
316+
}
317+
210318
// Given a list of tokens, return a list of matched tokens/line numbers regions
211319
private matchGrammarTokens(tokens, document: vscode.TextDocument): IMatchedTokenList {
212320
const matchedTokens = [];
@@ -237,6 +345,23 @@ export class FoldingProvider implements vscode.FoldingRangeProvider {
237345
MatchType.Region, document)
238346
.forEach((x) => { matchedTokens.push(x); });
239347

348+
// Find matching Braces #region -> #endregion
349+
this.matchScopeElements(this.extractRegionScopeElements(tokens, document),
350+
"custom.start.region",
351+
"custom.end.region",
352+
MatchType.Region, document)
353+
.forEach( (x) => { matchedTokens.push(x); });
354+
355+
// Find blocks of line comments # comment1\n# comment2\n...
356+
this.matchBlockCommentScopeElements(tokens, document).forEach((x) => { matchedTokens.push(x); });
357+
358+
// Find matching function definitions <# -> #>
359+
this.matchScopeElements(tokens,
360+
"punctuation.definition.comment.block.begin.powershell",
361+
"punctuation.definition.comment.block.end.powershell",
362+
MatchType.Comment, document)
363+
.forEach( (x) => { matchedTokens.push(x); });
364+
240365
return matchedTokens;
241366
}
242367

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /