提交 777fddd4 编写于 作者: M Martin Aeschlimann

[folding] add folding marker to API and schema

上级 5ae1dc44
......@@ -27,8 +27,8 @@
],
"folding": {
"markers": {
"start": "^\\s*//\\s*#region",
"end": "^\\s*//\\s*#endregion"
"start": "^\\s*//\\s*#?region",
"end": "^\\s*//\\s*#?endregion"
}
}
}
\ No newline at end of file
......@@ -27,8 +27,8 @@
],
"folding": {
"markers": {
"start": "^\\s*//\\s*#region",
"end": "^\\s*//\\s*#endregion"
"start": "^\\s*//\\s*#?region",
"end": "^\\s*//\\s*#?endregion"
}
}
}
\ No newline at end of file
......@@ -6,6 +6,7 @@
'use strict';
import { ITextModel } from 'vs/editor/common/editorCommon';
import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';
export class IndentRange {
_indentRangeBrand: void;
......@@ -31,23 +32,15 @@ export class IndentRange {
}
}
export interface FoldMarkers {
start: string;
end: string;
indent?: number;
}
interface PreviousRegion { indent: number; line: number; marker: RegExp; };
export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldMarkers, minimumRangeSize: number = 1): IndentRange[] {
export function computeRanges(model: ITextModel, offSide: boolean, markers?: FoldingMarkers, minimumRangeSize: number = 1): IndentRange[] {
let result: IndentRange[] = [];
let pattern = void 0;
let patternIndent = -1;
if (markers) {
pattern = new RegExp(`(${markers.start})|(?:${markers.end})`);
patternIndent = typeof markers.indent === 'number' ? markers.indent : -1;
pattern = new RegExp(`(${markers.start.source})|(?:${markers.end.source})`);
}
let previousRegions: PreviousRegion[] = [];
......@@ -64,7 +57,7 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol
continue; // only whitespace
}
let m;
if (pattern && (patternIndent === -1 || patternIndent === indent) && (m = model.getLineContent(line).match(pattern))) {
if (pattern && (m = model.getLineContent(line).match(pattern))) {
// folding pattern match
if (m[1]) { // start pattern match
if (previous.indent >= 0 && !previous.marker) {
......
......@@ -845,7 +845,7 @@ export class TextModelWithTokens extends TextModel implements editorCommon.IToke
if (!this._indentRanges) {
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(this._languageIdentifier.id);
let offSide = foldingRules && foldingRules.offSide;
let markers = foldingRules && foldingRules['markers'];
let markers = foldingRules && foldingRules.markers;
this._indentRanges = computeRanges(this, offSide, markers);
}
return this._indentRanges;
......
......@@ -98,6 +98,17 @@ export interface IndentationRule {
}
/**
* Describes language specific folding markers such as '#region' and '#endregion'.
* The start and end regexes will be tested against the contents of all lines and must be designed efficiently:
* - the regex should start with '^'
* - regexp flags (i, g) are ignored
*/
export interface FoldingMarkers {
start: RegExp;
end: RegExp;
}
/**
* Describes folding rules for a language.
*/
......@@ -109,6 +120,11 @@ export interface FoldingRules {
* If not set, `false` is used and empty lines belong to the previous block.
*/
offSide?: boolean;
/**
* Region markers used by the language.
*/
markers?: FoldingMarkers;
}
/**
......
......@@ -7,7 +7,8 @@
import * as assert from 'assert';
import { Model } from 'vs/editor/common/model/model';
import { computeRanges, FoldMarkers } from 'vs/editor/common/model/indentRanges';
import { computeRanges } from 'vs/editor/common/model/indentRanges';
import { FoldingMarkers } from 'vs/editor/common/modes/languageConfiguration';
export interface IndentRange {
startLineNumber: number;
......@@ -16,7 +17,7 @@ export interface IndentRange {
marker: boolean;
}
function assertRanges(lines: string[], expected: IndentRange[], offside: boolean, markers?: FoldMarkers): void {
function assertRanges(lines: string[], expected: IndentRange[], offside: boolean, markers?: FoldingMarkers): void {
let model = Model.createFromString(lines.join('\n'));
let actual = computeRanges(model, offside, markers);
actual.sort((r1, r2) => r1.startLineNumber - r2.startLineNumber);
......@@ -144,9 +145,9 @@ function r(startLineNumber: number, endLineNumber: number, indent: number, marke
// });
// });
let foldPattern: FoldMarkers = {
start: '^\\s*#region',
end: '^\\s*#endregion'
let markers: FoldingMarkers = {
start: /^\\s*#region/,
end: /^\\s*#endregion/
};
suite('Folding with regions', () => {
......@@ -160,7 +161,7 @@ suite('Folding with regions', () => {
/* 6*/ ' }',
/* 7*/ ' #endregion',
/* 8*/ '}',
], [r(1, 7, 0), r(2, 7, 2, true), r(3, 5, 2)], false, foldPattern);
], [r(1, 7, 0), r(2, 7, 2, true), r(3, 5, 2)], false, markers);
});
test('Inside region, not indented', () => {
assertRanges([
......@@ -172,7 +173,7 @@ suite('Folding with regions', () => {
/* 6*/ ' }',
/* 7*/ '#endregion',
/* 8*/ '',
], [r(2, 7, 0, true), r(3, 6, 0)], false, foldPattern);
], [r(2, 7, 0, true), r(3, 6, 0)], false, markers);
});
test('Empty Regions', () => {
assertRanges([
......@@ -183,7 +184,7 @@ suite('Folding with regions', () => {
/* 5*/ '',
/* 6*/ '#endregion',
/* 7*/ 'var y;',
], [r(2, 3, 0, true), r(4, 6, 0, true)], false, foldPattern);
], [r(2, 3, 0, true), r(4, 6, 0, true)], false, markers);
});
test('Nested Regions', () => {
assertRanges([
......@@ -194,7 +195,7 @@ suite('Folding with regions', () => {
/* 5*/ '#endregion',
/* 6*/ '#endregion',
/* 7*/ 'var y;',
], [r(2, 6, 0, true), r(3, 5, 0, true)], false, foldPattern);
], [r(2, 6, 0, true), r(3, 5, 0, true)], false, markers);
});
test('Nested Regions 2', () => {
assertRanges([
......@@ -207,7 +208,7 @@ suite('Folding with regions', () => {
/* 7*/ ' // comment',
/* 8*/ ' #endregion',
/* 9*/ '}',
], [r(1, 8, 0), r(2, 8, 2, true), r(4, 6, 2, true)], false, foldPattern);
], [r(1, 8, 0), r(2, 8, 2, true), r(4, 6, 2, true)], false, markers);
});
test('Incomplete Regions', () => {
assertRanges([
......@@ -215,7 +216,7 @@ suite('Folding with regions', () => {
/* 2*/ '#region',
/* 3*/ ' // comment',
/* 4*/ '}',
], [], false, foldPattern);
], [], false, markers);
});
test('Incomplete Regions', () => {
assertRanges([
......@@ -227,7 +228,7 @@ suite('Folding with regions', () => {
/* 6*/ '#endregion',
/* 7*/ '#endregion',
/* 8*/ ' // hello',
], [r(3, 7, 0, true), r(4, 6, 0, true)], false, foldPattern);
], [r(3, 7, 0, true), r(4, 6, 0, true)], false, markers);
});
test('Indented region before', () => {
assertRanges([
......@@ -237,7 +238,7 @@ suite('Folding with regions', () => {
/* 4*/ '#region',
/* 5*/ ' // comment',
/* 6*/ '#endregion',
], [r(1, 3, 0), r(4, 6, 0, true)], false, foldPattern);
], [r(1, 3, 0), r(4, 6, 0, true)], false, markers);
});
test('Indented region before 2', () => {
assertRanges([
......@@ -247,7 +248,7 @@ suite('Folding with regions', () => {
/* 4*/ ' #region',
/* 5*/ ' // comment',
/* 6*/ ' #endregion',
], [r(1, 6, 0), r(2, 6, 2), r(4, 6, 4, true)], false, foldPattern);
], [r(1, 6, 0), r(2, 6, 2), r(4, 6, 4, true)], false, markers);
});
test('Indented region in-between', () => {
assertRanges([
......@@ -257,7 +258,7 @@ suite('Folding with regions', () => {
/* 4*/ ' return;',
/* 5*/ '',
/* 6*/ '#endregion',
], [r(1, 6, 0, true), r(3, 5, 2)], false, foldPattern);
], [r(1, 6, 0, true), r(3, 5, 2)], false, markers);
});
test('Indented region after', () => {
assertRanges([
......@@ -267,6 +268,6 @@ suite('Folding with regions', () => {
/* 4*/ '#endregion',
/* 5*/ ' if (x)',
/* 6*/ ' return;',
], [r(1, 4, 0, true), r(5, 6, 2)], false, foldPattern);
], [r(1, 4, 0, true), r(5, 6, 2)], false, markers);
});
});
\ No newline at end of file
......@@ -4361,6 +4361,17 @@ declare module monaco.languages {
unIndentedLinePattern?: RegExp;
}
/**
* Describes language specific folding markers such as '#region' and '#endregion'.
* The start and end regexes will be tested against the contents of all lines and must be designed efficiently:
* - the regex should start with '^'
* - regexp flags (i, g) are ignored
*/
export interface FoldingMarkers {
start: RegExp;
end: RegExp;
}
/**
* Describes folding rules for a language.
*/
......@@ -4372,6 +4383,10 @@ declare module monaco.languages {
* If not set, `false` is used and empty lines belong to the previous block.
*/
offSide?: boolean;
/**
* Region markers used by the language.
*/
markers?: FoldingMarkers;
}
/**
......
......@@ -119,7 +119,12 @@ export class LanguageConfigurationFileHandler {
}
if (configuration.folding) {
richEditConfig.folding = configuration.folding;
let markers = configuration.folding.markers;
richEditConfig.folding = {
offSide: configuration.folding.offSide,
markers: markers ? { start: new RegExp(markers.start), end: new RegExp(markers.end) } : void 0
};
}
LanguageConfigurationRegistry.register(languageIdentifier, richEditConfig);
......@@ -390,6 +395,20 @@ const schema: IJSONSchema = {
offSide: {
type: 'boolean',
description: nls.localize('schema.folding.offSide', 'A language adheres to the off-side rule if blocks in that language are expressed by their indentation. If set, empty lines belong to the subsequent block.'),
},
markers: {
type: 'object',
description: nls.localize('schema.folding.markers', 'Language specific folding markers such as \'#region\' and \'#endregion\'. The start and end regexes will be tested against the contents of all lines and must be designed efficiently'),
properties: {
start: {
type: 'string',
description: nls.localize('schema.folding.markers.start', 'The RegExp pattern for the start marker. The regexp must start with \'^\'.')
},
end: {
type: 'string',
description: nls.localize('schema.folding.markers.end', 'The RegExp pattern for the end marker. The regexp must start with \'^\'.')
},
}
}
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册