mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
[folding] add folding marker to API and schema
This commit is contained in:
parent
5ae1dc4496
commit
777fddd4f7
|
@ -27,8 +27,8 @@
|
|||
],
|
||||
"folding": {
|
||||
"markers": {
|
||||
"start": "^\\s*//\\s*#region",
|
||||
"end": "^\\s*//\\s*#endregion"
|
||||
"start": "^\\s*//\\s*#?region",
|
||||
"end": "^\\s*//\\s*#?endregion"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,8 +27,8 @@
|
|||
],
|
||||
"folding": {
|
||||
"markers": {
|
||||
"start": "^\\s*//\\s*#region",
|
||||
"end": "^\\s*//\\s*#endregion"
|
||||
"start": "^\\s*//\\s*#?region",
|
||||
"end": "^\\s*//\\s*#?endregion"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
});
|
15
src/vs/monaco.d.ts
vendored
15
src/vs/monaco.d.ts
vendored
|
@ -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 \'^\'.')
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue