UNPKG

monaco-editor-core

Version:

A browser based code editor

124 lines (123 loc) 5.2 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { findFirstIdxMonotonousOrArrLen } from '../../../../base/common/arraysFind.js'; import { Emitter } from '../../../../base/common/event.js'; import { Range } from '../../../common/core/range.js'; import { countEOL } from '../../../common/core/eolCounter.js'; export class HiddenRangeModel { get onDidChange() { return this._updateEventEmitter.event; } get hiddenRanges() { return this._hiddenRanges; } constructor(model) { this._updateEventEmitter = new Emitter(); this._hasLineChanges = false; this._foldingModel = model; this._foldingModelListener = model.onDidChange(_ => this.updateHiddenRanges()); this._hiddenRanges = []; if (model.regions.length) { this.updateHiddenRanges(); } } notifyChangeModelContent(e) { if (this._hiddenRanges.length && !this._hasLineChanges) { this._hasLineChanges = e.changes.some(change => { return change.range.endLineNumber !== change.range.startLineNumber || countEOL(change.text)[0] !== 0; }); } } updateHiddenRanges() { let updateHiddenAreas = false; const newHiddenAreas = []; let i = 0; // index into hidden let k = 0; let lastCollapsedStart = Number.MAX_VALUE; let lastCollapsedEnd = -1; const ranges = this._foldingModel.regions; for (; i < ranges.length; i++) { if (!ranges.isCollapsed(i)) { continue; } const startLineNumber = ranges.getStartLineNumber(i) + 1; // the first line is not hidden const endLineNumber = ranges.getEndLineNumber(i); if (lastCollapsedStart <= startLineNumber && endLineNumber <= lastCollapsedEnd) { // ignore ranges contained in collapsed regions continue; } if (!updateHiddenAreas && k < this._hiddenRanges.length && this._hiddenRanges[k].startLineNumber === startLineNumber && this._hiddenRanges[k].endLineNumber === endLineNumber) { // reuse the old ranges newHiddenAreas.push(this._hiddenRanges[k]); k++; } else { updateHiddenAreas = true; newHiddenAreas.push(new Range(startLineNumber, 1, endLineNumber, 1)); } lastCollapsedStart = startLineNumber; lastCollapsedEnd = endLineNumber; } if (this._hasLineChanges || updateHiddenAreas || k < this._hiddenRanges.length) { this.applyHiddenRanges(newHiddenAreas); } } applyHiddenRanges(newHiddenAreas) { this._hiddenRanges = newHiddenAreas; this._hasLineChanges = false; this._updateEventEmitter.fire(newHiddenAreas); } hasRanges() { return this._hiddenRanges.length > 0; } isHidden(line) { return findRange(this._hiddenRanges, line) !== null; } adjustSelections(selections) { let hasChanges = false; const editorModel = this._foldingModel.textModel; let lastRange = null; const adjustLine = (line) => { if (!lastRange || !isInside(line, lastRange)) { lastRange = findRange(this._hiddenRanges, line); } if (lastRange) { return lastRange.startLineNumber - 1; } return null; }; for (let i = 0, len = selections.length; i < len; i++) { let selection = selections[i]; const adjustedStartLine = adjustLine(selection.startLineNumber); if (adjustedStartLine) { selection = selection.setStartPosition(adjustedStartLine, editorModel.getLineMaxColumn(adjustedStartLine)); hasChanges = true; } const adjustedEndLine = adjustLine(selection.endLineNumber); if (adjustedEndLine) { selection = selection.setEndPosition(adjustedEndLine, editorModel.getLineMaxColumn(adjustedEndLine)); hasChanges = true; } selections[i] = selection; } return hasChanges; } dispose() { if (this.hiddenRanges.length > 0) { this._hiddenRanges = []; this._updateEventEmitter.fire(this._hiddenRanges); } if (this._foldingModelListener) { this._foldingModelListener.dispose(); this._foldingModelListener = null; } } } function isInside(line, range) { return line >= range.startLineNumber && line <= range.endLineNumber; } function findRange(ranges, line) { const i = findFirstIdxMonotonousOrArrLen(ranges, r => line < r.startLineNumber) - 1; if (i >= 0 && ranges[i].endLineNumber >= line) { return ranges[i]; } return null; }