mirror of
https://github.com/Microsoft/vscode
synced 2024-09-18 01:58:27 +00:00
[folding] add null checks
This commit is contained in:
parent
5d645696cc
commit
957518fdff
|
@ -284,6 +284,20 @@
|
|||
"./vs/editor/contrib/find/findState.ts",
|
||||
"./vs/editor/contrib/find/replaceAllCommand.ts",
|
||||
"./vs/editor/contrib/find/replacePattern.ts",
|
||||
"./vs/editor/contrib/folding/folding.ts",
|
||||
"./vs/editor/contrib/folding/foldingDecorations.ts",
|
||||
"./vs/editor/contrib/folding/foldingModel.ts",
|
||||
"./vs/editor/contrib/folding/foldingRanges.ts",
|
||||
"./vs/editor/contrib/folding/hiddenRangeModel.ts",
|
||||
"./vs/editor/contrib/folding/indentRangeProvider.ts",
|
||||
"./vs/editor/contrib/folding/intializingRangeProvider.ts",
|
||||
"./vs/editor/contrib/folding/syntaxRangeProvider.ts",
|
||||
"./vs/editor/contrib/folding/test/syntaxFold.test.ts",
|
||||
"./vs/editor/contrib/folding/test/indentRangeProvider.test.ts",
|
||||
"./vs/editor/contrib/folding/test/indentFold.test.ts",
|
||||
"./vs/editor/contrib/folding/test/hiddenRangeModel.test.ts",
|
||||
"./vs/editor/contrib/folding/test/foldingRanges.test.ts",
|
||||
"./vs/editor/contrib/folding/test/foldingModel.test.ts",
|
||||
"./vs/editor/contrib/fontZoom/fontZoom.ts",
|
||||
"./vs/editor/contrib/goToDefinition/clickLinkGesture.ts",
|
||||
"./vs/editor/contrib/hover/getHover.ts",
|
||||
|
|
|
@ -188,7 +188,6 @@ export class BracketMatchingController extends Disposable implements editorCommo
|
|||
|
||||
this._editor.getSelections().forEach(selection => {
|
||||
const position = selection.getStartPosition();
|
||||
|
||||
let brackets = model.matchBracket(position);
|
||||
|
||||
let openBracket: Position | null = null;
|
||||
|
|
|
@ -16,7 +16,7 @@ import { registerEditorAction, registerEditorContribution, ServicesAccessor, Edi
|
|||
import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { FoldingModel, setCollapseStateAtLevel, CollapseMemento, setCollapseStateLevelsDown, setCollapseStateLevelsUp, setCollapseStateForMatchingLines, setCollapseStateForType } from 'vs/editor/contrib/folding/foldingModel';
|
||||
import { FoldingDecorationProvider } from './foldingDecorations';
|
||||
import { FoldingRegions } from './foldingRanges';
|
||||
import { FoldingRegions, FoldingRegion } from './foldingRanges';
|
||||
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
|
||||
import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions';
|
||||
import { IMarginData, IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget';
|
||||
|
@ -36,7 +36,7 @@ export const ID = 'editor.contrib.folding';
|
|||
|
||||
export interface RangeProvider {
|
||||
readonly id: string;
|
||||
compute(cancelationToken: CancellationToken): Thenable<FoldingRegions>;
|
||||
compute(cancelationToken: CancellationToken): Thenable<FoldingRegions | null>;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
|
@ -62,20 +62,20 @@ export class FoldingController implements IEditorContribution {
|
|||
|
||||
private foldingDecorationProvider: FoldingDecorationProvider;
|
||||
|
||||
private foldingModel: FoldingModel;
|
||||
private hiddenRangeModel: HiddenRangeModel;
|
||||
private foldingModel: FoldingModel | null;
|
||||
private hiddenRangeModel: HiddenRangeModel | null;
|
||||
|
||||
private rangeProvider: RangeProvider;
|
||||
private foldingRegionPromise: CancelablePromise<FoldingRegions>;
|
||||
private rangeProvider: RangeProvider | null;
|
||||
private foldingRegionPromise: CancelablePromise<FoldingRegions | null> | null;
|
||||
|
||||
private foldingStateMemento: FoldingStateMemento;
|
||||
private foldingStateMemento: FoldingStateMemento | null;
|
||||
|
||||
private foldingModelPromise: Thenable<FoldingModel>;
|
||||
private updateScheduler: Delayer<FoldingModel>;
|
||||
private foldingModelPromise: Thenable<FoldingModel | null> | null;
|
||||
private updateScheduler: Delayer<FoldingModel | null> | null;
|
||||
|
||||
private globalToDispose: IDisposable[];
|
||||
|
||||
private cursorChangedScheduler: RunOnceScheduler;
|
||||
private cursorChangedScheduler: RunOnceScheduler | null;
|
||||
|
||||
private localToDispose: IDisposable[];
|
||||
|
||||
|
@ -129,13 +129,13 @@ export class FoldingController implements IEditorContribution {
|
|||
/**
|
||||
* Store view state.
|
||||
*/
|
||||
public saveViewState(): FoldingStateMemento {
|
||||
public saveViewState(): FoldingStateMemento | undefined {
|
||||
let model = this.editor.getModel();
|
||||
if (!model || !this._isEnabled || model.isTooLargeForTokenization()) {
|
||||
return {};
|
||||
}
|
||||
if (this.foldingModel) { // disposed ?
|
||||
let collapsedRegions = this.foldingModel.isInitialized ? this.foldingModel.getMemento() : this.hiddenRangeModel.getMemento();
|
||||
let collapsedRegions = this.foldingModel.isInitialized ? this.foldingModel.getMemento() : this.hiddenRangeModel!.getMemento();
|
||||
let provider = this.rangeProvider ? this.rangeProvider.id : void 0;
|
||||
return { collapsedRegions, lineCount: model.getLineCount(), provider };
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ export class FoldingController implements IEditorContribution {
|
|||
*/
|
||||
public restoreViewState(state: FoldingStateMemento): void {
|
||||
let model = this.editor.getModel();
|
||||
if (!model || !this._isEnabled || model.isTooLargeForTokenization()) {
|
||||
if (!model || !this._isEnabled || model.isTooLargeForTokenization() || !this.hiddenRangeModel) {
|
||||
return;
|
||||
}
|
||||
if (!state || !state.collapsedRegions || state.lineCount !== model.getLineCount()) {
|
||||
|
@ -158,15 +158,20 @@ export class FoldingController implements IEditorContribution {
|
|||
this.foldingStateMemento = state;
|
||||
}
|
||||
|
||||
const collapsedRegions = state.collapsedRegions;
|
||||
|
||||
// set the hidden ranges right away, before waiting for the folding model.
|
||||
if (this.hiddenRangeModel.applyMemento(state.collapsedRegions)) {
|
||||
this.getFoldingModel().then(foldingModel => {
|
||||
if (this.hiddenRangeModel.applyMemento(collapsedRegions)) {
|
||||
const foldingModel = this.getFoldingModel();
|
||||
if (foldingModel) {
|
||||
foldingModel.applyMemento(state.collapsedRegions);
|
||||
foldingModel.then(foldingModel => {
|
||||
if (foldingModel) {
|
||||
foldingModel.applyMemento(collapsedRegions);
|
||||
}
|
||||
}).then(undefined, onUnexpectedError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private onModelChanged(): void {
|
||||
this.localToDispose = dispose(this.localToDispose);
|
||||
|
@ -199,7 +204,9 @@ export class FoldingController implements IEditorContribution {
|
|||
this.foldingRegionPromise.cancel();
|
||||
this.foldingRegionPromise = null;
|
||||
}
|
||||
if (this.updateScheduler) {
|
||||
this.updateScheduler.cancel();
|
||||
}
|
||||
this.updateScheduler = null;
|
||||
this.foldingModel = null;
|
||||
this.foldingModelPromise = null;
|
||||
|
@ -229,15 +236,16 @@ export class FoldingController implements IEditorContribution {
|
|||
}
|
||||
this.rangeProvider = new IndentRangeProvider(editorModel); // fallback
|
||||
|
||||
if (this._useFoldingProviders) {
|
||||
|
||||
if (this._useFoldingProviders && this.foldingModel) {
|
||||
let foldingProviders = FoldingRangeProviderRegistry.ordered(this.foldingModel.textModel);
|
||||
if (foldingProviders.length === 0 && this.foldingStateMemento) {
|
||||
this.rangeProvider = new InitializingRangeProvider(editorModel, this.foldingStateMemento.collapsedRegions, () => {
|
||||
if (foldingProviders.length === 0 && this.foldingStateMemento && this.foldingStateMemento.collapsedRegions) {
|
||||
const rangeProvider = this.rangeProvider = new InitializingRangeProvider(editorModel, this.foldingStateMemento.collapsedRegions, () => {
|
||||
// if after 30 the InitializingRangeProvider is still not replaced, force a refresh
|
||||
this.foldingStateMemento = null;
|
||||
this.onFoldingStrategyChanged();
|
||||
}, 30000);
|
||||
return this.rangeProvider; // keep memento in case there are still no foldingProviders on the next request.
|
||||
return rangeProvider; // keep memento in case there are still no foldingProviders on the next request.
|
||||
} else if (foldingProviders.length > 0) {
|
||||
this.rangeProvider = new SyntaxRangeProvider(editorModel, foldingProviders);
|
||||
}
|
||||
|
@ -257,25 +265,26 @@ export class FoldingController implements IEditorContribution {
|
|||
this.foldingRegionPromise = null;
|
||||
}
|
||||
this.foldingModelPromise = this.updateScheduler.trigger(() => {
|
||||
if (!this.foldingModel) { // null if editor has been disposed, or folding turned off
|
||||
const foldingModel = this.foldingModel;
|
||||
if (!foldingModel) { // null if editor has been disposed, or folding turned off
|
||||
return null;
|
||||
}
|
||||
let foldingRegionPromise = this.foldingRegionPromise = createCancelablePromise(token => this.getRangeProvider(this.foldingModel.textModel).compute(token));
|
||||
let foldingRegionPromise = this.foldingRegionPromise = createCancelablePromise(token => this.getRangeProvider(foldingModel.textModel).compute(token));
|
||||
return foldingRegionPromise.then(foldingRanges => {
|
||||
if (foldingRanges && foldingRegionPromise === this.foldingRegionPromise) { // new request or cancelled in the meantime?
|
||||
// some cursors might have moved into hidden regions, make sure they are in expanded regions
|
||||
let selections = this.editor.getSelections();
|
||||
let selectionLineNumbers = selections ? selections.map(s => s.startLineNumber) : [];
|
||||
this.foldingModel.update(foldingRanges, selectionLineNumbers);
|
||||
foldingModel.update(foldingRanges, selectionLineNumbers);
|
||||
}
|
||||
return this.foldingModel;
|
||||
return foldingModel;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private onHiddenRangesChanges(hiddenRanges: IRange[]) {
|
||||
if (hiddenRanges.length) {
|
||||
if (this.hiddenRangeModel && hiddenRanges.length) {
|
||||
let selections = this.editor.getSelections();
|
||||
if (selections) {
|
||||
if (this.hiddenRangeModel.adjustSelections(selections)) {
|
||||
|
@ -287,20 +296,24 @@ export class FoldingController implements IEditorContribution {
|
|||
}
|
||||
|
||||
private onCursorPositionChanged() {
|
||||
if (this.hiddenRangeModel.hasRanges()) {
|
||||
this.cursorChangedScheduler.schedule();
|
||||
if (this.hiddenRangeModel && this.hiddenRangeModel.hasRanges()) {
|
||||
this.cursorChangedScheduler!.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
private revealCursor() {
|
||||
this.getFoldingModel().then(foldingModel => { // null is returned if folding got disabled in the meantime
|
||||
const foldingModel = this.getFoldingModel();
|
||||
if (!foldingModel) {
|
||||
return;
|
||||
}
|
||||
foldingModel.then(foldingModel => { // null is returned if folding got disabled in the meantime
|
||||
if (foldingModel) {
|
||||
let selections = this.editor.getSelections();
|
||||
if (selections && selections.length > 0) {
|
||||
let toToggle = [];
|
||||
let toToggle: FoldingRegion[] = [];
|
||||
for (let selection of selections) {
|
||||
let lineNumber = selection.selectionStartLineNumber;
|
||||
if (this.hiddenRangeModel.isHidden(lineNumber)) {
|
||||
if (this.hiddenRangeModel && this.hiddenRangeModel.isHidden(lineNumber)) {
|
||||
toToggle.push(...foldingModel.getAllRegionsAtLine(lineNumber, r => r.isCollapsed && lineNumber > r.startLineNumber));
|
||||
}
|
||||
}
|
||||
|
@ -314,18 +327,19 @@ export class FoldingController implements IEditorContribution {
|
|||
|
||||
}
|
||||
|
||||
private mouseDownInfo: { lineNumber: number, iconClicked: boolean };
|
||||
private mouseDownInfo: { lineNumber: number, iconClicked: boolean } | null;
|
||||
|
||||
private onEditorMouseDown(e: IEditorMouseEvent): void {
|
||||
this.mouseDownInfo = null;
|
||||
|
||||
let range = e.target.range;
|
||||
if (!this.hiddenRangeModel || !range) {
|
||||
|
||||
if (!this.hiddenRangeModel || !e.target || !e.target.range) {
|
||||
return;
|
||||
}
|
||||
if (!e.event.leftButton && !e.event.middleButton) {
|
||||
return;
|
||||
}
|
||||
const range = e.target.range;
|
||||
let iconClicked = false;
|
||||
switch (e.target.type) {
|
||||
case MouseTargetType.GUTTER_LINE_DECORATIONS:
|
||||
|
@ -368,7 +382,8 @@ export class FoldingController implements IEditorContribution {
|
|||
}
|
||||
|
||||
private onEditorMouseUp(e: IEditorMouseEvent): void {
|
||||
if (!this.mouseDownInfo) {
|
||||
const foldingModel = this.getFoldingModel();
|
||||
if (!foldingModel || !this.mouseDownInfo || !e.target) {
|
||||
return;
|
||||
}
|
||||
let lineNumber = this.mouseDownInfo.lineNumber;
|
||||
|
@ -385,12 +400,12 @@ export class FoldingController implements IEditorContribution {
|
|||
}
|
||||
} else {
|
||||
let model = this.editor.getModel();
|
||||
if (range.startColumn !== model.getLineMaxColumn(lineNumber)) {
|
||||
if (!model || range.startColumn !== model.getLineMaxColumn(lineNumber)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.getFoldingModel().then(foldingModel => {
|
||||
foldingModel.then(foldingModel => {
|
||||
if (foldingModel) {
|
||||
let region = foldingModel.getRegionAtLine(lineNumber);
|
||||
if (region && region.startLineNumber === lineNumber) {
|
||||
|
@ -428,7 +443,10 @@ abstract class FoldingAction<T> extends EditorAction {
|
|||
return foldingModelPromise.then(foldingModel => {
|
||||
if (foldingModel) {
|
||||
this.invoke(foldingController, foldingModel, editor, args);
|
||||
foldingController.reveal(editor.getSelection().getStartPosition());
|
||||
const selection = editor.getSelection();
|
||||
if (selection) {
|
||||
foldingController.reveal(selection.getStartPosition());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -626,7 +644,11 @@ class FoldAllBlockCommentsAction extends FoldingAction<void> {
|
|||
if (foldingModel.regions.hasTypes()) {
|
||||
setCollapseStateForType(foldingModel, FoldingRangeKind.Comment.value, true);
|
||||
} else {
|
||||
let comments = LanguageConfigurationRegistry.getComments(editor.getModel().getLanguageIdentifier().id);
|
||||
const editorModel = editor.getModel();
|
||||
if (!editorModel) {
|
||||
return;
|
||||
}
|
||||
let comments = LanguageConfigurationRegistry.getComments(editorModel.getLanguageIdentifier().id);
|
||||
if (comments && comments.blockCommentStartToken) {
|
||||
let regExp = new RegExp('^\\s*' + escapeRegExpCharacters(comments.blockCommentStartToken));
|
||||
setCollapseStateForMatchingLines(foldingModel, regExp, true);
|
||||
|
@ -655,7 +677,11 @@ class FoldAllRegionsAction extends FoldingAction<void> {
|
|||
if (foldingModel.regions.hasTypes()) {
|
||||
setCollapseStateForType(foldingModel, FoldingRangeKind.Region.value, true);
|
||||
} else {
|
||||
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editor.getModel().getLanguageIdentifier().id);
|
||||
const editorModel = editor.getModel();
|
||||
if (!editorModel) {
|
||||
return;
|
||||
}
|
||||
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editorModel.getLanguageIdentifier().id);
|
||||
if (foldingRules && foldingRules.markers && foldingRules.markers.start) {
|
||||
let regExp = new RegExp(foldingRules.markers.start);
|
||||
setCollapseStateForMatchingLines(foldingModel, regExp, true);
|
||||
|
@ -684,7 +710,11 @@ class UnfoldAllRegionsAction extends FoldingAction<void> {
|
|||
if (foldingModel.regions.hasTypes()) {
|
||||
setCollapseStateForType(foldingModel, FoldingRangeKind.Region.value, false);
|
||||
} else {
|
||||
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editor.getModel().getLanguageIdentifier().id);
|
||||
const editorModel = editor.getModel();
|
||||
if (!editorModel) {
|
||||
return;
|
||||
}
|
||||
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(editorModel.getLanguageIdentifier().id);
|
||||
if (foldingRules && foldingRules.markers && foldingRules.markers.start) {
|
||||
let regExp = new RegExp(foldingRules.markers.start);
|
||||
setCollapseStateForMatchingLines(foldingModel, regExp, false);
|
||||
|
|
|
@ -10,7 +10,7 @@ import { FoldingRegions, ILineRange, FoldingRegion } from './foldingRanges';
|
|||
export interface IDecorationProvider {
|
||||
getDecorationOption(isCollapsed: boolean): IModelDecorationOptions;
|
||||
deltaDecorations(oldDecorations: string[], newDecorations: IModelDeltaDecoration[]): string[];
|
||||
changeDecorations<T>(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T;
|
||||
changeDecorations<T>(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T | null;
|
||||
}
|
||||
|
||||
export interface FoldingModelChangeEvent {
|
||||
|
@ -64,7 +64,7 @@ export class FoldingModel {
|
|||
}
|
||||
|
||||
public update(newRegions: FoldingRegions, blockedLineNumers: number[] = []): void {
|
||||
let newEditorDecorations = [];
|
||||
let newEditorDecorations: IModelDeltaDecoration[] = [];
|
||||
|
||||
let isBlocked = (startLineNumber, endLineNumber) => {
|
||||
for (let blockedLineNumber of blockedLineNumers) {
|
||||
|
@ -138,7 +138,7 @@ export class FoldingModel {
|
|||
/**
|
||||
* Collapse state memento, for persistence only
|
||||
*/
|
||||
public getMemento(): CollapseMemento {
|
||||
public getMemento(): CollapseMemento | undefined {
|
||||
let collapsedRanges: ILineRange[] = [];
|
||||
for (let i = 0; i < this._regions.length; i++) {
|
||||
if (this._regions.isCollapsed(i)) {
|
||||
|
@ -153,7 +153,7 @@ export class FoldingModel {
|
|||
if (collapsedRanges.length > 0) {
|
||||
return collapsedRanges;
|
||||
}
|
||||
return null;
|
||||
return void 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -194,7 +194,7 @@ export class FoldingModel {
|
|||
return result;
|
||||
}
|
||||
|
||||
getRegionAtLine(lineNumber: number): FoldingRegion {
|
||||
getRegionAtLine(lineNumber: number): FoldingRegion | null {
|
||||
if (this._regions) {
|
||||
let index = this._regions.findRange(lineNumber);
|
||||
if (index >= 0) {
|
||||
|
@ -204,16 +204,16 @@ export class FoldingModel {
|
|||
return null;
|
||||
}
|
||||
|
||||
getRegionsInside(region: FoldingRegion, filter?: (r: FoldingRegion, level?: number) => boolean): FoldingRegion[] {
|
||||
let result = [];
|
||||
let trackLevel = filter && filter.length === 2;
|
||||
let levelStack: FoldingRegion[] = trackLevel ? [] : null;
|
||||
getRegionsInside(region: FoldingRegion | null, filter?: (r: FoldingRegion, level?: number) => boolean): FoldingRegion[] {
|
||||
let result: FoldingRegion[] = [];
|
||||
let index = region ? region.regionIndex + 1 : 0;
|
||||
let endLineNumber = region ? region.endLineNumber : Number.MAX_VALUE;
|
||||
|
||||
if (filter && filter.length === 2) {
|
||||
const levelStack: FoldingRegion[] = [];
|
||||
for (let i = index, len = this._regions.length; i < len; i++) {
|
||||
let current = this._regions.toRegion(i);
|
||||
if (this._regions.getStartLineNumber(i) < endLineNumber) {
|
||||
if (trackLevel) {
|
||||
while (levelStack.length > 0 && !current.containedBy(levelStack[levelStack.length - 1])) {
|
||||
levelStack.pop();
|
||||
}
|
||||
|
@ -221,13 +221,22 @@ export class FoldingModel {
|
|||
if (filter(current, levelStack.length)) {
|
||||
result.push(current);
|
||||
}
|
||||
} else if (!filter || filter(current)) {
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let i = index, len = this._regions.length; i < len; i++) {
|
||||
let current = this._regions.toRegion(i);
|
||||
if (this._regions.getStartLineNumber(i) < endLineNumber) {
|
||||
if (!filter || filter(current)) {
|
||||
result.push(current);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -242,7 +251,7 @@ export class FoldingModel {
|
|||
* @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model.
|
||||
*/
|
||||
export function setCollapseStateLevelsDown(foldingModel: FoldingModel, doCollapse: boolean, levels = Number.MAX_VALUE, lineNumbers?: number[]) {
|
||||
let toToggle = [];
|
||||
let toToggle: FoldingRegion[] = [];
|
||||
if (lineNumbers && lineNumbers.length > 0) {
|
||||
for (let lineNumber of lineNumbers) {
|
||||
let region = foldingModel.getRegionAtLine(lineNumber);
|
||||
|
@ -251,13 +260,13 @@ export function setCollapseStateLevelsDown(foldingModel: FoldingModel, doCollaps
|
|||
toToggle.push(region);
|
||||
}
|
||||
if (levels > 1) {
|
||||
let regionsInside = foldingModel.getRegionsInside(region, (r, level) => r.isCollapsed !== doCollapse && level < levels);
|
||||
let regionsInside = foldingModel.getRegionsInside(region, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);
|
||||
toToggle.push(...regionsInside);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let regionsInside = foldingModel.getRegionsInside(null, (r, level) => r.isCollapsed !== doCollapse && level < levels);
|
||||
let regionsInside = foldingModel.getRegionsInside(null, (r, level: number) => r.isCollapsed !== doCollapse && level < levels);
|
||||
toToggle.push(...regionsInside);
|
||||
}
|
||||
foldingModel.toggleCollapseState(toToggle);
|
||||
|
@ -270,7 +279,7 @@ export function setCollapseStateLevelsDown(foldingModel: FoldingModel, doCollaps
|
|||
* @param lineNumbers the location of the regions to collapse or expand, or if not set, all regions in the model.
|
||||
*/
|
||||
export function setCollapseStateLevelsUp(foldingModel: FoldingModel, doCollapse: boolean, levels: number, lineNumbers: number[]) {
|
||||
let toToggle = [];
|
||||
let toToggle: FoldingRegion[] = [];
|
||||
for (let lineNumber of lineNumbers) {
|
||||
let regions = foldingModel.getAllRegionsAtLine(lineNumber, (region, level) => region.isCollapsed !== doCollapse && level <= levels);
|
||||
toToggle.push(...regions);
|
||||
|
@ -297,7 +306,7 @@ export function setCollapseStateAtLevel(foldingModel: FoldingModel, foldLevel: n
|
|||
export function setCollapseStateForMatchingLines(foldingModel: FoldingModel, regExp: RegExp, doCollapse: boolean): void {
|
||||
let editorModel = foldingModel.textModel;
|
||||
let regions = foldingModel.regions;
|
||||
let toToggle = [];
|
||||
let toToggle: FoldingRegion[] = [];
|
||||
for (let i = regions.length - 1; i >= 0; i--) {
|
||||
if (doCollapse !== regions.isCollapsed(i)) {
|
||||
let startLineNumber = regions.getStartLineNumber(i);
|
||||
|
@ -315,7 +324,7 @@ export function setCollapseStateForMatchingLines(foldingModel: FoldingModel, reg
|
|||
*/
|
||||
export function setCollapseStateForType(foldingModel: FoldingModel, type: string, doCollapse: boolean): void {
|
||||
let regions = foldingModel.regions;
|
||||
let toToggle = [];
|
||||
let toToggle: FoldingRegion[] = [];
|
||||
for (let i = regions.length - 1; i >= 0; i--) {
|
||||
if (doCollapse !== regions.isCollapsed(i) && type === regions.getType(i)) {
|
||||
toToggle.push(regions.toRegion(i));
|
||||
|
|
|
@ -18,9 +18,9 @@ export class FoldingRegions {
|
|||
private _endIndexes: Uint32Array;
|
||||
private _collapseStates: Uint32Array;
|
||||
private _parentsComputed: boolean;
|
||||
private _types: string[] | undefined;
|
||||
private _types: (string | undefined)[] | undefined;
|
||||
|
||||
constructor(startIndexes: Uint32Array, endIndexes: Uint32Array, types?: string[]) {
|
||||
constructor(startIndexes: Uint32Array, endIndexes: Uint32Array, types?: (string | undefined)[]) {
|
||||
if (startIndexes.length !== endIndexes.length || startIndexes.length > MAX_FOLDING_REGIONS) {
|
||||
throw new Error('invalid startIndexes or endIndexes size');
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ export class FoldingRegions {
|
|||
private ensureParentIndices() {
|
||||
if (!this._parentsComputed) {
|
||||
this._parentsComputed = true;
|
||||
let parentIndexes = [];
|
||||
let parentIndexes: number[] = [];
|
||||
let isInsideLast = (startLineNumber: number, endLineNumber: number) => {
|
||||
let index = parentIndexes[parentIndexes.length - 1];
|
||||
return this.getStartLineNumber(index) <= startLineNumber && this.getEndLineNumber(index) >= endLineNumber;
|
||||
|
@ -144,7 +144,7 @@ export class FoldingRegions {
|
|||
}
|
||||
|
||||
public toString() {
|
||||
let res = [];
|
||||
let res: string[] = [];
|
||||
for (let i = 0; i < this.length; i++) {
|
||||
res[i] = `[${this.isCollapsed(i) ? '+' : '-'}] ${this.getStartLineNumber(i)}/${this.getEndLineNumber(i)}`;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import { findFirstInSorted } from 'vs/base/common/arrays';
|
|||
export class HiddenRangeModel {
|
||||
private _foldingModel: FoldingModel;
|
||||
private _hiddenRanges: IRange[];
|
||||
private _foldingModelListener: IDisposable;
|
||||
private _foldingModelListener: IDisposable | null;
|
||||
private _updateEventEmitter = new Emitter<IRange[]>();
|
||||
|
||||
public get onDidChange(): Event<IRange[]> { return this._updateEventEmitter.event; }
|
||||
|
@ -70,7 +70,7 @@ export class HiddenRangeModel {
|
|||
if (!Array.isArray(state) || state.length === 0) {
|
||||
return false;
|
||||
}
|
||||
let hiddenRanges = [];
|
||||
let hiddenRanges: IRange[] = [];
|
||||
for (let r of state) {
|
||||
if (!r.startLineNumber || !r.endLineNumber) {
|
||||
return false;
|
||||
|
@ -104,7 +104,7 @@ export class HiddenRangeModel {
|
|||
public adjustSelections(selections: Selection[]): boolean {
|
||||
let hasChanges = false;
|
||||
let editorModel = this._foldingModel.textModel;
|
||||
let lastRange = null;
|
||||
let lastRange: IRange | null = null;
|
||||
|
||||
let adjustLine = (line: number) => {
|
||||
if (!lastRange || !isInside(line, lastRange)) {
|
||||
|
@ -148,7 +148,7 @@ export class HiddenRangeModel {
|
|||
function isInside(line: number, range: IRange) {
|
||||
return line >= range.startLineNumber && line <= range.endLineNumber;
|
||||
}
|
||||
function findRange(ranges: IRange[], line: number): IRange {
|
||||
function findRange(ranges: IRange[], line: number): IRange | null {
|
||||
let i = findFirstInSorted(ranges, r => line < r.startLineNumber) - 1;
|
||||
if (i >= 0 && ranges[i].endLineNumber >= line) {
|
||||
return ranges[i];
|
||||
|
|
|
@ -28,7 +28,7 @@ export class IndentRangeProvider implements RangeProvider {
|
|||
|
||||
compute(cancelationToken: CancellationToken): Thenable<FoldingRegions> {
|
||||
let foldingRules = LanguageConfigurationRegistry.getFoldingRules(this.editorModel.getLanguageIdentifier().id);
|
||||
let offSide = foldingRules && foldingRules.offSide;
|
||||
let offSide = foldingRules && !!foldingRules.offSide;
|
||||
let markers = foldingRules && foldingRules.markers;
|
||||
return Promise.resolve(computeRanges(this.editorModel, offSide, markers));
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ export function computeRanges(model: ITextModel, offSide: boolean, markers?: Fol
|
|||
const tabSize = model.getOptions().tabSize;
|
||||
let result = new RangesCollector(foldingRangesLimit);
|
||||
|
||||
let pattern = void 0;
|
||||
let pattern: RegExp | undefined = void 0;
|
||||
if (markers) {
|
||||
pattern = new RegExp(`(${markers.start.source})|(?:${markers.end.source})`);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ export class SyntaxRangeProvider implements RangeProvider {
|
|||
constructor(private editorModel: ITextModel, private providers: FoldingRangeProvider[], private limit = MAX_FOLDING_REGIONS) {
|
||||
}
|
||||
|
||||
compute(cancellationToken: CancellationToken): Thenable<FoldingRegions> {
|
||||
compute(cancellationToken: CancellationToken): Thenable<FoldingRegions | null> {
|
||||
return collectSyntaxRanges(this.providers, this.editorModel, cancellationToken).then(ranges => {
|
||||
if (ranges) {
|
||||
let res = sanitizeRanges(ranges, this.limit);
|
||||
|
@ -73,7 +73,7 @@ export class RangesCollector {
|
|||
private _endIndexes: number[];
|
||||
private _nestingLevels: number[];
|
||||
private _nestingLevelCounts: number[];
|
||||
private _types: string[];
|
||||
private _types: (string | undefined)[];
|
||||
private _length: number;
|
||||
private _foldingRangesLimit: number;
|
||||
|
||||
|
@ -87,7 +87,7 @@ export class RangesCollector {
|
|||
this._foldingRangesLimit = foldingRangesLimit;
|
||||
}
|
||||
|
||||
public add(startLineNumber: number, endLineNumber: number, type: string, nestingLevel: number) {
|
||||
public add(startLineNumber: number, endLineNumber: number, type: string | undefined, nestingLevel: number) {
|
||||
if (startLineNumber > MAX_LINE_NUMBER || endLineNumber > MAX_LINE_NUMBER) {
|
||||
return;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ export class RangesCollector {
|
|||
|
||||
let startIndexes = new Uint32Array(this._foldingRangesLimit);
|
||||
let endIndexes = new Uint32Array(this._foldingRangesLimit);
|
||||
let types = [];
|
||||
let types: (string | undefined)[] = [];
|
||||
for (let i = 0, k = 0; i < this._length; i++) {
|
||||
let level = this._nestingLevels[i];
|
||||
if (level < maxLevel || (level === maxLevel && entries++ < this._foldingRangesLimit)) {
|
||||
|
@ -155,8 +155,8 @@ export function sanitizeRanges(rangeData: IFoldingRangeData[], limit: number): F
|
|||
});
|
||||
let collector = new RangesCollector(limit);
|
||||
|
||||
let top: IFoldingRangeData | null = null;
|
||||
let previous = [];
|
||||
let top: IFoldingRangeData | undefined = void 0;
|
||||
let previous: IFoldingRangeData[] = [];
|
||||
for (let entry of sorted) {
|
||||
if (!top) {
|
||||
top = entry;
|
||||
|
|
|
@ -38,7 +38,7 @@ export class TestDecorationProvider {
|
|||
return this.model.deltaDecorations(oldDecorations, newDecorations);
|
||||
}
|
||||
|
||||
changeDecorations<T>(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): T {
|
||||
changeDecorations<T>(callback: (changeAccessor: IModelDecorationsChangeAccessor) => T): (T | null) {
|
||||
return this.model.changeDecorations(callback);
|
||||
}
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ suite('Folding Model', () => {
|
|||
return { startLineNumber, endLineNumber, isCollapsed };
|
||||
}
|
||||
|
||||
function assertRegion(actual: FoldingRegion, expected: ExpectedRegion, message?: string) {
|
||||
function assertRegion(actual: FoldingRegion | null, expected: ExpectedRegion | null, message?: string) {
|
||||
assert.equal(!!actual, !!expected, message);
|
||||
if (actual) {
|
||||
if (actual && expected) {
|
||||
assert.equal(actual.startLineNumber, expected.startLineNumber, message);
|
||||
assert.equal(actual.endLineNumber, expected.endLineNumber, message);
|
||||
assert.equal(actual.isCollapsed, expected.isCollapsed, message);
|
||||
|
@ -58,7 +58,7 @@ suite('Folding Model', () => {
|
|||
}
|
||||
|
||||
function assertFoldedRanges(foldingModel: FoldingModel, expectedRegions: ExpectedRegion[], message?: string) {
|
||||
let actualRanges = [];
|
||||
let actualRanges: ExpectedRegion[] = [];
|
||||
let actual = foldingModel.regions;
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
if (actual.isCollapsed(i)) {
|
||||
|
@ -69,7 +69,7 @@ suite('Folding Model', () => {
|
|||
}
|
||||
|
||||
function assertRanges(foldingModel: FoldingModel, expectedRegions: ExpectedRegion[], message?: string) {
|
||||
let actualRanges = [];
|
||||
let actualRanges: ExpectedRegion[] = [];
|
||||
let actual = foldingModel.regions;
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
actualRanges.push(r(actual.getStartLineNumber(i), actual.getEndLineNumber(i), actual.isCollapsed(i)));
|
||||
|
@ -96,7 +96,7 @@ suite('Folding Model', () => {
|
|||
try {
|
||||
let foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel));
|
||||
|
||||
let ranges = computeRanges(textModel, false, null);
|
||||
let ranges = computeRanges(textModel, false, void 0);
|
||||
foldingModel.update(ranges);
|
||||
|
||||
let r1 = r(1, 3, false);
|
||||
|
@ -135,7 +135,7 @@ suite('Folding Model', () => {
|
|||
try {
|
||||
let foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel));
|
||||
|
||||
let ranges = computeRanges(textModel, false, null);
|
||||
let ranges = computeRanges(textModel, false, void 0);
|
||||
foldingModel.update(ranges);
|
||||
|
||||
let r1 = r(1, 3, false);
|
||||
|
@ -144,17 +144,17 @@ suite('Folding Model', () => {
|
|||
|
||||
assertRanges(foldingModel, [r1, r2, r3]);
|
||||
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1)]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1)!]);
|
||||
foldingModel.update(ranges);
|
||||
|
||||
assertRanges(foldingModel, [r(1, 3, true), r2, r3]);
|
||||
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(5)]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(5)!]);
|
||||
foldingModel.update(ranges);
|
||||
|
||||
assertRanges(foldingModel, [r(1, 3, true), r2, r(5, 6, true)]);
|
||||
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(7)]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(7)!]);
|
||||
foldingModel.update(ranges);
|
||||
|
||||
assertRanges(foldingModel, [r(1, 3, true), r(4, 7, true), r(5, 6, true)]);
|
||||
|
@ -181,7 +181,7 @@ suite('Folding Model', () => {
|
|||
try {
|
||||
let foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel));
|
||||
|
||||
let ranges = computeRanges(textModel, false, null);
|
||||
let ranges = computeRanges(textModel, false, void 0);
|
||||
foldingModel.update(ranges);
|
||||
|
||||
let r1 = r(1, 3, false);
|
||||
|
@ -189,11 +189,11 @@ suite('Folding Model', () => {
|
|||
let r3 = r(5, 6, false);
|
||||
|
||||
assertRanges(foldingModel, [r1, r2, r3]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(2), foldingModel.getRegionAtLine(5)]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(2)!, foldingModel.getRegionAtLine(5)!]);
|
||||
|
||||
textModel.applyEdits([EditOperation.insert(new Position(4, 1), '//hello\n')]);
|
||||
|
||||
foldingModel.update(computeRanges(textModel, false, null));
|
||||
foldingModel.update(computeRanges(textModel, false, void 0));
|
||||
|
||||
assertRanges(foldingModel, [r(1, 3, true), r(5, 8, false), r(6, 7, true)]);
|
||||
} finally {
|
||||
|
@ -221,7 +221,7 @@ suite('Folding Model', () => {
|
|||
try {
|
||||
let foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel));
|
||||
|
||||
let ranges = computeRanges(textModel, false, null);
|
||||
let ranges = computeRanges(textModel, false, void 0);
|
||||
foldingModel.update(ranges);
|
||||
|
||||
let r1 = r(1, 12, false);
|
||||
|
@ -231,11 +231,11 @@ suite('Folding Model', () => {
|
|||
let r5 = r(9, 11, false);
|
||||
|
||||
assertRanges(foldingModel, [r1, r2, r3, r4, r5]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(6)]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(6)!]);
|
||||
|
||||
textModel.applyEdits([EditOperation.delete(new Range(6, 11, 9, 0))]);
|
||||
|
||||
foldingModel.update(computeRanges(textModel, false, null));
|
||||
foldingModel.update(computeRanges(textModel, false, void 0));
|
||||
|
||||
assertRanges(foldingModel, [r(1, 9, false), r(2, 8, false), r(3, 5, false), r(6, 8, false)]);
|
||||
} finally {
|
||||
|
@ -258,7 +258,7 @@ suite('Folding Model', () => {
|
|||
try {
|
||||
let foldingModel = new FoldingModel(textModel, new TestDecorationProvider(textModel));
|
||||
|
||||
let ranges = computeRanges(textModel, false, null);
|
||||
let ranges = computeRanges(textModel, false, void 0);
|
||||
foldingModel.update(ranges);
|
||||
|
||||
let r1 = r(1, 3, false);
|
||||
|
|
|
@ -18,7 +18,7 @@ let markers: FoldingMarkers = {
|
|||
suite('FoldingRanges', () => {
|
||||
|
||||
test('test max folding regions', () => {
|
||||
let lines = [];
|
||||
let lines: string[] = [];
|
||||
let nRegions = MAX_FOLDING_REGIONS;
|
||||
for (let i = 0; i < nRegions; i++) {
|
||||
lines.push('#region');
|
||||
|
@ -83,7 +83,7 @@ suite('FoldingRanges', () => {
|
|||
});
|
||||
|
||||
test('setCollapsed', () => {
|
||||
let lines = [];
|
||||
let lines: string[] = [];
|
||||
let nRegions = 500;
|
||||
for (let i = 0; i < nRegions; i++) {
|
||||
lines.push('#region');
|
||||
|
|
|
@ -44,10 +44,10 @@ suite('Hidden Range Model', () => {
|
|||
|
||||
assert.equal(hiddenRangeModel.hasRanges(), false);
|
||||
|
||||
let ranges = computeRanges(textModel, false, null);
|
||||
let ranges = computeRanges(textModel, false, void 0);
|
||||
foldingModel.update(ranges);
|
||||
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1), foldingModel.getRegionAtLine(6)]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1)!, foldingModel.getRegionAtLine(6)!]);
|
||||
assertRanges(hiddenRangeModel.hiddenRanges, [r(2, 3), r(7, 7)]);
|
||||
|
||||
assert.equal(hiddenRangeModel.hasRanges(), true);
|
||||
|
@ -62,7 +62,7 @@ suite('Hidden Range Model', () => {
|
|||
assert.equal(hiddenRangeModel.isHidden(9), false);
|
||||
assert.equal(hiddenRangeModel.isHidden(10), false);
|
||||
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(4)]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(4)!]);
|
||||
assertRanges(hiddenRangeModel.hiddenRanges, [r(2, 3), r(5, 9)]);
|
||||
|
||||
assert.equal(hiddenRangeModel.hasRanges(), true);
|
||||
|
@ -77,7 +77,7 @@ suite('Hidden Range Model', () => {
|
|||
assert.equal(hiddenRangeModel.isHidden(9), true);
|
||||
assert.equal(hiddenRangeModel.isHidden(10), false);
|
||||
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1), foldingModel.getRegionAtLine(6), foldingModel.getRegionAtLine(4)]);
|
||||
foldingModel.toggleCollapseState([foldingModel.getRegionAtLine(1)!, foldingModel.getRegionAtLine(6)!, foldingModel.getRegionAtLine(4)!]);
|
||||
assertRanges(hiddenRangeModel.hiddenRanges, []);
|
||||
assert.equal(hiddenRangeModel.hasRanges(), false);
|
||||
assert.equal(hiddenRangeModel.isHidden(1), false);
|
||||
|
|
|
@ -50,9 +50,9 @@ suite('Indentation Folding', () => {
|
|||
let model = TextModel.createFromString(lines.join('\n'));
|
||||
|
||||
function assertLimit(maxEntries: number, expectedRanges: IndentRange[], message: string) {
|
||||
let indentRanges = computeRanges(model, true, null, maxEntries);
|
||||
let indentRanges = computeRanges(model, true, undefined, maxEntries);
|
||||
assert.ok(indentRanges.length <= maxEntries, 'max ' + message);
|
||||
let actual = [];
|
||||
let actual: IndentRange[] = [];
|
||||
for (let i = 0; i < indentRanges.length; i++) {
|
||||
actual.push({ start: indentRanges.getStartLineNumber(i), end: indentRanges.getEndLineNumber(i) });
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ function assertRanges(lines: string[], expected: ExpectedIndentRange[], offside:
|
|||
let model = TextModel.createFromString(lines.join('\n'));
|
||||
let actual = computeRanges(model, offside, markers);
|
||||
|
||||
let actualRanges = [];
|
||||
let actualRanges: ExpectedIndentRange[] = [];
|
||||
for (let i = 0; i < actual.length; i++) {
|
||||
actualRanges[i] = r(actual.getStartLineNumber(i), actual.getEndLineNumber(i), actual.getParentIndex(i));
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import * as assert from 'assert';
|
||||
import { TextModel } from 'vs/editor/common/model/textModel';
|
||||
import { SyntaxRangeProvider } from 'vs/editor/contrib/folding/syntaxRangeProvider';
|
||||
import { FoldingRangeProvider, FoldingRange, FoldingContext } from 'vs/editor/common/modes';
|
||||
import { FoldingRangeProvider, FoldingRange, FoldingContext, ProviderResult } from 'vs/editor/common/modes';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
||||
|
@ -18,7 +18,7 @@ class TestFoldingRangeProvider implements FoldingRangeProvider {
|
|||
constructor(private model: ITextModel, private ranges: IndentRange[]) {
|
||||
}
|
||||
|
||||
provideFoldingRanges(model: ITextModel, context: FoldingContext, token: CancellationToken): FoldingRange[] {
|
||||
provideFoldingRanges(model: ITextModel, context: FoldingContext, token: CancellationToken): ProviderResult<FoldingRange[]> {
|
||||
if (model === this.model) {
|
||||
return this.ranges;
|
||||
}
|
||||
|
@ -75,10 +75,12 @@ suite('Syntax folding', () => {
|
|||
|
||||
async function assertLimit(maxEntries: number, expectedRanges: IndentRange[], message: string) {
|
||||
let indentRanges = await new SyntaxRangeProvider(model, providers, maxEntries).compute(CancellationToken.None);
|
||||
let actual = [];
|
||||
let actual: IndentRange[] = [];
|
||||
if (indentRanges) {
|
||||
for (let i = 0; i < indentRanges.length; i++) {
|
||||
actual.push({ start: indentRanges.getStartLineNumber(i), end: indentRanges.getEndLineNumber(i) });
|
||||
}
|
||||
}
|
||||
assert.deepEqual(actual, expectedRanges, message);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue