297d04874c25e6a97f501e7969a55c0c4894f785eeed539d32626db724ee6a142062cd1b44a2088210d48ab2d5ab5235dd0c6a005e417e54d1738c8a9b0881 84 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821
  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 { ArrayQueue, pushMany } from '../../../base/common/arrays.js';
  15. import { Color } from '../../../base/common/color.js';
  16. import { onUnexpectedError } from '../../../base/common/errors.js';
  17. import { Emitter } from '../../../base/common/event.js';
  18. import { combinedDisposable, Disposable } from '../../../base/common/lifecycle.js';
  19. import * as strings from '../../../base/common/strings.js';
  20. import { URI } from '../../../base/common/uri.js';
  21. import { countEOL } from '../core/eolCounter.js';
  22. import { normalizeIndentation } from '../core/indentation.js';
  23. import { Position } from '../core/position.js';
  24. import { Range } from '../core/range.js';
  25. import { Selection } from '../core/selection.js';
  26. import { EDITOR_MODEL_DEFAULTS } from '../core/textModelDefaults.js';
  27. import { ILanguageService } from '../languages/language.js';
  28. import { ILanguageConfigurationService } from '../languages/languageConfigurationRegistry.js';
  29. import * as model from '../model.js';
  30. import { BracketPairsTextModelPart } from './bracketPairsTextModelPart/bracketPairsImpl.js';
  31. import { ColorizedBracketPairsDecorationProvider } from './bracketPairsTextModelPart/colorizedBracketPairsDecorationProvider.js';
  32. import { EditStack } from './editStack.js';
  33. import { GuidesTextModelPart } from './guidesTextModelPart.js';
  34. import { guessIndentation } from './indentationGuesser.js';
  35. import { IntervalNode, IntervalTree, recomputeMaxEnd } from './intervalTree.js';
  36. import { PieceTreeTextBuffer } from './pieceTreeTextBuffer/pieceTreeTextBuffer.js';
  37. import { PieceTreeTextBufferBuilder } from './pieceTreeTextBuffer/pieceTreeTextBufferBuilder.js';
  38. import { SearchParams, TextModelSearch } from './textModelSearch.js';
  39. import { TokenizationTextModelPart } from './tokenizationTextModelPart.js';
  40. import { InternalModelContentChangeEvent, LineInjectedText, ModelInjectedTextChangedEvent, ModelRawContentChangedEvent, ModelRawEOLChanged, ModelRawFlush, ModelRawLineChanged, ModelRawLinesDeleted, ModelRawLinesInserted } from '../textModelEvents.js';
  41. import { IUndoRedoService } from '../../../platform/undoRedo/common/undoRedo.js';
  42. export function createTextBufferFactory(text) {
  43. const builder = new PieceTreeTextBufferBuilder();
  44. builder.acceptChunk(text);
  45. return builder.finish();
  46. }
  47. export function createTextBufferFactoryFromSnapshot(snapshot) {
  48. const builder = new PieceTreeTextBufferBuilder();
  49. let chunk;
  50. while (typeof (chunk = snapshot.read()) === 'string') {
  51. builder.acceptChunk(chunk);
  52. }
  53. return builder.finish();
  54. }
  55. export function createTextBuffer(value, defaultEOL) {
  56. let factory;
  57. if (typeof value === 'string') {
  58. factory = createTextBufferFactory(value);
  59. }
  60. else if (model.isITextSnapshot(value)) {
  61. factory = createTextBufferFactoryFromSnapshot(value);
  62. }
  63. else {
  64. factory = value;
  65. }
  66. return factory.create(defaultEOL);
  67. }
  68. let MODEL_ID = 0;
  69. const LIMIT_FIND_COUNT = 999;
  70. export const LONG_LINE_BOUNDARY = 10000;
  71. class TextModelSnapshot {
  72. constructor(source) {
  73. this._source = source;
  74. this._eos = false;
  75. }
  76. read() {
  77. if (this._eos) {
  78. return null;
  79. }
  80. const result = [];
  81. let resultCnt = 0;
  82. let resultLength = 0;
  83. do {
  84. const tmp = this._source.read();
  85. if (tmp === null) {
  86. // end-of-stream
  87. this._eos = true;
  88. if (resultCnt === 0) {
  89. return null;
  90. }
  91. else {
  92. return result.join('');
  93. }
  94. }
  95. if (tmp.length > 0) {
  96. result[resultCnt++] = tmp;
  97. resultLength += tmp.length;
  98. }
  99. if (resultLength >= 64 * 1024) {
  100. return result.join('');
  101. }
  102. } while (true);
  103. }
  104. }
  105. const invalidFunc = () => { throw new Error(`Invalid change accessor`); };
  106. let TextModel = class TextModel extends Disposable {
  107. constructor(source, languageId, creationOptions, associatedResource = null, _undoRedoService, _languageService, _languageConfigurationService) {
  108. super();
  109. this._undoRedoService = _undoRedoService;
  110. this._languageService = _languageService;
  111. this._languageConfigurationService = _languageConfigurationService;
  112. //#region Events
  113. this._onWillDispose = this._register(new Emitter());
  114. this.onWillDispose = this._onWillDispose.event;
  115. this._onDidChangeDecorations = this._register(new DidChangeDecorationsEmitter(affectedInjectedTextLines => this.handleBeforeFireDecorationsChangedEvent(affectedInjectedTextLines)));
  116. this.onDidChangeDecorations = this._onDidChangeDecorations.event;
  117. this._onDidChangeOptions = this._register(new Emitter());
  118. this.onDidChangeOptions = this._onDidChangeOptions.event;
  119. this._onDidChangeAttached = this._register(new Emitter());
  120. this.onDidChangeAttached = this._onDidChangeAttached.event;
  121. this._onDidChangeInjectedText = this._register(new Emitter());
  122. this._eventEmitter = this._register(new DidChangeContentEmitter());
  123. this._deltaDecorationCallCnt = 0;
  124. // Generate a new unique model id
  125. MODEL_ID++;
  126. this.id = '$model' + MODEL_ID;
  127. this.isForSimpleWidget = creationOptions.isForSimpleWidget;
  128. if (typeof associatedResource === 'undefined' || associatedResource === null) {
  129. this._associatedResource = URI.parse('inmemory://model/' + MODEL_ID);
  130. }
  131. else {
  132. this._associatedResource = associatedResource;
  133. }
  134. this._attachedEditorCount = 0;
  135. const { textBuffer, disposable } = createTextBuffer(source, creationOptions.defaultEOL);
  136. this._buffer = textBuffer;
  137. this._bufferDisposable = disposable;
  138. this._options = TextModel.resolveOptions(this._buffer, creationOptions);
  139. this._bracketPairs = this._register(new BracketPairsTextModelPart(this, this._languageConfigurationService));
  140. this._guidesTextModelPart = this._register(new GuidesTextModelPart(this, this._languageConfigurationService));
  141. this._decorationProvider = this._register(new ColorizedBracketPairsDecorationProvider(this));
  142. this._tokenizationTextModelPart = new TokenizationTextModelPart(this._languageService, this._languageConfigurationService, this, this._bracketPairs, languageId);
  143. const bufferLineCount = this._buffer.getLineCount();
  144. const bufferTextLength = this._buffer.getValueLengthInRange(new Range(1, 1, bufferLineCount, this._buffer.getLineLength(bufferLineCount) + 1), 0 /* model.EndOfLinePreference.TextDefined */);
  145. // !!! Make a decision in the ctor and permanently respect this decision !!!
  146. // If a model is too large at construction time, it will never get tokenized,
  147. // under no circumstances.
  148. if (creationOptions.largeFileOptimizations) {
  149. this._isTooLargeForTokenization = ((bufferTextLength > TextModel.LARGE_FILE_SIZE_THRESHOLD)
  150. || (bufferLineCount > TextModel.LARGE_FILE_LINE_COUNT_THRESHOLD));
  151. }
  152. else {
  153. this._isTooLargeForTokenization = false;
  154. }
  155. this._isTooLargeForSyncing = (bufferTextLength > TextModel.MODEL_SYNC_LIMIT);
  156. this._versionId = 1;
  157. this._alternativeVersionId = 1;
  158. this._initialUndoRedoSnapshot = null;
  159. this._isDisposed = false;
  160. this.__isDisposing = false;
  161. this._instanceId = strings.singleLetterHash(MODEL_ID);
  162. this._lastDecorationId = 0;
  163. this._decorations = Object.create(null);
  164. this._decorationsTree = new DecorationsTrees();
  165. this._commandManager = new EditStack(this, this._undoRedoService);
  166. this._isUndoing = false;
  167. this._isRedoing = false;
  168. this._trimAutoWhitespaceLines = null;
  169. this._register(this._decorationProvider.onDidChange(() => {
  170. this._onDidChangeDecorations.beginDeferredEmit();
  171. this._onDidChangeDecorations.fire();
  172. this._onDidChangeDecorations.endDeferredEmit();
  173. }));
  174. }
  175. static resolveOptions(textBuffer, options) {
  176. if (options.detectIndentation) {
  177. const guessedIndentation = guessIndentation(textBuffer, options.tabSize, options.insertSpaces);
  178. return new model.TextModelResolvedOptions({
  179. tabSize: guessedIndentation.tabSize,
  180. indentSize: guessedIndentation.tabSize,
  181. insertSpaces: guessedIndentation.insertSpaces,
  182. trimAutoWhitespace: options.trimAutoWhitespace,
  183. defaultEOL: options.defaultEOL,
  184. bracketPairColorizationOptions: options.bracketPairColorizationOptions,
  185. });
  186. }
  187. return new model.TextModelResolvedOptions({
  188. tabSize: options.tabSize,
  189. indentSize: options.indentSize,
  190. insertSpaces: options.insertSpaces,
  191. trimAutoWhitespace: options.trimAutoWhitespace,
  192. defaultEOL: options.defaultEOL,
  193. bracketPairColorizationOptions: options.bracketPairColorizationOptions,
  194. });
  195. }
  196. get onDidChangeLanguage() { return this._tokenizationTextModelPart.onDidChangeLanguage; }
  197. get onDidChangeLanguageConfiguration() { return this._tokenizationTextModelPart.onDidChangeLanguageConfiguration; }
  198. get onDidChangeTokens() { return this._tokenizationTextModelPart.onDidChangeTokens; }
  199. onDidChangeContent(listener) {
  200. return this._eventEmitter.slowEvent((e) => listener(e.contentChangedEvent));
  201. }
  202. onDidChangeContentOrInjectedText(listener) {
  203. return combinedDisposable(this._eventEmitter.fastEvent(e => listener(e)), this._onDidChangeInjectedText.event(e => listener(e)));
  204. }
  205. _isDisposing() { return this.__isDisposing; }
  206. get tokenization() { return this._tokenizationTextModelPart; }
  207. get bracketPairs() { return this._bracketPairs; }
  208. get guides() { return this._guidesTextModelPart; }
  209. dispose() {
  210. this.__isDisposing = true;
  211. this._onWillDispose.fire();
  212. this._tokenizationTextModelPart.dispose();
  213. this._isDisposed = true;
  214. super.dispose();
  215. this._bufferDisposable.dispose();
  216. this.__isDisposing = false;
  217. // Manually release reference to previous text buffer to avoid large leaks
  218. // in case someone leaks a TextModel reference
  219. const emptyDisposedTextBuffer = new PieceTreeTextBuffer([], '', '\n', false, false, true, true);
  220. emptyDisposedTextBuffer.dispose();
  221. this._buffer = emptyDisposedTextBuffer;
  222. this._bufferDisposable = Disposable.None;
  223. }
  224. _assertNotDisposed() {
  225. if (this._isDisposed) {
  226. throw new Error('Model is disposed!');
  227. }
  228. }
  229. _emitContentChangedEvent(rawChange, change) {
  230. if (this.__isDisposing) {
  231. // Do not confuse listeners by emitting any event after disposing
  232. return;
  233. }
  234. this._tokenizationTextModelPart.handleDidChangeContent(change);
  235. this._bracketPairs.handleDidChangeContent(change);
  236. this._eventEmitter.fire(new InternalModelContentChangeEvent(rawChange, change));
  237. }
  238. setValue(value) {
  239. this._assertNotDisposed();
  240. if (value === null) {
  241. // There's nothing to do
  242. return;
  243. }
  244. const { textBuffer, disposable } = createTextBuffer(value, this._options.defaultEOL);
  245. this._setValueFromTextBuffer(textBuffer, disposable);
  246. }
  247. _createContentChanged2(range, rangeOffset, rangeLength, text, isUndoing, isRedoing, isFlush) {
  248. return {
  249. changes: [{
  250. range: range,
  251. rangeOffset: rangeOffset,
  252. rangeLength: rangeLength,
  253. text: text,
  254. }],
  255. eol: this._buffer.getEOL(),
  256. versionId: this.getVersionId(),
  257. isUndoing: isUndoing,
  258. isRedoing: isRedoing,
  259. isFlush: isFlush
  260. };
  261. }
  262. _setValueFromTextBuffer(textBuffer, textBufferDisposable) {
  263. this._assertNotDisposed();
  264. const oldFullModelRange = this.getFullModelRange();
  265. const oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);
  266. const endLineNumber = this.getLineCount();
  267. const endColumn = this.getLineMaxColumn(endLineNumber);
  268. this._buffer = textBuffer;
  269. this._bufferDisposable.dispose();
  270. this._bufferDisposable = textBufferDisposable;
  271. this._increaseVersionId();
  272. // Flush all tokens
  273. this._tokenizationTextModelPart.flush();
  274. // Destroy all my decorations
  275. this._decorations = Object.create(null);
  276. this._decorationsTree = new DecorationsTrees();
  277. // Destroy my edit history and settings
  278. this._commandManager.clear();
  279. this._trimAutoWhitespaceLines = null;
  280. this._emitContentChangedEvent(new ModelRawContentChangedEvent([
  281. new ModelRawFlush()
  282. ], this._versionId, false, false), this._createContentChanged2(new Range(1, 1, endLineNumber, endColumn), 0, oldModelValueLength, this.getValue(), false, false, true));
  283. }
  284. setEOL(eol) {
  285. this._assertNotDisposed();
  286. const newEOL = (eol === 1 /* model.EndOfLineSequence.CRLF */ ? '\r\n' : '\n');
  287. if (this._buffer.getEOL() === newEOL) {
  288. // Nothing to do
  289. return;
  290. }
  291. const oldFullModelRange = this.getFullModelRange();
  292. const oldModelValueLength = this.getValueLengthInRange(oldFullModelRange);
  293. const endLineNumber = this.getLineCount();
  294. const endColumn = this.getLineMaxColumn(endLineNumber);
  295. this._onBeforeEOLChange();
  296. this._buffer.setEOL(newEOL);
  297. this._increaseVersionId();
  298. this._onAfterEOLChange();
  299. this._emitContentChangedEvent(new ModelRawContentChangedEvent([
  300. new ModelRawEOLChanged()
  301. ], this._versionId, false, false), this._createContentChanged2(new Range(1, 1, endLineNumber, endColumn), 0, oldModelValueLength, this.getValue(), false, false, false));
  302. }
  303. _onBeforeEOLChange() {
  304. // Ensure all decorations get their `range` set.
  305. this._decorationsTree.ensureAllNodesHaveRanges(this);
  306. }
  307. _onAfterEOLChange() {
  308. // Transform back `range` to offsets
  309. const versionId = this.getVersionId();
  310. const allDecorations = this._decorationsTree.collectNodesPostOrder();
  311. for (let i = 0, len = allDecorations.length; i < len; i++) {
  312. const node = allDecorations[i];
  313. const range = node.range; // the range is defined due to `_onBeforeEOLChange`
  314. const delta = node.cachedAbsoluteStart - node.start;
  315. const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
  316. const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
  317. node.cachedAbsoluteStart = startOffset;
  318. node.cachedAbsoluteEnd = endOffset;
  319. node.cachedVersionId = versionId;
  320. node.start = startOffset - delta;
  321. node.end = endOffset - delta;
  322. recomputeMaxEnd(node);
  323. }
  324. }
  325. onBeforeAttached() {
  326. this._attachedEditorCount++;
  327. if (this._attachedEditorCount === 1) {
  328. this._tokenizationTextModelPart.handleDidChangeAttached();
  329. this._onDidChangeAttached.fire(undefined);
  330. }
  331. }
  332. onBeforeDetached() {
  333. this._attachedEditorCount--;
  334. if (this._attachedEditorCount === 0) {
  335. this._tokenizationTextModelPart.handleDidChangeAttached();
  336. this._onDidChangeAttached.fire(undefined);
  337. }
  338. }
  339. isAttachedToEditor() {
  340. return this._attachedEditorCount > 0;
  341. }
  342. getAttachedEditorCount() {
  343. return this._attachedEditorCount;
  344. }
  345. isTooLargeForSyncing() {
  346. return this._isTooLargeForSyncing;
  347. }
  348. isTooLargeForTokenization() {
  349. return this._isTooLargeForTokenization;
  350. }
  351. isDisposed() {
  352. return this._isDisposed;
  353. }
  354. isDominatedByLongLines() {
  355. this._assertNotDisposed();
  356. if (this.isTooLargeForTokenization()) {
  357. // Cannot word wrap huge files anyways, so it doesn't really matter
  358. return false;
  359. }
  360. let smallLineCharCount = 0;
  361. let longLineCharCount = 0;
  362. const lineCount = this._buffer.getLineCount();
  363. for (let lineNumber = 1; lineNumber <= lineCount; lineNumber++) {
  364. const lineLength = this._buffer.getLineLength(lineNumber);
  365. if (lineLength >= LONG_LINE_BOUNDARY) {
  366. longLineCharCount += lineLength;
  367. }
  368. else {
  369. smallLineCharCount += lineLength;
  370. }
  371. }
  372. return (longLineCharCount > smallLineCharCount);
  373. }
  374. get uri() {
  375. return this._associatedResource;
  376. }
  377. //#region Options
  378. getOptions() {
  379. this._assertNotDisposed();
  380. return this._options;
  381. }
  382. getFormattingOptions() {
  383. return {
  384. tabSize: this._options.indentSize,
  385. insertSpaces: this._options.insertSpaces
  386. };
  387. }
  388. updateOptions(_newOpts) {
  389. this._assertNotDisposed();
  390. const tabSize = (typeof _newOpts.tabSize !== 'undefined') ? _newOpts.tabSize : this._options.tabSize;
  391. const indentSize = (typeof _newOpts.indentSize !== 'undefined') ? _newOpts.indentSize : this._options.indentSize;
  392. const insertSpaces = (typeof _newOpts.insertSpaces !== 'undefined') ? _newOpts.insertSpaces : this._options.insertSpaces;
  393. const trimAutoWhitespace = (typeof _newOpts.trimAutoWhitespace !== 'undefined') ? _newOpts.trimAutoWhitespace : this._options.trimAutoWhitespace;
  394. const bracketPairColorizationOptions = (typeof _newOpts.bracketColorizationOptions !== 'undefined') ? _newOpts.bracketColorizationOptions : this._options.bracketPairColorizationOptions;
  395. const newOpts = new model.TextModelResolvedOptions({
  396. tabSize: tabSize,
  397. indentSize: indentSize,
  398. insertSpaces: insertSpaces,
  399. defaultEOL: this._options.defaultEOL,
  400. trimAutoWhitespace: trimAutoWhitespace,
  401. bracketPairColorizationOptions,
  402. });
  403. if (this._options.equals(newOpts)) {
  404. return;
  405. }
  406. const e = this._options.createChangeEvent(newOpts);
  407. this._options = newOpts;
  408. this._bracketPairs.handleDidChangeOptions(e);
  409. this._decorationProvider.handleDidChangeOptions(e);
  410. this._onDidChangeOptions.fire(e);
  411. }
  412. detectIndentation(defaultInsertSpaces, defaultTabSize) {
  413. this._assertNotDisposed();
  414. const guessedIndentation = guessIndentation(this._buffer, defaultTabSize, defaultInsertSpaces);
  415. this.updateOptions({
  416. insertSpaces: guessedIndentation.insertSpaces,
  417. tabSize: guessedIndentation.tabSize,
  418. indentSize: guessedIndentation.tabSize, // TODO@Alex: guess indentSize independent of tabSize
  419. });
  420. }
  421. normalizeIndentation(str) {
  422. this._assertNotDisposed();
  423. return normalizeIndentation(str, this._options.indentSize, this._options.insertSpaces);
  424. }
  425. //#endregion
  426. //#region Reading
  427. getVersionId() {
  428. this._assertNotDisposed();
  429. return this._versionId;
  430. }
  431. mightContainRTL() {
  432. return this._buffer.mightContainRTL();
  433. }
  434. mightContainUnusualLineTerminators() {
  435. return this._buffer.mightContainUnusualLineTerminators();
  436. }
  437. removeUnusualLineTerminators(selections = null) {
  438. const matches = this.findMatches(strings.UNUSUAL_LINE_TERMINATORS.source, false, true, false, null, false, 1073741824 /* Constants.MAX_SAFE_SMALL_INTEGER */);
  439. this._buffer.resetMightContainUnusualLineTerminators();
  440. this.pushEditOperations(selections, matches.map(m => ({ range: m.range, text: null })), () => null);
  441. }
  442. mightContainNonBasicASCII() {
  443. return this._buffer.mightContainNonBasicASCII();
  444. }
  445. getAlternativeVersionId() {
  446. this._assertNotDisposed();
  447. return this._alternativeVersionId;
  448. }
  449. getInitialUndoRedoSnapshot() {
  450. this._assertNotDisposed();
  451. return this._initialUndoRedoSnapshot;
  452. }
  453. getOffsetAt(rawPosition) {
  454. this._assertNotDisposed();
  455. const position = this._validatePosition(rawPosition.lineNumber, rawPosition.column, 0 /* StringOffsetValidationType.Relaxed */);
  456. return this._buffer.getOffsetAt(position.lineNumber, position.column);
  457. }
  458. getPositionAt(rawOffset) {
  459. this._assertNotDisposed();
  460. const offset = (Math.min(this._buffer.getLength(), Math.max(0, rawOffset)));
  461. return this._buffer.getPositionAt(offset);
  462. }
  463. _increaseVersionId() {
  464. this._versionId = this._versionId + 1;
  465. this._alternativeVersionId = this._versionId;
  466. }
  467. _overwriteVersionId(versionId) {
  468. this._versionId = versionId;
  469. }
  470. _overwriteAlternativeVersionId(newAlternativeVersionId) {
  471. this._alternativeVersionId = newAlternativeVersionId;
  472. }
  473. _overwriteInitialUndoRedoSnapshot(newInitialUndoRedoSnapshot) {
  474. this._initialUndoRedoSnapshot = newInitialUndoRedoSnapshot;
  475. }
  476. getValue(eol, preserveBOM = false) {
  477. this._assertNotDisposed();
  478. const fullModelRange = this.getFullModelRange();
  479. const fullModelValue = this.getValueInRange(fullModelRange, eol);
  480. if (preserveBOM) {
  481. return this._buffer.getBOM() + fullModelValue;
  482. }
  483. return fullModelValue;
  484. }
  485. createSnapshot(preserveBOM = false) {
  486. return new TextModelSnapshot(this._buffer.createSnapshot(preserveBOM));
  487. }
  488. getValueLength(eol, preserveBOM = false) {
  489. this._assertNotDisposed();
  490. const fullModelRange = this.getFullModelRange();
  491. const fullModelValue = this.getValueLengthInRange(fullModelRange, eol);
  492. if (preserveBOM) {
  493. return this._buffer.getBOM().length + fullModelValue;
  494. }
  495. return fullModelValue;
  496. }
  497. getValueInRange(rawRange, eol = 0 /* model.EndOfLinePreference.TextDefined */) {
  498. this._assertNotDisposed();
  499. return this._buffer.getValueInRange(this.validateRange(rawRange), eol);
  500. }
  501. getValueLengthInRange(rawRange, eol = 0 /* model.EndOfLinePreference.TextDefined */) {
  502. this._assertNotDisposed();
  503. return this._buffer.getValueLengthInRange(this.validateRange(rawRange), eol);
  504. }
  505. getCharacterCountInRange(rawRange, eol = 0 /* model.EndOfLinePreference.TextDefined */) {
  506. this._assertNotDisposed();
  507. return this._buffer.getCharacterCountInRange(this.validateRange(rawRange), eol);
  508. }
  509. getLineCount() {
  510. this._assertNotDisposed();
  511. return this._buffer.getLineCount();
  512. }
  513. getLineContent(lineNumber) {
  514. this._assertNotDisposed();
  515. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  516. throw new Error('Illegal value for lineNumber');
  517. }
  518. return this._buffer.getLineContent(lineNumber);
  519. }
  520. getLineLength(lineNumber) {
  521. this._assertNotDisposed();
  522. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  523. throw new Error('Illegal value for lineNumber');
  524. }
  525. return this._buffer.getLineLength(lineNumber);
  526. }
  527. getLinesContent() {
  528. this._assertNotDisposed();
  529. return this._buffer.getLinesContent();
  530. }
  531. getEOL() {
  532. this._assertNotDisposed();
  533. return this._buffer.getEOL();
  534. }
  535. getEndOfLineSequence() {
  536. this._assertNotDisposed();
  537. return (this._buffer.getEOL() === '\n'
  538. ? 0 /* model.EndOfLineSequence.LF */
  539. : 1 /* model.EndOfLineSequence.CRLF */);
  540. }
  541. getLineMinColumn(lineNumber) {
  542. this._assertNotDisposed();
  543. return 1;
  544. }
  545. getLineMaxColumn(lineNumber) {
  546. this._assertNotDisposed();
  547. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  548. throw new Error('Illegal value for lineNumber');
  549. }
  550. return this._buffer.getLineLength(lineNumber) + 1;
  551. }
  552. getLineFirstNonWhitespaceColumn(lineNumber) {
  553. this._assertNotDisposed();
  554. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  555. throw new Error('Illegal value for lineNumber');
  556. }
  557. return this._buffer.getLineFirstNonWhitespaceColumn(lineNumber);
  558. }
  559. getLineLastNonWhitespaceColumn(lineNumber) {
  560. this._assertNotDisposed();
  561. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  562. throw new Error('Illegal value for lineNumber');
  563. }
  564. return this._buffer.getLineLastNonWhitespaceColumn(lineNumber);
  565. }
  566. /**
  567. * Validates `range` is within buffer bounds, but allows it to sit in between surrogate pairs, etc.
  568. * Will try to not allocate if possible.
  569. */
  570. _validateRangeRelaxedNoAllocations(range) {
  571. const linesCount = this._buffer.getLineCount();
  572. const initialStartLineNumber = range.startLineNumber;
  573. const initialStartColumn = range.startColumn;
  574. let startLineNumber = Math.floor((typeof initialStartLineNumber === 'number' && !isNaN(initialStartLineNumber)) ? initialStartLineNumber : 1);
  575. let startColumn = Math.floor((typeof initialStartColumn === 'number' && !isNaN(initialStartColumn)) ? initialStartColumn : 1);
  576. if (startLineNumber < 1) {
  577. startLineNumber = 1;
  578. startColumn = 1;
  579. }
  580. else if (startLineNumber > linesCount) {
  581. startLineNumber = linesCount;
  582. startColumn = this.getLineMaxColumn(startLineNumber);
  583. }
  584. else {
  585. if (startColumn <= 1) {
  586. startColumn = 1;
  587. }
  588. else {
  589. const maxColumn = this.getLineMaxColumn(startLineNumber);
  590. if (startColumn >= maxColumn) {
  591. startColumn = maxColumn;
  592. }
  593. }
  594. }
  595. const initialEndLineNumber = range.endLineNumber;
  596. const initialEndColumn = range.endColumn;
  597. let endLineNumber = Math.floor((typeof initialEndLineNumber === 'number' && !isNaN(initialEndLineNumber)) ? initialEndLineNumber : 1);
  598. let endColumn = Math.floor((typeof initialEndColumn === 'number' && !isNaN(initialEndColumn)) ? initialEndColumn : 1);
  599. if (endLineNumber < 1) {
  600. endLineNumber = 1;
  601. endColumn = 1;
  602. }
  603. else if (endLineNumber > linesCount) {
  604. endLineNumber = linesCount;
  605. endColumn = this.getLineMaxColumn(endLineNumber);
  606. }
  607. else {
  608. if (endColumn <= 1) {
  609. endColumn = 1;
  610. }
  611. else {
  612. const maxColumn = this.getLineMaxColumn(endLineNumber);
  613. if (endColumn >= maxColumn) {
  614. endColumn = maxColumn;
  615. }
  616. }
  617. }
  618. if (initialStartLineNumber === startLineNumber
  619. && initialStartColumn === startColumn
  620. && initialEndLineNumber === endLineNumber
  621. && initialEndColumn === endColumn
  622. && range instanceof Range
  623. && !(range instanceof Selection)) {
  624. return range;
  625. }
  626. return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
  627. }
  628. _isValidPosition(lineNumber, column, validationType) {
  629. if (typeof lineNumber !== 'number' || typeof column !== 'number') {
  630. return false;
  631. }
  632. if (isNaN(lineNumber) || isNaN(column)) {
  633. return false;
  634. }
  635. if (lineNumber < 1 || column < 1) {
  636. return false;
  637. }
  638. if ((lineNumber | 0) !== lineNumber || (column | 0) !== column) {
  639. return false;
  640. }
  641. const lineCount = this._buffer.getLineCount();
  642. if (lineNumber > lineCount) {
  643. return false;
  644. }
  645. if (column === 1) {
  646. return true;
  647. }
  648. const maxColumn = this.getLineMaxColumn(lineNumber);
  649. if (column > maxColumn) {
  650. return false;
  651. }
  652. if (validationType === 1 /* StringOffsetValidationType.SurrogatePairs */) {
  653. // !!At this point, column > 1
  654. const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2);
  655. if (strings.isHighSurrogate(charCodeBefore)) {
  656. return false;
  657. }
  658. }
  659. return true;
  660. }
  661. _validatePosition(_lineNumber, _column, validationType) {
  662. const lineNumber = Math.floor((typeof _lineNumber === 'number' && !isNaN(_lineNumber)) ? _lineNumber : 1);
  663. const column = Math.floor((typeof _column === 'number' && !isNaN(_column)) ? _column : 1);
  664. const lineCount = this._buffer.getLineCount();
  665. if (lineNumber < 1) {
  666. return new Position(1, 1);
  667. }
  668. if (lineNumber > lineCount) {
  669. return new Position(lineCount, this.getLineMaxColumn(lineCount));
  670. }
  671. if (column <= 1) {
  672. return new Position(lineNumber, 1);
  673. }
  674. const maxColumn = this.getLineMaxColumn(lineNumber);
  675. if (column >= maxColumn) {
  676. return new Position(lineNumber, maxColumn);
  677. }
  678. if (validationType === 1 /* StringOffsetValidationType.SurrogatePairs */) {
  679. // If the position would end up in the middle of a high-low surrogate pair,
  680. // we move it to before the pair
  681. // !!At this point, column > 1
  682. const charCodeBefore = this._buffer.getLineCharCode(lineNumber, column - 2);
  683. if (strings.isHighSurrogate(charCodeBefore)) {
  684. return new Position(lineNumber, column - 1);
  685. }
  686. }
  687. return new Position(lineNumber, column);
  688. }
  689. validatePosition(position) {
  690. const validationType = 1 /* StringOffsetValidationType.SurrogatePairs */;
  691. this._assertNotDisposed();
  692. // Avoid object allocation and cover most likely case
  693. if (position instanceof Position) {
  694. if (this._isValidPosition(position.lineNumber, position.column, validationType)) {
  695. return position;
  696. }
  697. }
  698. return this._validatePosition(position.lineNumber, position.column, validationType);
  699. }
  700. _isValidRange(range, validationType) {
  701. const startLineNumber = range.startLineNumber;
  702. const startColumn = range.startColumn;
  703. const endLineNumber = range.endLineNumber;
  704. const endColumn = range.endColumn;
  705. if (!this._isValidPosition(startLineNumber, startColumn, 0 /* StringOffsetValidationType.Relaxed */)) {
  706. return false;
  707. }
  708. if (!this._isValidPosition(endLineNumber, endColumn, 0 /* StringOffsetValidationType.Relaxed */)) {
  709. return false;
  710. }
  711. if (validationType === 1 /* StringOffsetValidationType.SurrogatePairs */) {
  712. const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0);
  713. const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0);
  714. const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart);
  715. const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd);
  716. if (!startInsideSurrogatePair && !endInsideSurrogatePair) {
  717. return true;
  718. }
  719. return false;
  720. }
  721. return true;
  722. }
  723. validateRange(_range) {
  724. const validationType = 1 /* StringOffsetValidationType.SurrogatePairs */;
  725. this._assertNotDisposed();
  726. // Avoid object allocation and cover most likely case
  727. if ((_range instanceof Range) && !(_range instanceof Selection)) {
  728. if (this._isValidRange(_range, validationType)) {
  729. return _range;
  730. }
  731. }
  732. const start = this._validatePosition(_range.startLineNumber, _range.startColumn, 0 /* StringOffsetValidationType.Relaxed */);
  733. const end = this._validatePosition(_range.endLineNumber, _range.endColumn, 0 /* StringOffsetValidationType.Relaxed */);
  734. const startLineNumber = start.lineNumber;
  735. const startColumn = start.column;
  736. const endLineNumber = end.lineNumber;
  737. const endColumn = end.column;
  738. if (validationType === 1 /* StringOffsetValidationType.SurrogatePairs */) {
  739. const charCodeBeforeStart = (startColumn > 1 ? this._buffer.getLineCharCode(startLineNumber, startColumn - 2) : 0);
  740. const charCodeBeforeEnd = (endColumn > 1 && endColumn <= this._buffer.getLineLength(endLineNumber) ? this._buffer.getLineCharCode(endLineNumber, endColumn - 2) : 0);
  741. const startInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeStart);
  742. const endInsideSurrogatePair = strings.isHighSurrogate(charCodeBeforeEnd);
  743. if (!startInsideSurrogatePair && !endInsideSurrogatePair) {
  744. return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
  745. }
  746. if (startLineNumber === endLineNumber && startColumn === endColumn) {
  747. // do not expand a collapsed range, simply move it to a valid location
  748. return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn - 1);
  749. }
  750. if (startInsideSurrogatePair && endInsideSurrogatePair) {
  751. // expand range at both ends
  752. return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn + 1);
  753. }
  754. if (startInsideSurrogatePair) {
  755. // only expand range at the start
  756. return new Range(startLineNumber, startColumn - 1, endLineNumber, endColumn);
  757. }
  758. // only expand range at the end
  759. return new Range(startLineNumber, startColumn, endLineNumber, endColumn + 1);
  760. }
  761. return new Range(startLineNumber, startColumn, endLineNumber, endColumn);
  762. }
  763. modifyPosition(rawPosition, offset) {
  764. this._assertNotDisposed();
  765. const candidate = this.getOffsetAt(rawPosition) + offset;
  766. return this.getPositionAt(Math.min(this._buffer.getLength(), Math.max(0, candidate)));
  767. }
  768. getFullModelRange() {
  769. this._assertNotDisposed();
  770. const lineCount = this.getLineCount();
  771. return new Range(1, 1, lineCount, this.getLineMaxColumn(lineCount));
  772. }
  773. findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount) {
  774. return this._buffer.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
  775. }
  776. findMatches(searchString, rawSearchScope, isRegex, matchCase, wordSeparators, captureMatches, limitResultCount = LIMIT_FIND_COUNT) {
  777. this._assertNotDisposed();
  778. let searchRanges = null;
  779. if (rawSearchScope !== null) {
  780. if (!Array.isArray(rawSearchScope)) {
  781. rawSearchScope = [rawSearchScope];
  782. }
  783. if (rawSearchScope.every((searchScope) => Range.isIRange(searchScope))) {
  784. searchRanges = rawSearchScope.map((searchScope) => this.validateRange(searchScope));
  785. }
  786. }
  787. if (searchRanges === null) {
  788. searchRanges = [this.getFullModelRange()];
  789. }
  790. searchRanges = searchRanges.sort((d1, d2) => d1.startLineNumber - d2.startLineNumber || d1.startColumn - d2.startColumn);
  791. const uniqueSearchRanges = [];
  792. uniqueSearchRanges.push(searchRanges.reduce((prev, curr) => {
  793. if (Range.areIntersecting(prev, curr)) {
  794. return prev.plusRange(curr);
  795. }
  796. uniqueSearchRanges.push(prev);
  797. return curr;
  798. }));
  799. let matchMapper;
  800. if (!isRegex && searchString.indexOf('\n') < 0) {
  801. // not regex, not multi line
  802. const searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);
  803. const searchData = searchParams.parseSearchRequest();
  804. if (!searchData) {
  805. return [];
  806. }
  807. matchMapper = (searchRange) => this.findMatchesLineByLine(searchRange, searchData, captureMatches, limitResultCount);
  808. }
  809. else {
  810. matchMapper = (searchRange) => TextModelSearch.findMatches(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchRange, captureMatches, limitResultCount);
  811. }
  812. return uniqueSearchRanges.map(matchMapper).reduce((arr, matches) => arr.concat(matches), []);
  813. }
  814. findNextMatch(searchString, rawSearchStart, isRegex, matchCase, wordSeparators, captureMatches) {
  815. this._assertNotDisposed();
  816. const searchStart = this.validatePosition(rawSearchStart);
  817. if (!isRegex && searchString.indexOf('\n') < 0) {
  818. const searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);
  819. const searchData = searchParams.parseSearchRequest();
  820. if (!searchData) {
  821. return null;
  822. }
  823. const lineCount = this.getLineCount();
  824. let searchRange = new Range(searchStart.lineNumber, searchStart.column, lineCount, this.getLineMaxColumn(lineCount));
  825. let ret = this.findMatchesLineByLine(searchRange, searchData, captureMatches, 1);
  826. TextModelSearch.findNextMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
  827. if (ret.length > 0) {
  828. return ret[0];
  829. }
  830. searchRange = new Range(1, 1, searchStart.lineNumber, this.getLineMaxColumn(searchStart.lineNumber));
  831. ret = this.findMatchesLineByLine(searchRange, searchData, captureMatches, 1);
  832. if (ret.length > 0) {
  833. return ret[0];
  834. }
  835. return null;
  836. }
  837. return TextModelSearch.findNextMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
  838. }
  839. findPreviousMatch(searchString, rawSearchStart, isRegex, matchCase, wordSeparators, captureMatches) {
  840. this._assertNotDisposed();
  841. const searchStart = this.validatePosition(rawSearchStart);
  842. return TextModelSearch.findPreviousMatch(this, new SearchParams(searchString, isRegex, matchCase, wordSeparators), searchStart, captureMatches);
  843. }
  844. //#endregion
  845. //#region Editing
  846. pushStackElement() {
  847. this._commandManager.pushStackElement();
  848. }
  849. popStackElement() {
  850. this._commandManager.popStackElement();
  851. }
  852. pushEOL(eol) {
  853. const currentEOL = (this.getEOL() === '\n' ? 0 /* model.EndOfLineSequence.LF */ : 1 /* model.EndOfLineSequence.CRLF */);
  854. if (currentEOL === eol) {
  855. return;
  856. }
  857. try {
  858. this._onDidChangeDecorations.beginDeferredEmit();
  859. this._eventEmitter.beginDeferredEmit();
  860. if (this._initialUndoRedoSnapshot === null) {
  861. this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
  862. }
  863. this._commandManager.pushEOL(eol);
  864. }
  865. finally {
  866. this._eventEmitter.endDeferredEmit();
  867. this._onDidChangeDecorations.endDeferredEmit();
  868. }
  869. }
  870. _validateEditOperation(rawOperation) {
  871. if (rawOperation instanceof model.ValidAnnotatedEditOperation) {
  872. return rawOperation;
  873. }
  874. return new model.ValidAnnotatedEditOperation(rawOperation.identifier || null, this.validateRange(rawOperation.range), rawOperation.text, rawOperation.forceMoveMarkers || false, rawOperation.isAutoWhitespaceEdit || false, rawOperation._isTracked || false);
  875. }
  876. _validateEditOperations(rawOperations) {
  877. const result = [];
  878. for (let i = 0, len = rawOperations.length; i < len; i++) {
  879. result[i] = this._validateEditOperation(rawOperations[i]);
  880. }
  881. return result;
  882. }
  883. pushEditOperations(beforeCursorState, editOperations, cursorStateComputer) {
  884. try {
  885. this._onDidChangeDecorations.beginDeferredEmit();
  886. this._eventEmitter.beginDeferredEmit();
  887. return this._pushEditOperations(beforeCursorState, this._validateEditOperations(editOperations), cursorStateComputer);
  888. }
  889. finally {
  890. this._eventEmitter.endDeferredEmit();
  891. this._onDidChangeDecorations.endDeferredEmit();
  892. }
  893. }
  894. _pushEditOperations(beforeCursorState, editOperations, cursorStateComputer) {
  895. if (this._options.trimAutoWhitespace && this._trimAutoWhitespaceLines) {
  896. // Go through each saved line number and insert a trim whitespace edit
  897. // if it is safe to do so (no conflicts with other edits).
  898. const incomingEdits = editOperations.map((op) => {
  899. return {
  900. range: this.validateRange(op.range),
  901. text: op.text
  902. };
  903. });
  904. // Sometimes, auto-formatters change ranges automatically which can cause undesired auto whitespace trimming near the cursor
  905. // We'll use the following heuristic: if the edits occur near the cursor, then it's ok to trim auto whitespace
  906. let editsAreNearCursors = true;
  907. if (beforeCursorState) {
  908. for (let i = 0, len = beforeCursorState.length; i < len; i++) {
  909. const sel = beforeCursorState[i];
  910. let foundEditNearSel = false;
  911. for (let j = 0, lenJ = incomingEdits.length; j < lenJ; j++) {
  912. const editRange = incomingEdits[j].range;
  913. const selIsAbove = editRange.startLineNumber > sel.endLineNumber;
  914. const selIsBelow = sel.startLineNumber > editRange.endLineNumber;
  915. if (!selIsAbove && !selIsBelow) {
  916. foundEditNearSel = true;
  917. break;
  918. }
  919. }
  920. if (!foundEditNearSel) {
  921. editsAreNearCursors = false;
  922. break;
  923. }
  924. }
  925. }
  926. if (editsAreNearCursors) {
  927. for (let i = 0, len = this._trimAutoWhitespaceLines.length; i < len; i++) {
  928. const trimLineNumber = this._trimAutoWhitespaceLines[i];
  929. const maxLineColumn = this.getLineMaxColumn(trimLineNumber);
  930. let allowTrimLine = true;
  931. for (let j = 0, lenJ = incomingEdits.length; j < lenJ; j++) {
  932. const editRange = incomingEdits[j].range;
  933. const editText = incomingEdits[j].text;
  934. if (trimLineNumber < editRange.startLineNumber || trimLineNumber > editRange.endLineNumber) {
  935. // `trimLine` is completely outside this edit
  936. continue;
  937. }
  938. // At this point:
  939. // editRange.startLineNumber <= trimLine <= editRange.endLineNumber
  940. if (trimLineNumber === editRange.startLineNumber && editRange.startColumn === maxLineColumn
  941. && editRange.isEmpty() && editText && editText.length > 0 && editText.charAt(0) === '\n') {
  942. // This edit inserts a new line (and maybe other text) after `trimLine`
  943. continue;
  944. }
  945. if (trimLineNumber === editRange.startLineNumber && editRange.startColumn === 1
  946. && editRange.isEmpty() && editText && editText.length > 0 && editText.charAt(editText.length - 1) === '\n') {
  947. // This edit inserts a new line (and maybe other text) before `trimLine`
  948. continue;
  949. }
  950. // Looks like we can't trim this line as it would interfere with an incoming edit
  951. allowTrimLine = false;
  952. break;
  953. }
  954. if (allowTrimLine) {
  955. const trimRange = new Range(trimLineNumber, 1, trimLineNumber, maxLineColumn);
  956. editOperations.push(new model.ValidAnnotatedEditOperation(null, trimRange, null, false, false, false));
  957. }
  958. }
  959. }
  960. this._trimAutoWhitespaceLines = null;
  961. }
  962. if (this._initialUndoRedoSnapshot === null) {
  963. this._initialUndoRedoSnapshot = this._undoRedoService.createSnapshot(this.uri);
  964. }
  965. return this._commandManager.pushEditOperation(beforeCursorState, editOperations, cursorStateComputer);
  966. }
  967. _applyUndo(changes, eol, resultingAlternativeVersionId, resultingSelection) {
  968. const edits = changes.map((change) => {
  969. const rangeStart = this.getPositionAt(change.newPosition);
  970. const rangeEnd = this.getPositionAt(change.newEnd);
  971. return {
  972. range: new Range(rangeStart.lineNumber, rangeStart.column, rangeEnd.lineNumber, rangeEnd.column),
  973. text: change.oldText
  974. };
  975. });
  976. this._applyUndoRedoEdits(edits, eol, true, false, resultingAlternativeVersionId, resultingSelection);
  977. }
  978. _applyRedo(changes, eol, resultingAlternativeVersionId, resultingSelection) {
  979. const edits = changes.map((change) => {
  980. const rangeStart = this.getPositionAt(change.oldPosition);
  981. const rangeEnd = this.getPositionAt(change.oldEnd);
  982. return {
  983. range: new Range(rangeStart.lineNumber, rangeStart.column, rangeEnd.lineNumber, rangeEnd.column),
  984. text: change.newText
  985. };
  986. });
  987. this._applyUndoRedoEdits(edits, eol, false, true, resultingAlternativeVersionId, resultingSelection);
  988. }
  989. _applyUndoRedoEdits(edits, eol, isUndoing, isRedoing, resultingAlternativeVersionId, resultingSelection) {
  990. try {
  991. this._onDidChangeDecorations.beginDeferredEmit();
  992. this._eventEmitter.beginDeferredEmit();
  993. this._isUndoing = isUndoing;
  994. this._isRedoing = isRedoing;
  995. this.applyEdits(edits, false);
  996. this.setEOL(eol);
  997. this._overwriteAlternativeVersionId(resultingAlternativeVersionId);
  998. }
  999. finally {
  1000. this._isUndoing = false;
  1001. this._isRedoing = false;
  1002. this._eventEmitter.endDeferredEmit(resultingSelection);
  1003. this._onDidChangeDecorations.endDeferredEmit();
  1004. }
  1005. }
  1006. applyEdits(rawOperations, computeUndoEdits = false) {
  1007. try {
  1008. this._onDidChangeDecorations.beginDeferredEmit();
  1009. this._eventEmitter.beginDeferredEmit();
  1010. const operations = this._validateEditOperations(rawOperations);
  1011. return this._doApplyEdits(operations, computeUndoEdits);
  1012. }
  1013. finally {
  1014. this._eventEmitter.endDeferredEmit();
  1015. this._onDidChangeDecorations.endDeferredEmit();
  1016. }
  1017. }
  1018. _doApplyEdits(rawOperations, computeUndoEdits) {
  1019. const oldLineCount = this._buffer.getLineCount();
  1020. const result = this._buffer.applyEdits(rawOperations, this._options.trimAutoWhitespace, computeUndoEdits);
  1021. const newLineCount = this._buffer.getLineCount();
  1022. const contentChanges = result.changes;
  1023. this._trimAutoWhitespaceLines = result.trimAutoWhitespaceLineNumbers;
  1024. if (contentChanges.length !== 0) {
  1025. // We do a first pass to update tokens and decorations
  1026. // because we want to read decorations in the second pass
  1027. // where we will emit content change events
  1028. // and we want to read the final decorations
  1029. for (let i = 0, len = contentChanges.length; i < len; i++) {
  1030. const change = contentChanges[i];
  1031. const [eolCount, firstLineLength, lastLineLength] = countEOL(change.text);
  1032. this._tokenizationTextModelPart.acceptEdit(change.range, change.text, eolCount, firstLineLength, lastLineLength);
  1033. this._decorationsTree.acceptReplace(change.rangeOffset, change.rangeLength, change.text.length, change.forceMoveMarkers);
  1034. }
  1035. const rawContentChanges = [];
  1036. this._increaseVersionId();
  1037. let lineCount = oldLineCount;
  1038. for (let i = 0, len = contentChanges.length; i < len; i++) {
  1039. const change = contentChanges[i];
  1040. const [eolCount] = countEOL(change.text);
  1041. this._onDidChangeDecorations.fire();
  1042. const startLineNumber = change.range.startLineNumber;
  1043. const endLineNumber = change.range.endLineNumber;
  1044. const deletingLinesCnt = endLineNumber - startLineNumber;
  1045. const insertingLinesCnt = eolCount;
  1046. const editingLinesCnt = Math.min(deletingLinesCnt, insertingLinesCnt);
  1047. const changeLineCountDelta = (insertingLinesCnt - deletingLinesCnt);
  1048. const currentEditStartLineNumber = newLineCount - lineCount - changeLineCountDelta + startLineNumber;
  1049. const firstEditLineNumber = currentEditStartLineNumber;
  1050. const lastInsertedLineNumber = currentEditStartLineNumber + insertingLinesCnt;
  1051. const decorationsWithInjectedTextInEditedRange = this._decorationsTree.getInjectedTextInInterval(this, this.getOffsetAt(new Position(firstEditLineNumber, 1)), this.getOffsetAt(new Position(lastInsertedLineNumber, this.getLineMaxColumn(lastInsertedLineNumber))), 0);
  1052. const injectedTextInEditedRange = LineInjectedText.fromDecorations(decorationsWithInjectedTextInEditedRange);
  1053. const injectedTextInEditedRangeQueue = new ArrayQueue(injectedTextInEditedRange);
  1054. for (let j = editingLinesCnt; j >= 0; j--) {
  1055. const editLineNumber = startLineNumber + j;
  1056. const currentEditLineNumber = currentEditStartLineNumber + j;
  1057. injectedTextInEditedRangeQueue.takeFromEndWhile(r => r.lineNumber > currentEditLineNumber);
  1058. const decorationsInCurrentLine = injectedTextInEditedRangeQueue.takeFromEndWhile(r => r.lineNumber === currentEditLineNumber);
  1059. rawContentChanges.push(new ModelRawLineChanged(editLineNumber, this.getLineContent(currentEditLineNumber), decorationsInCurrentLine));
  1060. }
  1061. if (editingLinesCnt < deletingLinesCnt) {
  1062. // Must delete some lines
  1063. const spliceStartLineNumber = startLineNumber + editingLinesCnt;
  1064. rawContentChanges.push(new ModelRawLinesDeleted(spliceStartLineNumber + 1, endLineNumber));
  1065. }
  1066. if (editingLinesCnt < insertingLinesCnt) {
  1067. const injectedTextInEditedRangeQueue = new ArrayQueue(injectedTextInEditedRange);
  1068. // Must insert some lines
  1069. const spliceLineNumber = startLineNumber + editingLinesCnt;
  1070. const cnt = insertingLinesCnt - editingLinesCnt;
  1071. const fromLineNumber = newLineCount - lineCount - cnt + spliceLineNumber + 1;
  1072. const injectedTexts = [];
  1073. const newLines = [];
  1074. for (let i = 0; i < cnt; i++) {
  1075. const lineNumber = fromLineNumber + i;
  1076. newLines[i] = this.getLineContent(lineNumber);
  1077. injectedTextInEditedRangeQueue.takeWhile(r => r.lineNumber < lineNumber);
  1078. injectedTexts[i] = injectedTextInEditedRangeQueue.takeWhile(r => r.lineNumber === lineNumber);
  1079. }
  1080. rawContentChanges.push(new ModelRawLinesInserted(spliceLineNumber + 1, startLineNumber + insertingLinesCnt, newLines, injectedTexts));
  1081. }
  1082. lineCount += changeLineCountDelta;
  1083. }
  1084. this._emitContentChangedEvent(new ModelRawContentChangedEvent(rawContentChanges, this.getVersionId(), this._isUndoing, this._isRedoing), {
  1085. changes: contentChanges,
  1086. eol: this._buffer.getEOL(),
  1087. versionId: this.getVersionId(),
  1088. isUndoing: this._isUndoing,
  1089. isRedoing: this._isRedoing,
  1090. isFlush: false
  1091. });
  1092. }
  1093. return (result.reverseEdits === null ? undefined : result.reverseEdits);
  1094. }
  1095. undo() {
  1096. return this._undoRedoService.undo(this.uri);
  1097. }
  1098. canUndo() {
  1099. return this._undoRedoService.canUndo(this.uri);
  1100. }
  1101. redo() {
  1102. return this._undoRedoService.redo(this.uri);
  1103. }
  1104. canRedo() {
  1105. return this._undoRedoService.canRedo(this.uri);
  1106. }
  1107. //#endregion
  1108. //#region Decorations
  1109. handleBeforeFireDecorationsChangedEvent(affectedInjectedTextLines) {
  1110. // This is called before the decoration changed event is fired.
  1111. if (affectedInjectedTextLines === null || affectedInjectedTextLines.size === 0) {
  1112. return;
  1113. }
  1114. const affectedLines = Array.from(affectedInjectedTextLines);
  1115. const lineChangeEvents = affectedLines.map(lineNumber => new ModelRawLineChanged(lineNumber, this.getLineContent(lineNumber), this._getInjectedTextInLine(lineNumber)));
  1116. this._onDidChangeInjectedText.fire(new ModelInjectedTextChangedEvent(lineChangeEvents));
  1117. }
  1118. changeDecorations(callback, ownerId = 0) {
  1119. this._assertNotDisposed();
  1120. try {
  1121. this._onDidChangeDecorations.beginDeferredEmit();
  1122. return this._changeDecorations(ownerId, callback);
  1123. }
  1124. finally {
  1125. this._onDidChangeDecorations.endDeferredEmit();
  1126. }
  1127. }
  1128. _changeDecorations(ownerId, callback) {
  1129. const changeAccessor = {
  1130. addDecoration: (range, options) => {
  1131. return this._deltaDecorationsImpl(ownerId, [], [{ range: range, options: options }])[0];
  1132. },
  1133. changeDecoration: (id, newRange) => {
  1134. this._changeDecorationImpl(id, newRange);
  1135. },
  1136. changeDecorationOptions: (id, options) => {
  1137. this._changeDecorationOptionsImpl(id, _normalizeOptions(options));
  1138. },
  1139. removeDecoration: (id) => {
  1140. this._deltaDecorationsImpl(ownerId, [id], []);
  1141. },
  1142. deltaDecorations: (oldDecorations, newDecorations) => {
  1143. if (oldDecorations.length === 0 && newDecorations.length === 0) {
  1144. // nothing to do
  1145. return [];
  1146. }
  1147. return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);
  1148. }
  1149. };
  1150. let result = null;
  1151. try {
  1152. result = callback(changeAccessor);
  1153. }
  1154. catch (e) {
  1155. onUnexpectedError(e);
  1156. }
  1157. // Invalidate change accessor
  1158. changeAccessor.addDecoration = invalidFunc;
  1159. changeAccessor.changeDecoration = invalidFunc;
  1160. changeAccessor.changeDecorationOptions = invalidFunc;
  1161. changeAccessor.removeDecoration = invalidFunc;
  1162. changeAccessor.deltaDecorations = invalidFunc;
  1163. return result;
  1164. }
  1165. deltaDecorations(oldDecorations, newDecorations, ownerId = 0) {
  1166. this._assertNotDisposed();
  1167. if (!oldDecorations) {
  1168. oldDecorations = [];
  1169. }
  1170. if (oldDecorations.length === 0 && newDecorations.length === 0) {
  1171. // nothing to do
  1172. return [];
  1173. }
  1174. try {
  1175. this._deltaDecorationCallCnt++;
  1176. if (this._deltaDecorationCallCnt > 1) {
  1177. console.warn(`Invoking deltaDecorations recursively could lead to leaking decorations.`);
  1178. onUnexpectedError(new Error(`Invoking deltaDecorations recursively could lead to leaking decorations.`));
  1179. }
  1180. this._onDidChangeDecorations.beginDeferredEmit();
  1181. return this._deltaDecorationsImpl(ownerId, oldDecorations, newDecorations);
  1182. }
  1183. finally {
  1184. this._onDidChangeDecorations.endDeferredEmit();
  1185. this._deltaDecorationCallCnt--;
  1186. }
  1187. }
  1188. _getTrackedRange(id) {
  1189. return this.getDecorationRange(id);
  1190. }
  1191. _setTrackedRange(id, newRange, newStickiness) {
  1192. const node = (id ? this._decorations[id] : null);
  1193. if (!node) {
  1194. if (!newRange) {
  1195. // node doesn't exist, the request is to delete => nothing to do
  1196. return null;
  1197. }
  1198. // node doesn't exist, the request is to set => add the tracked range
  1199. return this._deltaDecorationsImpl(0, [], [{ range: newRange, options: TRACKED_RANGE_OPTIONS[newStickiness] }])[0];
  1200. }
  1201. if (!newRange) {
  1202. // node exists, the request is to delete => delete node
  1203. this._decorationsTree.delete(node);
  1204. delete this._decorations[node.id];
  1205. return null;
  1206. }
  1207. // node exists, the request is to set => change the tracked range and its options
  1208. const range = this._validateRangeRelaxedNoAllocations(newRange);
  1209. const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
  1210. const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
  1211. this._decorationsTree.delete(node);
  1212. node.reset(this.getVersionId(), startOffset, endOffset, range);
  1213. node.setOptions(TRACKED_RANGE_OPTIONS[newStickiness]);
  1214. this._decorationsTree.insert(node);
  1215. return node.id;
  1216. }
  1217. removeAllDecorationsWithOwnerId(ownerId) {
  1218. if (this._isDisposed) {
  1219. return;
  1220. }
  1221. const nodes = this._decorationsTree.collectNodesFromOwner(ownerId);
  1222. for (let i = 0, len = nodes.length; i < len; i++) {
  1223. const node = nodes[i];
  1224. this._decorationsTree.delete(node);
  1225. delete this._decorations[node.id];
  1226. }
  1227. }
  1228. getDecorationOptions(decorationId) {
  1229. const node = this._decorations[decorationId];
  1230. if (!node) {
  1231. return null;
  1232. }
  1233. return node.options;
  1234. }
  1235. getDecorationRange(decorationId) {
  1236. const node = this._decorations[decorationId];
  1237. if (!node) {
  1238. return null;
  1239. }
  1240. return this._decorationsTree.getNodeRange(this, node);
  1241. }
  1242. getLineDecorations(lineNumber, ownerId = 0, filterOutValidation = false) {
  1243. if (lineNumber < 1 || lineNumber > this.getLineCount()) {
  1244. return [];
  1245. }
  1246. return this.getLinesDecorations(lineNumber, lineNumber, ownerId, filterOutValidation);
  1247. }
  1248. getLinesDecorations(_startLineNumber, _endLineNumber, ownerId = 0, filterOutValidation = false) {
  1249. const lineCount = this.getLineCount();
  1250. const startLineNumber = Math.min(lineCount, Math.max(1, _startLineNumber));
  1251. const endLineNumber = Math.min(lineCount, Math.max(1, _endLineNumber));
  1252. const endColumn = this.getLineMaxColumn(endLineNumber);
  1253. const range = new Range(startLineNumber, 1, endLineNumber, endColumn);
  1254. const decorations = this._getDecorationsInRange(range, ownerId, filterOutValidation);
  1255. pushMany(decorations, this._decorationProvider.getDecorationsInRange(range, ownerId, filterOutValidation));
  1256. return decorations;
  1257. }
  1258. getDecorationsInRange(range, ownerId = 0, filterOutValidation = false) {
  1259. const validatedRange = this.validateRange(range);
  1260. const decorations = this._getDecorationsInRange(validatedRange, ownerId, filterOutValidation);
  1261. pushMany(decorations, this._decorationProvider.getDecorationsInRange(validatedRange, ownerId, filterOutValidation));
  1262. return decorations;
  1263. }
  1264. getOverviewRulerDecorations(ownerId = 0, filterOutValidation = false) {
  1265. return this._decorationsTree.getAll(this, ownerId, filterOutValidation, true);
  1266. }
  1267. getInjectedTextDecorations(ownerId = 0) {
  1268. return this._decorationsTree.getAllInjectedText(this, ownerId);
  1269. }
  1270. _getInjectedTextInLine(lineNumber) {
  1271. const startOffset = this._buffer.getOffsetAt(lineNumber, 1);
  1272. const endOffset = startOffset + this._buffer.getLineLength(lineNumber);
  1273. const result = this._decorationsTree.getInjectedTextInInterval(this, startOffset, endOffset, 0);
  1274. return LineInjectedText.fromDecorations(result).filter(t => t.lineNumber === lineNumber);
  1275. }
  1276. getAllDecorations(ownerId = 0, filterOutValidation = false) {
  1277. let result = this._decorationsTree.getAll(this, ownerId, filterOutValidation, false);
  1278. result = result.concat(this._decorationProvider.getAllDecorations(ownerId, filterOutValidation));
  1279. return result;
  1280. }
  1281. _getDecorationsInRange(filterRange, filterOwnerId, filterOutValidation) {
  1282. const startOffset = this._buffer.getOffsetAt(filterRange.startLineNumber, filterRange.startColumn);
  1283. const endOffset = this._buffer.getOffsetAt(filterRange.endLineNumber, filterRange.endColumn);
  1284. return this._decorationsTree.getAllInInterval(this, startOffset, endOffset, filterOwnerId, filterOutValidation);
  1285. }
  1286. getRangeAt(start, end) {
  1287. return this._buffer.getRangeAt(start, end - start);
  1288. }
  1289. _changeDecorationImpl(decorationId, _range) {
  1290. const node = this._decorations[decorationId];
  1291. if (!node) {
  1292. return;
  1293. }
  1294. if (node.options.after) {
  1295. const oldRange = this.getDecorationRange(decorationId);
  1296. this._onDidChangeDecorations.recordLineAffectedByInjectedText(oldRange.endLineNumber);
  1297. }
  1298. if (node.options.before) {
  1299. const oldRange = this.getDecorationRange(decorationId);
  1300. this._onDidChangeDecorations.recordLineAffectedByInjectedText(oldRange.startLineNumber);
  1301. }
  1302. const range = this._validateRangeRelaxedNoAllocations(_range);
  1303. const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
  1304. const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
  1305. this._decorationsTree.delete(node);
  1306. node.reset(this.getVersionId(), startOffset, endOffset, range);
  1307. this._decorationsTree.insert(node);
  1308. this._onDidChangeDecorations.checkAffectedAndFire(node.options);
  1309. if (node.options.after) {
  1310. this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.endLineNumber);
  1311. }
  1312. if (node.options.before) {
  1313. this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.startLineNumber);
  1314. }
  1315. }
  1316. _changeDecorationOptionsImpl(decorationId, options) {
  1317. const node = this._decorations[decorationId];
  1318. if (!node) {
  1319. return;
  1320. }
  1321. const nodeWasInOverviewRuler = (node.options.overviewRuler && node.options.overviewRuler.color ? true : false);
  1322. const nodeIsInOverviewRuler = (options.overviewRuler && options.overviewRuler.color ? true : false);
  1323. this._onDidChangeDecorations.checkAffectedAndFire(node.options);
  1324. this._onDidChangeDecorations.checkAffectedAndFire(options);
  1325. if (node.options.after || options.after) {
  1326. const nodeRange = this._decorationsTree.getNodeRange(this, node);
  1327. this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.endLineNumber);
  1328. }
  1329. if (node.options.before || options.before) {
  1330. const nodeRange = this._decorationsTree.getNodeRange(this, node);
  1331. this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.startLineNumber);
  1332. }
  1333. if (nodeWasInOverviewRuler !== nodeIsInOverviewRuler) {
  1334. // Delete + Insert due to an overview ruler status change
  1335. this._decorationsTree.delete(node);
  1336. node.setOptions(options);
  1337. this._decorationsTree.insert(node);
  1338. }
  1339. else {
  1340. node.setOptions(options);
  1341. }
  1342. }
  1343. _deltaDecorationsImpl(ownerId, oldDecorationsIds, newDecorations) {
  1344. const versionId = this.getVersionId();
  1345. const oldDecorationsLen = oldDecorationsIds.length;
  1346. let oldDecorationIndex = 0;
  1347. const newDecorationsLen = newDecorations.length;
  1348. let newDecorationIndex = 0;
  1349. const result = new Array(newDecorationsLen);
  1350. while (oldDecorationIndex < oldDecorationsLen || newDecorationIndex < newDecorationsLen) {
  1351. let node = null;
  1352. if (oldDecorationIndex < oldDecorationsLen) {
  1353. // (1) get ourselves an old node
  1354. do {
  1355. node = this._decorations[oldDecorationsIds[oldDecorationIndex++]];
  1356. } while (!node && oldDecorationIndex < oldDecorationsLen);
  1357. // (2) remove the node from the tree (if it exists)
  1358. if (node) {
  1359. if (node.options.after) {
  1360. const nodeRange = this._decorationsTree.getNodeRange(this, node);
  1361. this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.endLineNumber);
  1362. }
  1363. if (node.options.before) {
  1364. const nodeRange = this._decorationsTree.getNodeRange(this, node);
  1365. this._onDidChangeDecorations.recordLineAffectedByInjectedText(nodeRange.startLineNumber);
  1366. }
  1367. this._decorationsTree.delete(node);
  1368. this._onDidChangeDecorations.checkAffectedAndFire(node.options);
  1369. }
  1370. }
  1371. if (newDecorationIndex < newDecorationsLen) {
  1372. // (3) create a new node if necessary
  1373. if (!node) {
  1374. const internalDecorationId = (++this._lastDecorationId);
  1375. const decorationId = `${this._instanceId};${internalDecorationId}`;
  1376. node = new IntervalNode(decorationId, 0, 0);
  1377. this._decorations[decorationId] = node;
  1378. }
  1379. // (4) initialize node
  1380. const newDecoration = newDecorations[newDecorationIndex];
  1381. const range = this._validateRangeRelaxedNoAllocations(newDecoration.range);
  1382. const options = _normalizeOptions(newDecoration.options);
  1383. const startOffset = this._buffer.getOffsetAt(range.startLineNumber, range.startColumn);
  1384. const endOffset = this._buffer.getOffsetAt(range.endLineNumber, range.endColumn);
  1385. node.ownerId = ownerId;
  1386. node.reset(versionId, startOffset, endOffset, range);
  1387. node.setOptions(options);
  1388. if (node.options.after) {
  1389. this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.endLineNumber);
  1390. }
  1391. if (node.options.before) {
  1392. this._onDidChangeDecorations.recordLineAffectedByInjectedText(range.startLineNumber);
  1393. }
  1394. this._onDidChangeDecorations.checkAffectedAndFire(options);
  1395. this._decorationsTree.insert(node);
  1396. result[newDecorationIndex] = node.id;
  1397. newDecorationIndex++;
  1398. }
  1399. else {
  1400. if (node) {
  1401. delete this._decorations[node.id];
  1402. }
  1403. }
  1404. }
  1405. return result;
  1406. }
  1407. //#endregion
  1408. //#region Tokenization
  1409. // TODO move them to the tokenization part.
  1410. getLanguageId() {
  1411. return this.tokenization.getLanguageId();
  1412. }
  1413. setMode(languageId) {
  1414. this.tokenization.setLanguageId(languageId);
  1415. }
  1416. getLanguageIdAtPosition(lineNumber, column) {
  1417. return this.tokenization.getLanguageIdAtPosition(lineNumber, column);
  1418. }
  1419. getWordAtPosition(position) {
  1420. return this._tokenizationTextModelPart.getWordAtPosition(position);
  1421. }
  1422. getWordUntilPosition(position) {
  1423. return this._tokenizationTextModelPart.getWordUntilPosition(position);
  1424. }
  1425. //#endregion
  1426. normalizePosition(position, affinity) {
  1427. return position;
  1428. }
  1429. /**
  1430. * Gets the column at which indentation stops at a given line.
  1431. * @internal
  1432. */
  1433. getLineIndentColumn(lineNumber) {
  1434. // Columns start with 1.
  1435. return indentOfLine(this.getLineContent(lineNumber)) + 1;
  1436. }
  1437. };
  1438. TextModel.MODEL_SYNC_LIMIT = 50 * 1024 * 1024; // 50 MB
  1439. TextModel.LARGE_FILE_SIZE_THRESHOLD = 20 * 1024 * 1024; // 20 MB;
  1440. TextModel.LARGE_FILE_LINE_COUNT_THRESHOLD = 300 * 1000; // 300K lines
  1441. TextModel.DEFAULT_CREATION_OPTIONS = {
  1442. isForSimpleWidget: false,
  1443. tabSize: EDITOR_MODEL_DEFAULTS.tabSize,
  1444. indentSize: EDITOR_MODEL_DEFAULTS.indentSize,
  1445. insertSpaces: EDITOR_MODEL_DEFAULTS.insertSpaces,
  1446. detectIndentation: false,
  1447. defaultEOL: 1 /* model.DefaultEndOfLine.LF */,
  1448. trimAutoWhitespace: EDITOR_MODEL_DEFAULTS.trimAutoWhitespace,
  1449. largeFileOptimizations: EDITOR_MODEL_DEFAULTS.largeFileOptimizations,
  1450. bracketPairColorizationOptions: EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions,
  1451. };
  1452. TextModel = __decorate([
  1453. __param(4, IUndoRedoService),
  1454. __param(5, ILanguageService),
  1455. __param(6, ILanguageConfigurationService)
  1456. ], TextModel);
  1457. export { TextModel };
  1458. function indentOfLine(line) {
  1459. let indent = 0;
  1460. for (const c of line) {
  1461. if (c === ' ' || c === '\t') {
  1462. indent++;
  1463. }
  1464. else {
  1465. break;
  1466. }
  1467. }
  1468. return indent;
  1469. }
  1470. //#region Decorations
  1471. function isNodeInOverviewRuler(node) {
  1472. return (node.options.overviewRuler && node.options.overviewRuler.color ? true : false);
  1473. }
  1474. function isNodeInjectedText(node) {
  1475. return !!node.options.after || !!node.options.before;
  1476. }
  1477. class DecorationsTrees {
  1478. constructor() {
  1479. this._decorationsTree0 = new IntervalTree();
  1480. this._decorationsTree1 = new IntervalTree();
  1481. this._injectedTextDecorationsTree = new IntervalTree();
  1482. }
  1483. ensureAllNodesHaveRanges(host) {
  1484. this.getAll(host, 0, false, false);
  1485. }
  1486. _ensureNodesHaveRanges(host, nodes) {
  1487. for (const node of nodes) {
  1488. if (node.range === null) {
  1489. node.range = host.getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd);
  1490. }
  1491. }
  1492. return nodes;
  1493. }
  1494. getAllInInterval(host, start, end, filterOwnerId, filterOutValidation) {
  1495. const versionId = host.getVersionId();
  1496. const result = this._intervalSearch(start, end, filterOwnerId, filterOutValidation, versionId);
  1497. return this._ensureNodesHaveRanges(host, result);
  1498. }
  1499. _intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId) {
  1500. const r0 = this._decorationsTree0.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
  1501. const r1 = this._decorationsTree1.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
  1502. const r2 = this._injectedTextDecorationsTree.intervalSearch(start, end, filterOwnerId, filterOutValidation, cachedVersionId);
  1503. return r0.concat(r1).concat(r2);
  1504. }
  1505. getInjectedTextInInterval(host, start, end, filterOwnerId) {
  1506. const versionId = host.getVersionId();
  1507. const result = this._injectedTextDecorationsTree.intervalSearch(start, end, filterOwnerId, false, versionId);
  1508. return this._ensureNodesHaveRanges(host, result).filter((i) => i.options.showIfCollapsed || !i.range.isEmpty());
  1509. }
  1510. getAllInjectedText(host, filterOwnerId) {
  1511. const versionId = host.getVersionId();
  1512. const result = this._injectedTextDecorationsTree.search(filterOwnerId, false, versionId);
  1513. return this._ensureNodesHaveRanges(host, result).filter((i) => i.options.showIfCollapsed || !i.range.isEmpty());
  1514. }
  1515. getAll(host, filterOwnerId, filterOutValidation, overviewRulerOnly) {
  1516. const versionId = host.getVersionId();
  1517. const result = this._search(filterOwnerId, filterOutValidation, overviewRulerOnly, versionId);
  1518. return this._ensureNodesHaveRanges(host, result);
  1519. }
  1520. _search(filterOwnerId, filterOutValidation, overviewRulerOnly, cachedVersionId) {
  1521. if (overviewRulerOnly) {
  1522. return this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId);
  1523. }
  1524. else {
  1525. const r0 = this._decorationsTree0.search(filterOwnerId, filterOutValidation, cachedVersionId);
  1526. const r1 = this._decorationsTree1.search(filterOwnerId, filterOutValidation, cachedVersionId);
  1527. const r2 = this._injectedTextDecorationsTree.search(filterOwnerId, filterOutValidation, cachedVersionId);
  1528. return r0.concat(r1).concat(r2);
  1529. }
  1530. }
  1531. collectNodesFromOwner(ownerId) {
  1532. const r0 = this._decorationsTree0.collectNodesFromOwner(ownerId);
  1533. const r1 = this._decorationsTree1.collectNodesFromOwner(ownerId);
  1534. const r2 = this._injectedTextDecorationsTree.collectNodesFromOwner(ownerId);
  1535. return r0.concat(r1).concat(r2);
  1536. }
  1537. collectNodesPostOrder() {
  1538. const r0 = this._decorationsTree0.collectNodesPostOrder();
  1539. const r1 = this._decorationsTree1.collectNodesPostOrder();
  1540. const r2 = this._injectedTextDecorationsTree.collectNodesPostOrder();
  1541. return r0.concat(r1).concat(r2);
  1542. }
  1543. insert(node) {
  1544. if (isNodeInjectedText(node)) {
  1545. this._injectedTextDecorationsTree.insert(node);
  1546. }
  1547. else if (isNodeInOverviewRuler(node)) {
  1548. this._decorationsTree1.insert(node);
  1549. }
  1550. else {
  1551. this._decorationsTree0.insert(node);
  1552. }
  1553. }
  1554. delete(node) {
  1555. if (isNodeInjectedText(node)) {
  1556. this._injectedTextDecorationsTree.delete(node);
  1557. }
  1558. else if (isNodeInOverviewRuler(node)) {
  1559. this._decorationsTree1.delete(node);
  1560. }
  1561. else {
  1562. this._decorationsTree0.delete(node);
  1563. }
  1564. }
  1565. getNodeRange(host, node) {
  1566. const versionId = host.getVersionId();
  1567. if (node.cachedVersionId !== versionId) {
  1568. this._resolveNode(node, versionId);
  1569. }
  1570. if (node.range === null) {
  1571. node.range = host.getRangeAt(node.cachedAbsoluteStart, node.cachedAbsoluteEnd);
  1572. }
  1573. return node.range;
  1574. }
  1575. _resolveNode(node, cachedVersionId) {
  1576. if (isNodeInjectedText(node)) {
  1577. this._injectedTextDecorationsTree.resolveNode(node, cachedVersionId);
  1578. }
  1579. else if (isNodeInOverviewRuler(node)) {
  1580. this._decorationsTree1.resolveNode(node, cachedVersionId);
  1581. }
  1582. else {
  1583. this._decorationsTree0.resolveNode(node, cachedVersionId);
  1584. }
  1585. }
  1586. acceptReplace(offset, length, textLength, forceMoveMarkers) {
  1587. this._decorationsTree0.acceptReplace(offset, length, textLength, forceMoveMarkers);
  1588. this._decorationsTree1.acceptReplace(offset, length, textLength, forceMoveMarkers);
  1589. this._injectedTextDecorationsTree.acceptReplace(offset, length, textLength, forceMoveMarkers);
  1590. }
  1591. }
  1592. function cleanClassName(className) {
  1593. return className.replace(/[^a-z0-9\-_]/gi, ' ');
  1594. }
  1595. class DecorationOptions {
  1596. constructor(options) {
  1597. this.color = options.color || '';
  1598. this.darkColor = options.darkColor || '';
  1599. }
  1600. }
  1601. export class ModelDecorationOverviewRulerOptions extends DecorationOptions {
  1602. constructor(options) {
  1603. super(options);
  1604. this._resolvedColor = null;
  1605. this.position = (typeof options.position === 'number' ? options.position : model.OverviewRulerLane.Center);
  1606. }
  1607. getColor(theme) {
  1608. if (!this._resolvedColor) {
  1609. if (theme.type !== 'light' && this.darkColor) {
  1610. this._resolvedColor = this._resolveColor(this.darkColor, theme);
  1611. }
  1612. else {
  1613. this._resolvedColor = this._resolveColor(this.color, theme);
  1614. }
  1615. }
  1616. return this._resolvedColor;
  1617. }
  1618. invalidateCachedColor() {
  1619. this._resolvedColor = null;
  1620. }
  1621. _resolveColor(color, theme) {
  1622. if (typeof color === 'string') {
  1623. return color;
  1624. }
  1625. const c = color ? theme.getColor(color.id) : null;
  1626. if (!c) {
  1627. return '';
  1628. }
  1629. return c.toString();
  1630. }
  1631. }
  1632. export class ModelDecorationMinimapOptions extends DecorationOptions {
  1633. constructor(options) {
  1634. super(options);
  1635. this.position = options.position;
  1636. }
  1637. getColor(theme) {
  1638. if (!this._resolvedColor) {
  1639. if (theme.type !== 'light' && this.darkColor) {
  1640. this._resolvedColor = this._resolveColor(this.darkColor, theme);
  1641. }
  1642. else {
  1643. this._resolvedColor = this._resolveColor(this.color, theme);
  1644. }
  1645. }
  1646. return this._resolvedColor;
  1647. }
  1648. invalidateCachedColor() {
  1649. this._resolvedColor = undefined;
  1650. }
  1651. _resolveColor(color, theme) {
  1652. if (typeof color === 'string') {
  1653. return Color.fromHex(color);
  1654. }
  1655. return theme.getColor(color.id);
  1656. }
  1657. }
  1658. export class ModelDecorationInjectedTextOptions {
  1659. constructor(options) {
  1660. this.content = options.content || '';
  1661. this.inlineClassName = options.inlineClassName || null;
  1662. this.inlineClassNameAffectsLetterSpacing = options.inlineClassNameAffectsLetterSpacing || false;
  1663. this.attachedData = options.attachedData || null;
  1664. this.cursorStops = options.cursorStops || null;
  1665. }
  1666. static from(options) {
  1667. if (options instanceof ModelDecorationInjectedTextOptions) {
  1668. return options;
  1669. }
  1670. return new ModelDecorationInjectedTextOptions(options);
  1671. }
  1672. }
  1673. export class ModelDecorationOptions {
  1674. constructor(options) {
  1675. var _a, _b;
  1676. this.description = options.description;
  1677. this.blockClassName = options.blockClassName ? cleanClassName(options.blockClassName) : null;
  1678. this.stickiness = options.stickiness || 0 /* model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges */;
  1679. this.zIndex = options.zIndex || 0;
  1680. this.className = options.className ? cleanClassName(options.className) : null;
  1681. this.hoverMessage = options.hoverMessage || null;
  1682. this.glyphMarginHoverMessage = options.glyphMarginHoverMessage || null;
  1683. this.isWholeLine = options.isWholeLine || false;
  1684. this.showIfCollapsed = options.showIfCollapsed || false;
  1685. this.collapseOnReplaceEdit = options.collapseOnReplaceEdit || false;
  1686. this.overviewRuler = options.overviewRuler ? new ModelDecorationOverviewRulerOptions(options.overviewRuler) : null;
  1687. this.minimap = options.minimap ? new ModelDecorationMinimapOptions(options.minimap) : null;
  1688. this.glyphMarginClassName = options.glyphMarginClassName ? cleanClassName(options.glyphMarginClassName) : null;
  1689. this.linesDecorationsClassName = options.linesDecorationsClassName ? cleanClassName(options.linesDecorationsClassName) : null;
  1690. this.firstLineDecorationClassName = options.firstLineDecorationClassName ? cleanClassName(options.firstLineDecorationClassName) : null;
  1691. this.marginClassName = options.marginClassName ? cleanClassName(options.marginClassName) : null;
  1692. this.inlineClassName = options.inlineClassName ? cleanClassName(options.inlineClassName) : null;
  1693. this.inlineClassNameAffectsLetterSpacing = options.inlineClassNameAffectsLetterSpacing || false;
  1694. this.beforeContentClassName = options.beforeContentClassName ? cleanClassName(options.beforeContentClassName) : null;
  1695. this.afterContentClassName = options.afterContentClassName ? cleanClassName(options.afterContentClassName) : null;
  1696. this.after = options.after ? ModelDecorationInjectedTextOptions.from(options.after) : null;
  1697. this.before = options.before ? ModelDecorationInjectedTextOptions.from(options.before) : null;
  1698. this.hideInCommentTokens = (_a = options.hideInCommentTokens) !== null && _a !== void 0 ? _a : false;
  1699. this.hideInStringTokens = (_b = options.hideInStringTokens) !== null && _b !== void 0 ? _b : false;
  1700. }
  1701. static register(options) {
  1702. return new ModelDecorationOptions(options);
  1703. }
  1704. static createDynamic(options) {
  1705. return new ModelDecorationOptions(options);
  1706. }
  1707. }
  1708. ModelDecorationOptions.EMPTY = ModelDecorationOptions.register({ description: 'empty' });
  1709. /**
  1710. * The order carefully matches the values of the enum.
  1711. */
  1712. const TRACKED_RANGE_OPTIONS = [
  1713. ModelDecorationOptions.register({ description: 'tracked-range-always-grows-when-typing-at-edges', stickiness: 0 /* model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges */ }),
  1714. ModelDecorationOptions.register({ description: 'tracked-range-never-grows-when-typing-at-edges', stickiness: 1 /* model.TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges */ }),
  1715. ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-before', stickiness: 2 /* model.TrackedRangeStickiness.GrowsOnlyWhenTypingBefore */ }),
  1716. ModelDecorationOptions.register({ description: 'tracked-range-grows-only-when-typing-after', stickiness: 3 /* model.TrackedRangeStickiness.GrowsOnlyWhenTypingAfter */ }),
  1717. ];
  1718. function _normalizeOptions(options) {
  1719. if (options instanceof ModelDecorationOptions) {
  1720. return options;
  1721. }
  1722. return ModelDecorationOptions.createDynamic(options);
  1723. }
  1724. export class DidChangeDecorationsEmitter extends Disposable {
  1725. constructor(handleBeforeFire) {
  1726. super();
  1727. this.handleBeforeFire = handleBeforeFire;
  1728. this._actual = this._register(new Emitter());
  1729. this.event = this._actual.event;
  1730. this._affectedInjectedTextLines = null;
  1731. this._deferredCnt = 0;
  1732. this._shouldFire = false;
  1733. this._affectsMinimap = false;
  1734. this._affectsOverviewRuler = false;
  1735. }
  1736. beginDeferredEmit() {
  1737. this._deferredCnt++;
  1738. }
  1739. endDeferredEmit() {
  1740. var _a;
  1741. this._deferredCnt--;
  1742. if (this._deferredCnt === 0) {
  1743. if (this._shouldFire) {
  1744. this.handleBeforeFire(this._affectedInjectedTextLines);
  1745. const event = {
  1746. affectsMinimap: this._affectsMinimap,
  1747. affectsOverviewRuler: this._affectsOverviewRuler
  1748. };
  1749. this._shouldFire = false;
  1750. this._affectsMinimap = false;
  1751. this._affectsOverviewRuler = false;
  1752. this._actual.fire(event);
  1753. }
  1754. (_a = this._affectedInjectedTextLines) === null || _a === void 0 ? void 0 : _a.clear();
  1755. this._affectedInjectedTextLines = null;
  1756. }
  1757. }
  1758. recordLineAffectedByInjectedText(lineNumber) {
  1759. if (!this._affectedInjectedTextLines) {
  1760. this._affectedInjectedTextLines = new Set();
  1761. }
  1762. this._affectedInjectedTextLines.add(lineNumber);
  1763. }
  1764. checkAffectedAndFire(options) {
  1765. if (!this._affectsMinimap) {
  1766. this._affectsMinimap = options.minimap && options.minimap.position ? true : false;
  1767. }
  1768. if (!this._affectsOverviewRuler) {
  1769. this._affectsOverviewRuler = options.overviewRuler && options.overviewRuler.color ? true : false;
  1770. }
  1771. this._shouldFire = true;
  1772. }
  1773. fire() {
  1774. this._affectsMinimap = true;
  1775. this._affectsOverviewRuler = true;
  1776. this._shouldFire = true;
  1777. }
  1778. }
  1779. //#endregion
  1780. export class DidChangeContentEmitter extends Disposable {
  1781. constructor() {
  1782. super();
  1783. /**
  1784. * Both `fastEvent` and `slowEvent` work the same way and contain the same events, but first we invoke `fastEvent` and then `slowEvent`.
  1785. */
  1786. this._fastEmitter = this._register(new Emitter());
  1787. this.fastEvent = this._fastEmitter.event;
  1788. this._slowEmitter = this._register(new Emitter());
  1789. this.slowEvent = this._slowEmitter.event;
  1790. this._deferredCnt = 0;
  1791. this._deferredEvent = null;
  1792. }
  1793. beginDeferredEmit() {
  1794. this._deferredCnt++;
  1795. }
  1796. endDeferredEmit(resultingSelection = null) {
  1797. this._deferredCnt--;
  1798. if (this._deferredCnt === 0) {
  1799. if (this._deferredEvent !== null) {
  1800. this._deferredEvent.rawContentChangedEvent.resultingSelection = resultingSelection;
  1801. const e = this._deferredEvent;
  1802. this._deferredEvent = null;
  1803. this._fastEmitter.fire(e);
  1804. this._slowEmitter.fire(e);
  1805. }
  1806. }
  1807. }
  1808. fire(e) {
  1809. if (this._deferredCnt > 0) {
  1810. if (this._deferredEvent) {
  1811. this._deferredEvent = this._deferredEvent.merge(e);
  1812. }
  1813. else {
  1814. this._deferredEvent = e;
  1815. }
  1816. return;
  1817. }
  1818. this._fastEmitter.fire(e);
  1819. this._slowEmitter.fire(e);
  1820. }
  1821. }