diff --git a/src/services/outliningElementsCollector.ts b/src/services/outliningElementsCollector.ts index e0d99d1d27165..03ae0529ca9d9 100644 --- a/src/services/outliningElementsCollector.ts +++ b/src/services/outliningElementsCollector.ts @@ -2,13 +2,17 @@ namespace ts.OutliningElementsCollector { const collapseText = "..."; const maxDepth = 20; + const defaultLabel = "#region"; + const regionMatch = new RegExp("^\\s*//\\s*#(end)?region(?:\\s+(.*))?$"); export function collectElements(sourceFile: SourceFile, cancellationToken: CancellationToken): OutliningSpan[] { const elements: OutliningSpan[] = []; let depth = 0; + const regions: OutliningSpan[] = []; walk(sourceFile); - return elements; + gatherRegions(); + return elements.sort((span1, span2) => span1.textSpan.start - span2.textSpan.start); /** If useFullStart is true, then the collapsing span includes leading whitespace, including linebreaks. */ function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean, useFullStart: boolean) { @@ -89,6 +93,39 @@ namespace ts.OutliningElementsCollector { return isFunctionBlock(node) && node.parent.kind !== SyntaxKind.ArrowFunction; } + function gatherRegions(): void { + const lineStarts = sourceFile.getLineStarts(); + + for (let i = 0; i < lineStarts.length; i++) { + const currentLineStart = lineStarts[i]; + const lineEnd = lineStarts[i + 1] - 1 || sourceFile.getEnd(); + const comment = sourceFile.text.substring(currentLineStart, lineEnd); + const result = comment.match(regionMatch); + + if (result && !isInComment(sourceFile, currentLineStart)) { + if (!result[1]) { + const start = sourceFile.getFullText().indexOf("//", currentLineStart); + const textSpan = createTextSpanFromBounds(start, lineEnd); + const region: OutliningSpan = { + textSpan, + hintSpan: textSpan, + bannerText: result[2] || defaultLabel, + autoCollapse: false + }; + regions.push(region); + } + else { + const region = regions.pop(); + if (region) { + region.textSpan.length = lineEnd - region.textSpan.start; + region.hintSpan.length = lineEnd - region.textSpan.start; + elements.push(region); + } + } + } + } + } + function walk(n: Node): void { cancellationToken.throwIfCancellationRequested(); if (depth > maxDepth) { diff --git a/tests/cases/fourslash/getOutliningSpansForRegions.ts b/tests/cases/fourslash/getOutliningSpansForRegions.ts new file mode 100644 index 0000000000000..fcd71e29ef13f --- /dev/null +++ b/tests/cases/fourslash/getOutliningSpansForRegions.ts @@ -0,0 +1,51 @@ +/// + +////// region without label +////[|// #region +//// +////// #endregion|] +//// +////// region without label with trailing spaces +////[|// #region +//// +////// #endregion|] +//// +////// region with label +////[|// #region label1 +//// +////// #endregion|] +//// +////// region with extra whitespace in all valid locations +//// [|// #region label2 label3 +//// +//// // #endregion|] +//// +////// No space before directive +////[|//#region label4 +//// +//////#endregion|] +//// +////// Nested regions +////[|// #region outer +//// +////[|// #region inner +//// +////// #endregion inner|] +//// +////// #endregion outer|] +//// +////// region delimiters not valid when there is preceding text on line +//// test // #region invalid1 +//// +////test // #endregion +//// +////// region delimiters not valid when in multiline comment +/////* +////// #region invalid2 +////*/ +//// +/////* +////// #endregion +////*/ + +verify.outliningSpansInCurrentFile(test.ranges()); \ No newline at end of file diff --git a/tests/cases/fourslash/getOutliningSpansForUnbalancedEndRegion.ts b/tests/cases/fourslash/getOutliningSpansForUnbalancedEndRegion.ts new file mode 100644 index 0000000000000..c15e23eba7576 --- /dev/null +++ b/tests/cases/fourslash/getOutliningSpansForUnbalancedEndRegion.ts @@ -0,0 +1,10 @@ +/// + +////// bottom-heavy region balance +////[|// #region matched +//// +////// #endregion matched|] +//// +////// #endregion unmatched + +verify.outliningSpansInCurrentFile(test.ranges()); \ No newline at end of file diff --git a/tests/cases/fourslash/getOutliningSpansForUnbalancedRegion.ts b/tests/cases/fourslash/getOutliningSpansForUnbalancedRegion.ts new file mode 100644 index 0000000000000..f50aae713a52b --- /dev/null +++ b/tests/cases/fourslash/getOutliningSpansForUnbalancedRegion.ts @@ -0,0 +1,11 @@ +/// + +////// top-heavy region balance +////// #region unmatched +//// +////[|// #region matched +//// +////// #endregion matched|] + +debugger; +verify.outliningSpansInCurrentFile(test.ranges()); \ No newline at end of file