1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
- return c > 3 && r && Object.defineProperty(target, key, r), r;
- };
- var __param = (this && this.__param) || function (paramIndex, decorator) {
- return function (target, key) { decorator(target, key, paramIndex); }
- };
- import { onUnexpectedError } from '../../../base/common/errors.js';
- import { Emitter } from '../../../base/common/event.js';
- import { Disposable } from '../../../base/common/lifecycle.js';
- import * as strings from '../../../base/common/strings.js';
- import { URI } from '../../../base/common/uri.js';
- import { EDITOR_MODEL_DEFAULTS } from '../config/editorOptions.js';
- import { Position } from '../core/position.js';
- import { Range } from '../core/range.js';
- import { Selection } from '../core/selection.js';
- import * as model from '../model.js';
- import { EditStack } from './editStack.js';
- import { guessIndentation } from './indentationGuesser.js';
- import { IntervalNode, IntervalTree, recomputeMaxEnd } from './intervalTree.js';
- import { PieceTreeTextBufferBuilder } from './pieceTreeTextBuffer/pieceTreeTextBufferBuilder.js';
- import { InternalModelContentChangeEvent, LineInjectedText, ModelInjectedTextChangedEvent, ModelRawContentChangedEvent, ModelRawEOLChanged, ModelRawFlush, ModelRawLineChanged, ModelRawLinesDeleted, ModelRawLinesInserted } from './textModelEvents.js';
- import { SearchParams, TextModelSearch } from './textModelSearch.js';
- import { TextModelTokenization } from './textModelTokens.js';
- import { getWordAtText } from './wordHelper.js';
- import { ILanguageConfigurationService } from '../modes/languageConfigurationRegistry.js';
- import { NULL_MODE_ID } from '../modes/nullMode.js';
- import { TokensStore, countEOL, TokensStore2 } from './tokensStore.js';
- import { Color } from '../../../base/common/color.js';
- import { IUndoRedoService } from '../../../platform/undoRedo/common/undoRedo.js';
- import { PieceTreeTextBuffer } from './pieceTreeTextBuffer/pieceTreeTextBuffer.js';
- import { ArrayQueue, findLast } from '../../../base/common/arrays.js';
- import { BracketPairs } from './bracketPairs/bracketPairsImpl.js';
- import { ColorizedBracketPairsDecorationProvider } from './bracketPairs/colorizedBracketPairsDecorationProvider.js';
- import { CursorColumns } from '../controller/cursorColumns.js';
- import { IModeService } from '../services/modeService.js';
- function createTextBufferBuilder() {
- return new PieceTreeTextBufferBuilder();
- }
- export function createTextBufferFactory(text) {
- const builder = createTextBufferBuilder();
- builder.acceptChunk(text);
- return builder.finish();
- }
- export function createTextBuffer(value, defaultEOL) {
- const factory = (typeof value === 'string' ? createTextBufferFactory(value) : value);
- return factory.create(defaultEOL);
- }
- let MODEL_ID = 0;
- const LIMIT_FIND_COUNT = 999;
- export const LONG_LINE_BOUNDARY = 10000;
- class TextModelSnapshot {
- constructor(source) {
- this._source = source;
- this._eos = false;
- }
- read() {
- if (this._eos) {
- return null;
- }
- let result = [], resultCnt = 0, resultLength = 0;
- do {
- let tmp = this._source.read();
- if (tmp === null) {
- // end-of-stream
- this._eos = true;
- if (resultCnt === 0) {
- return null;
- }
- else {
- return result.join('');
- }
- }
- if (tmp.length > 0) {
- result[resultCnt++] = tmp;
- resultLength += tmp.length;
- }
- if (resultLength >= 64 * 1024) {
- return result.join('');
- }
- } while (true);
- }
- }
- const invalidFunc = () => { throw new Error(`Invalid change accessor`); };
- let TextModel = class TextModel extends Disposable {
- constructor(source, creationOptions, languageId, associatedResource = null, _undoRedoService, _modeService, _languageConfigurationService) {
- super();
- this._undoRedoService = _undoRedoService;
- this._modeService = _modeService;
- this._languageConfigurationService = _languageConfigurationService;
- //#region Events
- this._onWillDispose = this._register(new Emitter());
- this.onWillDispose = this._onWillDispose.event;
- this._onDidChangeDecorations = this._register(new DidChangeDecorationsEmitter(affectedInjectedTextLines => this.handleBeforeFireDecorationsChangedEvent(affectedInjectedTextLines)));
- this.onDidChangeDecorations = this._onDidChangeDecorations.event;
- this._onDidChangeLanguage = this._register(new Emitter());
- this.onDidChangeLanguage = this._onDidChangeLanguage.event;
- this._onDidChangeLanguageConfiguration = this._register(new Emitter());
- this.onDidChangeLanguageConfiguration = this._onDidChangeLanguageConfiguration.event;
- this._onDidChangeTokens = this._register(new Emitter());
- this.onDidChangeTokens = this._onDidChangeTokens.event;
- this._onDidChangeOptions = this._register(new Emitter());
- this.onDidChangeOptions = this._onDidChangeOptions.event;
- this._onDidChangeAttached = this._register(new Emitter());
- this.onDidChangeAttached = this._onDidChangeAttached.event;
- this._onDidChangeContentOrInjectedText = this._register(new Emitter());
- this.onDidChangeContentOrInjectedText = this._onDidChangeContentOrInjectedText.event;
- this._eventEmitter = this._register(new DidChangeContentEmitter());
- this._backgroundTokenizationState = 0 /* Uninitialized */;
- this._onBackgroundTokenizationStateChanged = this._register(new Emitter());
- this.onBackgroundTokenizationStateChanged = this._onBackgroundTokenizationStateChanged.event;
- this._register(this._eventEmitter.fastEvent((e) => {
- this._onDidChangeContentOrInjectedText.fire(e.rawContentChangedEvent);
- }));
- // Generate a new unique model id
- MODEL_ID++;
- this.id = '$model' + MODEL_ID;
- this.isForSimpleWidget = creationOptions.isForSimpleWidget;
- if (typeof associatedResource === 'undefined' || associatedResource === null) {
- this._associatedResource = URI.parse('inmemory://model/' + MODEL_ID);
- }
- else {
- this._associatedResource = associatedResource;
- }
- this._attachedEditorCount = 0;
- const { textBuffer, disposable } = createTextBuffer(source, creationOptions.defaultEOL);
- this._buffer = textBuffer;
- this._bufferDisposable = disposable;
- this._options = TextModel.resolveOptions(this._buffer, creationOptions);
- const bufferLineCount = this._buffer.getLineCount();
- const bufferTextLength = this._buffer.getValueLengthInRange(new Range(1, 1, bufferLineCount, this._buffer.getLineLength(bufferLineCount) + 1), 0 /* TextDefined */);
- // !!! Make a decision in the ctor and permanently respect this decision !!!
- // If a model is too large at construction time, it will never get tokenized,
- // under no circumstances.
- if (creationOptions.largeFileOptimizations) {
- this._isTooLargeForTokenization = ((bufferTextLength > TextModel.LARGE_FILE_SIZE_THRESHOLD)
- || (bufferLineCount > TextModel.LARGE_FILE_LINE_COUNT_THRESHOLD));
- }
- else {
- this._isTooLargeForTokenization = false;
- }
- this._isTooLargeForSyncing = (bufferTextLength > TextModel.MODEL_SYNC_LIMIT);
- this._versionId = 1;
- this._alternativeVersionId = 1;
- this._initialUndoRedoSnapshot = null;
- this._isDisposed = false;
- this._isDisposing = false;
- this._languageId = languageId || NULL_MODE_ID;
- this._languageRegistryListener = this._languageConfigurationService.onDidChange(e => {
- if (e.affects(this._languageId)) {
- this._onDidChangeLanguageConfiguration.fire({});
- }
- });
- this._instanceId = strings.singleLetterHash(MODEL_ID);
- this._lastDecorationId = 0;
- this._decorations = Object.create(null);
- this._decorationsTree = new DecorationsTrees();
- this._commandManager = new EditStack(this, this._undoRedoService);
- this._isUndoing = false;
- this._isRedoing = false;
- this._trimAutoWhitespaceLines = null;
- this._tokens = new TokensStore(this._modeService.languageIdCodec);
- this._tokens2 = new TokensStore2(this._modeService.languageIdCodec);
- this._tokenization = new TextModelTokenization(this, this._modeService.languageIdCodec);
- this._bracketPairColorizer = this._register(new BracketPairs(this, this._languageConfigurationService));
- this._decorationProvider = this._register(new ColorizedBracketPairsDecorationProvider(this));
- this._register(this._decorationProvider.onDidChange(() => {
- this._onDidChangeDecorations.beginDeferredEmit();
- this._onDidChangeDecorations.fire();
- this._onDidChangeDecorations.endDeferredEmit();
- }));
- }
- static resolveOptions(textBuffer, options) {
- if (options.detectIndentation) {
- const guessedIndentation = guessIndentation(textBuffer, options.tabSize, options.insertSpaces);
- return new model.TextModelResolvedOptions({
- tabSize: guessedIndentation.tabSize,
- indentSize: guessedIndentation.tabSize,
- insertSpaces: guessedIndentation.insertSpaces,
- trimAutoWhitespace: options.trimAutoWhitespace,
- defaultEOL: options.defaultEOL,
- bracketPairColorizationOptions: options.bracketPairColorizationOptions,
- });
- }
- return new model.TextModelResolvedOptions({
- tabSize: options.tabSize,
- indentSize: options.indentSize,
- insertSpaces: options.insertSpaces,
- trimAutoWhitespace: options.trimAutoWhitespace,
- defaultEOL: options.defaultEOL,
- bracketPairColorizationOptions: options.bracketPairColorizationOptions,
- });
- }
- onDidChangeContentFast(listener) {
- return this._eventEmitter.fastEvent((e) => listener(e.contentChangedEvent));
- }
- onDidChangeContent(listener) {
- return this._eventEmitter.slowEvent((e) => listener(e.contentChangedEvent));
- }
- get bracketPairs() { return this._bracketPairColorizer; }
- get backgroundTokenizationState() {
- return this._backgroundTokenizationState;
- }
- handleTokenizationProgress(completed) {
- if (this._backgroundTokenizationState === 2 /* Completed */) {
- // We already did a full tokenization and don't go back to progressing.
- return;
- }
- const newState = completed ? 2 /* Completed */ : 1 /* InProgress */;
- if (this._backgroundTokenizationState !== newState) {
- this._backgroundTokenizationState = newState;
- this._onBackgroundTokenizationStateChanged.fire();
- }
- }
- dispose() {
- this._isDisposing = true;
- this._onWillDispose.fire();
- this._languageRegistryListener.dispose();
- this._tokenization.dispose();
- this._isDisposed = true;
- super.dispose();
- this._bufferDisposable.dispose();
- this._isDisposing = false;
- // Manually release reference to previous text buffer to avoid large leaks
- // in case someone leaks a TextModel reference
- const emptyDisposedTextBuffer = new PieceTreeTextBuffer([], '', '\n', false, false, true, true);
- emptyDisposedTextBuffer.dispose();
- this._buffer = emptyDisposedTextBuffer;
- }
- _assertNotDisposed() {
- if (this._isDisposed) {
- throw new Error('Model is disposed!');
- }
- }
- _emitContentChangedEvent(rawChange, change) {
- this._bracketPairColorizer.handleContentChanged(change);
- if (this._isDisposing) {
- // Do not confuse listeners by emitting any event after disposing
- return;
- }
- this._eventEmitter.fire(new InternalModelContentChangeEvent(rawChange, change));
- }
- setValue(value) {
- this._assertNotDisposed();
- if (value === null) {
- // There's nothing to do
- return;
- }
- const { textBuffer, disposable } = createTextBuffer(value, this._options.defaultEOL);
- this._setValueFromTextBuffer(textBuffer, disposable);
- }
- _createContentChanged2(range, rangeOffset, rangeLength, text, isUndoing, isRedoing, isFlush) {
- return {
- changes: [{
- range: range,
- rangeOffset: rangeOffset,
- rangeLength: rangeLength,
- text: text,
- }],
- eol: this._buffer.getEOL(),
- versionId: this.getVersionId(),
- isUndoing: isUndoing,
- isRedoing: isRedoing,
- isFlush: isFlush
- };
- }
- _setValueFromTextBuffer(textBuffer, textBufferDisposable) {
- this._assertNotDisposed();
- const oldFullModelRange = this.getFullModelRange();
- const oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);
- const endLineNumber = this.getLineCount();
- const endColumn = this.getLineMaxColumn(endLineNumber);
- this._buffer = textBuffer;
- this._bufferDisposable.dispose();
- this._bufferDisposable = textBufferDisposable;
- this._increaseVersionId();
- // Flush all tokens
- this._tokens.flush();
- this._tokens2.flush();
- // Destroy all my decorations
- this._decorations = Object.create(null);
- this._decorationsTree = new DecorationsTrees();
- // Destroy my edit history and settings
- this._commandManager.clear();
- this._trimAutoWhitespaceLines = null;
- this._emitContentChangedEvent(new ModelRawContentChangedEvent([
- new ModelRawFlush()
- ], this._versionId, false, false), this._createContentChanged2(new Range(1, 1, endLineNumber, endColumn), 0, oldModelValueLength, this.getValue(), false, false, true));
- }
- setEOL(eol) {
- this._assertNotDisposed();
- const newEOL = (eol === 1 /* CRLF */ ? '\r\n' : '\n');
- if (this._buffer.getEOL() === newEOL) {
- // Nothing to do
- return;
- }
- const oldFullModelRange = this.getFullModelRange();
- const oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);
- const endLineNumber = this.getLineCount();
- const endColumn = this.getLineMaxColumn(endLineNumber);
- this._onBeforeEOLChange();
- this._buffer.setEOL(newEOL);
- this._increaseVersionId();
- this._onAfterEOLChange();
- this._emitContentChangedEvent(new ModelRawContentChangedEvent([
- new ModelRawEOLChanged()
- ], this._versionId, false, false), this._createContentChanged2(new Range(1, 1, endLineNumber, endColumn), 0, oldModelValueLength, this.getValue(), false, false, false));
- }
- _onBeforeEOLChange() {
- // Ensure all decorations get their `range` set.
- this._decorationsTree.ensureAllNodesHaveRanges(this);
- }
- _onAfterEOLChange() {
- // Transform back `range` to offsets
- const versionId = this.getVersionId();
- const allDecorations = this._decorationsTree.collectNodesPostOrder();
- for (let i = 0, len = allDecorations.length; i < len; i++) {
- const node = allDecorations[i];
- const range = node.range; // the range is defined due to `_onBeforeEOLChange`
- const delta = node.cachedAbsoluteStart - node.start;
- const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
- const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
- node.cachedAbsoluteStart = startOffset;
- node.cachedAbsoluteEnd = endOffset;
- node.cachedVersionId = versionId;
- node.start = startOffset - delta;
- node.end = endOffset - delta;
- recomputeMaxEnd(node);
- }
- }
- onBeforeAttached() {
- this._attachedEditorCount++;
- if (this._attachedEditorCount === 1) {
- this._onDidChangeAttached.fire(undefined);
- }
- }
- onBeforeDetached() {
- this._attachedEditorCount--;
- if (this._attachedEditorCount === 0) {
- this._onDidChangeAttached.fire(undefined);
- }
- }
- isAttachedToEditor() {
- return this._attachedEditorCount > 0;
- }
- getAttachedEditorCount() {
- return this._attachedEditorCount;
- }
- isTooLargeForSyncing() {
- return this._isTooLargeForSyncing;
- }
- isTooLargeForTokenization() {
- return this._isTooLargeForTokenization;
- }
- isDisposed() {
- return this._isDisposed;
- }
- isDominatedByLongLines() {
- this._assertNotDisposed();
- if (this.isTooLargeForTokenization()) {
- // Cannot word wrap huge files anyways, so it doesn't really matter
- return false;
- }
- let smallLineCharCount = 0;
- let longLineCharCount = 0;
- const lineCount = this._buffer.getLineCount();
- for (let lineNumber = 1; lineNumber <= lineCount; lineNumber++) {
- const lineLength = this._buffer.getLineLength(lineNumber);
- if (lineLength >= LONG_LINE_BOUNDARY) {
- longLineCharCount += lineLength;
- }
- else {
- smallLineCharCount += lineLength;
- }
- }
- return (longLineCharCount > smallLineCharCount);
- }
- get uri() {
- return this._associatedResource;
- }
- //#region Options
- getOptions() {
- this._assertNotDisposed();
- return this._options;
- }
- getFormattingOptions() {
- return {
- tabSize: this._options.indentSize,
- insertSpaces: this._options.insertSpaces
- };
- }
- updateOptions(_newOpts) {
- this._assertNotDisposed();
- let tabSize = (typeof _newOpts.tabSize !== 'undefined') ? _newOpts.tabSize : this._options.tabSize;
- let indentSize = (typeof _newOpts.indentSize !== 'undefined') ? _newOpts.indentSize : this._options.indentSize;
- let insertSpaces = (typeof _newOpts.insertSpaces !== 'undefined') ? _newOpts.insertSpaces : this._options.insertSpaces;
- let trimAutoWhitespace = (typeof _newOpts.trimAutoWhitespace !== 'undefined') ? _newOpts.trimAutoWhitespace : this._options.trimAutoWhitespace;
- let bracketPairColorizationOptions = (typeof _newOpts.bracketColorizationOptions !== 'undefined') ? _newOpts.bracketColorizationOptions : this._options.bracketPairColorizationOptions;
- let newOpts = new model.TextModelResolvedOptions({
- tabSize: tabSize,
- indentSize: indentSize,
- insertSpaces: insertSpaces,
- defaultEOL: this._options.defaultEOL,
- trimAutoWhitespace: trimAutoWhitespace,
- bracketPairColorizationOptions,
- });
- if (this._options.equals(newOpts)) {
- return;
- }
- let e = this._options.createChangeEvent(newOpts);
- this._options = newOpts;
- this._onDidChangeOptions.fire(e);
- }
- detectIndentation(defaultInsertSpaces, defaultTabSize) {
- this._assertNotDisposed();
- let guessedIndentation = guessIndentation(this._buffer, defaultTabSize, defaultInsertSpaces);
- this.updateOptions({
- insertSpaces: guessedIndentation.insertSpaces,
- tabSize: guessedIndentation.tabSize,
- indentSize: guessedIndentation.tabSize, // TODO@Alex: guess indentSize independent of tabSize
- });
- }
- static _normalizeIndentationFromWhitespace(str, indentSize, insertSpaces) {
- let spacesCnt = 0;
- for (let i = 0; i < str.length; i++) {
- if (str.charAt(i) === '\t') {
- spacesCnt += indentSize;
- }
- else {
- spacesCnt++;
- }
- }
- let result = '';
- if (!insertSpaces) {
- let tabsCnt = Math.floor(spacesCnt / indentSize);
- spacesCnt = spacesCnt % indentSize;
- for (let i = 0; i < tabsCnt; i++) {
- result += '\t';
- }
- }
- for (let i = 0; i < spacesCnt; i++) {
- result += ' ';
- }
- return result;
- }
- static normalizeIndentation(str, indentSize, insertSpaces) {
- let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(str);
- if (firstNonWhitespaceIndex === -1) {
- firstNonWhitespaceIndex = str.length;
- }
- return TextModel._normalizeIndentationFromWhitespace(str.substring(0, firstNonWhitespaceIndex), indentSize, insertSpaces) + str.substring(firstNonWhitespaceIndex);
- }
- normalizeIndentation(str) {
- this._assertNotDisposed();
- return TextModel.normalizeIndentation(str, this._options.indentSize, this._options.insertSpaces);
- }
- //#endregion
- //#region Reading
- getVersionId() {
- this._assertNotDisposed();
- return this._versionId;
- }
- mightContainRTL() {
- return this._buffer.mightContainRTL();
- }
- mightContainUnusualLineTerminators() {
- return this._buffer.mightContainUnusualLineTerminators();
- }
- removeUnusualLineTerminators(selections = null) {
- const matches = this.findMatches(strings.UNUSUAL_LINE_TERMINATORS.source, false, true, false, null, false, 1073741824 /* MAX_SAFE_SMALL_INTEGER */);
- this._buffer.resetMightContainUnusualLineTerminators();
- this.pushEditOperations(selections, matches.map(m => ({ range: m.range, text: null })), () => null);
- }
- mightContainNonBasicASCII() {
- return this._buffer.mightContainNonBasicASCII();
- }
- getAlternativeVersionId() {
- this._assertNotDisposed();
- return this._alternativeVersionId;
- }
- getInitialUndoRedoSnapshot() {
- this._assertNotDisposed();
- return this._initialUndoRedoSnapshot;
- }
- getOffsetAt(rawPosition) {
- this._assertNotDisposed();
- let position = this._validatePosition(rawPosition.lineNumber, rawPosition.column, 0 /* Relaxed */);
- return this._buffer.getOffsetAt(position.lineNumber, position.column);
- }
- getPositionAt(rawOffset) {
- this._assertNotDisposed();
- let offset = (Math.min(this._buffer.getLength(), Math.max(0, rawOffset)));
- return this._buffer.getPositionAt(offset);
- }
- _increaseVersionId() {
- this._versionId = this._versionId + 1;
- this._alternativeVersionId = this._versionId;
- }
- _overwriteVersionId(versionId) {
- this._versionId = versionId;
- }
- _overwriteAlternativeVersionId(newAlternativeVersionId) {
- this._alternativeVersionId = newAlternativeVersionId;
- }
- _overwriteInitialUndoRedoSnapshot(newInitialUndoRedoSnapshot) {
- this._initialUndoRedoSnapshot = newInitialUndoRedoSnapshot;
- }
- getValue(eol, preserveBOM = false) {
- this._assertNotDisposed();
- const fullModelRange = this.getFullModelRange();
- const fullModelValue = this.getValueInRange(fullModelRange, eol);
- if (preserveBOM) {
- return this._buffer.getBOM() + fullModelValue;
- }
- return fullModelValue;
- }
- createSnapshot(preserveBOM = false) {
- return new TextModelSnapshot(this._buffer.createSnapshot(preserveBOM));
- }
- getValueLength(eol, preserveBOM = false) {
- this._assertNotDisposed();
- const fullModelRange = this.getFullModelRange();
- const fullModelValue = this.getValueLengthInRange(fullModelRange, eol);
- if (preserveBOM) {
- return this._buffer.getBOM().length + fullModelValue;
- }
- return fullModelValue;
- }
- getValueInRange(rawRange, eol = 0 /* TextDefined */) {
- this._assertNotDisposed();
- return this._buffer.getValueInRange(this.validateRange(rawRange), eol);
- }
- getValueLengthInRange(rawRange, eol = 0 /* TextDefined */) {
- this._assertNotDisposed();
- return this._buffer.getValueLengthInRange(this.validateRange(rawRange), eol);
- }
- getCharacterCountInRange(rawRange, eol = 0 /* TextDefined */) {
- this._assertNotDisposed();
- return this._buffer.getCharacterCountInRange(this.validateRange(rawRange), eol);
- }
- getLineCount() {
- this._assertNotDisposed();
- return this._buffer.getLineCount();
- }
- getLineContent(lineNumber) {
- this._assertNotDisposed();
- if (lineNumber < 1 || lineNumber > this.getLineCount()) {
- throw new Error('Illegal value for lineNumber');
- }
- return this._buffer.getLineContent(lineNumber);
- }
- getLineLength(lineNumber) {
- this._assertNotDisposed();
- if (lineNumber < 1 || lineNumber > this.getLineCount()) {
- throw new Error('Illegal value for lineNumber');
- }
- return this._buffer.getLineLength(lineNumber);
- }
- getLinesContent() {
- this._assertNotDisposed();
- return this._buffer.getLinesContent();
- }
- getEOL() {
- this._assertNotDisposed();
- return this._buffer.getEOL();
- }
- getEndOfLineSequence() {
- this._assertNotDisposed();
- return (this._buffer.getEOL() === '\n'
- ? 0 /* LF */
- : 1 /* CRLF */);
- }
- getLineMinColumn(lineNumber) {
- this._assertNotDisposed();
- return 1;
- }
- getLineMaxColumn(lineNumber) {
- this._assertNotDisposed();
- if (lineNumber < 1 || lineNumber > this.getLineCount()) {
- throw new Error('Illegal value for lineNumber');
- }
- return this._buffer.getLineLength(lineNumber) + 1;
- }
- getLineFirstNonWhitespaceColumn(lineNumber) {
- this._assertNotDisposed();
- if (lineNumber < 1 || lineNumber > this.getLineCount()) {
- throw new Error('Illegal value for lineNumber');
- }
- return this._buffer.getLineFirstNonWhitespaceColumn(lineNumber);
- }
- getLineLastNonWhitespaceColumn(lineNumber) {
- this._assertNotDisposed();
- if (lineNumber < 1 || lineNumber > this.getLineCount()) {
- throw new Error('Illegal value for lineNumber');
- }
- return this._buffer.getLineLastNonWhitespaceColumn(lineNumber);
- }
- /**
- * Validates `range` is within buffer bounds, but allows it to sit in between surrogate pairs, etc.
- * Will try to not allocate if possible.
- */
- _validateRangeRelaxedNoAllocations(range) {
- const linesCount = this._buffer.getLineCount();
- const initialStartLineNumber = range.startLineNumber;
- const initialStartColumn = range.startColumn;
- let startLineNumber = Math.floor((typeof initialStartLineNumber === 'number' && !isNaN(initialStartLineNumber)) ? initialStartLineNumber : 1);
- let startColumn = Math.floor((typeof initialStartColumn === 'number' && !isNaN(initialStartColumn)) ? initialStartColumn : 1);
- if (startLineNumber < 1) {
- startLineNumber = 1;
- startColumn = 1;
- }
- else if (startLineNumber > linesCount) {
- startLineNumber = linesCount;
- startColumn = this.getLineMaxColumn(startLineNumber);
- }
- else {
- if (startColumn <= 1) {
- startColumn = 1;
- }
- else {
- const maxColumn = this.getLineMaxColumn(startLineNumber);
- if (startColumn >= maxColumn) {
- startColumn = maxColumn;
- }
- }
- }
- const initialEndLineNumber = range.endLineNumber;
- const initialEndColumn = range.endColumn;
- let endLineNumber = Math.floor((typeof initialEndLineNumber === 'number' && !isNaN(initialEndLineNumber)) ? initialEndLineNumber : 1);
- let endColumn = Math.floor((typeof initialEndColumn === 'number' && !isNaN(initialEndColumn)) ? initialEndColumn : 1);
- if (endLineNumber < 1) {
- endLineNumber = 1;
- endColumn = 1;
- }
- else if (endLineNumber > linesCount) {
- endLineNumber = linesCount;
- endColumn = this.getLineMaxColumn(endLineNumber);
- }
- else {
- if (endColumn <= 1) {
- endColumn = 1;
- }
- else {
- const maxColumn = this.getLineMaxColumn(endLineNumber);
- if (endColumn >= maxColumn) {
- endColumn = maxColumn;
- }
- }
- }
- if (initialStartLineNumber === startLineNumber
- && initialStartColumn === startColumn
- && initialEndLineNumber === endLineNumber
- && initialEndColumn === endColumn
- && range instanceof Range
- && !(range instanceof Selection)) {
- return range;
- }
- return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
- }
- _isValidPosition(lineNumber, column, validationType) {
- if (typeof lineNumber !== 'number' || typeof column !== 'number') {
- return false;
- }
- if (isNaN(lineNumber) || isNaN(column)) {
- return false;
- }
- if (lineNumber < 1 || column < 1) {
- return false;
- }
- if ((lineNumber | 0) !== lineNumber || (column | 0) !== column) {
- return false;
- }
- const lineCount = this._buffer.getLineCount();
- if (lineNumber > lineCount) {
- return false;
- }
- if (column === 1) {
- return true;
- }
- const maxColumn = this.getLineMaxColumn(lineNumber);
- if (column > maxColumn) {
- return false;
- }
- if (validationType === 1 /* SurrogatePairs */) {
- // !!At this point, column > 1
- const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2);
- if (strings.isHighSurrogate(charCodeBefore)) {
- return false;
- }
- }
- return true;
- }
- _validatePosition(_lineNumber, _column, validationType) {
- const lineNumber = Math.floor((typeof _lineNumber === 'number' && !isNaN(_lineNumber)) ? _lineNumber : 1);
- const column = Math.floor((typeof _column === 'number' && !isNaN(_column)) ? _column : 1);
- const lineCount = this._buffer.getLineCount();
- if (lineNumber < 1) {
- return new Position(1, 1);
- }
- if (lineNumber > lineCount) {
- return new Position(lineCount, this.getLineMaxColumn(lineCount));
- }
- if (column <= 1) {
- return new Position(lineNumber, 1);
- }
- const maxColumn = this.getLineMaxColumn(lineNumber);
- if (column >= maxColumn) {
- return new Position(lineNumber, maxColumn);
- }
- if (validationType === 1 /* SurrogatePairs */) {
- // If the position would end up in the middle of a high-low surrogate pair,
- // we move it to before the pair
- // !!At this point, column > 1
- const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2);
- if (strings.isHighSurrogate(charCodeBefore)) {
- return new Position(lineNumber, column - 1);
- }
- }
- return new Position(lineNumber, column);
- }
- validatePosition(position) {
- const validationType = 1 /* SurrogatePairs */;
- this._assertNotDisposed();
- // Avoid object allocation and cover most likely case
- if (position instanceof Position) {
- if (this._isValidPosition(position.lineNumber, position.column, validationType)) {
- return position;
- }
- }
- return this._validatePosition(position.lineNumber, position.column, validationType);
- }
- _isValidRange(range, validationType) {
- const startLineNumber = range.startLineNumber;
- const startColumn = range.startColumn;
- const endLineNumber = range.endLineNumber;
- const endColumn = range.endColumn;
- if (!this._isValidPosition(startLineNumber, startColumn, 0 /* Relaxed */)) {
- return false;
- }
- if (!this._isValidPosition(endLineNumber, endColumn, 0 /* Relaxed */)) {
- return false;
- }
- if (validationType === 1 /* SurrogatePairs */) {
- const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0);
- const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0);
- const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart);
- const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd);
- if (!startInsideSurrogatePair && !endInsideSurrogatePair) {
- return true;
- }
- return false;
- }
- return true;
- }
- validateRange(_range) {
- const validationType = 1 /* SurrogatePairs */;
- this._assertNotDisposed();
- // Avoid object allocation and cover most likely case
- if ((_range instanceof Range) && !(_range instanceof Selection)) {
- if (this._isValidRange(_range, validationType)) {
- return _range;
- }
- }
- const start = this._validatePosition(_range.startLineNumber, _range.startColumn, 0 /* Relaxed */);
- const end = this._validatePosition(_range.endLineNumber, _range.endColumn, 0 /* Relaxed */);
- const startLineNumber = start.lineNumber;
- const startColumn = start.column;
- const endLineNumber = end.lineNumber;
- const endColumn = end.column;
- if (validationType === 1 /* SurrogatePairs */) {
- const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0);
- const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0);
- const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart);
- const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd);
- if (!startInsideSurrogatePair && !endInsideSurrogatePair) {
- return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
- }
- if (startLineNumber === endLineNumber && startColumn === endColumn) {
- // do not expand a collapsed range, simply move it to a valid location
- return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn - 1);
- }
- if (startInsideSurrogatePair && endInsideSurrogatePair) {
- // expand range at both ends
- return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn + 1);
- }
- if (startInsideSurrogatePair) {
- // only expand range at the start
- return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn);
- }
- // only expand range at the end
- return new Range(startLineNumber, startColumn, endLineNumber, endColumn + 1);
- }
- return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
- }
- modifyPosition(rawPosition, offset) {
- this._assertNotDisposed();
- let candidate = this.getOffsetAt(rawPosition) + offset;
- return this.getPositionAt(Math.min(this._buffer.getLength(), Math.max(0, candidate)));
- }
- getFullModelRange() {
- this._assertNotDisposed();
- const lineCount = this.getLineCount();
- return new Range(1, 1, lineCount, this.getLineMaxColumn(lineCount));
- }
- findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount) {
- return this._buffer.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
- }
- findMatches(searchString, rawSearchScope, isRegex, matchCase, wordSeparators, captureMatches, limitResultCount = LIMIT_FIND_COUNT) {
- this._assertNotDisposed();
- let searchRanges = null;
- if (rawSearchScope !== null) {
- if (!Array.isArray(rawSearchScope)) {
- rawSearchScope = [rawSearchScope];
- }
- if (rawSearchScope.every((searchScope) => Range.isIRange(searchScope))) {
- searchRanges = rawSearchScope.map((searchScope) => this.validateRange(searchScope));
- }
- }
- if (searchRanges === null) {
- searchRanges = [this.getFullModelRange()];
- }
- searchRanges = searchRanges.sort((d1, d2) => d1.startLineNumber - d2.startLineNumber || d1.startColumn - d2.startColumn);
- const uniqueSearchRanges = [];
- uniqueSearchRanges.push(searchRanges.reduce((prev, curr) => {
- if (Range.areIntersecting(prev, curr)) {
- return prev.plusRange(curr);
- }
- uniqueSearchRanges.push(prev);
- return curr;
- }));
- let matchMapper;
- if (!isRegex && searchString.indexOf('\n') < 0) {
- // not regex, not multi line
- const searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);
- const searchData = searchParams.parseSearchRequest();
- if (!searchData) {
- return [];
- }
- matchMapper = (searchRange) => this.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
- }
- else {
- matchMapper = (searchRange) => TextModelSearch.findMatches(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchRange, captureMatches, limitResultCount);
- }
- return uniqueSearchRanges.map(matchMapper).reduce((arr, matches) => arr.concat(matches), []);
- }
- findNextMatch(searchString, rawSearchStart, isRegex, matchCase, wordSeparators, captureMatches) {
- this._assertNotDisposed();
- const searchStart = this.validatePosition(rawSearchStart);
- if (!isRegex && searchString.indexOf('\n') < 0) {
- const searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);
- const searchData = searchParams.parseSearchRequest();
- if (!searchData) {
- return null;
- }
- const lineCount = this.getLineCount();
- let searchRange = new Range(searchStart.lineNumber, searchStart.column, lineCount, this.getLineMaxColumn(lineCount));
- let ret = this.findMatchesLineByLine(searchRange, searchData, captureMatches, 1);
- TextModelSearch.findNextMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
- if (ret.length > 0) {
- return ret[0];
- }
- searchRange = new Range(1, 1, searchStart.lineNumber, this.getLineMaxColumn(searchStart.lineNumber));
- ret = this.findMatchesLineByLine(searchRange, searchData, captureMatches, 1);
- if (ret.length > 0) {
- return ret[0];
- }
- return null;
- }
- return TextModelSearch.findNextMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
- }
- findPreviousMatch(searchString, rawSearchStart, isRegex, matchCase, wordSeparators, captureMatches) {
- this._assertNotDisposed();
- const searchStart = this.validatePosition(rawSearchStart);
- return TextModelSearch.findPreviousMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
- }
- //#endregion
- //#region Editing
- pushStackElement() {
- this._commandManager.pushStackElement();
- }
- popStackElement() {
- this._commandManager.popStackElement();
- }
- pushEOL(eol) {
- const currentEOL = (this.getEOL() === '\n' ? 0 /* LF */ : 1 /* CRLF */);
- if (currentEOL === eol) {
- return;
- }
- try {
- this._onDidChangeDecorations.beginDeferredEmit();
- this._eventEmitter.beginDeferredEmit();
- if (this._initialUndoRedoSnapshot === null) {
- this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
- }
- this._commandManager.pushEOL(eol);
- }
- finally {
- this._eventEmitter.endDeferredEmit();
- this._onDidChangeDecorations.endDeferredEmit();
- }
- }
- _validateEditOperation(rawOperation) {
- if (rawOperation instanceof model.ValidAnnotatedEditOperation) {
- return rawOperation;
- }
- return new model.ValidAnnotatedEditOperation(rawOperation.identifier || null, this.validateRange(rawOperation.range), rawOperation.text, rawOperation.forceMoveMarkers || false, rawOperation.isAutoWhitespaceEdit || false, rawOperation._isTracked || false);
- }
- _validateEditOperations(rawOperations) {
- const result = [];
- for (let i = 0, len = rawOperations.length; i < len; i++) {
- result[i] = this._validateEditOperation(rawOperations[i]);
- }
- return result;
- }
- pushEditOperations(beforeCursorState, editOperations, cursorStateComputer) {
- try {
- this._onDidChangeDecorations.beginDeferredEmit();
- this._eventEmitter.beginDeferredEmit();
- return this._pushEditOperations(beforeCursorState, this._validateEditOperations(editOperations), cursorStateComputer);
- }
- finally {
- this._eventEmitter.endDeferredEmit();
- this._onDidChangeDecorations.endDeferredEmit();
- }
- }
- _pushEditOperations(beforeCursorState, editOperations, cursorStateComputer) {
- if (this._options.trimAutoWhitespace && this._trimAutoWhitespaceLines) {
- // Go through each saved line number and insert a trim whitespace edit
- // if it is safe to do so (no conflicts with other edits).
- let incomingEdits = editOperations.map((op) => {
- return {
- range: this.validateRange(op.range),
- text: op.text
- };
- });
- // Sometimes, auto-formatters change ranges automatically which can cause undesired auto whitespace trimming near the cursor
- // We'll use the following heuristic: if the edits occur near the cursor, then it's ok to trim auto whitespace
- let editsAreNearCursors = true;
- if (beforeCursorState) {
- for (let i = 0, len = beforeCursorState.length; i < len; i++) {
- let sel = beforeCursorState[i];
- let foundEditNearSel = false;
- for (let j = 0, lenJ = incomingEdits.length; j < lenJ; j++) {
- let editRange = incomingEdits[j].range;
- let selIsAbove = editRange.startLineNumber > sel.endLineNumber;
- let selIsBelow = sel.startLineNumber > editRange.endLineNumber;
- if (!selIsAbove && !selIsBelow) {
- foundEditNearSel = true;
- break;
- }
- }
- if (!foundEditNearSel) {
- editsAreNearCursors = false;
- break;
- }
- }
- }
- if (editsAreNearCursors) {
- for (let i = 0, len = this._trimAutoWhitespaceLines.length; i < len; i++) {
- let trimLineNumber = this._trimAutoWhitespaceLines[i];
- let maxLineColumn = this.getLineMaxColumn(trimLineNumber);
- let allowTrimLine = true;
- for (let j = 0, lenJ = incomingEdits.length; j < lenJ; j++) {
- let editRange = incomingEdits[j].range;
- let editText = incomingEdits[j].text;
- if (trimLineNumber < editRange.startLineNumber || trimLineNumber > editRange.endLineNumber) {
- // `trimLine` is completely outside this edit
- continue;
- }
- // At this point:
- // editRange.startLineNumber <= trimLine <= editRange.endLineNumber
- if (trimLineNumber === editRange.startLineNumber && editRange.startColumn === maxLineColumn
- && editRange.isEmpty() && editText && editText.length > 0 && editText.charAt(0) === '\n') {
- // This edit inserts a new line (and maybe other text) after `trimLine`
- continue;
- }
- if (trimLineNumber === editRange.startLineNumber && editRange.startColumn === 1
- && editRange.isEmpty() && editText && editText.length > 0 && editText.charAt(editText.length - 1) === '\n') {
- // This edit inserts a new line (and maybe other text) before `trimLine`
- continue;
- }
- // Looks like we can't trim this line as it would interfere with an incoming edit
- allowTrimLine = false;
- break;
- }
- if (allowTrimLine) {
- const trimRange = new Range(trimLineNumber, 1, trimLineNumber, maxLineColumn);
- editOperations.push(new model.ValidAnnotatedEditOperation(null, trimRange, null, false, false, false));
- }
- }
- }
- this._trimAutoWhitespaceLines = null;
- }
- if (this._initialUndoRedoSnapshot === null) {
- this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
- }
- return this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer);
- }
- _applyUndo(changes, eol, resultingAlternativeVersionId, resultingSelection) {
- const edits = changes.map((change) => {
- const rangeStart = this.getPositionAt(change.newPosition);
- const rangeEnd = this.getPositionAt(change.newEnd);
- return {
- range: new Range(rangeStart.lineNumber, rangeStart.column, rangeEnd.lineNumber, rangeEnd.column),
- text: change.oldText
- };
- });
- this._applyUndoRedoEdits(edits, eol, true, false, resultingAlternativeVersionId, resultingSelection);
- }
- _applyRedo(changes, eol, resultingAlternativeVersionId, resultingSelection) {
- const edits = changes.map((change) => {
- const rangeStart = this.getPositionAt(change.oldPosition);
- const rangeEnd = this.getPositionAt(change.oldEnd);
- return {
- range: new Range(rangeStart.lineNumber, rangeStart.column, rangeEnd.lineNumber, rangeEnd.column),
- text: change.newText
- };
- });
- this._applyUndoRedoEdits(edits, eol, false, true, resultingAlternativeVersionId, resultingSelection);
- }
- _applyUndoRedoEdits(edits, eol, isUndoing, isRedoing, resultingAlternativeVersionId, resultingSelection) {
- try {
- this._onDidChangeDecorations.beginDeferredEmit();
- this._eventEmitter.beginDeferredEmit();
- this._isUndoing = isUndoing;
- this._isRedoing = isRedoing;
- this.applyEdits(edits, false);
- this.setEOL(eol);
- this._overwriteAlternativeVersionId(resultingAlternativeVersionId);
- }
- finally {
- this._isUndoing = false;
- this._isRedoing = false;
- this._eventEmitter.endDeferredEmit(resultingSelection);
- this._onDidChangeDecorations.endDeferredEmit();
- }
- }
- applyEdits(rawOperations, computeUndoEdits = false) {
- try {
- this._onDidChangeDecorations.beginDeferredEmit();
- this._eventEmitter.beginDeferredEmit();
- const operations = this._validateEditOperations(rawOperations);
- return this._doApplyEdits(operations, computeUndoEdits);
- }
- finally {
- this._eventEmitter.endDeferredEmit();
- this._onDidChangeDecorations.endDeferredEmit();
- }
- }
- _doApplyEdits(rawOperations, computeUndoEdits) {
- const oldLineCount = this._buffer.getLineCount();
- const result = this._buffer.applyEdits(rawOperations, this._options.trimAutoWhitespace, computeUndoEdits);
- const newLineCount = this._buffer.getLineCount();
- const contentChanges = result.changes;
- this._trimAutoWhitespaceLines = result.trimAutoWhitespaceLineNumbers;
- if (contentChanges.length !== 0) {
- // We do a first pass to update tokens and decorations
- // because we want to read decorations in the second pass
- // where we will emit content change events
- // and we want to read the final decorations
- for (let i = 0, len = contentChanges.length; i < len; i++) {
- const change = contentChanges[i];
- const [eolCount, firstLineLength, lastLineLength] = countEOL(change.text);
- this._tokens.acceptEdit(change.range, eolCount, firstLineLength);
- this._tokens2.acceptEdit(change.range, eolCount, firstLineLength, lastLineLength, change.text.length > 0 ? change.text.charCodeAt(0) : 0 /* Null */);
- this._decorationsTree.acceptReplace(change.rangeOffset, change.rangeLength, change.text.length, change.forceMoveMarkers);
- }
- let rawContentChanges = [];
- this._increaseVersionId();
- let lineCount = oldLineCount;
- for (let i = 0, len = contentChanges.length; i < len; i++) {
- const change = contentChanges[i];
- const [eolCount] = countEOL(change.text);
- this._onDidChangeDecorations.fire();
- const startLineNumber = change.range.startLineNumber;
- const endLineNumber = change.range.endLineNumber;
- const deletingLinesCnt = endLineNumber - startLineNumber;
- const insertingLinesCnt = eolCount;
- const editingLinesCnt = Math.min(deletingLinesCnt, insertingLinesCnt);
- const changeLineCountDelta = (insertingLinesCnt - deletingLinesCnt);
- const currentEditStartLineNumber = newLineCount - lineCount - changeLineCountDelta + startLineNumber;
- const firstEditLineNumber = currentEditStartLineNumber;
- const lastInsertedLineNumber = currentEditStartLineNumber + insertingLinesCnt;
- const decorationsWithInjectedTextInEditedRange = this._decorationsTree.getInjectedTextInInterval(this, this.getOffsetAt(new Position(firstEditLineNumber, 1)), this.getOffsetAt(new Position(lastInsertedLineNumber, this.getLineMaxColumn(lastInsertedLineNumber))), 0);
- const injectedTextInEditedRange = LineInjectedText.fromDecorations(decorationsWithInjectedTextInEditedRange);
- const injectedTextInEditedRangeQueue = new ArrayQueue(injectedTextInEditedRange);
- for (let j = editingLinesCnt; j >= 0; j--) {
- const editLineNumber = startLineNumber + j;
- const currentEditLineNumber = currentEditStartLineNumber + j;
- injectedTextInEditedRangeQueue.takeFromEndWhile(r => r.lineNumber > currentEditLineNumber);
- const decorationsInCurrentLine = injectedTextInEditedRangeQueue.takeFromEndWhile(r => r.lineNumber === currentEditLineNumber);
- rawContentChanges.push(new ModelRawLineChanged(editLineNumber, this.getLineContent(currentEditLineNumber), decorationsInCurrentLine));
- }
- if (editingLinesCnt < deletingLinesCnt) {
- // Must delete some lines
- const spliceStartLineNumber = startLineNumber + editingLinesCnt;
- rawContentChanges.push(new ModelRawLinesDeleted(spliceStartLineNumber + 1, endLineNumber));
- }
- if (editingLinesCnt < insertingLinesCnt) {
- const injectedTextInEditedRangeQueue = new ArrayQueue(injectedTextInEditedRange);
- // Must insert some lines
- const spliceLineNumber = startLineNumber + editingLinesCnt;
- const cnt = insertingLinesCnt - editingLinesCnt;
- const fromLineNumber = newLineCount - lineCount - cnt + spliceLineNumber + 1;
- let injectedTexts = [];
- let newLines = [];
- for (let i = 0; i < cnt; i++) {
- let lineNumber = fromLineNumber + i;
- newLines[i] = this.getLineContent(lineNumber);
- injectedTextInEditedRangeQueue.takeWhile(r => r.lineNumber < lineNumber);
- injectedTexts[i] = injectedTextInEditedRangeQueue.takeWhile(r => r.lineNumber === lineNumber);
- }
- rawContentChanges.push(new ModelRawLinesInserted(spliceLineNumber + 1, startLineNumber + insertingLinesCnt, newLines, injectedTexts));
- }
- lineCount += changeLineCountDelta;
- }
- this._emitContentChangedEvent(new ModelRawContentChangedEvent(rawContentChanges, this.getVersionId(), this._isUndoing, this._isRedoing), {
- changes: contentChanges,
- eol: this._buffer.getEOL(),
- versionId: this.getVersionId(),
- isUndoing: this._isUndoing,
- isRedoing: this._isRedoing,
- isFlush: false
- });
- }
- return (result.reverseEdits === null ? undefined : result.reverseEdits);
- }
- undo() {
- return this._undoRedoService.undo(this.uri);
- }
- canUndo() {
- return this._undoRedoService.canUndo(this.uri);
- }
- redo() {
- return this._undoRedoService.redo(this.uri);
- }
- canRedo() {
- return this._undoRedoService.canRedo(this.uri);
- }
- //#endregion
- //#region Decorations
- handleBeforeFireDecorationsChangedEvent(affectedInjectedTextLines) {
- // This is called before the decoration changed event is fired.
- if (affectedInjectedTextLines === null || affectedInjectedTextLines.size === 0) {
- return;
- }
- const affectedLines = [...affectedInjectedTextLines];
- const lineChangeEvents = affectedLines.map(lineNumber => new ModelRawLineChanged(lineNumber, this.getLineContent(lineNumber), this._getInjectedTextInLine(lineNumber)));
- this._onDidChangeContentOrInjectedText.fire(new ModelInjectedTextChangedEvent(lineChangeEvents));
- }
- changeDecorations(callback, ownerId = 0) {
- this._assertNotDisposed();
- try {
- this._onDidChangeDecorations.beginDeferredEmit();
- return this._changeDecorations(ownerId, callback);
- }
- finally {
- this._onDidChangeDecorations.endDeferredEmit();
- }
- }
- _changeDecorations(ownerId, callback) {
- let changeAccessor = {
- addDecoration: (range, options) => {
- return this._deltaDecorationsImpl(ownerId, [], [{ range: range, options: options }])[0];
- },
- changeDecoration: (id, newRange) => {
- this._changeDecorationImpl(id, newRange);
- },
- changeDecorationOptions: (id, options) => {
- this._changeDecorationOptionsImpl(id, _normalizeOptions(options));
- },
- removeDecoration: (id) => {
- this._deltaDecorationsImpl(ownerId, [id], []);
- },
- deltaDecorations: (oldDecorations, newDecorations) => {
- if (oldDecorations.length === 0 && newDecorations.length === 0) {
- // nothing to do
- return [];
- }
- return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);
- }
- };
- let result = null;
- try {
- result = callback(changeAccessor);
- }
- catch (e) {
- onUnexpectedError(e);
- }
- // Invalidate change accessor
- changeAccessor.addDecoration = invalidFunc;
- changeAccessor.changeDecoration = invalidFunc;
- changeAccessor.changeDecorationOptions = invalidFunc;
- changeAccessor.removeDecoration = invalidFunc;
- changeAccessor.deltaDecorations = invalidFunc;
- return result;
- }
- deltaDecorations(oldDecorations, newDecorations, ownerId = 0) {
- this._assertNotDisposed();
- if (!oldDecorations) {
- oldDecorations = [];
- }
- if (oldDecorations.length === 0 && newDecorations.length === 0) {
- // nothing to do
- return [];
- }
- try {
- this._onDidChangeDecorations.beginDeferredEmit();
- return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);
- }
- finally {
- this._onDidChangeDecorations.endDeferredEmit();
- }
- }
- _getTrackedRange(id) {
- return this.getDecorationRange(id);
- }
- _setTrackedRange(id, newRange, newStickiness) {
- const node = (id ? this._decorations[id] : null);
- if (!node) {
- if (!newRange) {
- // node doesn't exist, the request is to delete => nothing to do
- return null;
- }
- // node doesn't exist, the request is to set => add the tracked range
- return this._deltaDecorationsImpl(0, [], [{ range: newRange, options: TRACKED_RANGE_OPTIONS[newStickiness] }])[0];
- }
- if (!newRange) {
- // node exists, the request is to delete => delete node
- this._decorationsTree.delete(node);
- delete this._decorations[node.id];
- return null;
- }
- // node exists, the request is to set => change the tracked range and its options
- const range = this._validateRangeRelaxedNoAllocations(newRange);
- const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
- const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
- this._decorationsTree.delete(node);
- node.reset(this.getVersionId(), startOffset, endOffset, range);
- node.setOptions(TRACKED_RANGE_OPTIONS[newStickiness]);
- this._decorationsTree.insert(node);
- return node.id;
- }
- removeAllDecorationsWithOwnerId(ownerId) {
- if (this._isDisposed) {
- return;
- }
- const nodes = this._decorationsTree.collectNodesFromOwner(ownerId);
- for (let i = 0, len = nodes.length; i < len; i++) {
- const node = nodes[i];
- this._decorationsTree.delete(node);
- delete this._decorations[node.id];
- }
- }
- getDecorationOptions(decorationId) {
- const node = this._decorations[decorationId];
- if (!node) {
- return null;
- }
- return node.options;
- }
- getDecorationRange(decorationId) {
- const node = this._decorations[decorationId];
- if (!node) {
- return null;
- }
- return this._decorationsTree.getNodeRange(this, node);
- }
- getLineDecorations(lineNumber, ownerId = 0, filterOutValidation = false) {
- if (lineNumber < 1 || lineNumber > this.getLineCount()) {
- return [];
- }
- return this.getLinesDecorations(lineNumber, lineNumber, ownerId, filterOutValidation);
- }
- getLinesDecorations(_startLineNumber, _endLineNumber, ownerId = 0, filterOutValidation = false) {
- let lineCount = this.getLineCount();
- let startLineNumber = Math.min(lineCount, Math.max(1, _startLineNumber));
- let endLineNumber = Math.min(lineCount, Math.max(1, _endLineNumber));
- let endColumn = this.getLineMaxColumn(endLineNumber);
- const range = new Range(startLineNumber, 1, endLineNumber, endColumn);
- const decorations = this._getDecorationsInRange(range, ownerId, filterOutValidation);
- decorations.push(...this._decorationProvider.getDecorationsInRange(range, ownerId, filterOutValidation));
- return decorations;
- }
- getDecorationsInRange(range, ownerId = 0, filterOutValidation = false) {
- let validatedRange = this.validateRange(range);
- const decorations = this._getDecorationsInRange(validatedRange, ownerId, filterOutValidation);
- decorations.push(...this._decorationProvider.getDecorationsInRange(validatedRange, ownerId, filterOutValidation));
- return decorations;
- }
- getOverviewRulerDecorations(ownerId = 0, filterOutValidation = false) {
- return this._decorationsTree.getAll(this, ownerId, filterOutValidation, true);
- }
- getInjectedTextDecorations(ownerId = 0) {
- return this._decorationsTree.getAllInjectedText(this, ownerId);
- }
- _getInjectedTextInLine(lineNumber) {
- const startOffset = this._buffer.getOffsetAt(lineNumber, 1);
- const endOffset = startOffset + this._buffer.getLineLength(lineNumber);
- const result = this._decorationsTree.getInjectedTextInInterval(this, startOffset, endOffset, 0);
- return LineInjectedText.fromDecorations(result).filter(t => t.lineNumber === lineNumber);
- }
- getAllDecorations(ownerId = 0, filterOutValidation = false) {
- let result = this._decorationsTree.getAll(this, ownerId, filterOutValidation, false);
- result = result.concat(this._decorationProvider.getAllDecorations(ownerId, filterOutValidation));
- return result;
- }
- _getDecorationsInRange(filterRange, filterOwnerId, filterOutValidation) {
- const startOffset = this._buffer.getOffsetAt(filterRange.startLineNumber, filterRange.startColumn);
- const endOffset = this._buffer.getOffsetAt(filterRange.endLineNumber, filterRange.endColumn);
- return this._decorationsTree.getAllInInterval(this, startOffset, endOffset, filterOwnerId, filterOutValidation);
- }
- getRangeAt(start, end) {
- return this._buffer.getRangeAt(start, end - start);
- }
- _changeDecorationImpl(decorationId, _range) {
- const node = this._decorations[decorationId];
- if (!node) {
- return;
- }
- if (node.options.after) {
- const oldRange = this.getDecorationRange(decorationId);
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(oldRange.endLineNumber);
- }
- if (node.options.before) {
- const oldRange = this.getDecorationRange(decorationId);
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(oldRange.startLineNumber);
- }
- const range = this._validateRangeRelaxedNoAllocations(_range);
- const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
- const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
- this._decorationsTree.delete(node);
- node.reset(this.getVersionId(), startOffset, endOffset, range);
- this._decorationsTree.insert(node);
- this._onDidChangeDecorations.checkAffectedAndFire(node.options);
- if (node.options.after) {
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.endLineNumber);
- }
- if (node.options.before) {
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.startLineNumber);
- }
- }
- _changeDecorationOptionsImpl(decorationId, options) {
- const node = this._decorations[decorationId];
- if (!node) {
- return;
- }
- const nodeWasInOverviewRuler = (node.options.overviewRuler && node.options.overviewRuler.color ? true : false);
- const nodeIsInOverviewRuler = (options.overviewRuler && options.overviewRuler.color ? true : false);
- this._onDidChangeDecorations.checkAffectedAndFire(node.options);
- this._onDidChangeDecorations.checkAffectedAndFire(options);
- if (node.options.after || options.after) {
- const nodeRange = this._decorationsTree.getNodeRange(this, node);
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.endLineNumber);
- }
- if (node.options.before || options.before) {
- const nodeRange = this._decorationsTree.getNodeRange(this, node);
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.startLineNumber);
- }
- if (nodeWasInOverviewRuler !== nodeIsInOverviewRuler) {
- // Delete + Insert due to an overview ruler status change
- this._decorationsTree.delete(node);
- node.setOptions(options);
- this._decorationsTree.insert(node);
- }
- else {
- node.setOptions(options);
- }
- }
- _deltaDecorationsImpl(ownerId, oldDecorationsIds, newDecorations) {
- const versionId = this.getVersionId();
- const oldDecorationsLen = oldDecorationsIds.length;
- let oldDecorationIndex = 0;
- const newDecorationsLen = newDecorations.length;
- let newDecorationIndex = 0;
- let result = new Array(newDecorationsLen);
- while (oldDecorationIndex < oldDecorationsLen || newDecorationIndex < newDecorationsLen) {
- let node = null;
- if (oldDecorationIndex < oldDecorationsLen) {
- // (1) get ourselves an old node
- do {
- node = this._decorations[oldDecorationsIds[oldDecorationIndex++]];
- } while (!node && oldDecorationIndex < oldDecorationsLen);
- // (2) remove the node from the tree (if it exists)
- if (node) {
- if (node.options.after) {
- const nodeRange = this._decorationsTree.getNodeRange(this, node);
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.endLineNumber);
- }
- if (node.options.before) {
- const nodeRange = this._decorationsTree.getNodeRange(this, node);
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.startLineNumber);
- }
- this._decorationsTree.delete(node);
- this._onDidChangeDecorations.checkAffectedAndFire(node.options);
- }
- }
- if (newDecorationIndex < newDecorationsLen) {
- // (3) create a new node if necessary
- if (!node) {
- const internalDecorationId = (++this._lastDecorationId);
- const decorationId = `${this._instanceId};${internalDecorationId}`;
- node = new IntervalNode(decorationId, 0, 0);
- this._decorations[decorationId] = node;
- }
- // (4) initialize node
- const newDecoration = newDecorations[newDecorationIndex];
- const range = this._validateRangeRelaxedNoAllocations(newDecoration.range);
- const options = _normalizeOptions(newDecoration.options);
- const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
- const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
- node.ownerId = ownerId;
- node.reset(versionId, startOffset, endOffset, range);
- node.setOptions(options);
- if (node.options.after) {
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.endLineNumber);
- }
- if (node.options.before) {
- this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.startLineNumber);
- }
- this._onDidChangeDecorations.checkAffectedAndFire(options);
- this._decorationsTree.insert(node);
- result[newDecorationIndex] = node.id;
- newDecorationIndex++;
- }
- else {
- if (node) {
- delete this._decorations[node.id];
- }
- }
- }
- return result;
- }
- setTokens(tokens, backgroundTokenizationCompleted = false) {
- if (tokens.length !== 0) {
- let ranges = [];
- for (let i = 0, len = tokens.length; i < len; i++) {
- const element = tokens[i];
- let minChangedLineNumber = 0;
- let maxChangedLineNumber = 0;
- let hasChange = false;
- for (let j = 0, lenJ = element.tokens.length; j < lenJ; j++) {
- const lineNumber = element.startLineNumber + j;
- if (hasChange) {
- this._tokens.setTokens(this._languageId, lineNumber - 1, this._buffer.getLineLength(lineNumber), element.tokens[j], false);
- maxChangedLineNumber = lineNumber;
- }
- else {
- const lineHasChange = this._tokens.setTokens(this._languageId, lineNumber - 1, this._buffer.getLineLength(lineNumber), element.tokens[j], true);
- if (lineHasChange) {
- hasChange = true;
- minChangedLineNumber = lineNumber;
- maxChangedLineNumber = lineNumber;
- }
- }
- }
- if (hasChange) {
- ranges.push({ fromLineNumber: minChangedLineNumber, toLineNumber: maxChangedLineNumber });
- }
- }
- if (ranges.length > 0) {
- this._emitModelTokensChangedEvent({
- tokenizationSupportChanged: false,
- semanticTokensApplied: false,
- ranges: ranges
- });
- }
- }
- this.handleTokenizationProgress(backgroundTokenizationCompleted);
- }
- setSemanticTokens(tokens, isComplete) {
- this._tokens2.set(tokens, isComplete);
- this._emitModelTokensChangedEvent({
- tokenizationSupportChanged: false,
- semanticTokensApplied: tokens !== null,
- ranges: [{ fromLineNumber: 1, toLineNumber: this.getLineCount() }]
- });
- }
- hasCompleteSemanticTokens() {
- return this._tokens2.isComplete();
- }
- hasSomeSemanticTokens() {
- return !this._tokens2.isEmpty();
- }
- setPartialSemanticTokens(range, tokens) {
- if (this.hasCompleteSemanticTokens()) {
- return;
- }
- const changedRange = this._tokens2.setPartial(range, tokens);
- this._emitModelTokensChangedEvent({
- tokenizationSupportChanged: false,
- semanticTokensApplied: true,
- ranges: [{ fromLineNumber: changedRange.startLineNumber, toLineNumber: changedRange.endLineNumber }]
- });
- }
- tokenizeViewport(startLineNumber, endLineNumber) {
- startLineNumber = Math.max(1, startLineNumber);
- endLineNumber = Math.min(this._buffer.getLineCount(), endLineNumber);
- this._tokenization.tokenizeViewport(startLineNumber, endLineNumber);
- }
- clearTokens() {
- this._tokens.flush();
- this._emitModelTokensChangedEvent({
- tokenizationSupportChanged: true,
- semanticTokensApplied: false,
- ranges: [{
- fromLineNumber: 1,
- toLineNumber: this._buffer.getLineCount()
- }]
- });
- }
- _emitModelTokensChangedEvent(e) {
- if (!this._isDisposing) {
- this._onDidChangeTokens.fire(e);
- }
- }
- resetTokenization() {
- this._tokenization.reset();
- }
- forceTokenization(lineNumber) {
- if (lineNumber < 1 || lineNumber > this.getLineCount()) {
- throw new Error('Illegal value for lineNumber');
- }
- this._tokenization.forceTokenization(lineNumber);
- }
- isCheapToTokenize(lineNumber) {
- return this._tokenization.isCheapToTokenize(lineNumber);
- }
- tokenizeIfCheap(lineNumber) {
- if (this.isCheapToTokenize(lineNumber)) {
- this.forceTokenization(lineNumber);
- }
- }
- getLineTokens(lineNumber) {
- if (lineNumber < 1 || lineNumber > this.getLineCount()) {
- throw new Error('Illegal value for lineNumber');
- }
- return this._getLineTokens(lineNumber);
- }
- _getLineTokens(lineNumber) {
- const lineText = this.getLineContent(lineNumber);
- const syntacticTokens = this._tokens.getTokens(this._languageId, lineNumber - 1, lineText);
- return this._tokens2.addSemanticTokens(lineNumber, syntacticTokens);
- }
- getLanguageId() {
- return this._languageId;
- }
- setMode(languageId) {
- if (this._languageId === languageId) {
- // There's nothing to do
- return;
- }
- let e = {
- oldLanguage: this._languageId,
- newLanguage: languageId
- };
- this._languageId = languageId;
- this._onDidChangeLanguage.fire(e);
- this._onDidChangeLanguageConfiguration.fire({});
- }
- getLanguageIdAtPosition(lineNumber, column) {
- const position = this.validatePosition(new Position(lineNumber, column));
- const lineTokens = this.getLineTokens(position.lineNumber);
- return lineTokens.getLanguageId(lineTokens.findTokenIndexAtOffset(position.column - 1));
- }
- getTokenTypeIfInsertingCharacter(lineNumber, column, character) {
- const position = this.validatePosition(new Position(lineNumber, column));
- return this._tokenization.getTokenTypeIfInsertingCharacter(position, character);
- }
- getLanguageConfiguration(languageId) {
- return this._languageConfigurationService.getLanguageConfiguration(languageId);
- }
- // Having tokens allows implementing additional helper methods
- getWordAtPosition(_position) {
- this._assertNotDisposed();
- const position = this.validatePosition(_position);
- const lineContent = this.getLineContent(position.lineNumber);
- const lineTokens = this._getLineTokens(position.lineNumber);
- const tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);
- // (1). First try checking right biased word
- const [rbStartOffset, rbEndOffset] = TextModel._findLanguageBoundaries(lineTokens, tokenIndex);
- const rightBiasedWord = getWordAtText(position.column, this.getLanguageConfiguration(lineTokens.getLanguageId(tokenIndex)).getWordDefinition(), lineContent.substring(rbStartOffset, rbEndOffset), rbStartOffset);
- // Make sure the result touches the original passed in position
- if (rightBiasedWord && rightBiasedWord.startColumn <= _position.column && _position.column <= rightBiasedWord.endColumn) {
- return rightBiasedWord;
- }
- // (2). Else, if we were at a language boundary, check the left biased word
- if (tokenIndex > 0 && rbStartOffset === position.column - 1) {
- // edge case, where `position` sits between two tokens belonging to two different languages
- const [lbStartOffset, lbEndOffset] = TextModel._findLanguageBoundaries(lineTokens, tokenIndex - 1);
- const leftBiasedWord = getWordAtText(position.column, this.getLanguageConfiguration(lineTokens.getLanguageId(tokenIndex - 1)).getWordDefinition(), lineContent.substring(lbStartOffset, lbEndOffset), lbStartOffset);
- // Make sure the result touches the original passed in position
- if (leftBiasedWord && leftBiasedWord.startColumn <= _position.column && _position.column <= leftBiasedWord.endColumn) {
- return leftBiasedWord;
- }
- }
- return null;
- }
- static _findLanguageBoundaries(lineTokens, tokenIndex) {
- const languageId = lineTokens.getLanguageId(tokenIndex);
- // go left until a different language is hit
- let startOffset = 0;
- for (let i = tokenIndex; i >= 0 && lineTokens.getLanguageId(i) === languageId; i--) {
- startOffset = lineTokens.getStartOffset(i);
- }
- // go right until a different language is hit
- let endOffset = lineTokens.getLineContent().length;
- for (let i = tokenIndex, tokenCount = lineTokens.getCount(); i < tokenCount && lineTokens.getLanguageId(i) === languageId; i++) {
- endOffset = lineTokens.getEndOffset(i);
- }
- return [startOffset, endOffset];
- }
- getWordUntilPosition(position) {
- const wordAtPosition = this.getWordAtPosition(position);
- if (!wordAtPosition) {
- return {
- word: '',
- startColumn: position.column,
- endColumn: position.column
- };
- }
- return {
- word: wordAtPosition.word.substr(0, position.column - wordAtPosition.startColumn),
- startColumn: wordAtPosition.startColumn,
- endColumn: position.column
- };
- }
- /**
- * Returns:
- * - -1 => the line consists of whitespace
- * - otherwise => the indent level is returned value
- */
- static computeIndentLevel(line, tabSize) {
- let indent = 0;
- let i = 0;
- let len = line.length;
- while (i < len) {
- let chCode = line.charCodeAt(i);
- if (chCode === 32 /* Space */) {
- indent++;
- }
- else if (chCode === 9 /* Tab */) {
- indent = indent - indent % tabSize + tabSize;
- }
- else {
- break;
- }
- i++;
- }
- if (i === len) {
- return -1; // line only consists of whitespace
- }
- return indent;
- }
- _computeIndentLevel(lineIndex) {
- return TextModel.computeIndentLevel(this._buffer.getLineContent(lineIndex + 1), this._options.tabSize);
- }
- getActiveIndentGuide(lineNumber, minLineNumber, maxLineNumber) {
- this._assertNotDisposed();
- const lineCount = this.getLineCount();
- if (lineNumber < 1 || lineNumber > lineCount) {
- throw new Error('Illegal value for lineNumber');
- }
- const foldingRules = this.getLanguageConfiguration(this._languageId).foldingRules;
- const offSide = Boolean(foldingRules && foldingRules.offSide);
- let up_aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */
- let up_aboveContentLineIndent = -1;
- let up_belowContentLineIndex = -2; /* -2 is a marker for not having computed it */
- let up_belowContentLineIndent = -1;
- const up_resolveIndents = (lineNumber) => {
- if (up_aboveContentLineIndex !== -1 && (up_aboveContentLineIndex === -2 || up_aboveContentLineIndex > lineNumber - 1)) {
- up_aboveContentLineIndex = -1;
- up_aboveContentLineIndent = -1;
- // must find previous line with content
- for (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {
- let indent = this._computeIndentLevel(lineIndex);
- if (indent >= 0) {
- up_aboveContentLineIndex = lineIndex;
- up_aboveContentLineIndent = indent;
- break;
- }
- }
- }
- if (up_belowContentLineIndex === -2) {
- up_belowContentLineIndex = -1;
- up_belowContentLineIndent = -1;
- // must find next line with content
- for (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {
- let indent = this._computeIndentLevel(lineIndex);
- if (indent >= 0) {
- up_belowContentLineIndex = lineIndex;
- up_belowContentLineIndent = indent;
- break;
- }
- }
- }
- };
- let down_aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */
- let down_aboveContentLineIndent = -1;
- let down_belowContentLineIndex = -2; /* -2 is a marker for not having computed it */
- let down_belowContentLineIndent = -1;
- const down_resolveIndents = (lineNumber) => {
- if (down_aboveContentLineIndex === -2) {
- down_aboveContentLineIndex = -1;
- down_aboveContentLineIndent = -1;
- // must find previous line with content
- for (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {
- let indent = this._computeIndentLevel(lineIndex);
- if (indent >= 0) {
- down_aboveContentLineIndex = lineIndex;
- down_aboveContentLineIndent = indent;
- break;
- }
- }
- }
- if (down_belowContentLineIndex !== -1 && (down_belowContentLineIndex === -2 || down_belowContentLineIndex < lineNumber - 1)) {
- down_belowContentLineIndex = -1;
- down_belowContentLineIndent = -1;
- // must find next line with content
- for (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {
- let indent = this._computeIndentLevel(lineIndex);
- if (indent >= 0) {
- down_belowContentLineIndex = lineIndex;
- down_belowContentLineIndent = indent;
- break;
- }
- }
- }
- };
- let startLineNumber = 0;
- let goUp = true;
- let endLineNumber = 0;
- let goDown = true;
- let indent = 0;
- let initialIndent = 0;
- for (let distance = 0; goUp || goDown; distance++) {
- const upLineNumber = lineNumber - distance;
- const downLineNumber = lineNumber + distance;
- if (distance > 1 && (upLineNumber < 1 || upLineNumber < minLineNumber)) {
- goUp = false;
- }
- if (distance > 1 && (downLineNumber > lineCount || downLineNumber > maxLineNumber)) {
- goDown = false;
- }
- if (distance > 50000) {
- // stop processing
- goUp = false;
- goDown = false;
- }
- let upLineIndentLevel = -1;
- if (goUp) {
- // compute indent level going up
- const currentIndent = this._computeIndentLevel(upLineNumber - 1);
- if (currentIndent >= 0) {
- // This line has content (besides whitespace)
- // Use the line's indent
- up_belowContentLineIndex = upLineNumber - 1;
- up_belowContentLineIndent = currentIndent;
- upLineIndentLevel = Math.ceil(currentIndent / this._options.indentSize);
- }
- else {
- up_resolveIndents(upLineNumber);
- upLineIndentLevel = this._getIndentLevelForWhitespaceLine(offSide, up_aboveContentLineIndent, up_belowContentLineIndent);
- }
- }
- let downLineIndentLevel = -1;
- if (goDown) {
- // compute indent level going down
- const currentIndent = this._computeIndentLevel(downLineNumber - 1);
- if (currentIndent >= 0) {
- // This line has content (besides whitespace)
- // Use the line's indent
- down_aboveContentLineIndex = downLineNumber - 1;
- down_aboveContentLineIndent = currentIndent;
- downLineIndentLevel = Math.ceil(currentIndent / this._options.indentSize);
- }
- else {
- down_resolveIndents(downLineNumber);
- downLineIndentLevel = this._getIndentLevelForWhitespaceLine(offSide, down_aboveContentLineIndent, down_belowContentLineIndent);
- }
- }
- if (distance === 0) {
- initialIndent = upLineIndentLevel;
- continue;
- }
- if (distance === 1) {
- if (downLineNumber <= lineCount && downLineIndentLevel >= 0 && initialIndent + 1 === downLineIndentLevel) {
- // This is the beginning of a scope, we have special handling here, since we want the
- // child scope indent to be active, not the parent scope
- goUp = false;
- startLineNumber = downLineNumber;
- endLineNumber = downLineNumber;
- indent = downLineIndentLevel;
- continue;
- }
- if (upLineNumber >= 1 && upLineIndentLevel >= 0 && upLineIndentLevel - 1 === initialIndent) {
- // This is the end of a scope, just like above
- goDown = false;
- startLineNumber = upLineNumber;
- endLineNumber = upLineNumber;
- indent = upLineIndentLevel;
- continue;
- }
- startLineNumber = lineNumber;
- endLineNumber = lineNumber;
- indent = initialIndent;
- if (indent === 0) {
- // No need to continue
- return { startLineNumber, endLineNumber, indent };
- }
- }
- if (goUp) {
- if (upLineIndentLevel >= indent) {
- startLineNumber = upLineNumber;
- }
- else {
- goUp = false;
- }
- }
- if (goDown) {
- if (downLineIndentLevel >= indent) {
- endLineNumber = downLineNumber;
- }
- else {
- goDown = false;
- }
- }
- }
- return { startLineNumber, endLineNumber, indent };
- }
- getLinesBracketGuides(startLineNumber, endLineNumber, activePosition, options) {
- var _a, _b, _c, _d, _e;
- const result = [];
- const bracketPairs = this._bracketPairColorizer.getBracketPairsInRangeWithMinIndentation(new Range(startLineNumber, 1, endLineNumber, this.getLineMaxColumn(endLineNumber)));
- let activeBracketPairRange = undefined;
- if (activePosition && bracketPairs.length > 0) {
- const bracketsContainingActivePosition = (startLineNumber <= activePosition.lineNumber && activePosition.lineNumber <= endLineNumber)
- // Does active position intersect with the view port? -> Intersect bracket pairs with activePosition
- ? bracketPairs.filter(bp => Range.strictContainsPosition(bp.range, activePosition))
- : this._bracketPairColorizer.getBracketPairsInRange(Range.fromPositions(activePosition));
- activeBracketPairRange = (_a = findLast(bracketsContainingActivePosition,
- /* Exclude single line bracket pairs for cases such as
- * ```
- * function test() {
- * if (true) { | }
- * }
- * ```
- */
- (i) => i.range.startLineNumber !== i.range.endLineNumber)) === null || _a === void 0 ? void 0 : _a.range;
- }
- const queue = new ArrayQueue(bracketPairs);
- /** Indexed by nesting level */
- const activeGuides = new Array();
- const nextGuides = new Array();
- const colorProvider = new BracketPairGuidesClassNames();
- for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
- let guides = new Array();
- if (nextGuides.length > 0) {
- guides = guides.concat(nextGuides);
- nextGuides.length = 0;
- }
- result.push(guides);
- // Update activeGuides
- for (const pair of queue.takeWhile(b => b.openingBracketRange.startLineNumber <= lineNumber) || []) {
- if (pair.range.startLineNumber === pair.range.endLineNumber) {
- // ignore single line brackets
- continue;
- }
- const guideVisibleColumn = Math.min(this.getVisibleColumnFromPosition(pair.openingBracketRange.getStartPosition()), this.getVisibleColumnFromPosition((_c = (_b = pair.closingBracketRange) === null || _b === void 0 ? void 0 : _b.getStartPosition()) !== null && _c !== void 0 ? _c : pair.range.getEndPosition()), pair.minVisibleColumnIndentation + 1);
- let renderHorizontalEndLineAtTheBottom = false;
- if (pair.closingBracketRange) {
- const firstNonWsIndex = strings.firstNonWhitespaceIndex(this.getLineContent(pair.closingBracketRange.startLineNumber));
- if (firstNonWsIndex < pair.closingBracketRange.startColumn - 1) {
- renderHorizontalEndLineAtTheBottom = true;
- }
- }
- const start = pair.openingBracketRange.getStartPosition();
- const end = ((_e = (_d = pair.closingBracketRange) === null || _d === void 0 ? void 0 : _d.getStartPosition()) !== null && _e !== void 0 ? _e : pair.range.getEndPosition());
- if (pair.closingBracketRange === undefined) {
- // Don't show guides for bracket pairs that are not balanced.
- // See #135125.
- activeGuides[pair.nestingLevel] = null;
- }
- else {
- activeGuides[pair.nestingLevel] = {
- nestingLevel: pair.nestingLevel,
- guideVisibleColumn,
- start,
- visibleStartColumn: this.getVisibleColumnFromPosition(start),
- end,
- visibleEndColumn: this.getVisibleColumnFromPosition(end),
- bracketPair: pair,
- renderHorizontalEndLineAtTheBottom
- };
- }
- }
- for (const line of activeGuides) {
- if (!line) {
- continue;
- }
- const isActive = activeBracketPairRange && line.bracketPair.range.equalsRange(activeBracketPairRange);
- const className = colorProvider.getInlineClassNameOfLevel(line.nestingLevel) +
- (options.highlightActive && isActive ? ' ' + colorProvider.activeClassName : '');
- if ((isActive && options.horizontalGuides !== model.HorizontalGuidesState.Disabled)
- || (options.includeInactive && options.horizontalGuides === model.HorizontalGuidesState.Enabled)) {
- if (line.start.lineNumber === lineNumber) {
- if (line.guideVisibleColumn < line.visibleStartColumn) {
- guides.push(new model.IndentGuide(line.guideVisibleColumn, className, new model.IndentGuideHorizontalLine(false, line.start.column)));
- }
- }
- if (line.end.lineNumber === lineNumber + 1) {
- // The next line might have horizontal guides.
- // However, the next line might also have a new bracket pair with the same indentation,
- // so the current bracket pair might get replaced. That's why we push the guide to nextGuides one line ahead.
- if (line.guideVisibleColumn < line.visibleEndColumn) {
- nextGuides.push(new model.IndentGuide(line.guideVisibleColumn, className, new model.IndentGuideHorizontalLine(!line.renderHorizontalEndLineAtTheBottom, line.end.column)));
- }
- }
- }
- }
- let lastVisibleColumnCount = Number.MAX_SAFE_INTEGER;
- // Going backwards, so the last guide potentially replaces others
- for (let i = activeGuides.length - 1; i >= 0; i--) {
- const line = activeGuides[i];
- if (!line) {
- continue;
- }
- const isActive = options.highlightActive && activeBracketPairRange &&
- line.bracketPair.range.equalsRange(activeBracketPairRange);
- const className = colorProvider.getInlineClassNameOfLevel(line.nestingLevel) +
- (isActive ? ' ' + colorProvider.activeClassName : '');
- if (isActive || options.includeInactive) {
- if (line.renderHorizontalEndLineAtTheBottom && line.end.lineNumber === lineNumber + 1) {
- nextGuides.push(new model.IndentGuide(line.guideVisibleColumn, className, null));
- }
- }
- if (line.end.lineNumber <= lineNumber
- || line.start.lineNumber >= lineNumber) {
- continue;
- }
- if (line.guideVisibleColumn >= lastVisibleColumnCount && !isActive) {
- // Don't render a guide on top of an existing guide, unless it is active.
- continue;
- }
- lastVisibleColumnCount = line.guideVisibleColumn;
- if (isActive || options.includeInactive) {
- guides.push(new model.IndentGuide(line.guideVisibleColumn, className, null));
- }
- }
- guides.sort((a, b) => a.visibleColumn - b.visibleColumn);
- }
- return result;
- }
- getVisibleColumnFromPosition(position) {
- return CursorColumns.visibleColumnFromColumn(this.getLineContent(position.lineNumber), position.column, this._options.tabSize) + 1;
- }
- getLinesIndentGuides(startLineNumber, endLineNumber) {
- this._assertNotDisposed();
- const lineCount = this.getLineCount();
- if (startLineNumber < 1 || startLineNumber > lineCount) {
- throw new Error('Illegal value for startLineNumber');
- }
- if (endLineNumber < 1 || endLineNumber > lineCount) {
- throw new Error('Illegal value for endLineNumber');
- }
- const foldingRules = this.getLanguageConfiguration(this._languageId).foldingRules;
- const offSide = Boolean(foldingRules && foldingRules.offSide);
- let result = new Array(endLineNumber - startLineNumber + 1);
- let aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */
- let aboveContentLineIndent = -1;
- let belowContentLineIndex = -2; /* -2 is a marker for not having computed it */
- let belowContentLineIndent = -1;
- for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
- let resultIndex = lineNumber - startLineNumber;
- const currentIndent = this._computeIndentLevel(lineNumber - 1);
- if (currentIndent >= 0) {
- // This line has content (besides whitespace)
- // Use the line's indent
- aboveContentLineIndex = lineNumber - 1;
- aboveContentLineIndent = currentIndent;
- result[resultIndex] = Math.ceil(currentIndent / this._options.indentSize);
- continue;
- }
- if (aboveContentLineIndex === -2) {
- aboveContentLineIndex = -1;
- aboveContentLineIndent = -1;
- // must find previous line with content
- for (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {
- let indent = this._computeIndentLevel(lineIndex);
- if (indent >= 0) {
- aboveContentLineIndex = lineIndex;
- aboveContentLineIndent = indent;
- break;
- }
- }
- }
- if (belowContentLineIndex !== -1 && (belowContentLineIndex === -2 || belowContentLineIndex < lineNumber - 1)) {
- belowContentLineIndex = -1;
- belowContentLineIndent = -1;
- // must find next line with content
- for (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {
- let indent = this._computeIndentLevel(lineIndex);
- if (indent >= 0) {
- belowContentLineIndex = lineIndex;
- belowContentLineIndent = indent;
- break;
- }
- }
- }
- result[resultIndex] = this._getIndentLevelForWhitespaceLine(offSide, aboveContentLineIndent, belowContentLineIndent);
- }
- return result;
- }
- _getIndentLevelForWhitespaceLine(offSide, aboveContentLineIndent, belowContentLineIndent) {
- if (aboveContentLineIndent === -1 || belowContentLineIndent === -1) {
- // At the top or bottom of the file
- return 0;
- }
- else if (aboveContentLineIndent < belowContentLineIndent) {
- // we are inside the region above
- return (1 + Math.floor(aboveContentLineIndent / this._options.indentSize));
- }
- else if (aboveContentLineIndent === belowContentLineIndent) {
- // we are in between two regions
- return Math.ceil(belowContentLineIndent / this._options.indentSize);
- }
- else {
- if (offSide) {
- // same level as region below
- return Math.ceil(belowContentLineIndent / this._options.indentSize);
- }
- else {
- // we are inside the region that ends below
- return (1 + Math.floor(belowContentLineIndent / this._options.indentSize));
- }
- }
- }
- //#endregion
- normalizePosition(position, affinity) {
- return position;
- }
- /**
- * Gets the column at which indentation stops at a given line.
- * @internal
- */
- getLineIndentColumn(lineNumber) {
- // Columns start with 1.
- return indentOfLine(this.getLineContent(lineNumber)) + 1;
- }
- };
- TextModel.MODEL_SYNC_LIMIT = 50 * 1024 * 1024; // 50 MB
- TextModel.LARGE_FILE_SIZE_THRESHOLD = 20 * 1024 * 1024; // 20 MB;
- TextModel.LARGE_FILE_LINE_COUNT_THRESHOLD = 300 * 1000; // 300K lines
- TextModel.DEFAULT_CREATION_OPTIONS = {
- isForSimpleWidget: false,
- tabSize: EDITOR_MODEL_DEFAULTS.tabSize,
- indentSize: EDITOR_MODEL_DEFAULTS.indentSize,
- insertSpaces: EDITOR_MODEL_DEFAULTS.insertSpaces,
- detectIndentation: false,
- defaultEOL: 1 /* LF */,
- trimAutoWhitespace: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace,
- largeFileOptimizations: EDITOR_MODEL_DEFAULTS.largeFileOptimizations,
- bracketPairColorizationOptions: EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions,
- };
- TextModel = __decorate([
- __param(4, IUndoRedoService),
- __param(5, IModeService),
- __param(6, ILanguageConfigurationService)
- ], TextModel);
- export { TextModel };
- function indentOfLine(line) {
- let indent = 0;
- for (const c of line) {
- if (c === ' ' || c === '\t') {
- indent++;
- }
- else {
- break;
- }
- }
- return indent;
- }
- export class BracketPairGuidesClassNames {
- constructor() {
- this.activeClassName = 'indent-active';
- }
- getInlineClassNameOfLevel(level) {
- // To support a dynamic amount of colors up to 6 colors,
- // we use a number that is a lcm of all numbers from 1 to 6.
- return `bracket-indent-guide lvl-${level % 30}`;
- }
- }
- //#region Decorations
- function isNodeInOverviewRuler(node) {
- return (node.options.overviewRuler && node.options.overviewRuler.color ? true : false);
- }
- function isNodeInjectedText(node) {
- return !!node.options.after || !!node.options.before;
- }
- class DecorationsTrees {
- constructor() {
- this._decorationsTree0 = new IntervalTree();
- this._decorationsTree1 = new IntervalTree();
- this._injectedTextDecorationsTree = new IntervalTree();
- }
- ensureAllNodesHaveRanges(host) {
- this.getAll(host, 0, false, false);
- }
- _ensureNodesHaveRanges(host, nodes) {
- for (const node of nodes) {
- if (node.range === null) {
- node.range = host.getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd);
- }
- }
- return nodes;
- }
- getAllInInterval(host, start, end, filterOwnerId, filterOutValidation) {
- const versionId = host.getVersionId();
- const result = this._intervalSearch(start, end, filterOwnerId, filterOutValidation, versionId);
- return this._ensureNodesHaveRanges(host, result);
- }
- _intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId) {
- const r0 = this._decorationsTree0.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
- const r1 = this._decorationsTree1.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
- const r2 = this._injectedTextDecorationsTree.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
- return r0.concat(r1).concat(r2);
- }
- getInjectedTextInInterval(host, start, end, filterOwnerId) {
- const versionId = host.getVersionId();
- const result = this._injectedTextDecorationsTree.intervalSearch(start, end, filterOwnerId, false, versionId);
- return this._ensureNodesHaveRanges(host, result).filter((i) => i.options.showIfCollapsed || !i.range.isEmpty());
- }
- getAllInjectedText(host, filterOwnerId) {
- const versionId = host.getVersionId();
- const result = this._injectedTextDecorationsTree.search(filterOwnerId, false, versionId);
- return this._ensureNodesHaveRanges(host, result).filter((i) => i.options.showIfCollapsed || !i.range.isEmpty());
- }
- getAll(host, filterOwnerId, filterOutValidation, overviewRulerOnly) {
- const versionId = host.getVersionId();
- const result = this._search(filterOwnerId, filterOutValidation, overviewRulerOnly, versionId);
- return this._ensureNodesHaveRanges(host, result);
- }
- _search(filterOwnerId, filterOutValidation, overviewRulerOnly, cachedVersionId) {
- if (overviewRulerOnly) {
- return this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId);
- }
- else {
- const r0 = this._decorationsTree0.search(filterOwnerId, filterOutValidation, cachedVersionId);
- const r1 = this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId);
- const r2 = this._injectedTextDecorationsTree.search(filterOwnerId, filterOutValidation, cachedVersionId);
- return r0.concat(r1).concat(r2);
- }
- }
- collectNodesFromOwner(ownerId) {
- const r0 = this._decorationsTree0.collectNodesFromOwner(ownerId);
- const r1 = this._decorationsTree1.collectNodesFromOwner(ownerId);
- const r2 = this._injectedTextDecorationsTree.collectNodesFromOwner(ownerId);
- return r0.concat(r1).concat(r2);
- }
- collectNodesPostOrder() {
- const r0 = this._decorationsTree0.collectNodesPostOrder();
- const r1 = this._decorationsTree1.collectNodesPostOrder();
- const r2 = this._injectedTextDecorationsTree.collectNodesPostOrder();
- return r0.concat(r1).concat(r2);
- }
- insert(node) {
- if (isNodeInjectedText(node)) {
- this._injectedTextDecorationsTree.insert(node);
- }
- else if (isNodeInOverviewRuler(node)) {
- this._decorationsTree1.insert(node);
- }
- else {
- this._decorationsTree0.insert(node);
- }
- }
- delete(node) {
- if (isNodeInjectedText(node)) {
- this._injectedTextDecorationsTree.delete(node);
- }
- else if (isNodeInOverviewRuler(node)) {
- this._decorationsTree1.delete(node);
- }
- else {
- this._decorationsTree0.delete(node);
- }
- }
- getNodeRange(host, node) {
- const versionId = host.getVersionId();
- if (node.cachedVersionId !== versionId) {
- this._resolveNode(node, versionId);
- }
- if (node.range === null) {
- node.range = host.getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd);
- }
- return node.range;
- }
- _resolveNode(node, cachedVersionId) {
- if (isNodeInjectedText(node)) {
- this._injectedTextDecorationsTree.resolveNode(node, cachedVersionId);
- }
- else if (isNodeInOverviewRuler(node)) {
- this._decorationsTree1.resolveNode(node, cachedVersionId);
- }
- else {
- this._decorationsTree0.resolveNode(node, cachedVersionId);
- }
- }
- acceptReplace(offset, length, textLength, forceMoveMarkers) {
- this._decorationsTree0.acceptReplace(offset, length, textLength, forceMoveMarkers);
- this._decorationsTree1.acceptReplace(offset, length, textLength, forceMoveMarkers);
- this._injectedTextDecorationsTree.acceptReplace(offset, length, textLength, forceMoveMarkers);
- }
- }
- function cleanClassName(className) {
- return className.replace(/[^a-z0-9\-_]/gi, ' ');
- }
- class DecorationOptions {
- constructor(options) {
- this.color = options.color || '';
- this.darkColor = options.darkColor || '';
- }
- }
- export class ModelDecorationOverviewRulerOptions extends DecorationOptions {
- constructor(options) {
- super(options);
- this._resolvedColor = null;
- this.position = (typeof options.position === 'number' ? options.position : model.OverviewRulerLane.Center);
- }
- getColor(theme) {
- if (!this._resolvedColor) {
- if (theme.type !== 'light' && this.darkColor) {
- this._resolvedColor = this._resolveColor(this.darkColor, theme);
- }
- else {
- this._resolvedColor = this._resolveColor(this.color, theme);
- }
- }
- return this._resolvedColor;
- }
- invalidateCachedColor() {
- this._resolvedColor = null;
- }
- _resolveColor(color, theme) {
- if (typeof color === 'string') {
- return color;
- }
- let c = color ? theme.getColor(color.id) : null;
- if (!c) {
- return '';
- }
- return c.toString();
- }
- }
- export class ModelDecorationMinimapOptions extends DecorationOptions {
- constructor(options) {
- super(options);
- this.position = options.position;
- }
- getColor(theme) {
- if (!this._resolvedColor) {
- if (theme.type !== 'light' && this.darkColor) {
- this._resolvedColor = this._resolveColor(this.darkColor, theme);
- }
- else {
- this._resolvedColor = this._resolveColor(this.color, theme);
- }
- }
- return this._resolvedColor;
- }
- invalidateCachedColor() {
- this._resolvedColor = undefined;
- }
- _resolveColor(color, theme) {
- if (typeof color === 'string') {
- return Color.fromHex(color);
- }
- return theme.getColor(color.id);
- }
- }
- export class ModelDecorationInjectedTextOptions {
- constructor(options) {
- this.content = options.content || '';
- this.inlineClassName = options.inlineClassName || null;
- this.inlineClassNameAffectsLetterSpacing = options.inlineClassNameAffectsLetterSpacing || false;
- }
- static from(options) {
- if (options instanceof ModelDecorationInjectedTextOptions) {
- return options;
- }
- return new ModelDecorationInjectedTextOptions(options);
- }
- }
- export class ModelDecorationOptions {
- constructor(options) {
- var _a;
- this.description = options.description;
- this.stickiness = options.stickiness || 0 /* AlwaysGrowsWhenTypingAtEdges */;
- this.zIndex = options.zIndex || 0;
- this.className = options.className ? cleanClassName(options.className) : null;
- this.hoverMessage = options.hoverMessage || null;
- this.glyphMarginHoverMessage = options.glyphMarginHoverMessage || null;
- this.isWholeLine = options.isWholeLine || false;
- this.showIfCollapsed = options.showIfCollapsed || false;
- this.collapseOnReplaceEdit = options.collapseOnReplaceEdit || false;
- this.overviewRuler = options.overviewRuler ? new ModelDecorationOverviewRulerOptions(options.overviewRuler) : null;
- this.minimap = options.minimap ? new ModelDecorationMinimapOptions(options.minimap) : null;
- this.glyphMarginClassName = options.glyphMarginClassName ? cleanClassName(options.glyphMarginClassName) : null;
- this.linesDecorationsClassName = options.linesDecorationsClassName ? cleanClassName(options.linesDecorationsClassName) : null;
- this.firstLineDecorationClassName = options.firstLineDecorationClassName ? cleanClassName(options.firstLineDecorationClassName) : null;
- this.marginClassName = options.marginClassName ? cleanClassName(options.marginClassName) : null;
- this.inlineClassName = options.inlineClassName ? cleanClassName(options.inlineClassName) : null;
- this.inlineClassNameAffectsLetterSpacing = options.inlineClassNameAffectsLetterSpacing || false;
- this.beforeContentClassName = options.beforeContentClassName ? cleanClassName(options.beforeContentClassName) : null;
- this.afterContentClassName = options.afterContentClassName ? cleanClassName(options.afterContentClassName) : null;
- this.after = options.after ? ModelDecorationInjectedTextOptions.from(options.after) : null;
- this.before = options.before ? ModelDecorationInjectedTextOptions.from(options.before) : null;
- this.hideInCommentTokens = (_a = options.hideInCommentTokens) !== null && _a !== void 0 ? _a : false;
- }
- static register(options) {
- return new ModelDecorationOptions(options);
- }
- static createDynamic(options) {
- return new ModelDecorationOptions(options);
- }
- }
- ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({ description: 'empty' });
- /**
- * The order carefully matches the values of the enum.
- */
- const TRACKED_RANGE_OPTIONS = [
- ModelDecorationOptions.register({ description: 'tracked-range-always-grows-when-typing-at-edges', stickiness: 0 /* AlwaysGrowsWhenTypingAtEdges */ }),
- ModelDecorationOptions.register({ description: 'tracked-range-never-grows-when-typing-at-edges', stickiness: 1 /* NeverGrowsWhenTypingAtEdges */ }),
- ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-before', stickiness: 2 /* GrowsOnlyWhenTypingBefore */ }),
- ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-after', stickiness: 3 /* GrowsOnlyWhenTypingAfter */ }),
- ];
- function _normalizeOptions(options) {
- if (options instanceof ModelDecorationOptions) {
- return options;
- }
- return ModelDecorationOptions.createDynamic(options);
- }
- export class DidChangeDecorationsEmitter extends Disposable {
- constructor(handleBeforeFire) {
- super();
- this.handleBeforeFire = handleBeforeFire;
- this._actual = this._register(new Emitter());
- this.event = this._actual.event;
- this._affectedInjectedTextLines = null;
- this._deferredCnt = 0;
- this._shouldFire = false;
- this._affectsMinimap = false;
- this._affectsOverviewRuler = false;
- }
- beginDeferredEmit() {
- this._deferredCnt++;
- }
- endDeferredEmit() {
- var _a;
- this._deferredCnt--;
- if (this._deferredCnt === 0) {
- if (this._shouldFire) {
- this.handleBeforeFire(this._affectedInjectedTextLines);
- const event = {
- affectsMinimap: this._affectsMinimap,
- affectsOverviewRuler: this._affectsOverviewRuler
- };
- this._shouldFire = false;
- this._affectsMinimap = false;
- this._affectsOverviewRuler = false;
- this._actual.fire(event);
- }
- (_a = this._affectedInjectedTextLines) === null || _a === void 0 ? void 0 : _a.clear();
- this._affectedInjectedTextLines = null;
- }
- }
- recordLineAffectedByInjectedText(lineNumber) {
- if (!this._affectedInjectedTextLines) {
- this._affectedInjectedTextLines = new Set();
- }
- this._affectedInjectedTextLines.add(lineNumber);
- }
- checkAffectedAndFire(options) {
- if (!this._affectsMinimap) {
- this._affectsMinimap = options.minimap && options.minimap.position ? true : false;
- }
- if (!this._affectsOverviewRuler) {
- this._affectsOverviewRuler = options.overviewRuler && options.overviewRuler.color ? true : false;
- }
- this._shouldFire = true;
- }
- fire() {
- this._affectsMinimap = true;
- this._affectsOverviewRuler = true;
- this._shouldFire = true;
- }
- }
- //#endregion
- export class DidChangeContentEmitter extends Disposable {
- constructor() {
- super();
- /**
- * Both `fastEvent` and `slowEvent` work the same way and contain the same events, but first we invoke `fastEvent` and then `slowEvent`.
- */
- this._fastEmitter = this._register(new Emitter());
- this.fastEvent = this._fastEmitter.event;
- this._slowEmitter = this._register(new Emitter());
- this.slowEvent = this._slowEmitter.event;
- this._deferredCnt = 0;
- this._deferredEvent = null;
- }
- beginDeferredEmit() {
- this._deferredCnt++;
- }
- endDeferredEmit(resultingSelection = null) {
- this._deferredCnt--;
- if (this._deferredCnt === 0) {
- if (this._deferredEvent !== null) {
- this._deferredEvent.rawContentChangedEvent.resultingSelection = resultingSelection;
- const e = this._deferredEvent;
- this._deferredEvent = null;
- this._fastEmitter.fire(e);
- this._slowEmitter.fire(e);
- }
- }
- }
- fire(e) {
- if (this._deferredCnt > 0) {
- if (this._deferredEvent) {
- this._deferredEvent = this._deferredEvent.merge(e);
- }
- else {
- this._deferredEvent = e;
- }
- return;
- }
- this._fastEmitter.fire(e);
- this._slowEmitter.fire(e);
- }
- }
|