diff --git a/src/language/folding.ts b/src/language/folding.ts index 02157696b..0dd89f9cc 100644 --- a/src/language/folding.ts +++ b/src/language/folding.ts @@ -2,6 +2,7 @@ import * as vscode from 'vscode' export class FoldingProvider implements vscode.FoldingRangeProvider { private readonly sectionRegex: RegExp[] = [] + protected readonly envRegex = /\\(begin){(.*?)}|\\(begingroup)[%\s\\]|\\(end){(.*?)}|\\(endgroup)[%\s\\]|^%\s*#?([rR]egion)|^%\s*#?([eE]ndregion)|^%\s*<\*([|_()\-a-zA-Z0-9]+)>|^%\s*<\/([|_()\-a-zA-Z0-9]+)>|^%\s*\\iffalse\s*(meta-comment)|^%\s*\\(fi)/gm constructor() { const sections = vscode.workspace.getConfiguration('latex-workshop').get('view.outline.sections') as string[] @@ -20,7 +21,7 @@ export class FoldingProvider implements vscode.FoldingRangeProvider { return sections.map(section => RegExp(`\\\\(?:${section})(?:\\*)?(?:\\[[^\\[\\]\\{\\}]*\\])?{(.*)}`, 'm')) } - protected getSectionFoldingRanges(document: vscode.TextDocument) { + private getSectionFoldingRanges(document: vscode.TextDocument) { const startingIndices: number[] = this.sectionRegex.map(_ => -1) const lines = document.getText().split(/\r?\n/g) let documentClassLine = -1 @@ -82,67 +83,13 @@ export class FoldingProvider implements vscode.FoldingRangeProvider { return sections.map(section => new vscode.FoldingRange(section.from, section.to)) } - protected getEnvironmentFoldingRanges(document: vscode.TextDocument) { + private getEnvironmentFoldingRanges(document: vscode.TextDocument) { const ranges: vscode.FoldingRange[] = [] const opStack: { keyword: string, index: number }[] = [] const text: string = document.getText() - const envRegex: RegExp = /\\(begin){(.*?)}|\\(begingroup)[%\s\\]|\\(end){(.*?)}|\\(endgroup)[%\s\\]|^%\s*#?([rR]egion)|^%\s*#?([eE]ndregion)/gm //to match one 'begin' OR 'end' - while (true) { - const match = envRegex.exec(text) - if (match === null) { - //TODO: if opStack still not empty - return ranges - } - //for 'begin': match[1] contains 'begin', match[2] contains keyword - //for 'end': match[4] contains 'end', match[5] contains keyword - //for 'begingroup': match[3] contains 'begingroup', keyword is 'group' - //for 'endgroup': match[6] contains 'endgroup', keyword is 'group' - //for '% region': match[7] contains 'region', keyword is 'region' - //for '% endregion': match[8] contains 'endregion', keyword is 'region' - let keyword: string = '' - if (match[1]) { - keyword = match[2] - } else if (match[4]) { - keyword = match[5] - } else if (match[3] || match[6]) { - keyword = 'group' - } else if (match[7] || match[8]) { - keyword = 'region' - } - - const item = { - keyword, - index: match.index - } - const lastItem = opStack[opStack.length - 1] - - if ((match[4] || match[6] || match[8]) && lastItem && lastItem.keyword === item.keyword) { // match 'end' with its 'begin' - opStack.pop() - ranges.push(new vscode.FoldingRange( - document.positionAt(lastItem.index).line, - document.positionAt(item.index).line - 1 - )) - } else { - opStack.push(item) - } - } - } -} - -export class DoctexFoldingProvider extends FoldingProvider { - - protected buildSectionRegex(sections: string[]) { - return sections.map(section => RegExp(`%\\s*\\\\(?:${section})(?:\\*)?(?:\\[[^\\[\\]\\{\\}]*\\])?{(.*)}`, 'm')) - } - - protected getEnvironmentFoldingRanges(document: vscode.TextDocument) { - const ranges: vscode.FoldingRange[] = [] - const opStack: { keyword: string, index: number }[] = [] - const text: string = document.getText() - const envRegex: RegExp = /\\(begin){(.*?)}|\\(begingroup)[%\s\\]|\\(end){(.*?)}|\\(endgroup)[%\s\\]|^%\s*#?([rR]egion)|^%\s*#?([eE]ndregion)|^%\s*<\*([|_()\-a-zA-Z0-9]+)>|^%\s*<\/([|_()\-a-zA-Z0-9]+)>/gm while (true) { - const match = envRegex.exec(text) + const match = this.envRegex.exec(text) if (match === null) { //TODO: if opStack still not empty return ranges @@ -153,8 +100,11 @@ export class DoctexFoldingProvider extends FoldingProvider { //for 'endgroup': match[6] contains 'endgroup', keyword is 'group' //for '% region': match[7] contains 'region', keyword is 'region' //for '% endregion': match[8] contains 'endregion', keyword is 'region' + //DocTeX folding support //for '%<*abc>': match[9] contains '%<*>', keyword is 'abc' //for '%': match[10] contains '%', keyword is 'abc' + //for '% \iffalse meta-comment': match[11] contains '\iffalse meta-comment', keyword is 'meta-comment' + //for '% \fi': match[12] contains '\fi', keyword is 'meta-comment' let keyword: string = '' if (match[1]) { keyword = match[2] @@ -168,6 +118,8 @@ export class DoctexFoldingProvider extends FoldingProvider { keyword = match[9] } else if (match[10]) { keyword = match[10] + } else if (match[11] || match[12]) { + keyword = 'meta-comment' } const item = { @@ -176,7 +128,7 @@ export class DoctexFoldingProvider extends FoldingProvider { } const lastItem = opStack[opStack.length - 1] - if ((match[4] || match[6] || match[8] || match[10]) && lastItem && lastItem.keyword === item.keyword) { // match 'end' with its 'begin' + if ((match[4] || match[6] || match[8] || match[10] || match[12]) && lastItem && lastItem.keyword === item.keyword) { // match 'end' with its 'begin' opStack.pop() ranges.push(new vscode.FoldingRange( document.positionAt(lastItem.index).line, @@ -189,6 +141,14 @@ export class DoctexFoldingProvider extends FoldingProvider { } } +export class DoctexFoldingProvider extends FoldingProvider { + protected readonly envRegex: RegExp = /\\(begin){(.*?)}|\\(begingroup)[%\s\\]|\\(end){(.*?)}|\\(endgroup)[%\s\\]|^%\s*#?([rR]egion)|^%\s*#?([eE]ndregion)|^%\s*<\*([|_()\-a-zA-Z0-9]+)>|^%\s*<\/([|_()\-a-zA-Z0-9]+)>|^%\s*\\iffalse\s*(meta-comment)|^%\s*\\(fi)/gm + + protected buildSectionRegex(sections: string[]) { + return sections.map(section => RegExp(`%\\s*\\\\(?:${section})(?:\\*)?(?:\\[[^\\[\\]\\{\\}]*\\])?{(.*)}`, 'm')) + } +} + export class WeaveFoldingProvider implements vscode.FoldingRangeProvider { public provideFoldingRanges( document: vscode.TextDocument,