textModel.js 113 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
  6. var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
  7. if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
  8. 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;
  9. return c > 3 && r && Object.defineProperty(target, key, r), r;
  10. };
  11. var __param = (this && this.__param) || function (paramIndex, decorator) {
  12. return function (target, key) { decorator(target, key, paramIndex); }
  13. };
  14. import { onUnexpectedError } from '../../../base/common/errors.js';
  15. import { Emitter } from '../../../base/common/event.js';
  16. import { Disposable } from '../../../base/common/lifecycle.js';
  17. import * as strings from '../../../base/common/strings.js';
  18. import { URI } from '../../../base/common/uri.js';
  19. import { EDITOR_MODEL_DEFAULTS } from '../config/editorOptions.js';
  20. import { Position } from '../core/position.js';
  21. import { Range } from '../core/range.js';
  22. import { Selection } from '../core/selection.js';
  23. import * as model from '../model.js';
  24. import { EditStack } from './editStack.js';
  25. import { guessIndentation } from './indentationGuesser.js';
  26. import { IntervalNode, IntervalTree, recomputeMaxEnd } from './intervalTree.js';
  27. import { PieceTreeTextBufferBuilder } from './pieceTreeTextBuffer/pieceTreeTextBufferBuilder.js';
  28. import { InternalModelContentChangeEvent, LineInjectedText, ModelInjectedTextChangedEvent, ModelRawContentChangedEvent, ModelRawEOLChanged, ModelRawFlush, ModelRawLineChanged, ModelRawLinesDeleted, ModelRawLinesInserted } from './textModelEvents.js';
  29. import { SearchParams, TextModelSearch } from './textModelSearch.js';
  30. import { TextModelTokenization } from './textModelTokens.js';
  31. import { getWordAtText } from './wordHelper.js';
  32. import { ILanguageConfigurationService } from '../modes/languageConfigurationRegistry.js';
  33. import { NULL_MODE_ID } from '../modes/nullMode.js';
  34. import { TokensStore, countEOL, TokensStore2 } from './tokensStore.js';
  35. import { Color } from '../../../base/common/color.js';
  36. import { IUndoRedoService } from '../../../platform/undoRedo/common/undoRedo.js';
  37. import { PieceTreeTextBuffer } from './pieceTreeTextBuffer/pieceTreeTextBuffer.js';
  38. import { ArrayQueue, findLast } from '../../../base/common/arrays.js';
  39. import { BracketPairs } from './bracketPairs/bracketPairsImpl.js';
  40. import { ColorizedBracketPairsDecorationProvider } from './bracketPairs/colorizedBracketPairsDecorationProvider.js';
  41. import { CursorColumns } from '../controller/cursorColumns.js';
  42. import { IModeService } from '../services/modeService.js';
  43. function createTextBufferBuilder() {
  44. return new PieceTreeTextBufferBuilder();
  45. }
  46. export function createTextBufferFactory(text) {
  47. const builder = createTextBufferBuilder();
  48. builder.acceptChunk(text);
  49. return builder.finish();
  50. }
  51. export function createTextBuffer(value, defaultEOL) {
  52. const factory = (typeof value === 'string' ? createTextBufferFactory(value) : value);
  53. return factory.create(defaultEOL);
  54. }
  55. let MODEL_ID = 0;
  56. const LIMIT_FIND_COUNT = 999;
  57. export const LONG_LINE_BOUNDARY = 10000;
  58. class TextModelSnapshot {
  59. constructor(source) {
  60. this._source = source;
  61. this._eos = false;
  62. }
  63. read() {
  64. if (this._eos) {
  65. return null;
  66. }
  67. let result = [], resultCnt = 0, resultLength = 0;
  68. do {
  69. let tmp = this._source.read();
  70. if (tmp === null) {
  71. // end-of-stream
  72. this._eos = true;
  73. if (resultCnt === 0) {
  74. return null;
  75. }
  76. else {
  77. return result.join('');
  78. }
  79. }
  80. if (tmp.length > 0) {
  81. result[resultCnt++] = tmp;
  82. resultLength += tmp.length;
  83. }
  84. if (resultLength >= 64 * 1024) {
  85. return result.join('');
  86. }
  87. } while (true);
  88. }
  89. }
  90. const invalidFunc = () => { throw new Error(`Invalid change accessor`); };
  91. let TextModel = class TextModel extends Disposable {
  92. constructor(source, creationOptions, languageId, associatedResource = null, _undoRedoService, _modeService, _languageConfigurationService) {
  93. super();
  94. this._undoRedoService = _undoRedoService;
  95. this._modeService = _modeService;
  96. this._languageConfigurationService = _languageConfigurationService;
  97. //#region Events
  98. this._onWillDispose = this._register(new Emitter());
  99. this.onWillDispose = this._onWillDispose.event;
  100. this._onDidChangeDecorations = this._register(new DidChangeDecorationsEmitter(affectedInjectedTextLines => this.handleBeforeFireDecorationsChangedEvent(affectedInjectedTextLines)));
  101. this.onDidChangeDecorations = this._onDidChangeDecorations.event;
  102. this._onDidChangeLanguage = this._register(new Emitter());
  103. this.onDidChangeLanguage = this._onDidChangeLanguage.event;
  104. this._onDidChangeLanguageConfiguration = this._register(new Emitter());
  105. this.onDidChangeLanguageConfiguration = this._onDidChangeLanguageConfiguration.event;
  106. this._onDidChangeTokens = this._register(new Emitter());
  107. this.onDidChangeTokens = this._onDidChangeTokens.event;
  108. this._onDidChangeOptions = this._register(new Emitter());
  109. this.onDidChangeOptions = this._onDidChangeOptions.event;
  110. this._onDidChangeAttached = this._register(new Emitter());
  111. this.onDidChangeAttached = this._onDidChangeAttached.event;
  112. this._onDidChangeContentOrInjectedText = this._register(new Emitter());
  113. this.onDidChangeContentOrInjectedText = this._onDidChangeContentOrInjectedText.event;
  114. this._eventEmitter = this._register(new DidChangeContentEmitter());
  115. this._backgroundTokenizationState = 0 /* Uninitialized */;
  116. this._onBackgroundTokenizationStateChanged = this._register(new Emitter());
  117. this.onBackgroundTokenizationStateChanged = this._onBackgroundTokenizationStateChanged.event;
  118. this._register(this._eventEmitter.fastEvent((e) => {
  119. this._onDidChangeContentOrInjectedText.fire(e.rawContentChangedEvent);
  120. }));
  121. // Generate a new unique model id
  122. MODEL_ID++;
  123. this.id = '$model' + MODEL_ID;
  124. this.isForSimpleWidget = creationOptions.isForSimpleWidget;
  125. if (typeof associatedResource === 'undefined' || associatedResource === null) {
  126. this._associatedResource = URI.parse('inmemory://model/' + MODEL_ID);
  127. }
  128. else {
  129. this._associatedResource = associatedResource;
  130. }
  131. this._attachedEditorCount = 0;
  132. const { textBuffer, disposable } = createTextBuffer(source, creationOptions.defaultEOL);
  133. this._buffer = textBuffer;
  134. this._bufferDisposable = disposable;
  135. this._options = TextModel.resolveOptions(this._buffer, creationOptions);
  136. const bufferLineCount = this._buffer.getLineCount();
  137. const bufferTextLength = this._buffer.getValueLengthInRange(new Range(1, 1, bufferLineCount, this._buffer.getLineLength(bufferLineCount) + 1), 0 /* TextDefined */);
  138. // !!! Make a decision in the ctor and permanently respect this decision !!!
  139. // If a model is too large at construction time, it will never get tokenized,
  140. // under no circumstances.
  141. if (creationOptions.largeFileOptimizations) {
  142. this._isTooLargeForTokenization = ((bufferTextLength > TextModel.LARGE_FILE_SIZE_THRESHOLD)
  143. || (bufferLineCount > TextModel.LARGE_FILE_LINE_COUNT_THRESHOLD));
  144. }
  145. else {
  146. this._isTooLargeForTokenization = false;
  147. }
  148. this._isTooLargeForSyncing = (bufferTextLength > TextModel.MODEL_SYNC_LIMIT);
  149. this._versionId = 1;
  150. this._alternativeVersionId = 1;
  151. this._initialUndoRedoSnapshot = null;
  152. this._isDisposed = false;
  153. this._isDisposing = false;
  154. this._languageId = languageId || NULL_MODE_ID;
  155. this._languageRegistryListener = this._languageConfigurationService.onDidChange(e => {
  156. if (e.affects(this._languageId)) {
  157. this._onDidChangeLanguageConfiguration.fire({});
  158. }
  159. });
  160. this._instanceId = strings.singleLetterHash(MODEL_ID);
  161. this._lastDecorationId = 0;
  162. this._decorations = Object.create(null);
  163. this._decorationsTree = new DecorationsTrees();
  164. this._commandManager = new EditStack(this, this._undoRedoService);
  165. this._isUndoing = false;
  166. this._isRedoing = false;
  167. this._trimAutoWhitespaceLines = null;
  168. this._tokens = new TokensStore(this._modeService.languageIdCodec);
  169. this._tokens2 = new TokensStore2(this._modeService.languageIdCodec);
  170. this._tokenization = new TextModelTokenization(this, this._modeService.languageIdCodec);
  171. this._bracketPairColorizer = this._register(new BracketPairs(this, this._languageConfigurationService));
  172. this._decorationProvider = this._register(new ColorizedBracketPairsDecorationProvider(this));
  173. this._register(this._decorationProvider.onDidChange(() => {
  174. this._onDidChangeDecorations.beginDeferredEmit();
  175. this._onDidChangeDecorations.fire();
  176. this._onDidChangeDecorations.endDeferredEmit();
  177. }));
  178. }
  179. static resolveOptions(textBuffer, options) {
  180. if (options.detectIndentation) {
  181. const guessedIndentation = guessIndentation(textBuffer, options.tabSize, options.insertSpaces);
  182. return new model.TextModelResolvedOptions({
  183. tabSize: guessedIndentation.tabSize,
  184. indentSize: guessedIndentation.tabSize,
  185. insertSpaces: guessedIndentation.insertSpaces,
  186. trimAutoWhitespace: options.trimAutoWhitespace,
  187. defaultEOL: options.defaultEOL,
  188. bracketPairColorizationOptions: options.bracketPairColorizationOptions,
  189. });
  190. }
  191. return new model.TextModelResolvedOptions({
  192. tabSize: options.tabSize,
  193. indentSize: options.indentSize,
  194. insertSpaces: options.insertSpaces,
  195. trimAutoWhitespace: options.trimAutoWhitespace,
  196. defaultEOL: options.defaultEOL,
  197. bracketPairColorizationOptions: options.bracketPairColorizationOptions,
  198. });
  199. }
  200. onDidChangeContentFast(listener) {
  201. return this._eventEmitter.fastEvent((e) => listener(e.contentChangedEvent));
  202. }
  203. onDidChangeContent(listener) {
  204. return this._eventEmitter.slowEvent((e) => listener(e.contentChangedEvent));
  205. }
  206. get bracketPairs() { return this._bracketPairColorizer; }
  207. get backgroundTokenizationState() {
  208. return this._backgroundTokenizationState;
  209. }
  210. handleTokenizationProgress(completed) {
  211. if (this._backgroundTokenizationState === 2 /* Completed */) {
  212. // We already did a full tokenization and don't go back to progressing.
  213. return;
  214. }
  215. const newState = completed ? 2 /* Completed */ : 1 /* InProgress */;
  216. if (this._backgroundTokenizationState !== newState) {
  217. this._backgroundTokenizationState = newState;
  218. this._onBackgroundTokenizationStateChanged.fire();
  219. }
  220. }
  221. dispose() {
  222. this._isDisposing = true;
  223. this._onWillDispose.fire();
  224. this._languageRegistryListener.dispose();
  225. this._tokenization.dispose();
  226. this._isDisposed = true;
  227. super.dispose();
  228. this._bufferDisposable.dispose();
  229. this._isDisposing = false;
  230. // Manually release reference to previous text buffer to avoid large leaks
  231. // in case someone leaks a TextModel reference
  232. const emptyDisposedTextBuffer = new PieceTreeTextBuffer([], '', '\n', false, false, true, true);
  233. emptyDisposedTextBuffer.dispose();
  234. this._buffer = emptyDisposedTextBuffer;
  235. }
  236. _assertNotDisposed() {
  237. if (this._isDisposed) {
  238. throw new Error('Model is disposed!');
  239. }
  240. }
  241. _emitContentChangedEvent(rawChange, change) {
  242. this._bracketPairColorizer.handleContentChanged(change);
  243. if (this._isDisposing) {
  244. // Do not confuse listeners by emitting any event after disposing
  245. return;
  246. }
  247. this._eventEmitter.fire(new InternalModelContentChangeEvent(rawChange, change));
  248. }
  249. setValue(value) {
  250. this._assertNotDisposed();
  251. if (value === null) {
  252. // There's nothing to do
  253. return;
  254. }
  255. const { textBuffer, disposable } = createTextBuffer(value, this._options.defaultEOL);
  256. this._setValueFromTextBuffer(textBuffer, disposable);
  257. }
  258. _createContentChanged2(range, rangeOffset, rangeLength, text, isUndoing, isRedoing, isFlush) {
  259. return {
  260. changes: [{
  261. range: range,
  262. rangeOffset: rangeOffset,
  263. rangeLength: rangeLength,
  264. text: text,
  265. }],
  266. eol: this._buffer.getEOL(),
  267. versionId: this.getVersionId(),
  268. isUndoing: isUndoing,
  269. isRedoing: isRedoing,
  270. isFlush: isFlush
  271. };
  272. }
  273. _setValueFromTextBuffer(textBuffer, textBufferDisposable) {
  274. this._assertNotDisposed();
  275. const oldFullModelRange = this.getFullModelRange();
  276. const oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);
  277. const endLineNumber = this.getLineCount();
  278. const endColumn = this.getLineMaxColumn(endLineNumber);
  279. this._buffer = textBuffer;
  280. this._bufferDisposable.dispose();
  281. this._bufferDisposable = textBufferDisposable;
  282. this._increaseVersionId();
  283. // Flush all tokens
  284. this._tokens.flush();
  285. this._tokens2.flush();
  286. // Destroy all my decorations
  287. this._decorations = Object.create(null);
  288. this._decorationsTree = new DecorationsTrees();
  289. // Destroy my edit history and settings
  290. this._commandManager.clear();
  291. this._trimAutoWhitespaceLines = null;
  292. this._emitContentChangedEvent(new ModelRawContentChangedEvent([
  293. new ModelRawFlush()
  294. ], this._versionId, false, false), this._createContentChanged2(new Range(1, 1, endLineNumber, endColumn), 0, oldModelValueLength, this.getValue(), false, false, true));
  295. }
  296. setEOL(eol) {
  297. this._assertNotDisposed();
  298. const newEOL = (eol === 1 /* CRLF */ ? '\r\n' : '\n');
  299. if (this._buffer.getEOL() === newEOL) {
  300. // Nothing to do
  301. return;
  302. }
  303. const oldFullModelRange = this.getFullModelRange();
  304. const oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);
  305. const endLineNumber = this.getLineCount();
  306. const endColumn = this.getLineMaxColumn(endLineNumber);
  307. this._onBeforeEOLChange();
  308. this._buffer.setEOL(newEOL);
  309. this._increaseVersionId();
  310. this._onAfterEOLChange();
  311. this._emitContentChangedEvent(new ModelRawContentChangedEvent([
  312. new ModelRawEOLChanged()
  313. ], this._versionId, false, false), this._createContentChanged2(new Range(1, 1, endLineNumber, endColumn), 0, oldModelValueLength, this.getValue(), false, false, false));
  314. }
  315. _onBeforeEOLChange() {
  316. // Ensure all decorations get their `range` set.
  317. this._decorationsTree.ensureAllNodesHaveRanges(this);
  318. }
  319. _onAfterEOLChange() {
  320. // Transform back `range` to offsets
  321. const versionId = this.getVersionId();
  322. const allDecorations = this._decorationsTree.collectNodesPostOrder();
  323. for (let i = 0, len = allDecorations.length; i < len; i++) {
  324. const node = allDecorations[i];
  325. const range = node.range; // the range is defined due to `_onBeforeEOLChange`
  326. const delta = node.cachedAbsoluteStart - node.start;
  327. const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
  328. const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
  329. node.cachedAbsoluteStart = startOffset;
  330. node.cachedAbsoluteEnd = endOffset;
  331. node.cachedVersionId = versionId;
  332. node.start = startOffset - delta;
  333. node.end = endOffset - delta;
  334. recomputeMaxEnd(node);
  335. }
  336. }
  337. onBeforeAttached() {
  338. this._attachedEditorCount++;
  339. if (this._attachedEditorCount === 1) {
  340. this._onDidChangeAttached.fire(undefined);
  341. }
  342. }
  343. onBeforeDetached() {
  344. this._attachedEditorCount--;
  345. if (this._attachedEditorCount === 0) {
  346. this._onDidChangeAttached.fire(undefined);
  347. }
  348. }
  349. isAttachedToEditor() {
  350. return this._attachedEditorCount > 0;
  351. }
  352. getAttachedEditorCount() {
  353. return this._attachedEditorCount;
  354. }
  355. isTooLargeForSyncing() {
  356. return this._isTooLargeForSyncing;
  357. }
  358. isTooLargeForTokenization() {
  359. return this._isTooLargeForTokenization;
  360. }
  361. isDisposed() {
  362. return this._isDisposed;
  363. }
  364. isDominatedByLongLines() {
  365. this._assertNotDisposed();
  366. if (this.isTooLargeForTokenization()) {
  367. // Cannot word wrap huge files anyways, so it doesn't really matter
  368. return false;
  369. }
  370. let smallLineCharCount = 0;
  371. let longLineCharCount = 0;
  372. const lineCount = this._buffer.getLineCount();
  373. for (let lineNumber = 1; lineNumber <= lineCount; lineNumber++) {
  374. const lineLength = this._buffer.getLineLength(lineNumber);
  375. if (lineLength >= LONG_LINE_BOUNDARY) {
  376. longLineCharCount += lineLength;
  377. }
  378. else {
  379. smallLineCharCount += lineLength;
  380. }
  381. }
  382. return (longLineCharCount > smallLineCharCount);
  383. }
  384. get uri() {
  385. return this._associatedResource;
  386. }
  387. //#region Options
  388. getOptions() {
  389. this._assertNotDisposed();
  390. return this._options;
  391. }
  392. getFormattingOptions() {
  393. return {
  394. tabSize: this._options.indentSize,
  395. insertSpaces: this._options.insertSpaces
  396. };
  397. }
  398. updateOptions(_newOpts) {
  399. this._assertNotDisposed();
  400. let tabSize = (typeof _newOpts.tabSize !== 'undefined') ? _newOpts.tabSize : this._options.tabSize;
  401. let indentSize = (typeof _newOpts.indentSize !== 'undefined') ? _newOpts.indentSize : this._options.indentSize;
  402. let insertSpaces = (typeof _newOpts.insertSpaces !== 'undefined') ? _newOpts.insertSpaces : this._options.insertSpaces;
  403. let trimAutoWhitespace = (typeof _newOpts.trimAutoWhitespace !== 'undefined') ? _newOpts.trimAutoWhitespace : this._options.trimAutoWhitespace;
  404. let bracketPairColorizationOptions = (typeof _newOpts.bracketColorizationOptions !== 'undefined') ? _newOpts.bracketColorizationOptions : this._options.bracketPairColorizationOptions;
  405. let newOpts = new model.TextModelResolvedOptions({
  406. tabSize: tabSize,
  407. indentSize: indentSize,
  408. insertSpaces: insertSpaces,
  409. defaultEOL: this._options.defaultEOL,
  410. trimAutoWhitespace: trimAutoWhitespace,
  411. bracketPairColorizationOptions,
  412. });
  413. if (this._options.equals(newOpts)) {
  414. return;
  415. }
  416. let e = this._options.createChangeEvent(newOpts);
  417. this._options = newOpts;
  418. this._onDidChangeOptions.fire(e);
  419. }
  420. detectIndentation(defaultInsertSpaces, defaultTabSize) {
  421. this._assertNotDisposed();
  422. let guessedIndentation = guessIndentation(this._buffer, defaultTabSize, defaultInsertSpaces);
  423. this.updateOptions({
  424. insertSpaces: guessedIndentation.insertSpaces,
  425. tabSize: guessedIndentation.tabSize,
  426. indentSize: guessedIndentation.tabSize, // TODO@Alex: guess indentSize independent of tabSize
  427. });
  428. }
  429. static _normalizeIndentationFromWhitespace(str, indentSize, insertSpaces) {
  430. let spacesCnt = 0;
  431. for (let i = 0; i < str.length; i++) {
  432. if (str.charAt(i) === '\t') {
  433. spacesCnt += indentSize;
  434. }
  435. else {
  436. spacesCnt++;
  437. }
  438. }
  439. let result = '';
  440. if (!insertSpaces) {
  441. let tabsCnt = Math.floor(spacesCnt / indentSize);
  442. spacesCnt = spacesCnt % indentSize;
  443. for (let i = 0; i < tabsCnt; i++) {
  444. result += '\t';
  445. }
  446. }
  447. for (let i = 0; i < spacesCnt; i++) {
  448. result += ' ';
  449. }
  450. return result;
  451. }
  452. static normalizeIndentation(str, indentSize, insertSpaces) {
  453. let firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(str);
  454. if (firstNonWhitespaceIndex === -1) {
  455. firstNonWhitespaceIndex = str.length;
  456. }
  457. return TextModel._normalizeIndentationFromWhitespace(str.substring(0, firstNonWhitespaceIndex), indentSize, insertSpaces) + str.substring(firstNonWhitespaceIndex);
  458. }
  459. normalizeIndentation(str) {
  460. this._assertNotDisposed();
  461. return TextModel.normalizeIndentation(str, this._options.indentSize, this._options.insertSpaces);
  462. }
  463. //#endregion
  464. //#region Reading
  465. getVersionId() {
  466. this._assertNotDisposed();
  467. return this._versionId;
  468. }
  469. mightContainRTL() {
  470. return this._buffer.mightContainRTL();
  471. }
  472. mightContainUnusualLineTerminators() {
  473. return this._buffer.mightContainUnusualLineTerminators();
  474. }
  475. removeUnusualLineTerminators(selections = null) {
  476. const matches = this.findMatches(strings.UNUSUAL_LINE_TERMINATORS.source, false, true, false, null, false, 1073741824 /* MAX_SAFE_SMALL_INTEGER */);
  477. this._buffer.resetMightContainUnusualLineTerminators();
  478. this.pushEditOperations(selections, matches.map(m => ({ range: m.range, text: null })), () => null);
  479. }
  480. mightContainNonBasicASCII() {
  481. return this._buffer.mightContainNonBasicASCII();
  482. }
  483. getAlternativeVersionId() {
  484. this._assertNotDisposed();
  485. return this._alternativeVersionId;
  486. }
  487. getInitialUndoRedoSnapshot() {
  488. this._assertNotDisposed();
  489. return this._initialUndoRedoSnapshot;
  490. }
  491. getOffsetAt(rawPosition) {
  492. this._assertNotDisposed();
  493. let position = this._validatePosition(rawPosition.lineNumber, rawPosition.column, 0 /* Relaxed */);
  494. return this._buffer.getOffsetAt(position.lineNumber, position.column);
  495. }
  496. getPositionAt(rawOffset) {
  497. this._assertNotDisposed();
  498. let offset = (Math.min(this._buffer.getLength(), Math.max(0, rawOffset)));
  499. return this._buffer.getPositionAt(offset);
  500. }
  501. _increaseVersionId() {
  502. this._versionId = this._versionId + 1;
  503. this._alternativeVersionId = this._versionId;
  504. }
  505. _overwriteVersionId(versionId) {
  506. this._versionId = versionId;
  507. }
  508. _overwriteAlternativeVersionId(newAlternativeVersionId) {
  509. this._alternativeVersionId = newAlternativeVersionId;
  510. }
  511. _overwriteInitialUndoRedoSnapshot(newInitialUndoRedoSnapshot) {
  512. this._initialUndoRedoSnapshot = newInitialUndoRedoSnapshot;
  513. }
  514. getValue(eol, preserveBOM = false) {
  515. this._assertNotDisposed();
  516. const fullModelRange = this.getFullModelRange();
  517. const fullModelValue = this.getValueInRange(fullModelRange, eol);
  518. if (preserveBOM) {
  519. return this._buffer.getBOM() + fullModelValue;
  520. }
  521. return fullModelValue;
  522. }
  523. createSnapshot(preserveBOM = false) {
  524. return new TextModelSnapshot(this._buffer.createSnapshot(preserveBOM));
  525. }
  526. getValueLength(eol, preserveBOM = false) {
  527. this._assertNotDisposed();
  528. const fullModelRange = this.getFullModelRange();
  529. const fullModelValue = this.getValueLengthInRange(fullModelRange, eol);
  530. if (preserveBOM) {
  531. return this._buffer.getBOM().length + fullModelValue;
  532. }
  533. return fullModelValue;
  534. }
  535. getValueInRange(rawRange, eol = 0 /* TextDefined */) {
  536. this._assertNotDisposed();
  537. return this._buffer.getValueInRange(this.validateRange(rawRange), eol);
  538. }
  539. getValueLengthInRange(rawRange, eol = 0 /* TextDefined */) {
  540. this._assertNotDisposed();
  541. return this._buffer.getValueLengthInRange(this.validateRange(rawRange), eol);
  542. }
  543. getCharacterCountInRange(rawRange, eol = 0 /* TextDefined */) {
  544. this._assertNotDisposed();
  545. return this._buffer.getCharacterCountInRange(this.validateRange(rawRange), eol);
  546. }
  547. getLineCount() {
  548. this._assertNotDisposed();
  549. return this._buffer.getLineCount();
  550. }
  551. getLineContent(lineNumber) {
  552. this._assertNotDisposed();
  553. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  554. throw new Error('Illegal value for lineNumber');
  555. }
  556. return this._buffer.getLineContent(lineNumber);
  557. }
  558. getLineLength(lineNumber) {
  559. this._assertNotDisposed();
  560. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  561. throw new Error('Illegal value for lineNumber');
  562. }
  563. return this._buffer.getLineLength(lineNumber);
  564. }
  565. getLinesContent() {
  566. this._assertNotDisposed();
  567. return this._buffer.getLinesContent();
  568. }
  569. getEOL() {
  570. this._assertNotDisposed();
  571. return this._buffer.getEOL();
  572. }
  573. getEndOfLineSequence() {
  574. this._assertNotDisposed();
  575. return (this._buffer.getEOL() === '\n'
  576. ? 0 /* LF */
  577. : 1 /* CRLF */);
  578. }
  579. getLineMinColumn(lineNumber) {
  580. this._assertNotDisposed();
  581. return 1;
  582. }
  583. getLineMaxColumn(lineNumber) {
  584. this._assertNotDisposed();
  585. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  586. throw new Error('Illegal value for lineNumber');
  587. }
  588. return this._buffer.getLineLength(lineNumber) + 1;
  589. }
  590. getLineFirstNonWhitespaceColumn(lineNumber) {
  591. this._assertNotDisposed();
  592. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  593. throw new Error('Illegal value for lineNumber');
  594. }
  595. return this._buffer.getLineFirstNonWhitespaceColumn(lineNumber);
  596. }
  597. getLineLastNonWhitespaceColumn(lineNumber) {
  598. this._assertNotDisposed();
  599. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  600. throw new Error('Illegal value for lineNumber');
  601. }
  602. return this._buffer.getLineLastNonWhitespaceColumn(lineNumber);
  603. }
  604. /**
  605. * Validates `range` is within buffer bounds, but allows it to sit in between surrogate pairs, etc.
  606. * Will try to not allocate if possible.
  607. */
  608. _validateRangeRelaxedNoAllocations(range) {
  609. const linesCount = this._buffer.getLineCount();
  610. const initialStartLineNumber = range.startLineNumber;
  611. const initialStartColumn = range.startColumn;
  612. let startLineNumber = Math.floor((typeof initialStartLineNumber === 'number' && !isNaN(initialStartLineNumber)) ? initialStartLineNumber : 1);
  613. let startColumn = Math.floor((typeof initialStartColumn === 'number' && !isNaN(initialStartColumn)) ? initialStartColumn : 1);
  614. if (startLineNumber < 1) {
  615. startLineNumber = 1;
  616. startColumn = 1;
  617. }
  618. else if (startLineNumber > linesCount) {
  619. startLineNumber = linesCount;
  620. startColumn = this.getLineMaxColumn(startLineNumber);
  621. }
  622. else {
  623. if (startColumn <= 1) {
  624. startColumn = 1;
  625. }
  626. else {
  627. const maxColumn = this.getLineMaxColumn(startLineNumber);
  628. if (startColumn >= maxColumn) {
  629. startColumn = maxColumn;
  630. }
  631. }
  632. }
  633. const initialEndLineNumber = range.endLineNumber;
  634. const initialEndColumn = range.endColumn;
  635. let endLineNumber = Math.floor((typeof initialEndLineNumber === 'number' && !isNaN(initialEndLineNumber)) ? initialEndLineNumber : 1);
  636. let endColumn = Math.floor((typeof initialEndColumn === 'number' && !isNaN(initialEndColumn)) ? initialEndColumn : 1);
  637. if (endLineNumber < 1) {
  638. endLineNumber = 1;
  639. endColumn = 1;
  640. }
  641. else if (endLineNumber > linesCount) {
  642. endLineNumber = linesCount;
  643. endColumn = this.getLineMaxColumn(endLineNumber);
  644. }
  645. else {
  646. if (endColumn <= 1) {
  647. endColumn = 1;
  648. }
  649. else {
  650. const maxColumn = this.getLineMaxColumn(endLineNumber);
  651. if (endColumn >= maxColumn) {
  652. endColumn = maxColumn;
  653. }
  654. }
  655. }
  656. if (initialStartLineNumber === startLineNumber
  657. && initialStartColumn === startColumn
  658. && initialEndLineNumber === endLineNumber
  659. && initialEndColumn === endColumn
  660. && range instanceof Range
  661. && !(range instanceof Selection)) {
  662. return range;
  663. }
  664. return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
  665. }
  666. _isValidPosition(lineNumber, column, validationType) {
  667. if (typeof lineNumber !== 'number' || typeof column !== 'number') {
  668. return false;
  669. }
  670. if (isNaN(lineNumber) || isNaN(column)) {
  671. return false;
  672. }
  673. if (lineNumber < 1 || column < 1) {
  674. return false;
  675. }
  676. if ((lineNumber | 0) !== lineNumber || (column | 0) !== column) {
  677. return false;
  678. }
  679. const lineCount = this._buffer.getLineCount();
  680. if (lineNumber > lineCount) {
  681. return false;
  682. }
  683. if (column === 1) {
  684. return true;
  685. }
  686. const maxColumn = this.getLineMaxColumn(lineNumber);
  687. if (column > maxColumn) {
  688. return false;
  689. }
  690. if (validationType === 1 /* SurrogatePairs */) {
  691. // !!At this point, column > 1
  692. const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2);
  693. if (strings.isHighSurrogate(charCodeBefore)) {
  694. return false;
  695. }
  696. }
  697. return true;
  698. }
  699. _validatePosition(_lineNumber, _column, validationType) {
  700. const lineNumber = Math.floor((typeof _lineNumber === 'number' && !isNaN(_lineNumber)) ? _lineNumber : 1);
  701. const column = Math.floor((typeof _column === 'number' && !isNaN(_column)) ? _column : 1);
  702. const lineCount = this._buffer.getLineCount();
  703. if (lineNumber < 1) {
  704. return new Position(1, 1);
  705. }
  706. if (lineNumber > lineCount) {
  707. return new Position(lineCount, this.getLineMaxColumn(lineCount));
  708. }
  709. if (column <= 1) {
  710. return new Position(lineNumber, 1);
  711. }
  712. const maxColumn = this.getLineMaxColumn(lineNumber);
  713. if (column >= maxColumn) {
  714. return new Position(lineNumber, maxColumn);
  715. }
  716. if (validationType === 1 /* SurrogatePairs */) {
  717. // If the position would end up in the middle of a high-low surrogate pair,
  718. // we move it to before the pair
  719. // !!At this point, column > 1
  720. const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2);
  721. if (strings.isHighSurrogate(charCodeBefore)) {
  722. return new Position(lineNumber, column - 1);
  723. }
  724. }
  725. return new Position(lineNumber, column);
  726. }
  727. validatePosition(position) {
  728. const validationType = 1 /* SurrogatePairs */;
  729. this._assertNotDisposed();
  730. // Avoid object allocation and cover most likely case
  731. if (position instanceof Position) {
  732. if (this._isValidPosition(position.lineNumber, position.column, validationType)) {
  733. return position;
  734. }
  735. }
  736. return this._validatePosition(position.lineNumber, position.column, validationType);
  737. }
  738. _isValidRange(range, validationType) {
  739. const startLineNumber = range.startLineNumber;
  740. const startColumn = range.startColumn;
  741. const endLineNumber = range.endLineNumber;
  742. const endColumn = range.endColumn;
  743. if (!this._isValidPosition(startLineNumber, startColumn, 0 /* Relaxed */)) {
  744. return false;
  745. }
  746. if (!this._isValidPosition(endLineNumber, endColumn, 0 /* Relaxed */)) {
  747. return false;
  748. }
  749. if (validationType === 1 /* SurrogatePairs */) {
  750. const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0);
  751. const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0);
  752. const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart);
  753. const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd);
  754. if (!startInsideSurrogatePair && !endInsideSurrogatePair) {
  755. return true;
  756. }
  757. return false;
  758. }
  759. return true;
  760. }
  761. validateRange(_range) {
  762. const validationType = 1 /* SurrogatePairs */;
  763. this._assertNotDisposed();
  764. // Avoid object allocation and cover most likely case
  765. if ((_range instanceof Range) && !(_range instanceof Selection)) {
  766. if (this._isValidRange(_range, validationType)) {
  767. return _range;
  768. }
  769. }
  770. const start = this._validatePosition(_range.startLineNumber, _range.startColumn, 0 /* Relaxed */);
  771. const end = this._validatePosition(_range.endLineNumber, _range.endColumn, 0 /* Relaxed */);
  772. const startLineNumber = start.lineNumber;
  773. const startColumn = start.column;
  774. const endLineNumber = end.lineNumber;
  775. const endColumn = end.column;
  776. if (validationType === 1 /* SurrogatePairs */) {
  777. const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0);
  778. const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0);
  779. const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart);
  780. const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd);
  781. if (!startInsideSurrogatePair && !endInsideSurrogatePair) {
  782. return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
  783. }
  784. if (startLineNumber === endLineNumber && startColumn === endColumn) {
  785. // do not expand a collapsed range, simply move it to a valid location
  786. return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn - 1);
  787. }
  788. if (startInsideSurrogatePair && endInsideSurrogatePair) {
  789. // expand range at both ends
  790. return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn + 1);
  791. }
  792. if (startInsideSurrogatePair) {
  793. // only expand range at the start
  794. return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn);
  795. }
  796. // only expand range at the end
  797. return new Range(startLineNumber, startColumn, endLineNumber, endColumn + 1);
  798. }
  799. return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
  800. }
  801. modifyPosition(rawPosition, offset) {
  802. this._assertNotDisposed();
  803. let candidate = this.getOffsetAt(rawPosition) + offset;
  804. return this.getPositionAt(Math.min(this._buffer.getLength(), Math.max(0, candidate)));
  805. }
  806. getFullModelRange() {
  807. this._assertNotDisposed();
  808. const lineCount = this.getLineCount();
  809. return new Range(1, 1, lineCount, this.getLineMaxColumn(lineCount));
  810. }
  811. findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount) {
  812. return this._buffer.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
  813. }
  814. findMatches(searchString, rawSearchScope, isRegex, matchCase, wordSeparators, captureMatches, limitResultCount = LIMIT_FIND_COUNT) {
  815. this._assertNotDisposed();
  816. let searchRanges = null;
  817. if (rawSearchScope !== null) {
  818. if (!Array.isArray(rawSearchScope)) {
  819. rawSearchScope = [rawSearchScope];
  820. }
  821. if (rawSearchScope.every((searchScope) => Range.isIRange(searchScope))) {
  822. searchRanges = rawSearchScope.map((searchScope) => this.validateRange(searchScope));
  823. }
  824. }
  825. if (searchRanges === null) {
  826. searchRanges = [this.getFullModelRange()];
  827. }
  828. searchRanges = searchRanges.sort((d1, d2) => d1.startLineNumber - d2.startLineNumber || d1.startColumn - d2.startColumn);
  829. const uniqueSearchRanges = [];
  830. uniqueSearchRanges.push(searchRanges.reduce((prev, curr) => {
  831. if (Range.areIntersecting(prev, curr)) {
  832. return prev.plusRange(curr);
  833. }
  834. uniqueSearchRanges.push(prev);
  835. return curr;
  836. }));
  837. let matchMapper;
  838. if (!isRegex && searchString.indexOf('\n') < 0) {
  839. // not regex, not multi line
  840. const searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);
  841. const searchData = searchParams.parseSearchRequest();
  842. if (!searchData) {
  843. return [];
  844. }
  845. matchMapper = (searchRange) => this.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
  846. }
  847. else {
  848. matchMapper = (searchRange) => TextModelSearch.findMatches(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchRange, captureMatches, limitResultCount);
  849. }
  850. return uniqueSearchRanges.map(matchMapper).reduce((arr, matches) => arr.concat(matches), []);
  851. }
  852. findNextMatch(searchString, rawSearchStart, isRegex, matchCase, wordSeparators, captureMatches) {
  853. this._assertNotDisposed();
  854. const searchStart = this.validatePosition(rawSearchStart);
  855. if (!isRegex && searchString.indexOf('\n') < 0) {
  856. const searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);
  857. const searchData = searchParams.parseSearchRequest();
  858. if (!searchData) {
  859. return null;
  860. }
  861. const lineCount = this.getLineCount();
  862. let searchRange = new Range(searchStart.lineNumber, searchStart.column, lineCount, this.getLineMaxColumn(lineCount));
  863. let ret = this.findMatchesLineByLine(searchRange, searchData, captureMatches, 1);
  864. TextModelSearch.findNextMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
  865. if (ret.length > 0) {
  866. return ret[0];
  867. }
  868. searchRange = new Range(1, 1, searchStart.lineNumber, this.getLineMaxColumn(searchStart.lineNumber));
  869. ret = this.findMatchesLineByLine(searchRange, searchData, captureMatches, 1);
  870. if (ret.length > 0) {
  871. return ret[0];
  872. }
  873. return null;
  874. }
  875. return TextModelSearch.findNextMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
  876. }
  877. findPreviousMatch(searchString, rawSearchStart, isRegex, matchCase, wordSeparators, captureMatches) {
  878. this._assertNotDisposed();
  879. const searchStart = this.validatePosition(rawSearchStart);
  880. return TextModelSearch.findPreviousMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
  881. }
  882. //#endregion
  883. //#region Editing
  884. pushStackElement() {
  885. this._commandManager.pushStackElement();
  886. }
  887. popStackElement() {
  888. this._commandManager.popStackElement();
  889. }
  890. pushEOL(eol) {
  891. const currentEOL = (this.getEOL() === '\n' ? 0 /* LF */ : 1 /* CRLF */);
  892. if (currentEOL === eol) {
  893. return;
  894. }
  895. try {
  896. this._onDidChangeDecorations.beginDeferredEmit();
  897. this._eventEmitter.beginDeferredEmit();
  898. if (this._initialUndoRedoSnapshot === null) {
  899. this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
  900. }
  901. this._commandManager.pushEOL(eol);
  902. }
  903. finally {
  904. this._eventEmitter.endDeferredEmit();
  905. this._onDidChangeDecorations.endDeferredEmit();
  906. }
  907. }
  908. _validateEditOperation(rawOperation) {
  909. if (rawOperation instanceof model.ValidAnnotatedEditOperation) {
  910. return rawOperation;
  911. }
  912. return new model.ValidAnnotatedEditOperation(rawOperation.identifier || null, this.validateRange(rawOperation.range), rawOperation.text, rawOperation.forceMoveMarkers || false, rawOperation.isAutoWhitespaceEdit || false, rawOperation._isTracked || false);
  913. }
  914. _validateEditOperations(rawOperations) {
  915. const result = [];
  916. for (let i = 0, len = rawOperations.length; i < len; i++) {
  917. result[i] = this._validateEditOperation(rawOperations[i]);
  918. }
  919. return result;
  920. }
  921. pushEditOperations(beforeCursorState, editOperations, cursorStateComputer) {
  922. try {
  923. this._onDidChangeDecorations.beginDeferredEmit();
  924. this._eventEmitter.beginDeferredEmit();
  925. return this._pushEditOperations(beforeCursorState, this._validateEditOperations(editOperations), cursorStateComputer);
  926. }
  927. finally {
  928. this._eventEmitter.endDeferredEmit();
  929. this._onDidChangeDecorations.endDeferredEmit();
  930. }
  931. }
  932. _pushEditOperations(beforeCursorState, editOperations, cursorStateComputer) {
  933. if (this._options.trimAutoWhitespace && this._trimAutoWhitespaceLines) {
  934. // Go through each saved line number and insert a trim whitespace edit
  935. // if it is safe to do so (no conflicts with other edits).
  936. let incomingEdits = editOperations.map((op) => {
  937. return {
  938. range: this.validateRange(op.range),
  939. text: op.text
  940. };
  941. });
  942. // Sometimes, auto-formatters change ranges automatically which can cause undesired auto whitespace trimming near the cursor
  943. // We'll use the following heuristic: if the edits occur near the cursor, then it's ok to trim auto whitespace
  944. let editsAreNearCursors = true;
  945. if (beforeCursorState) {
  946. for (let i = 0, len = beforeCursorState.length; i < len; i++) {
  947. let sel = beforeCursorState[i];
  948. let foundEditNearSel = false;
  949. for (let j = 0, lenJ = incomingEdits.length; j < lenJ; j++) {
  950. let editRange = incomingEdits[j].range;
  951. let selIsAbove = editRange.startLineNumber > sel.endLineNumber;
  952. let selIsBelow = sel.startLineNumber > editRange.endLineNumber;
  953. if (!selIsAbove && !selIsBelow) {
  954. foundEditNearSel = true;
  955. break;
  956. }
  957. }
  958. if (!foundEditNearSel) {
  959. editsAreNearCursors = false;
  960. break;
  961. }
  962. }
  963. }
  964. if (editsAreNearCursors) {
  965. for (let i = 0, len = this._trimAutoWhitespaceLines.length; i < len; i++) {
  966. let trimLineNumber = this._trimAutoWhitespaceLines[i];
  967. let maxLineColumn = this.getLineMaxColumn(trimLineNumber);
  968. let allowTrimLine = true;
  969. for (let j = 0, lenJ = incomingEdits.length; j < lenJ; j++) {
  970. let editRange = incomingEdits[j].range;
  971. let editText = incomingEdits[j].text;
  972. if (trimLineNumber < editRange.startLineNumber || trimLineNumber > editRange.endLineNumber) {
  973. // `trimLine` is completely outside this edit
  974. continue;
  975. }
  976. // At this point:
  977. // editRange.startLineNumber <= trimLine <= editRange.endLineNumber
  978. if (trimLineNumber === editRange.startLineNumber && editRange.startColumn === maxLineColumn
  979. && editRange.isEmpty() && editText && editText.length > 0 && editText.charAt(0) === '\n') {
  980. // This edit inserts a new line (and maybe other text) after `trimLine`
  981. continue;
  982. }
  983. if (trimLineNumber === editRange.startLineNumber && editRange.startColumn === 1
  984. && editRange.isEmpty() && editText && editText.length > 0 && editText.charAt(editText.length - 1) === '\n') {
  985. // This edit inserts a new line (and maybe other text) before `trimLine`
  986. continue;
  987. }
  988. // Looks like we can't trim this line as it would interfere with an incoming edit
  989. allowTrimLine = false;
  990. break;
  991. }
  992. if (allowTrimLine) {
  993. const trimRange = new Range(trimLineNumber, 1, trimLineNumber, maxLineColumn);
  994. editOperations.push(new model.ValidAnnotatedEditOperation(null, trimRange, null, false, false, false));
  995. }
  996. }
  997. }
  998. this._trimAutoWhitespaceLines = null;
  999. }
  1000. if (this._initialUndoRedoSnapshot === null) {
  1001. this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
  1002. }
  1003. return this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer);
  1004. }
  1005. _applyUndo(changes, eol, resultingAlternativeVersionId, resultingSelection) {
  1006. const edits = changes.map((change) => {
  1007. const rangeStart = this.getPositionAt(change.newPosition);
  1008. const rangeEnd = this.getPositionAt(change.newEnd);
  1009. return {
  1010. range: new Range(rangeStart.lineNumber, rangeStart.column, rangeEnd.lineNumber, rangeEnd.column),
  1011. text: change.oldText
  1012. };
  1013. });
  1014. this._applyUndoRedoEdits(edits, eol, true, false, resultingAlternativeVersionId, resultingSelection);
  1015. }
  1016. _applyRedo(changes, eol, resultingAlternativeVersionId, resultingSelection) {
  1017. const edits = changes.map((change) => {
  1018. const rangeStart = this.getPositionAt(change.oldPosition);
  1019. const rangeEnd = this.getPositionAt(change.oldEnd);
  1020. return {
  1021. range: new Range(rangeStart.lineNumber, rangeStart.column, rangeEnd.lineNumber, rangeEnd.column),
  1022. text: change.newText
  1023. };
  1024. });
  1025. this._applyUndoRedoEdits(edits, eol, false, true, resultingAlternativeVersionId, resultingSelection);
  1026. }
  1027. _applyUndoRedoEdits(edits, eol, isUndoing, isRedoing, resultingAlternativeVersionId, resultingSelection) {
  1028. try {
  1029. this._onDidChangeDecorations.beginDeferredEmit();
  1030. this._eventEmitter.beginDeferredEmit();
  1031. this._isUndoing = isUndoing;
  1032. this._isRedoing = isRedoing;
  1033. this.applyEdits(edits, false);
  1034. this.setEOL(eol);
  1035. this._overwriteAlternativeVersionId(resultingAlternativeVersionId);
  1036. }
  1037. finally {
  1038. this._isUndoing = false;
  1039. this._isRedoing = false;
  1040. this._eventEmitter.endDeferredEmit(resultingSelection);
  1041. this._onDidChangeDecorations.endDeferredEmit();
  1042. }
  1043. }
  1044. applyEdits(rawOperations, computeUndoEdits = false) {
  1045. try {
  1046. this._onDidChangeDecorations.beginDeferredEmit();
  1047. this._eventEmitter.beginDeferredEmit();
  1048. const operations = this._validateEditOperations(rawOperations);
  1049. return this._doApplyEdits(operations, computeUndoEdits);
  1050. }
  1051. finally {
  1052. this._eventEmitter.endDeferredEmit();
  1053. this._onDidChangeDecorations.endDeferredEmit();
  1054. }
  1055. }
  1056. _doApplyEdits(rawOperations, computeUndoEdits) {
  1057. const oldLineCount = this._buffer.getLineCount();
  1058. const result = this._buffer.applyEdits(rawOperations, this._options.trimAutoWhitespace, computeUndoEdits);
  1059. const newLineCount = this._buffer.getLineCount();
  1060. const contentChanges = result.changes;
  1061. this._trimAutoWhitespaceLines = result.trimAutoWhitespaceLineNumbers;
  1062. if (contentChanges.length !== 0) {
  1063. // We do a first pass to update tokens and decorations
  1064. // because we want to read decorations in the second pass
  1065. // where we will emit content change events
  1066. // and we want to read the final decorations
  1067. for (let i = 0, len = contentChanges.length; i < len; i++) {
  1068. const change = contentChanges[i];
  1069. const [eolCount, firstLineLength, lastLineLength] = countEOL(change.text);
  1070. this._tokens.acceptEdit(change.range, eolCount, firstLineLength);
  1071. this._tokens2.acceptEdit(change.range, eolCount, firstLineLength, lastLineLength, change.text.length > 0 ? change.text.charCodeAt(0) : 0 /* Null */);
  1072. this._decorationsTree.acceptReplace(change.rangeOffset, change.rangeLength, change.text.length, change.forceMoveMarkers);
  1073. }
  1074. let rawContentChanges = [];
  1075. this._increaseVersionId();
  1076. let lineCount = oldLineCount;
  1077. for (let i = 0, len = contentChanges.length; i < len; i++) {
  1078. const change = contentChanges[i];
  1079. const [eolCount] = countEOL(change.text);
  1080. this._onDidChangeDecorations.fire();
  1081. const startLineNumber = change.range.startLineNumber;
  1082. const endLineNumber = change.range.endLineNumber;
  1083. const deletingLinesCnt = endLineNumber - startLineNumber;
  1084. const insertingLinesCnt = eolCount;
  1085. const editingLinesCnt = Math.min(deletingLinesCnt, insertingLinesCnt);
  1086. const changeLineCountDelta = (insertingLinesCnt - deletingLinesCnt);
  1087. const currentEditStartLineNumber = newLineCount - lineCount - changeLineCountDelta + startLineNumber;
  1088. const firstEditLineNumber = currentEditStartLineNumber;
  1089. const lastInsertedLineNumber = currentEditStartLineNumber + insertingLinesCnt;
  1090. const decorationsWithInjectedTextInEditedRange = this._decorationsTree.getInjectedTextInInterval(this, this.getOffsetAt(new Position(firstEditLineNumber, 1)), this.getOffsetAt(new Position(lastInsertedLineNumber, this.getLineMaxColumn(lastInsertedLineNumber))), 0);
  1091. const injectedTextInEditedRange = LineInjectedText.fromDecorations(decorationsWithInjectedTextInEditedRange);
  1092. const injectedTextInEditedRangeQueue = new ArrayQueue(injectedTextInEditedRange);
  1093. for (let j = editingLinesCnt; j >= 0; j--) {
  1094. const editLineNumber = startLineNumber + j;
  1095. const currentEditLineNumber = currentEditStartLineNumber + j;
  1096. injectedTextInEditedRangeQueue.takeFromEndWhile(r => r.lineNumber > currentEditLineNumber);
  1097. const decorationsInCurrentLine = injectedTextInEditedRangeQueue.takeFromEndWhile(r => r.lineNumber === currentEditLineNumber);
  1098. rawContentChanges.push(new ModelRawLineChanged(editLineNumber, this.getLineContent(currentEditLineNumber), decorationsInCurrentLine));
  1099. }
  1100. if (editingLinesCnt < deletingLinesCnt) {
  1101. // Must delete some lines
  1102. const spliceStartLineNumber = startLineNumber + editingLinesCnt;
  1103. rawContentChanges.push(new ModelRawLinesDeleted(spliceStartLineNumber + 1, endLineNumber));
  1104. }
  1105. if (editingLinesCnt < insertingLinesCnt) {
  1106. const injectedTextInEditedRangeQueue = new ArrayQueue(injectedTextInEditedRange);
  1107. // Must insert some lines
  1108. const spliceLineNumber = startLineNumber + editingLinesCnt;
  1109. const cnt = insertingLinesCnt - editingLinesCnt;
  1110. const fromLineNumber = newLineCount - lineCount - cnt + spliceLineNumber + 1;
  1111. let injectedTexts = [];
  1112. let newLines = [];
  1113. for (let i = 0; i < cnt; i++) {
  1114. let lineNumber = fromLineNumber + i;
  1115. newLines[i] = this.getLineContent(lineNumber);
  1116. injectedTextInEditedRangeQueue.takeWhile(r => r.lineNumber < lineNumber);
  1117. injectedTexts[i] = injectedTextInEditedRangeQueue.takeWhile(r => r.lineNumber === lineNumber);
  1118. }
  1119. rawContentChanges.push(new ModelRawLinesInserted(spliceLineNumber + 1, startLineNumber + insertingLinesCnt, newLines, injectedTexts));
  1120. }
  1121. lineCount += changeLineCountDelta;
  1122. }
  1123. this._emitContentChangedEvent(new ModelRawContentChangedEvent(rawContentChanges, this.getVersionId(), this._isUndoing, this._isRedoing), {
  1124. changes: contentChanges,
  1125. eol: this._buffer.getEOL(),
  1126. versionId: this.getVersionId(),
  1127. isUndoing: this._isUndoing,
  1128. isRedoing: this._isRedoing,
  1129. isFlush: false
  1130. });
  1131. }
  1132. return (result.reverseEdits === null ? undefined : result.reverseEdits);
  1133. }
  1134. undo() {
  1135. return this._undoRedoService.undo(this.uri);
  1136. }
  1137. canUndo() {
  1138. return this._undoRedoService.canUndo(this.uri);
  1139. }
  1140. redo() {
  1141. return this._undoRedoService.redo(this.uri);
  1142. }
  1143. canRedo() {
  1144. return this._undoRedoService.canRedo(this.uri);
  1145. }
  1146. //#endregion
  1147. //#region Decorations
  1148. handleBeforeFireDecorationsChangedEvent(affectedInjectedTextLines) {
  1149. // This is called before the decoration changed event is fired.
  1150. if (affectedInjectedTextLines === null || affectedInjectedTextLines.size === 0) {
  1151. return;
  1152. }
  1153. const affectedLines = [...affectedInjectedTextLines];
  1154. const lineChangeEvents = affectedLines.map(lineNumber => new ModelRawLineChanged(lineNumber, this.getLineContent(lineNumber), this._getInjectedTextInLine(lineNumber)));
  1155. this._onDidChangeContentOrInjectedText.fire(new ModelInjectedTextChangedEvent(lineChangeEvents));
  1156. }
  1157. changeDecorations(callback, ownerId = 0) {
  1158. this._assertNotDisposed();
  1159. try {
  1160. this._onDidChangeDecorations.beginDeferredEmit();
  1161. return this._changeDecorations(ownerId, callback);
  1162. }
  1163. finally {
  1164. this._onDidChangeDecorations.endDeferredEmit();
  1165. }
  1166. }
  1167. _changeDecorations(ownerId, callback) {
  1168. let changeAccessor = {
  1169. addDecoration: (range, options) => {
  1170. return this._deltaDecorationsImpl(ownerId, [], [{ range: range, options: options }])[0];
  1171. },
  1172. changeDecoration: (id, newRange) => {
  1173. this._changeDecorationImpl(id, newRange);
  1174. },
  1175. changeDecorationOptions: (id, options) => {
  1176. this._changeDecorationOptionsImpl(id, _normalizeOptions(options));
  1177. },
  1178. removeDecoration: (id) => {
  1179. this._deltaDecorationsImpl(ownerId, [id], []);
  1180. },
  1181. deltaDecorations: (oldDecorations, newDecorations) => {
  1182. if (oldDecorations.length === 0 && newDecorations.length === 0) {
  1183. // nothing to do
  1184. return [];
  1185. }
  1186. return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);
  1187. }
  1188. };
  1189. let result = null;
  1190. try {
  1191. result = callback(changeAccessor);
  1192. }
  1193. catch (e) {
  1194. onUnexpectedError(e);
  1195. }
  1196. // Invalidate change accessor
  1197. changeAccessor.addDecoration = invalidFunc;
  1198. changeAccessor.changeDecoration = invalidFunc;
  1199. changeAccessor.changeDecorationOptions = invalidFunc;
  1200. changeAccessor.removeDecoration = invalidFunc;
  1201. changeAccessor.deltaDecorations = invalidFunc;
  1202. return result;
  1203. }
  1204. deltaDecorations(oldDecorations, newDecorations, ownerId = 0) {
  1205. this._assertNotDisposed();
  1206. if (!oldDecorations) {
  1207. oldDecorations = [];
  1208. }
  1209. if (oldDecorations.length === 0 && newDecorations.length === 0) {
  1210. // nothing to do
  1211. return [];
  1212. }
  1213. try {
  1214. this._onDidChangeDecorations.beginDeferredEmit();
  1215. return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);
  1216. }
  1217. finally {
  1218. this._onDidChangeDecorations.endDeferredEmit();
  1219. }
  1220. }
  1221. _getTrackedRange(id) {
  1222. return this.getDecorationRange(id);
  1223. }
  1224. _setTrackedRange(id, newRange, newStickiness) {
  1225. const node = (id ? this._decorations[id] : null);
  1226. if (!node) {
  1227. if (!newRange) {
  1228. // node doesn't exist, the request is to delete => nothing to do
  1229. return null;
  1230. }
  1231. // node doesn't exist, the request is to set => add the tracked range
  1232. return this._deltaDecorationsImpl(0, [], [{ range: newRange, options: TRACKED_RANGE_OPTIONS[newStickiness] }])[0];
  1233. }
  1234. if (!newRange) {
  1235. // node exists, the request is to delete => delete node
  1236. this._decorationsTree.delete(node);
  1237. delete this._decorations[node.id];
  1238. return null;
  1239. }
  1240. // node exists, the request is to set => change the tracked range and its options
  1241. const range = this._validateRangeRelaxedNoAllocations(newRange);
  1242. const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
  1243. const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
  1244. this._decorationsTree.delete(node);
  1245. node.reset(this.getVersionId(), startOffset, endOffset, range);
  1246. node.setOptions(TRACKED_RANGE_OPTIONS[newStickiness]);
  1247. this._decorationsTree.insert(node);
  1248. return node.id;
  1249. }
  1250. removeAllDecorationsWithOwnerId(ownerId) {
  1251. if (this._isDisposed) {
  1252. return;
  1253. }
  1254. const nodes = this._decorationsTree.collectNodesFromOwner(ownerId);
  1255. for (let i = 0, len = nodes.length; i < len; i++) {
  1256. const node = nodes[i];
  1257. this._decorationsTree.delete(node);
  1258. delete this._decorations[node.id];
  1259. }
  1260. }
  1261. getDecorationOptions(decorationId) {
  1262. const node = this._decorations[decorationId];
  1263. if (!node) {
  1264. return null;
  1265. }
  1266. return node.options;
  1267. }
  1268. getDecorationRange(decorationId) {
  1269. const node = this._decorations[decorationId];
  1270. if (!node) {
  1271. return null;
  1272. }
  1273. return this._decorationsTree.getNodeRange(this, node);
  1274. }
  1275. getLineDecorations(lineNumber, ownerId = 0, filterOutValidation = false) {
  1276. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  1277. return [];
  1278. }
  1279. return this.getLinesDecorations(lineNumber, lineNumber, ownerId, filterOutValidation);
  1280. }
  1281. getLinesDecorations(_startLineNumber, _endLineNumber, ownerId = 0, filterOutValidation = false) {
  1282. let lineCount = this.getLineCount();
  1283. let startLineNumber = Math.min(lineCount, Math.max(1, _startLineNumber));
  1284. let endLineNumber = Math.min(lineCount, Math.max(1, _endLineNumber));
  1285. let endColumn = this.getLineMaxColumn(endLineNumber);
  1286. const range = new Range(startLineNumber, 1, endLineNumber, endColumn);
  1287. const decorations = this._getDecorationsInRange(range, ownerId, filterOutValidation);
  1288. decorations.push(...this._decorationProvider.getDecorationsInRange(range, ownerId, filterOutValidation));
  1289. return decorations;
  1290. }
  1291. getDecorationsInRange(range, ownerId = 0, filterOutValidation = false) {
  1292. let validatedRange = this.validateRange(range);
  1293. const decorations = this._getDecorationsInRange(validatedRange, ownerId, filterOutValidation);
  1294. decorations.push(...this._decorationProvider.getDecorationsInRange(validatedRange, ownerId, filterOutValidation));
  1295. return decorations;
  1296. }
  1297. getOverviewRulerDecorations(ownerId = 0, filterOutValidation = false) {
  1298. return this._decorationsTree.getAll(this, ownerId, filterOutValidation, true);
  1299. }
  1300. getInjectedTextDecorations(ownerId = 0) {
  1301. return this._decorationsTree.getAllInjectedText(this, ownerId);
  1302. }
  1303. _getInjectedTextInLine(lineNumber) {
  1304. const startOffset = this._buffer.getOffsetAt(lineNumber, 1);
  1305. const endOffset = startOffset + this._buffer.getLineLength(lineNumber);
  1306. const result = this._decorationsTree.getInjectedTextInInterval(this, startOffset, endOffset, 0);
  1307. return LineInjectedText.fromDecorations(result).filter(t => t.lineNumber === lineNumber);
  1308. }
  1309. getAllDecorations(ownerId = 0, filterOutValidation = false) {
  1310. let result = this._decorationsTree.getAll(this, ownerId, filterOutValidation, false);
  1311. result = result.concat(this._decorationProvider.getAllDecorations(ownerId, filterOutValidation));
  1312. return result;
  1313. }
  1314. _getDecorationsInRange(filterRange, filterOwnerId, filterOutValidation) {
  1315. const startOffset = this._buffer.getOffsetAt(filterRange.startLineNumber, filterRange.startColumn);
  1316. const endOffset = this._buffer.getOffsetAt(filterRange.endLineNumber, filterRange.endColumn);
  1317. return this._decorationsTree.getAllInInterval(this, startOffset, endOffset, filterOwnerId, filterOutValidation);
  1318. }
  1319. getRangeAt(start, end) {
  1320. return this._buffer.getRangeAt(start, end - start);
  1321. }
  1322. _changeDecorationImpl(decorationId, _range) {
  1323. const node = this._decorations[decorationId];
  1324. if (!node) {
  1325. return;
  1326. }
  1327. if (node.options.after) {
  1328. const oldRange = this.getDecorationRange(decorationId);
  1329. this._onDidChangeDecorations.recordLineAffectedByInjectedText(oldRange.endLineNumber);
  1330. }
  1331. if (node.options.before) {
  1332. const oldRange = this.getDecorationRange(decorationId);
  1333. this._onDidChangeDecorations.recordLineAffectedByInjectedText(oldRange.startLineNumber);
  1334. }
  1335. const range = this._validateRangeRelaxedNoAllocations(_range);
  1336. const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
  1337. const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
  1338. this._decorationsTree.delete(node);
  1339. node.reset(this.getVersionId(), startOffset, endOffset, range);
  1340. this._decorationsTree.insert(node);
  1341. this._onDidChangeDecorations.checkAffectedAndFire(node.options);
  1342. if (node.options.after) {
  1343. this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.endLineNumber);
  1344. }
  1345. if (node.options.before) {
  1346. this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.startLineNumber);
  1347. }
  1348. }
  1349. _changeDecorationOptionsImpl(decorationId, options) {
  1350. const node = this._decorations[decorationId];
  1351. if (!node) {
  1352. return;
  1353. }
  1354. const nodeWasInOverviewRuler = (node.options.overviewRuler && node.options.overviewRuler.color ? true : false);
  1355. const nodeIsInOverviewRuler = (options.overviewRuler && options.overviewRuler.color ? true : false);
  1356. this._onDidChangeDecorations.checkAffectedAndFire(node.options);
  1357. this._onDidChangeDecorations.checkAffectedAndFire(options);
  1358. if (node.options.after || options.after) {
  1359. const nodeRange = this._decorationsTree.getNodeRange(this, node);
  1360. this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.endLineNumber);
  1361. }
  1362. if (node.options.before || options.before) {
  1363. const nodeRange = this._decorationsTree.getNodeRange(this, node);
  1364. this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.startLineNumber);
  1365. }
  1366. if (nodeWasInOverviewRuler !== nodeIsInOverviewRuler) {
  1367. // Delete + Insert due to an overview ruler status change
  1368. this._decorationsTree.delete(node);
  1369. node.setOptions(options);
  1370. this._decorationsTree.insert(node);
  1371. }
  1372. else {
  1373. node.setOptions(options);
  1374. }
  1375. }
  1376. _deltaDecorationsImpl(ownerId, oldDecorationsIds, newDecorations) {
  1377. const versionId = this.getVersionId();
  1378. const oldDecorationsLen = oldDecorationsIds.length;
  1379. let oldDecorationIndex = 0;
  1380. const newDecorationsLen = newDecorations.length;
  1381. let newDecorationIndex = 0;
  1382. let result = new Array(newDecorationsLen);
  1383. while (oldDecorationIndex < oldDecorationsLen || newDecorationIndex < newDecorationsLen) {
  1384. let node = null;
  1385. if (oldDecorationIndex < oldDecorationsLen) {
  1386. // (1) get ourselves an old node
  1387. do {
  1388. node = this._decorations[oldDecorationsIds[oldDecorationIndex++]];
  1389. } while (!node && oldDecorationIndex < oldDecorationsLen);
  1390. // (2) remove the node from the tree (if it exists)
  1391. if (node) {
  1392. if (node.options.after) {
  1393. const nodeRange = this._decorationsTree.getNodeRange(this, node);
  1394. this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.endLineNumber);
  1395. }
  1396. if (node.options.before) {
  1397. const nodeRange = this._decorationsTree.getNodeRange(this, node);
  1398. this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.startLineNumber);
  1399. }
  1400. this._decorationsTree.delete(node);
  1401. this._onDidChangeDecorations.checkAffectedAndFire(node.options);
  1402. }
  1403. }
  1404. if (newDecorationIndex < newDecorationsLen) {
  1405. // (3) create a new node if necessary
  1406. if (!node) {
  1407. const internalDecorationId = (++this._lastDecorationId);
  1408. const decorationId = `${this._instanceId};${internalDecorationId}`;
  1409. node = new IntervalNode(decorationId, 0, 0);
  1410. this._decorations[decorationId] = node;
  1411. }
  1412. // (4) initialize node
  1413. const newDecoration = newDecorations[newDecorationIndex];
  1414. const range = this._validateRangeRelaxedNoAllocations(newDecoration.range);
  1415. const options = _normalizeOptions(newDecoration.options);
  1416. const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
  1417. const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
  1418. node.ownerId = ownerId;
  1419. node.reset(versionId, startOffset, endOffset, range);
  1420. node.setOptions(options);
  1421. if (node.options.after) {
  1422. this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.endLineNumber);
  1423. }
  1424. if (node.options.before) {
  1425. this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.startLineNumber);
  1426. }
  1427. this._onDidChangeDecorations.checkAffectedAndFire(options);
  1428. this._decorationsTree.insert(node);
  1429. result[newDecorationIndex] = node.id;
  1430. newDecorationIndex++;
  1431. }
  1432. else {
  1433. if (node) {
  1434. delete this._decorations[node.id];
  1435. }
  1436. }
  1437. }
  1438. return result;
  1439. }
  1440. setTokens(tokens, backgroundTokenizationCompleted = false) {
  1441. if (tokens.length !== 0) {
  1442. let ranges = [];
  1443. for (let i = 0, len = tokens.length; i < len; i++) {
  1444. const element = tokens[i];
  1445. let minChangedLineNumber = 0;
  1446. let maxChangedLineNumber = 0;
  1447. let hasChange = false;
  1448. for (let j = 0, lenJ = element.tokens.length; j < lenJ; j++) {
  1449. const lineNumber = element.startLineNumber + j;
  1450. if (hasChange) {
  1451. this._tokens.setTokens(this._languageId, lineNumber - 1, this._buffer.getLineLength(lineNumber), element.tokens[j], false);
  1452. maxChangedLineNumber = lineNumber;
  1453. }
  1454. else {
  1455. const lineHasChange = this._tokens.setTokens(this._languageId, lineNumber - 1, this._buffer.getLineLength(lineNumber), element.tokens[j], true);
  1456. if (lineHasChange) {
  1457. hasChange = true;
  1458. minChangedLineNumber = lineNumber;
  1459. maxChangedLineNumber = lineNumber;
  1460. }
  1461. }
  1462. }
  1463. if (hasChange) {
  1464. ranges.push({ fromLineNumber: minChangedLineNumber, toLineNumber: maxChangedLineNumber });
  1465. }
  1466. }
  1467. if (ranges.length > 0) {
  1468. this._emitModelTokensChangedEvent({
  1469. tokenizationSupportChanged: false,
  1470. semanticTokensApplied: false,
  1471. ranges: ranges
  1472. });
  1473. }
  1474. }
  1475. this.handleTokenizationProgress(backgroundTokenizationCompleted);
  1476. }
  1477. setSemanticTokens(tokens, isComplete) {
  1478. this._tokens2.set(tokens, isComplete);
  1479. this._emitModelTokensChangedEvent({
  1480. tokenizationSupportChanged: false,
  1481. semanticTokensApplied: tokens !== null,
  1482. ranges: [{ fromLineNumber: 1, toLineNumber: this.getLineCount() }]
  1483. });
  1484. }
  1485. hasCompleteSemanticTokens() {
  1486. return this._tokens2.isComplete();
  1487. }
  1488. hasSomeSemanticTokens() {
  1489. return !this._tokens2.isEmpty();
  1490. }
  1491. setPartialSemanticTokens(range, tokens) {
  1492. if (this.hasCompleteSemanticTokens()) {
  1493. return;
  1494. }
  1495. const changedRange = this._tokens2.setPartial(range, tokens);
  1496. this._emitModelTokensChangedEvent({
  1497. tokenizationSupportChanged: false,
  1498. semanticTokensApplied: true,
  1499. ranges: [{ fromLineNumber: changedRange.startLineNumber, toLineNumber: changedRange.endLineNumber }]
  1500. });
  1501. }
  1502. tokenizeViewport(startLineNumber, endLineNumber) {
  1503. startLineNumber = Math.max(1, startLineNumber);
  1504. endLineNumber = Math.min(this._buffer.getLineCount(), endLineNumber);
  1505. this._tokenization.tokenizeViewport(startLineNumber, endLineNumber);
  1506. }
  1507. clearTokens() {
  1508. this._tokens.flush();
  1509. this._emitModelTokensChangedEvent({
  1510. tokenizationSupportChanged: true,
  1511. semanticTokensApplied: false,
  1512. ranges: [{
  1513. fromLineNumber: 1,
  1514. toLineNumber: this._buffer.getLineCount()
  1515. }]
  1516. });
  1517. }
  1518. _emitModelTokensChangedEvent(e) {
  1519. if (!this._isDisposing) {
  1520. this._onDidChangeTokens.fire(e);
  1521. }
  1522. }
  1523. resetTokenization() {
  1524. this._tokenization.reset();
  1525. }
  1526. forceTokenization(lineNumber) {
  1527. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  1528. throw new Error('Illegal value for lineNumber');
  1529. }
  1530. this._tokenization.forceTokenization(lineNumber);
  1531. }
  1532. isCheapToTokenize(lineNumber) {
  1533. return this._tokenization.isCheapToTokenize(lineNumber);
  1534. }
  1535. tokenizeIfCheap(lineNumber) {
  1536. if (this.isCheapToTokenize(lineNumber)) {
  1537. this.forceTokenization(lineNumber);
  1538. }
  1539. }
  1540. getLineTokens(lineNumber) {
  1541. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  1542. throw new Error('Illegal value for lineNumber');
  1543. }
  1544. return this._getLineTokens(lineNumber);
  1545. }
  1546. _getLineTokens(lineNumber) {
  1547. const lineText = this.getLineContent(lineNumber);
  1548. const syntacticTokens = this._tokens.getTokens(this._languageId, lineNumber - 1, lineText);
  1549. return this._tokens2.addSemanticTokens(lineNumber, syntacticTokens);
  1550. }
  1551. getLanguageId() {
  1552. return this._languageId;
  1553. }
  1554. setMode(languageId) {
  1555. if (this._languageId === languageId) {
  1556. // There's nothing to do
  1557. return;
  1558. }
  1559. let e = {
  1560. oldLanguage: this._languageId,
  1561. newLanguage: languageId
  1562. };
  1563. this._languageId = languageId;
  1564. this._onDidChangeLanguage.fire(e);
  1565. this._onDidChangeLanguageConfiguration.fire({});
  1566. }
  1567. getLanguageIdAtPosition(lineNumber, column) {
  1568. const position = this.validatePosition(new Position(lineNumber, column));
  1569. const lineTokens = this.getLineTokens(position.lineNumber);
  1570. return lineTokens.getLanguageId(lineTokens.findTokenIndexAtOffset(position.column - 1));
  1571. }
  1572. getTokenTypeIfInsertingCharacter(lineNumber, column, character) {
  1573. const position = this.validatePosition(new Position(lineNumber, column));
  1574. return this._tokenization.getTokenTypeIfInsertingCharacter(position, character);
  1575. }
  1576. getLanguageConfiguration(languageId) {
  1577. return this._languageConfigurationService.getLanguageConfiguration(languageId);
  1578. }
  1579. // Having tokens allows implementing additional helper methods
  1580. getWordAtPosition(_position) {
  1581. this._assertNotDisposed();
  1582. const position = this.validatePosition(_position);
  1583. const lineContent = this.getLineContent(position.lineNumber);
  1584. const lineTokens = this._getLineTokens(position.lineNumber);
  1585. const tokenIndex = lineTokens.findTokenIndexAtOffset(position.column - 1);
  1586. // (1). First try checking right biased word
  1587. const [rbStartOffset, rbEndOffset] = TextModel._findLanguageBoundaries(lineTokens, tokenIndex);
  1588. const rightBiasedWord = getWordAtText(position.column, this.getLanguageConfiguration(lineTokens.getLanguageId(tokenIndex)).getWordDefinition(), lineContent.substring(rbStartOffset, rbEndOffset), rbStartOffset);
  1589. // Make sure the result touches the original passed in position
  1590. if (rightBiasedWord && rightBiasedWord.startColumn <= _position.column && _position.column <= rightBiasedWord.endColumn) {
  1591. return rightBiasedWord;
  1592. }
  1593. // (2). Else, if we were at a language boundary, check the left biased word
  1594. if (tokenIndex > 0 && rbStartOffset === position.column - 1) {
  1595. // edge case, where `position` sits between two tokens belonging to two different languages
  1596. const [lbStartOffset, lbEndOffset] = TextModel._findLanguageBoundaries(lineTokens, tokenIndex - 1);
  1597. const leftBiasedWord = getWordAtText(position.column, this.getLanguageConfiguration(lineTokens.getLanguageId(tokenIndex - 1)).getWordDefinition(), lineContent.substring(lbStartOffset, lbEndOffset), lbStartOffset);
  1598. // Make sure the result touches the original passed in position
  1599. if (leftBiasedWord && leftBiasedWord.startColumn <= _position.column && _position.column <= leftBiasedWord.endColumn) {
  1600. return leftBiasedWord;
  1601. }
  1602. }
  1603. return null;
  1604. }
  1605. static _findLanguageBoundaries(lineTokens, tokenIndex) {
  1606. const languageId = lineTokens.getLanguageId(tokenIndex);
  1607. // go left until a different language is hit
  1608. let startOffset = 0;
  1609. for (let i = tokenIndex; i >= 0 && lineTokens.getLanguageId(i) === languageId; i--) {
  1610. startOffset = lineTokens.getStartOffset(i);
  1611. }
  1612. // go right until a different language is hit
  1613. let endOffset = lineTokens.getLineContent().length;
  1614. for (let i = tokenIndex, tokenCount = lineTokens.getCount(); i < tokenCount && lineTokens.getLanguageId(i) === languageId; i++) {
  1615. endOffset = lineTokens.getEndOffset(i);
  1616. }
  1617. return [startOffset, endOffset];
  1618. }
  1619. getWordUntilPosition(position) {
  1620. const wordAtPosition = this.getWordAtPosition(position);
  1621. if (!wordAtPosition) {
  1622. return {
  1623. word: '',
  1624. startColumn: position.column,
  1625. endColumn: position.column
  1626. };
  1627. }
  1628. return {
  1629. word: wordAtPosition.word.substr(0, position.column - wordAtPosition.startColumn),
  1630. startColumn: wordAtPosition.startColumn,
  1631. endColumn: position.column
  1632. };
  1633. }
  1634. /**
  1635. * Returns:
  1636. * - -1 => the line consists of whitespace
  1637. * - otherwise => the indent level is returned value
  1638. */
  1639. static computeIndentLevel(line, tabSize) {
  1640. let indent = 0;
  1641. let i = 0;
  1642. let len = line.length;
  1643. while (i < len) {
  1644. let chCode = line.charCodeAt(i);
  1645. if (chCode === 32 /* Space */) {
  1646. indent++;
  1647. }
  1648. else if (chCode === 9 /* Tab */) {
  1649. indent = indent - indent % tabSize + tabSize;
  1650. }
  1651. else {
  1652. break;
  1653. }
  1654. i++;
  1655. }
  1656. if (i === len) {
  1657. return -1; // line only consists of whitespace
  1658. }
  1659. return indent;
  1660. }
  1661. _computeIndentLevel(lineIndex) {
  1662. return TextModel.computeIndentLevel(this._buffer.getLineContent(lineIndex + 1), this._options.tabSize);
  1663. }
  1664. getActiveIndentGuide(lineNumber, minLineNumber, maxLineNumber) {
  1665. this._assertNotDisposed();
  1666. const lineCount = this.getLineCount();
  1667. if (lineNumber < 1 || lineNumber > lineCount) {
  1668. throw new Error('Illegal value for lineNumber');
  1669. }
  1670. const foldingRules = this.getLanguageConfiguration(this._languageId).foldingRules;
  1671. const offSide = Boolean(foldingRules && foldingRules.offSide);
  1672. let up_aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */
  1673. let up_aboveContentLineIndent = -1;
  1674. let up_belowContentLineIndex = -2; /* -2 is a marker for not having computed it */
  1675. let up_belowContentLineIndent = -1;
  1676. const up_resolveIndents = (lineNumber) => {
  1677. if (up_aboveContentLineIndex !== -1 && (up_aboveContentLineIndex === -2 || up_aboveContentLineIndex > lineNumber - 1)) {
  1678. up_aboveContentLineIndex = -1;
  1679. up_aboveContentLineIndent = -1;
  1680. // must find previous line with content
  1681. for (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {
  1682. let indent = this._computeIndentLevel(lineIndex);
  1683. if (indent >= 0) {
  1684. up_aboveContentLineIndex = lineIndex;
  1685. up_aboveContentLineIndent = indent;
  1686. break;
  1687. }
  1688. }
  1689. }
  1690. if (up_belowContentLineIndex === -2) {
  1691. up_belowContentLineIndex = -1;
  1692. up_belowContentLineIndent = -1;
  1693. // must find next line with content
  1694. for (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {
  1695. let indent = this._computeIndentLevel(lineIndex);
  1696. if (indent >= 0) {
  1697. up_belowContentLineIndex = lineIndex;
  1698. up_belowContentLineIndent = indent;
  1699. break;
  1700. }
  1701. }
  1702. }
  1703. };
  1704. let down_aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */
  1705. let down_aboveContentLineIndent = -1;
  1706. let down_belowContentLineIndex = -2; /* -2 is a marker for not having computed it */
  1707. let down_belowContentLineIndent = -1;
  1708. const down_resolveIndents = (lineNumber) => {
  1709. if (down_aboveContentLineIndex === -2) {
  1710. down_aboveContentLineIndex = -1;
  1711. down_aboveContentLineIndent = -1;
  1712. // must find previous line with content
  1713. for (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {
  1714. let indent = this._computeIndentLevel(lineIndex);
  1715. if (indent >= 0) {
  1716. down_aboveContentLineIndex = lineIndex;
  1717. down_aboveContentLineIndent = indent;
  1718. break;
  1719. }
  1720. }
  1721. }
  1722. if (down_belowContentLineIndex !== -1 && (down_belowContentLineIndex === -2 || down_belowContentLineIndex < lineNumber - 1)) {
  1723. down_belowContentLineIndex = -1;
  1724. down_belowContentLineIndent = -1;
  1725. // must find next line with content
  1726. for (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {
  1727. let indent = this._computeIndentLevel(lineIndex);
  1728. if (indent >= 0) {
  1729. down_belowContentLineIndex = lineIndex;
  1730. down_belowContentLineIndent = indent;
  1731. break;
  1732. }
  1733. }
  1734. }
  1735. };
  1736. let startLineNumber = 0;
  1737. let goUp = true;
  1738. let endLineNumber = 0;
  1739. let goDown = true;
  1740. let indent = 0;
  1741. let initialIndent = 0;
  1742. for (let distance = 0; goUp || goDown; distance++) {
  1743. const upLineNumber = lineNumber - distance;
  1744. const downLineNumber = lineNumber + distance;
  1745. if (distance > 1 && (upLineNumber < 1 || upLineNumber < minLineNumber)) {
  1746. goUp = false;
  1747. }
  1748. if (distance > 1 && (downLineNumber > lineCount || downLineNumber > maxLineNumber)) {
  1749. goDown = false;
  1750. }
  1751. if (distance > 50000) {
  1752. // stop processing
  1753. goUp = false;
  1754. goDown = false;
  1755. }
  1756. let upLineIndentLevel = -1;
  1757. if (goUp) {
  1758. // compute indent level going up
  1759. const currentIndent = this._computeIndentLevel(upLineNumber - 1);
  1760. if (currentIndent >= 0) {
  1761. // This line has content (besides whitespace)
  1762. // Use the line's indent
  1763. up_belowContentLineIndex = upLineNumber - 1;
  1764. up_belowContentLineIndent = currentIndent;
  1765. upLineIndentLevel = Math.ceil(currentIndent / this._options.indentSize);
  1766. }
  1767. else {
  1768. up_resolveIndents(upLineNumber);
  1769. upLineIndentLevel = this._getIndentLevelForWhitespaceLine(offSide, up_aboveContentLineIndent, up_belowContentLineIndent);
  1770. }
  1771. }
  1772. let downLineIndentLevel = -1;
  1773. if (goDown) {
  1774. // compute indent level going down
  1775. const currentIndent = this._computeIndentLevel(downLineNumber - 1);
  1776. if (currentIndent >= 0) {
  1777. // This line has content (besides whitespace)
  1778. // Use the line's indent
  1779. down_aboveContentLineIndex = downLineNumber - 1;
  1780. down_aboveContentLineIndent = currentIndent;
  1781. downLineIndentLevel = Math.ceil(currentIndent / this._options.indentSize);
  1782. }
  1783. else {
  1784. down_resolveIndents(downLineNumber);
  1785. downLineIndentLevel = this._getIndentLevelForWhitespaceLine(offSide, down_aboveContentLineIndent, down_belowContentLineIndent);
  1786. }
  1787. }
  1788. if (distance === 0) {
  1789. initialIndent = upLineIndentLevel;
  1790. continue;
  1791. }
  1792. if (distance === 1) {
  1793. if (downLineNumber <= lineCount && downLineIndentLevel >= 0 && initialIndent + 1 === downLineIndentLevel) {
  1794. // This is the beginning of a scope, we have special handling here, since we want the
  1795. // child scope indent to be active, not the parent scope
  1796. goUp = false;
  1797. startLineNumber = downLineNumber;
  1798. endLineNumber = downLineNumber;
  1799. indent = downLineIndentLevel;
  1800. continue;
  1801. }
  1802. if (upLineNumber >= 1 && upLineIndentLevel >= 0 && upLineIndentLevel - 1 === initialIndent) {
  1803. // This is the end of a scope, just like above
  1804. goDown = false;
  1805. startLineNumber = upLineNumber;
  1806. endLineNumber = upLineNumber;
  1807. indent = upLineIndentLevel;
  1808. continue;
  1809. }
  1810. startLineNumber = lineNumber;
  1811. endLineNumber = lineNumber;
  1812. indent = initialIndent;
  1813. if (indent === 0) {
  1814. // No need to continue
  1815. return { startLineNumber, endLineNumber, indent };
  1816. }
  1817. }
  1818. if (goUp) {
  1819. if (upLineIndentLevel >= indent) {
  1820. startLineNumber = upLineNumber;
  1821. }
  1822. else {
  1823. goUp = false;
  1824. }
  1825. }
  1826. if (goDown) {
  1827. if (downLineIndentLevel >= indent) {
  1828. endLineNumber = downLineNumber;
  1829. }
  1830. else {
  1831. goDown = false;
  1832. }
  1833. }
  1834. }
  1835. return { startLineNumber, endLineNumber, indent };
  1836. }
  1837. getLinesBracketGuides(startLineNumber, endLineNumber, activePosition, options) {
  1838. var _a, _b, _c, _d, _e;
  1839. const result = [];
  1840. const bracketPairs = this._bracketPairColorizer.getBracketPairsInRangeWithMinIndentation(new Range(startLineNumber, 1, endLineNumber, this.getLineMaxColumn(endLineNumber)));
  1841. let activeBracketPairRange = undefined;
  1842. if (activePosition && bracketPairs.length > 0) {
  1843. const bracketsContainingActivePosition = (startLineNumber <= activePosition.lineNumber && activePosition.lineNumber <= endLineNumber)
  1844. // Does active position intersect with the view port? -> Intersect bracket pairs with activePosition
  1845. ? bracketPairs.filter(bp => Range.strictContainsPosition(bp.range, activePosition))
  1846. : this._bracketPairColorizer.getBracketPairsInRange(Range.fromPositions(activePosition));
  1847. activeBracketPairRange = (_a = findLast(bracketsContainingActivePosition,
  1848. /* Exclude single line bracket pairs for cases such as
  1849. * ```
  1850. * function test() {
  1851. * if (true) { | }
  1852. * }
  1853. * ```
  1854. */
  1855. (i) => i.range.startLineNumber !== i.range.endLineNumber)) === null || _a === void 0 ? void 0 : _a.range;
  1856. }
  1857. const queue = new ArrayQueue(bracketPairs);
  1858. /** Indexed by nesting level */
  1859. const activeGuides = new Array();
  1860. const nextGuides = new Array();
  1861. const colorProvider = new BracketPairGuidesClassNames();
  1862. for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
  1863. let guides = new Array();
  1864. if (nextGuides.length > 0) {
  1865. guides = guides.concat(nextGuides);
  1866. nextGuides.length = 0;
  1867. }
  1868. result.push(guides);
  1869. // Update activeGuides
  1870. for (const pair of queue.takeWhile(b => b.openingBracketRange.startLineNumber <= lineNumber) || []) {
  1871. if (pair.range.startLineNumber === pair.range.endLineNumber) {
  1872. // ignore single line brackets
  1873. continue;
  1874. }
  1875. 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);
  1876. let renderHorizontalEndLineAtTheBottom = false;
  1877. if (pair.closingBracketRange) {
  1878. const firstNonWsIndex = strings.firstNonWhitespaceIndex(this.getLineContent(pair.closingBracketRange.startLineNumber));
  1879. if (firstNonWsIndex < pair.closingBracketRange.startColumn - 1) {
  1880. renderHorizontalEndLineAtTheBottom = true;
  1881. }
  1882. }
  1883. const start = pair.openingBracketRange.getStartPosition();
  1884. const end = ((_e = (_d = pair.closingBracketRange) === null || _d === void 0 ? void 0 : _d.getStartPosition()) !== null && _e !== void 0 ? _e : pair.range.getEndPosition());
  1885. if (pair.closingBracketRange === undefined) {
  1886. // Don't show guides for bracket pairs that are not balanced.
  1887. // See #135125.
  1888. activeGuides[pair.nestingLevel] = null;
  1889. }
  1890. else {
  1891. activeGuides[pair.nestingLevel] = {
  1892. nestingLevel: pair.nestingLevel,
  1893. guideVisibleColumn,
  1894. start,
  1895. visibleStartColumn: this.getVisibleColumnFromPosition(start),
  1896. end,
  1897. visibleEndColumn: this.getVisibleColumnFromPosition(end),
  1898. bracketPair: pair,
  1899. renderHorizontalEndLineAtTheBottom
  1900. };
  1901. }
  1902. }
  1903. for (const line of activeGuides) {
  1904. if (!line) {
  1905. continue;
  1906. }
  1907. const isActive = activeBracketPairRange && line.bracketPair.range.equalsRange(activeBracketPairRange);
  1908. const className = colorProvider.getInlineClassNameOfLevel(line.nestingLevel) +
  1909. (options.highlightActive && isActive ? ' ' + colorProvider.activeClassName : '');
  1910. if ((isActive && options.horizontalGuides !== model.HorizontalGuidesState.Disabled)
  1911. || (options.includeInactive && options.horizontalGuides === model.HorizontalGuidesState.Enabled)) {
  1912. if (line.start.lineNumber === lineNumber) {
  1913. if (line.guideVisibleColumn < line.visibleStartColumn) {
  1914. guides.push(new model.IndentGuide(line.guideVisibleColumn, className, new model.IndentGuideHorizontalLine(false, line.start.column)));
  1915. }
  1916. }
  1917. if (line.end.lineNumber === lineNumber + 1) {
  1918. // The next line might have horizontal guides.
  1919. // However, the next line might also have a new bracket pair with the same indentation,
  1920. // so the current bracket pair might get replaced. That's why we push the guide to nextGuides one line ahead.
  1921. if (line.guideVisibleColumn < line.visibleEndColumn) {
  1922. nextGuides.push(new model.IndentGuide(line.guideVisibleColumn, className, new model.IndentGuideHorizontalLine(!line.renderHorizontalEndLineAtTheBottom, line.end.column)));
  1923. }
  1924. }
  1925. }
  1926. }
  1927. let lastVisibleColumnCount = Number.MAX_SAFE_INTEGER;
  1928. // Going backwards, so the last guide potentially replaces others
  1929. for (let i = activeGuides.length - 1; i >= 0; i--) {
  1930. const line = activeGuides[i];
  1931. if (!line) {
  1932. continue;
  1933. }
  1934. const isActive = options.highlightActive && activeBracketPairRange &&
  1935. line.bracketPair.range.equalsRange(activeBracketPairRange);
  1936. const className = colorProvider.getInlineClassNameOfLevel(line.nestingLevel) +
  1937. (isActive ? ' ' + colorProvider.activeClassName : '');
  1938. if (isActive || options.includeInactive) {
  1939. if (line.renderHorizontalEndLineAtTheBottom && line.end.lineNumber === lineNumber + 1) {
  1940. nextGuides.push(new model.IndentGuide(line.guideVisibleColumn, className, null));
  1941. }
  1942. }
  1943. if (line.end.lineNumber <= lineNumber
  1944. || line.start.lineNumber >= lineNumber) {
  1945. continue;
  1946. }
  1947. if (line.guideVisibleColumn >= lastVisibleColumnCount && !isActive) {
  1948. // Don't render a guide on top of an existing guide, unless it is active.
  1949. continue;
  1950. }
  1951. lastVisibleColumnCount = line.guideVisibleColumn;
  1952. if (isActive || options.includeInactive) {
  1953. guides.push(new model.IndentGuide(line.guideVisibleColumn, className, null));
  1954. }
  1955. }
  1956. guides.sort((a, b) => a.visibleColumn - b.visibleColumn);
  1957. }
  1958. return result;
  1959. }
  1960. getVisibleColumnFromPosition(position) {
  1961. return CursorColumns.visibleColumnFromColumn(this.getLineContent(position.lineNumber), position.column, this._options.tabSize) + 1;
  1962. }
  1963. getLinesIndentGuides(startLineNumber, endLineNumber) {
  1964. this._assertNotDisposed();
  1965. const lineCount = this.getLineCount();
  1966. if (startLineNumber < 1 || startLineNumber > lineCount) {
  1967. throw new Error('Illegal value for startLineNumber');
  1968. }
  1969. if (endLineNumber < 1 || endLineNumber > lineCount) {
  1970. throw new Error('Illegal value for endLineNumber');
  1971. }
  1972. const foldingRules = this.getLanguageConfiguration(this._languageId).foldingRules;
  1973. const offSide = Boolean(foldingRules && foldingRules.offSide);
  1974. let result = new Array(endLineNumber - startLineNumber + 1);
  1975. let aboveContentLineIndex = -2; /* -2 is a marker for not having computed it */
  1976. let aboveContentLineIndent = -1;
  1977. let belowContentLineIndex = -2; /* -2 is a marker for not having computed it */
  1978. let belowContentLineIndent = -1;
  1979. for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
  1980. let resultIndex = lineNumber - startLineNumber;
  1981. const currentIndent = this._computeIndentLevel(lineNumber - 1);
  1982. if (currentIndent >= 0) {
  1983. // This line has content (besides whitespace)
  1984. // Use the line's indent
  1985. aboveContentLineIndex = lineNumber - 1;
  1986. aboveContentLineIndent = currentIndent;
  1987. result[resultIndex] = Math.ceil(currentIndent / this._options.indentSize);
  1988. continue;
  1989. }
  1990. if (aboveContentLineIndex === -2) {
  1991. aboveContentLineIndex = -1;
  1992. aboveContentLineIndent = -1;
  1993. // must find previous line with content
  1994. for (let lineIndex = lineNumber - 2; lineIndex >= 0; lineIndex--) {
  1995. let indent = this._computeIndentLevel(lineIndex);
  1996. if (indent >= 0) {
  1997. aboveContentLineIndex = lineIndex;
  1998. aboveContentLineIndent = indent;
  1999. break;
  2000. }
  2001. }
  2002. }
  2003. if (belowContentLineIndex !== -1 && (belowContentLineIndex === -2 || belowContentLineIndex < lineNumber - 1)) {
  2004. belowContentLineIndex = -1;
  2005. belowContentLineIndent = -1;
  2006. // must find next line with content
  2007. for (let lineIndex = lineNumber; lineIndex < lineCount; lineIndex++) {
  2008. let indent = this._computeIndentLevel(lineIndex);
  2009. if (indent >= 0) {
  2010. belowContentLineIndex = lineIndex;
  2011. belowContentLineIndent = indent;
  2012. break;
  2013. }
  2014. }
  2015. }
  2016. result[resultIndex] = this._getIndentLevelForWhitespaceLine(offSide, aboveContentLineIndent, belowContentLineIndent);
  2017. }
  2018. return result;
  2019. }
  2020. _getIndentLevelForWhitespaceLine(offSide, aboveContentLineIndent, belowContentLineIndent) {
  2021. if (aboveContentLineIndent === -1 || belowContentLineIndent === -1) {
  2022. // At the top or bottom of the file
  2023. return 0;
  2024. }
  2025. else if (aboveContentLineIndent < belowContentLineIndent) {
  2026. // we are inside the region above
  2027. return (1 + Math.floor(aboveContentLineIndent / this._options.indentSize));
  2028. }
  2029. else if (aboveContentLineIndent === belowContentLineIndent) {
  2030. // we are in between two regions
  2031. return Math.ceil(belowContentLineIndent / this._options.indentSize);
  2032. }
  2033. else {
  2034. if (offSide) {
  2035. // same level as region below
  2036. return Math.ceil(belowContentLineIndent / this._options.indentSize);
  2037. }
  2038. else {
  2039. // we are inside the region that ends below
  2040. return (1 + Math.floor(belowContentLineIndent / this._options.indentSize));
  2041. }
  2042. }
  2043. }
  2044. //#endregion
  2045. normalizePosition(position, affinity) {
  2046. return position;
  2047. }
  2048. /**
  2049. * Gets the column at which indentation stops at a given line.
  2050. * @internal
  2051. */
  2052. getLineIndentColumn(lineNumber) {
  2053. // Columns start with 1.
  2054. return indentOfLine(this.getLineContent(lineNumber)) + 1;
  2055. }
  2056. };
  2057. TextModel.MODEL_SYNC_LIMIT = 50 * 1024 * 1024; // 50 MB
  2058. TextModel.LARGE_FILE_SIZE_THRESHOLD = 20 * 1024 * 1024; // 20 MB;
  2059. TextModel.LARGE_FILE_LINE_COUNT_THRESHOLD = 300 * 1000; // 300K lines
  2060. TextModel.DEFAULT_CREATION_OPTIONS = {
  2061. isForSimpleWidget: false,
  2062. tabSize: EDITOR_MODEL_DEFAULTS.tabSize,
  2063. indentSize: EDITOR_MODEL_DEFAULTS.indentSize,
  2064. insertSpaces: EDITOR_MODEL_DEFAULTS.insertSpaces,
  2065. detectIndentation: false,
  2066. defaultEOL: 1 /* LF */,
  2067. trimAutoWhitespace: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace,
  2068. largeFileOptimizations: EDITOR_MODEL_DEFAULTS.largeFileOptimizations,
  2069. bracketPairColorizationOptions: EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions,
  2070. };
  2071. TextModel = __decorate([
  2072. __param(4, IUndoRedoService),
  2073. __param(5, IModeService),
  2074. __param(6, ILanguageConfigurationService)
  2075. ], TextModel);
  2076. export { TextModel };
  2077. function indentOfLine(line) {
  2078. let indent = 0;
  2079. for (const c of line) {
  2080. if (c === ' ' || c === '\t') {
  2081. indent++;
  2082. }
  2083. else {
  2084. break;
  2085. }
  2086. }
  2087. return indent;
  2088. }
  2089. export class BracketPairGuidesClassNames {
  2090. constructor() {
  2091. this.activeClassName = 'indent-active';
  2092. }
  2093. getInlineClassNameOfLevel(level) {
  2094. // To support a dynamic amount of colors up to 6 colors,
  2095. // we use a number that is a lcm of all numbers from 1 to 6.
  2096. return `bracket-indent-guide lvl-${level % 30}`;
  2097. }
  2098. }
  2099. //#region Decorations
  2100. function isNodeInOverviewRuler(node) {
  2101. return (node.options.overviewRuler && node.options.overviewRuler.color ? true : false);
  2102. }
  2103. function isNodeInjectedText(node) {
  2104. return !!node.options.after || !!node.options.before;
  2105. }
  2106. class DecorationsTrees {
  2107. constructor() {
  2108. this._decorationsTree0 = new IntervalTree();
  2109. this._decorationsTree1 = new IntervalTree();
  2110. this._injectedTextDecorationsTree = new IntervalTree();
  2111. }
  2112. ensureAllNodesHaveRanges(host) {
  2113. this.getAll(host, 0, false, false);
  2114. }
  2115. _ensureNodesHaveRanges(host, nodes) {
  2116. for (const node of nodes) {
  2117. if (node.range === null) {
  2118. node.range = host.getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd);
  2119. }
  2120. }
  2121. return nodes;
  2122. }
  2123. getAllInInterval(host, start, end, filterOwnerId, filterOutValidation) {
  2124. const versionId = host.getVersionId();
  2125. const result = this._intervalSearch(start, end, filterOwnerId, filterOutValidation, versionId);
  2126. return this._ensureNodesHaveRanges(host, result);
  2127. }
  2128. _intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId) {
  2129. const r0 = this._decorationsTree0.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
  2130. const r1 = this._decorationsTree1.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
  2131. const r2 = this._injectedTextDecorationsTree.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
  2132. return r0.concat(r1).concat(r2);
  2133. }
  2134. getInjectedTextInInterval(host, start, end, filterOwnerId) {
  2135. const versionId = host.getVersionId();
  2136. const result = this._injectedTextDecorationsTree.intervalSearch(start, end, filterOwnerId, false, versionId);
  2137. return this._ensureNodesHaveRanges(host, result).filter((i) => i.options.showIfCollapsed || !i.range.isEmpty());
  2138. }
  2139. getAllInjectedText(host, filterOwnerId) {
  2140. const versionId = host.getVersionId();
  2141. const result = this._injectedTextDecorationsTree.search(filterOwnerId, false, versionId);
  2142. return this._ensureNodesHaveRanges(host, result).filter((i) => i.options.showIfCollapsed || !i.range.isEmpty());
  2143. }
  2144. getAll(host, filterOwnerId, filterOutValidation, overviewRulerOnly) {
  2145. const versionId = host.getVersionId();
  2146. const result = this._search(filterOwnerId, filterOutValidation, overviewRulerOnly, versionId);
  2147. return this._ensureNodesHaveRanges(host, result);
  2148. }
  2149. _search(filterOwnerId, filterOutValidation, overviewRulerOnly, cachedVersionId) {
  2150. if (overviewRulerOnly) {
  2151. return this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId);
  2152. }
  2153. else {
  2154. const r0 = this._decorationsTree0.search(filterOwnerId, filterOutValidation, cachedVersionId);
  2155. const r1 = this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId);
  2156. const r2 = this._injectedTextDecorationsTree.search(filterOwnerId, filterOutValidation, cachedVersionId);
  2157. return r0.concat(r1).concat(r2);
  2158. }
  2159. }
  2160. collectNodesFromOwner(ownerId) {
  2161. const r0 = this._decorationsTree0.collectNodesFromOwner(ownerId);
  2162. const r1 = this._decorationsTree1.collectNodesFromOwner(ownerId);
  2163. const r2 = this._injectedTextDecorationsTree.collectNodesFromOwner(ownerId);
  2164. return r0.concat(r1).concat(r2);
  2165. }
  2166. collectNodesPostOrder() {
  2167. const r0 = this._decorationsTree0.collectNodesPostOrder();
  2168. const r1 = this._decorationsTree1.collectNodesPostOrder();
  2169. const r2 = this._injectedTextDecorationsTree.collectNodesPostOrder();
  2170. return r0.concat(r1).concat(r2);
  2171. }
  2172. insert(node) {
  2173. if (isNodeInjectedText(node)) {
  2174. this._injectedTextDecorationsTree.insert(node);
  2175. }
  2176. else if (isNodeInOverviewRuler(node)) {
  2177. this._decorationsTree1.insert(node);
  2178. }
  2179. else {
  2180. this._decorationsTree0.insert(node);
  2181. }
  2182. }
  2183. delete(node) {
  2184. if (isNodeInjectedText(node)) {
  2185. this._injectedTextDecorationsTree.delete(node);
  2186. }
  2187. else if (isNodeInOverviewRuler(node)) {
  2188. this._decorationsTree1.delete(node);
  2189. }
  2190. else {
  2191. this._decorationsTree0.delete(node);
  2192. }
  2193. }
  2194. getNodeRange(host, node) {
  2195. const versionId = host.getVersionId();
  2196. if (node.cachedVersionId !== versionId) {
  2197. this._resolveNode(node, versionId);
  2198. }
  2199. if (node.range === null) {
  2200. node.range = host.getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd);
  2201. }
  2202. return node.range;
  2203. }
  2204. _resolveNode(node, cachedVersionId) {
  2205. if (isNodeInjectedText(node)) {
  2206. this._injectedTextDecorationsTree.resolveNode(node, cachedVersionId);
  2207. }
  2208. else if (isNodeInOverviewRuler(node)) {
  2209. this._decorationsTree1.resolveNode(node, cachedVersionId);
  2210. }
  2211. else {
  2212. this._decorationsTree0.resolveNode(node, cachedVersionId);
  2213. }
  2214. }
  2215. acceptReplace(offset, length, textLength, forceMoveMarkers) {
  2216. this._decorationsTree0.acceptReplace(offset, length, textLength, forceMoveMarkers);
  2217. this._decorationsTree1.acceptReplace(offset, length, textLength, forceMoveMarkers);
  2218. this._injectedTextDecorationsTree.acceptReplace(offset, length, textLength, forceMoveMarkers);
  2219. }
  2220. }
  2221. function cleanClassName(className) {
  2222. return className.replace(/[^a-z0-9\-_]/gi, ' ');
  2223. }
  2224. class DecorationOptions {
  2225. constructor(options) {
  2226. this.color = options.color || '';
  2227. this.darkColor = options.darkColor || '';
  2228. }
  2229. }
  2230. export class ModelDecorationOverviewRulerOptions extends DecorationOptions {
  2231. constructor(options) {
  2232. super(options);
  2233. this._resolvedColor = null;
  2234. this.position = (typeof options.position === 'number' ? options.position : model.OverviewRulerLane.Center);
  2235. }
  2236. getColor(theme) {
  2237. if (!this._resolvedColor) {
  2238. if (theme.type !== 'light' && this.darkColor) {
  2239. this._resolvedColor = this._resolveColor(this.darkColor, theme);
  2240. }
  2241. else {
  2242. this._resolvedColor = this._resolveColor(this.color, theme);
  2243. }
  2244. }
  2245. return this._resolvedColor;
  2246. }
  2247. invalidateCachedColor() {
  2248. this._resolvedColor = null;
  2249. }
  2250. _resolveColor(color, theme) {
  2251. if (typeof color === 'string') {
  2252. return color;
  2253. }
  2254. let c = color ? theme.getColor(color.id) : null;
  2255. if (!c) {
  2256. return '';
  2257. }
  2258. return c.toString();
  2259. }
  2260. }
  2261. export class ModelDecorationMinimapOptions extends DecorationOptions {
  2262. constructor(options) {
  2263. super(options);
  2264. this.position = options.position;
  2265. }
  2266. getColor(theme) {
  2267. if (!this._resolvedColor) {
  2268. if (theme.type !== 'light' && this.darkColor) {
  2269. this._resolvedColor = this._resolveColor(this.darkColor, theme);
  2270. }
  2271. else {
  2272. this._resolvedColor = this._resolveColor(this.color, theme);
  2273. }
  2274. }
  2275. return this._resolvedColor;
  2276. }
  2277. invalidateCachedColor() {
  2278. this._resolvedColor = undefined;
  2279. }
  2280. _resolveColor(color, theme) {
  2281. if (typeof color === 'string') {
  2282. return Color.fromHex(color);
  2283. }
  2284. return theme.getColor(color.id);
  2285. }
  2286. }
  2287. export class ModelDecorationInjectedTextOptions {
  2288. constructor(options) {
  2289. this.content = options.content || '';
  2290. this.inlineClassName = options.inlineClassName || null;
  2291. this.inlineClassNameAffectsLetterSpacing = options.inlineClassNameAffectsLetterSpacing || false;
  2292. }
  2293. static from(options) {
  2294. if (options instanceof ModelDecorationInjectedTextOptions) {
  2295. return options;
  2296. }
  2297. return new ModelDecorationInjectedTextOptions(options);
  2298. }
  2299. }
  2300. export class ModelDecorationOptions {
  2301. constructor(options) {
  2302. var _a;
  2303. this.description = options.description;
  2304. this.stickiness = options.stickiness || 0 /* AlwaysGrowsWhenTypingAtEdges */;
  2305. this.zIndex = options.zIndex || 0;
  2306. this.className = options.className ? cleanClassName(options.className) : null;
  2307. this.hoverMessage = options.hoverMessage || null;
  2308. this.glyphMarginHoverMessage = options.glyphMarginHoverMessage || null;
  2309. this.isWholeLine = options.isWholeLine || false;
  2310. this.showIfCollapsed = options.showIfCollapsed || false;
  2311. this.collapseOnReplaceEdit = options.collapseOnReplaceEdit || false;
  2312. this.overviewRuler = options.overviewRuler ? new ModelDecorationOverviewRulerOptions(options.overviewRuler) : null;
  2313. this.minimap = options.minimap ? new ModelDecorationMinimapOptions(options.minimap) : null;
  2314. this.glyphMarginClassName = options.glyphMarginClassName ? cleanClassName(options.glyphMarginClassName) : null;
  2315. this.linesDecorationsClassName = options.linesDecorationsClassName ? cleanClassName(options.linesDecorationsClassName) : null;
  2316. this.firstLineDecorationClassName = options.firstLineDecorationClassName ? cleanClassName(options.firstLineDecorationClassName) : null;
  2317. this.marginClassName = options.marginClassName ? cleanClassName(options.marginClassName) : null;
  2318. this.inlineClassName = options.inlineClassName ? cleanClassName(options.inlineClassName) : null;
  2319. this.inlineClassNameAffectsLetterSpacing = options.inlineClassNameAffectsLetterSpacing || false;
  2320. this.beforeContentClassName = options.beforeContentClassName ? cleanClassName(options.beforeContentClassName) : null;
  2321. this.afterContentClassName = options.afterContentClassName ? cleanClassName(options.afterContentClassName) : null;
  2322. this.after = options.after ? ModelDecorationInjectedTextOptions.from(options.after) : null;
  2323. this.before = options.before ? ModelDecorationInjectedTextOptions.from(options.before) : null;
  2324. this.hideInCommentTokens = (_a = options.hideInCommentTokens) !== null && _a !== void 0 ? _a : false;
  2325. }
  2326. static register(options) {
  2327. return new ModelDecorationOptions(options);
  2328. }
  2329. static createDynamic(options) {
  2330. return new ModelDecorationOptions(options);
  2331. }
  2332. }
  2333. ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({ description: 'empty' });
  2334. /**
  2335. * The order carefully matches the values of the enum.
  2336. */
  2337. const TRACKED_RANGE_OPTIONS = [
  2338. ModelDecorationOptions.register({ description: 'tracked-range-always-grows-when-typing-at-edges', stickiness: 0 /* AlwaysGrowsWhenTypingAtEdges */ }),
  2339. ModelDecorationOptions.register({ description: 'tracked-range-never-grows-when-typing-at-edges', stickiness: 1 /* NeverGrowsWhenTypingAtEdges */ }),
  2340. ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-before', stickiness: 2 /* GrowsOnlyWhenTypingBefore */ }),
  2341. ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-after', stickiness: 3 /* GrowsOnlyWhenTypingAfter */ }),
  2342. ];
  2343. function _normalizeOptions(options) {
  2344. if (options instanceof ModelDecorationOptions) {
  2345. return options;
  2346. }
  2347. return ModelDecorationOptions.createDynamic(options);
  2348. }
  2349. export class DidChangeDecorationsEmitter extends Disposable {
  2350. constructor(handleBeforeFire) {
  2351. super();
  2352. this.handleBeforeFire = handleBeforeFire;
  2353. this._actual = this._register(new Emitter());
  2354. this.event = this._actual.event;
  2355. this._affectedInjectedTextLines = null;
  2356. this._deferredCnt = 0;
  2357. this._shouldFire = false;
  2358. this._affectsMinimap = false;
  2359. this._affectsOverviewRuler = false;
  2360. }
  2361. beginDeferredEmit() {
  2362. this._deferredCnt++;
  2363. }
  2364. endDeferredEmit() {
  2365. var _a;
  2366. this._deferredCnt--;
  2367. if (this._deferredCnt === 0) {
  2368. if (this._shouldFire) {
  2369. this.handleBeforeFire(this._affectedInjectedTextLines);
  2370. const event = {
  2371. affectsMinimap: this._affectsMinimap,
  2372. affectsOverviewRuler: this._affectsOverviewRuler
  2373. };
  2374. this._shouldFire = false;
  2375. this._affectsMinimap = false;
  2376. this._affectsOverviewRuler = false;
  2377. this._actual.fire(event);
  2378. }
  2379. (_a = this._affectedInjectedTextLines) === null || _a === void 0 ? void 0 : _a.clear();
  2380. this._affectedInjectedTextLines = null;
  2381. }
  2382. }
  2383. recordLineAffectedByInjectedText(lineNumber) {
  2384. if (!this._affectedInjectedTextLines) {
  2385. this._affectedInjectedTextLines = new Set();
  2386. }
  2387. this._affectedInjectedTextLines.add(lineNumber);
  2388. }
  2389. checkAffectedAndFire(options) {
  2390. if (!this._affectsMinimap) {
  2391. this._affectsMinimap = options.minimap && options.minimap.position ? true : false;
  2392. }
  2393. if (!this._affectsOverviewRuler) {
  2394. this._affectsOverviewRuler = options.overviewRuler && options.overviewRuler.color ? true : false;
  2395. }
  2396. this._shouldFire = true;
  2397. }
  2398. fire() {
  2399. this._affectsMinimap = true;
  2400. this._affectsOverviewRuler = true;
  2401. this._shouldFire = true;
  2402. }
  2403. }
  2404. //#endregion
  2405. export class DidChangeContentEmitter extends Disposable {
  2406. constructor() {
  2407. super();
  2408. /**
  2409. * Both `fastEvent` and `slowEvent` work the same way and contain the same events, but first we invoke `fastEvent` and then `slowEvent`.
  2410. */
  2411. this._fastEmitter = this._register(new Emitter());
  2412. this.fastEvent = this._fastEmitter.event;
  2413. this._slowEmitter = this._register(new Emitter());
  2414. this.slowEvent = this._slowEmitter.event;
  2415. this._deferredCnt = 0;
  2416. this._deferredEvent = null;
  2417. }
  2418. beginDeferredEmit() {
  2419. this._deferredCnt++;
  2420. }
  2421. endDeferredEmit(resultingSelection = null) {
  2422. this._deferredCnt--;
  2423. if (this._deferredCnt === 0) {
  2424. if (this._deferredEvent !== null) {
  2425. this._deferredEvent.rawContentChangedEvent.resultingSelection = resultingSelection;
  2426. const e = this._deferredEvent;
  2427. this._deferredEvent = null;
  2428. this._fastEmitter.fire(e);
  2429. this._slowEmitter.fire(e);
  2430. }
  2431. }
  2432. }
  2433. fire(e) {
  2434. if (this._deferredCnt > 0) {
  2435. if (this._deferredEvent) {
  2436. this._deferredEvent = this._deferredEvent.merge(e);
  2437. }
  2438. else {
  2439. this._deferredEvent = e;
  2440. }
  2441. return;
  2442. }
  2443. this._fastEmitter.fire(e);
  2444. this._slowEmitter.fire(e);
  2445. }
  2446. }