parent
0fd1ba9903
commit
bce608e4bf
|
@ -8,6 +8,7 @@
|
|||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as types from 'vs/base/common/types';
|
||||
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||
import { RunOnceScheduler, Delayer } from 'vs/base/common/async';
|
||||
import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
|
@ -15,7 +16,7 @@ import { TPromise } from 'vs/base/common/winjs.base';
|
|||
import { ScrollType, IModel, IEditorContribution } from 'vs/editor/common/editorCommon';
|
||||
import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, registerInstantiatedEditorAction } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingDecorationProvider } from './foldingDecorations';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
|
@ -508,6 +509,30 @@ class FoldRecursivelyAction extends FoldingAction<void> {
|
|||
}
|
||||
}
|
||||
|
||||
class FoldAllBlockCommentsAction extends FoldingAction<void> {
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
id: 'editor.foldAllBlockComments',
|
||||
label: nls.localize('foldAllBlockComments.label', "Fold All Block Comments"),
|
||||
alias: 'Fold All Block Comments',
|
||||
precondition: null,
|
||||
kbOpts: {
|
||||
kbExpr: EditorContextKeys.textFocus,
|
||||
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyCode.US_SLASH)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {
|
||||
let comments = LanguageConfigurationRegistry.getComments(editor.getModel().getLanguageIdentifier().id);
|
||||
if (comments && comments.blockCommentStartToken) {
|
||||
let regExp = new RegExp('^\\s*' + escapeRegExpCharacters(comments.blockCommentStartToken));
|
||||
setCollapseStateForMatchingLines(foldingModel, regExp, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FoldAllAction extends FoldingAction<void> {
|
||||
|
||||
constructor() {
|
||||
|
@ -568,6 +593,7 @@ registerEditorAction(FoldAction);
|
|||
registerEditorAction(FoldRecursivelyAction);
|
||||
registerEditorAction(FoldAllAction);
|
||||
registerEditorAction(UnfoldAllAction);
|
||||
registerEditorAction(FoldAllBlockCommentsAction);
|
||||
|
||||
for (let i = 1; i <= 9; i++) {
|
||||
registerInstantiatedEditorAction(
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { IModel, IModelDecorationOptions, IModelDeltaDecoration, IModelDecorationsChangeAccessor } from 'vs/editor/common/editorCommon';
|
||||
import Event, { Emitter } from 'vs/base/common/event';
|
||||
import { FoldingRanges, ILineRange } from './foldingRanges';
|
||||
import { FoldingRanges, ILineRange, FoldingRegion } from './foldingRanges';
|
||||
|
||||
export interface IDecorationProvider {
|
||||
getDecorationOption(isCollapsed: boolean): IModelDecorationOptions;
|
||||
|
@ -167,7 +167,7 @@ export class FoldingModel {
|
|||
let index = this._ranges.findRange(lineNumber);
|
||||
let level = 1;
|
||||
while (index >= 0) {
|
||||
let current = new FoldingRegion(this._ranges, index);
|
||||
let current = this._ranges.toRegion(index);
|
||||
if (!filter || filter(current, level)) {
|
||||
result.push(current);
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ export class FoldingModel {
|
|||
if (this._ranges) {
|
||||
let index = this._ranges.findRange(lineNumber);
|
||||
if (index >= 0) {
|
||||
return new FoldingRegion(this._ranges, index);
|
||||
return this._ranges.toRegion(index);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -195,7 +195,7 @@ export class FoldingModel {
|
|||
let index = region ? region.regionIndex + 1 : 0;
|
||||
let endLineNumber = region ? region.endLineNumber : Number.MAX_VALUE;
|
||||
for (let i = index, len = this._ranges.length; i < len; i++) {
|
||||
let current = new FoldingRegion(this._ranges, i);
|
||||
let current = this._ranges.toRegion(i);
|
||||
if (this._ranges.getStartLineNumber(i) < endLineNumber) {
|
||||
if (trackLevel) {
|
||||
while (levelStack.length > 0 && !current.containedBy(levelStack[levelStack.length - 1])) {
|
||||
|
@ -217,41 +217,7 @@ export class FoldingModel {
|
|||
|
||||
}
|
||||
|
||||
export class FoldingRegion {
|
||||
|
||||
constructor(private ranges: FoldingRanges, private index: number) {
|
||||
}
|
||||
|
||||
public get startLineNumber() {
|
||||
return this.ranges.getStartLineNumber(this.index);
|
||||
}
|
||||
|
||||
public get endLineNumber() {
|
||||
return this.ranges.getEndLineNumber(this.index);
|
||||
}
|
||||
|
||||
public get regionIndex() {
|
||||
return this.index;
|
||||
}
|
||||
|
||||
public get parentIndex() {
|
||||
return this.ranges.getParentIndex(this.index);
|
||||
}
|
||||
|
||||
public get isCollapsed() {
|
||||
return this.ranges.isCollapsed(this.index);
|
||||
}
|
||||
|
||||
containedBy(range: ILineRange): boolean {
|
||||
return range.startLineNumber <= this.startLineNumber && range.endLineNumber >= this.endLineNumber;
|
||||
}
|
||||
containsLine(lineNumber: number) {
|
||||
return this.startLineNumber <= lineNumber && lineNumber <= this.endLineNumber;
|
||||
}
|
||||
hidesLine(lineNumber: number) {
|
||||
return this.startLineNumber < lineNumber && lineNumber <= this.endLineNumber;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse or expand the regions at the given locations including all children.
|
||||
|
@ -306,4 +272,23 @@ export function setCollapseStateAtLevel(foldingModel: FoldingModel, foldLevel: n
|
|||
let filter = (region: FoldingRegion, level: number) => level === foldLevel && region.isCollapsed !== doCollapse && !blockedLineNumbers.some(line => region.containsLine(line));
|
||||
let toToggle = foldingModel.getRegionsInside(null, filter);
|
||||
foldingModel.toggleCollapseState(toToggle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Folds all regions for which the lines start with a given regex
|
||||
* @param foldingModel the folding model
|
||||
*/
|
||||
export function setCollapseStateForMatchingLines(foldingModel: FoldingModel, regExp: RegExp, doCollapse: boolean): void {
|
||||
let editorModel = foldingModel.textModel;
|
||||
let ranges = foldingModel.ranges;
|
||||
let toToggle = [];
|
||||
for (let i = ranges.length - 1; i >= 0; i--) {
|
||||
if (doCollapse !== ranges.isCollapsed(i)) {
|
||||
let startLineNumber = ranges.getStartLineNumber(i);
|
||||
if (regExp.test(editorModel.getLineContent(startLineNumber))) {
|
||||
toToggle.push(ranges.toRegion(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
foldingModel.toggleCollapseState(toToggle);
|
||||
}
|
|
@ -84,6 +84,10 @@ export class FoldingRanges {
|
|||
}
|
||||
}
|
||||
|
||||
public toRegion(index: number): FoldingRegion {
|
||||
return new FoldingRegion(this, index);
|
||||
}
|
||||
|
||||
public getParentIndex(index: number) {
|
||||
this.ensureParentIndices();
|
||||
let parent = ((this._startIndexes[index] & MASK_INDENT) >>> 24) + ((this._endIndexes[index] & MASK_INDENT) >>> 16);
|
||||
|
@ -130,4 +134,40 @@ export class FoldingRanges {
|
|||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
export class FoldingRegion {
|
||||
|
||||
constructor(private ranges: FoldingRanges, private index: number) {
|
||||
}
|
||||
|
||||
public get startLineNumber() {
|
||||
return this.ranges.getStartLineNumber(this.index);
|
||||
}
|
||||
|
||||
public get endLineNumber() {
|
||||
return this.ranges.getEndLineNumber(this.index);
|
||||
}
|
||||
|
||||
public get regionIndex() {
|
||||
return this.index;
|
||||
}
|
||||
|
||||
public get parentIndex() {
|
||||
return this.ranges.getParentIndex(this.index);
|
||||
}
|
||||
|
||||
public get isCollapsed() {
|
||||
return this.ranges.isCollapsed(this.index);
|
||||
}
|
||||
|
||||
containedBy(range: ILineRange): boolean {
|
||||
return range.startLineNumber <= this.startLineNumber && range.endLineNumber >= this.endLineNumber;
|
||||
}
|
||||
containsLine(lineNumber: number) {
|
||||
return this.startLineNumber <= lineNumber && lineNumber <= this.endLineNumber;
|
||||
}
|
||||
hidesLine(lineNumber: number) {
|
||||
return this.startLineNumber < lineNumber && lineNumber <= this.endLineNumber;
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { FoldingModel, FoldingRegion, setCollapseStateAtLevel, setCollapseStateLevelsDown, setCollapseStateLevelsUp } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingModel, setCollapseStateAtLevel, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { Model } from 'vs/editor/common/model/model';
|
||||
import { computeRanges } from 'vs/editor/contrib/folding/indentRangeProvider';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModelWithDecorations';
|
||||
|
@ -13,6 +13,8 @@ import { TrackedRangeStickiness, IModelDeltaDecoration, IModel, IModelDecoration
|
|||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { FoldingRegion } from 'vs/editor/contrib/folding/foldingRanges';
|
||||
import { escapeRegExpCharacters } from 'vs/base/common/strings';
|
||||
|
||||
|
||||
interface ExpectedRegion {
|
||||
|
@ -588,4 +590,44 @@ suite('Folding Model', () => {
|
|||
|
||||
});
|
||||
|
||||
|
||||
test('setCollapseStateForMatchingLines', () => {
|
||||
let lines = [
|
||||
/* 1*/ '/**',
|
||||
/* 2*/ ' * the class',
|
||||
/* 3*/ ' */',
|
||||
/* 4*/ 'class A {',
|
||||
/* 5*/ ' /**',
|
||||
/* 6*/ ' * the foo',
|
||||
/* 7*/ ' */',
|
||||
/* 8*/ ' void foo() {',
|
||||
/* 9*/ ' /*',
|
||||
/* 10*/ ' * the comment',
|
||||
/* 11*/ ' */',
|
||||
/* 12*/ ' }',
|
||||
/* 13*/ '}'];
|
||||
|
||||
let textModel = Model.createFromString(lines.join('\n'));
|
||||
try {
|
||||
let foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel));
|
||||
|
||||
let ranges = computeRanges(textModel, false, { start: /^\/\/#region$/, end: /^\/\/#endregion$/ });
|
||||
foldingModel.update(ranges);
|
||||
|
||||
let r1 = r(1, 3, false);
|
||||
let r2 = r(4, 12, false);
|
||||
let r3 = r(5, 7, false);
|
||||
let r4 = r(8, 11, false);
|
||||
let r5 = r(9, 11, false);
|
||||
assertRanges(foldingModel, [r1, r2, r3, r4, r5]);
|
||||
|
||||
let regExp = new RegExp('^\\s*' + escapeRegExpCharacters('/*'));
|
||||
setCollapseStateForMatchingLines(foldingModel, regExp, true);
|
||||
assertFoldedRanges(foldingModel, [r1, r3, r5], '1');
|
||||
} finally {
|
||||
textModel.dispose();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
Loading…
Reference in a new issue