[folding] fold comments / region

This commit is contained in:
Martin Aeschlimann
2018-02-23 08:30:56 +01:00
parent 6e3d28192a
commit cd21d906ca
6 changed files with 66 additions and 24 deletions

View File

@@ -17,7 +17,7 @@ import { ScrollType, IEditorContribution } from 'vs/editor/common/editorCommon';
import { ITextModel } from 'vs/editor/common/model';
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, setCollapseStateForMatchingLines } from 'vs/editor/contrib/folding/foldingModel';
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType } from 'vs/editor/contrib/folding/foldingModel';
import { FoldingDecorationProvider } from './foldingDecorations';
import { FoldingRegions } from './foldingRanges';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
@@ -28,7 +28,7 @@ import { IRange } from 'vs/editor/common/core/range';
import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry';
import { IndentRangeProvider } from 'vs/editor/contrib/folding/indentRangeProvider';
import { IPosition } from 'vs/editor/common/core/position';
import { FoldingProviderRegistry } from 'vs/editor/common/modes';
import { FoldingProviderRegistry, FoldingRangeType } from 'vs/editor/common/modes';
import { SyntaxRangeProvider } from './syntaxRangeProvider';
export const ID = 'editor.contrib.folding';
@@ -553,10 +553,14 @@ class FoldAllBlockCommentsAction extends FoldingAction<void> {
}
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);
if (foldingModel.regions.hasTypes()) {
setCollapseStateForType(foldingModel, FoldingRangeType.Comment, true);
} else {
let comments = LanguageConfigurationRegistry.getComments(editor.getModel().getLanguageIdentifier().id);
if (comments && comments.blockCommentStartToken) {
let regExp = new RegExp('^\\s*' + escapeRegExpCharacters(comments.blockCommentStartToken));
setCollapseStateForMatchingLines(foldingModel, regExp, true);
}
}
}
}
@@ -577,10 +581,14 @@ class FoldAllRegionsAction extends FoldingAction<void> {
}
invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editor.getModel().getLanguageIdentifier().id);
if (foldingRules && foldingRules.markers && foldingRules.markers.start) {
let regExp = new RegExp(foldingRules.markers.start);
setCollapseStateForMatchingLines(foldingModel, regExp, true);
if (foldingModel.regions.hasTypes()) {
setCollapseStateForType(foldingModel, FoldingRangeType.Region, true);
} else {
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editor.getModel().getLanguageIdentifier().id);
if (foldingRules && foldingRules.markers && foldingRules.markers.start) {
let regExp = new RegExp(foldingRules.markers.start);
setCollapseStateForMatchingLines(foldingModel, regExp, true);
}
}
}
}
@@ -601,10 +609,14 @@ class UnfoldAllRegionsAction extends FoldingAction<void> {
}
invoke(foldingController: FoldingController, foldingModel: FoldingModel, editor: ICodeEditor): void {
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editor.getModel().getLanguageIdentifier().id);
if (foldingRules && foldingRules.markers && foldingRules.markers.start) {
let regExp = new RegExp(foldingRules.markers.start);
setCollapseStateForMatchingLines(foldingModel, regExp, false);
if (foldingModel.regions.hasTypes()) {
setCollapseStateForType(foldingModel, FoldingRangeType.Region, false);
} else {
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editor.getModel().getLanguageIdentifier().id);
if (foldingRules && foldingRules.markers && foldingRules.markers.start) {
let regExp = new RegExp(foldingRules.markers.start);
setCollapseStateForMatchingLines(foldingModel, regExp, false);
}
}
}
}

View File

@@ -308,3 +308,18 @@ export function setCollapseStateForMatchingLines(foldingModel: FoldingModel, reg
}
foldingModel.toggleCollapseState(toToggle);
}
/**
* Folds all regions of the given type
* @param foldingModel the folding model
*/
export function setCollapseStateForType(foldingModel: FoldingModel, type: string, doCollapse: boolean): void {
let regions = foldingModel.regions;
let toToggle = [];
for (let i = regions.length - 1; i >= 0; i--) {
if (doCollapse !== regions.isCollapsed(i) && type === regions.getType(i)) {
toToggle.push(regions.toRegion(i));
}
}
foldingModel.toggleCollapseState(toToggle);
}

View File

@@ -20,14 +20,16 @@ export class FoldingRegions {
private _endIndexes: Uint32Array;
private _collapseStates: Uint32Array;
private _parentsComputed: boolean;
private _types: string[] | undefined;
constructor(startIndexes: Uint32Array, endIndexes: Uint32Array) {
constructor(startIndexes: Uint32Array, endIndexes: Uint32Array, types?: string[]) {
if (startIndexes.length !== endIndexes.length || startIndexes.length > MAX_FOLDING_REGIONS) {
throw new Error('invalid startIndexes or endIndexes size');
}
this._startIndexes = startIndexes;
this._endIndexes = endIndexes;
this._collapseStates = new Uint32Array(Math.ceil(startIndexes.length / 32));
this._types = types;
}
private ensureParentIndices() {
@@ -67,6 +69,14 @@ export class FoldingRegions {
return this._endIndexes[index] & MAX_LINE_NUMBER;
}
public getType(index: number): string | undefined {
return this._types ? this._types[index] : void 0;
}
public hasTypes() {
return !!this._types;
}
public isCollapsed(index: number): boolean {
let arrayIndex = (index / 32) | 0;
let bit = index % 32;

View File

@@ -52,6 +52,7 @@ export class RangesCollector {
private _endIndexes: number[];
private _nestingLevels: number[];
private _nestingLevelCounts: number[];
private _types: string[];
private _length: number;
private _foldingRangesLimit: number;
@@ -60,11 +61,12 @@ export class RangesCollector {
this._endIndexes = [];
this._nestingLevels = [];
this._nestingLevelCounts = [];
this._types = [];
this._length = 0;
this._foldingRangesLimit = foldingRangesLimit;
}
public add(startLineNumber: number, endLineNumber: number, nestingLevel: number) {
public add(startLineNumber: number, endLineNumber: number, type: string, nestingLevel: number) {
if (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {
return;
}
@@ -72,6 +74,7 @@ export class RangesCollector {
this._startIndexes[index] = startLineNumber;
this._endIndexes[index] = endLineNumber;
this._nestingLevels[index] = nestingLevel;
this._types[index] = type;
this._length++;
if (nestingLevel < 30) {
this._nestingLevelCounts[nestingLevel] = (this._nestingLevelCounts[nestingLevel] || 0) + 1;
@@ -86,7 +89,7 @@ export class RangesCollector {
startIndexes[i] = this._startIndexes[i];
endIndexes[i] = this._endIndexes[i];
}
return new FoldingRegions(startIndexes, endIndexes);
return new FoldingRegions(startIndexes, endIndexes, this._types);
} else {
let entries = 0;
let maxLevel = this._nestingLevelCounts.length;
@@ -102,15 +105,17 @@ export class RangesCollector {
}
let startIndexes = new Uint32Array(entries);
let endIndexes = new Uint32Array(entries);
let types = [];
for (let i = 0, k = 0; i < this._length; i++) {
let level = this._nestingLevels[i];
if (level < maxLevel) {
startIndexes[k] = this._startIndexes[i];
endIndexes[k] = this._endIndexes[i];
types[k] = this._types[i];
k++;
}
}
return new FoldingRegions(startIndexes, endIndexes);
return new FoldingRegions(startIndexes, endIndexes, types);
}
}
@@ -132,20 +137,20 @@ export function sanitizeRanges(rangeData: IFoldingRangeData[]): FoldingRegions {
for (let entry of sorted) {
if (!top) {
top = entry;
collector.add(entry.startLineNumber, entry.endLineNumber, previous.length);
collector.add(entry.startLineNumber, entry.endLineNumber, entry.type, previous.length);
} else {
if (entry.startLineNumber > top.startLineNumber) {
if (entry.endLineNumber <= top.endLineNumber) {
previous.push(top);
top = entry;
collector.add(entry.startLineNumber, entry.endLineNumber, previous.length);
collector.add(entry.startLineNumber, entry.endLineNumber, entry.type, previous.length);
} else if (entry.startLineNumber > top.endLineNumber) {
do {
top = previous.pop();
} while (top && entry.startLineNumber > top.endLineNumber);
previous.push(top);
top = entry;
collector.add(entry.startLineNumber, entry.endLineNumber, previous.length);
collector.add(entry.startLineNumber, entry.endLineNumber, entry.type, previous.length);
}
}
}

View File

@@ -589,7 +589,7 @@ export namespace ProgressLocation {
export namespace FoldingRangeList {
export function from(rangeList: vscode.FoldingRangeList): modes.IFoldingRangeList {
return {
ranges: rangeList.ranges.map(r => ({ startLineNumber: r.startLine + 1, endLineNumber: r.endLine + 1 }))
ranges: rangeList.ranges.map(r => ({ startLineNumber: r.startLine + 1, endLineNumber: r.endLine + 1, type: r.type }))
};
}
}

View File

@@ -1677,9 +1677,9 @@ export class FoldingRange {
endLine: number;
type?: FoldingRangeType;
type?: FoldingRangeType | string;
constructor(startLine: number, endLine: number, type?: FoldingRangeType) {
constructor(startLine: number, endLine: number, type?: FoldingRangeType | string) {
this.startLine = startLine;
this.endLine = endLine;
this.type = type;