0c549d17153ba0a280d6422261a1603da7a4baea3059d4480c4fd7f7df627a6cef725287ad14d01d48975f07db42d3f0cde9dd6de27e2cd9b558e97405c002 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  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 { Emitter } from '../../../base/common/event.js';
  15. import { Disposable, DisposableStore, dispose } from '../../../base/common/lifecycle.js';
  16. import * as platform from '../../../base/common/platform.js';
  17. import * as errors from '../../../base/common/errors.js';
  18. import { TextModel } from '../model/textModel.js';
  19. import { EDITOR_MODEL_DEFAULTS } from '../core/textModelDefaults.js';
  20. import { PLAINTEXT_LANGUAGE_ID } from '../languages/modesRegistry.js';
  21. import { ILanguageService } from '../languages/language.js';
  22. import { IModelService } from './model.js';
  23. import { ITextResourcePropertiesService } from './textResourceConfiguration.js';
  24. import { IConfigurationService } from '../../../platform/configuration/common/configuration.js';
  25. import { RunOnceScheduler } from '../../../base/common/async.js';
  26. import { CancellationTokenSource } from '../../../base/common/cancellation.js';
  27. import { IThemeService } from '../../../platform/theme/common/themeService.js';
  28. import { ILogService } from '../../../platform/log/common/log.js';
  29. import { IUndoRedoService } from '../../../platform/undoRedo/common/undoRedo.js';
  30. import { StringSHA1 } from '../../../base/common/hash.js';
  31. import { isEditStackElement } from '../model/editStack.js';
  32. import { Schemas } from '../../../base/common/network.js';
  33. import { SemanticTokensProviderStyling, toMultilineTokens2 } from './semanticTokensProviderStyling.js';
  34. import { getDocumentSemanticTokens, hasDocumentSemanticTokensProvider, isSemanticTokens, isSemanticTokensEdits } from './getSemanticTokens.js';
  35. import { equals } from '../../../base/common/objects.js';
  36. import { ILanguageConfigurationService } from '../languages/languageConfigurationRegistry.js';
  37. import { ILanguageFeatureDebounceService } from './languageFeatureDebounce.js';
  38. import { StopWatch } from '../../../base/common/stopwatch.js';
  39. import { ILanguageFeaturesService } from './languageFeatures.js';
  40. function MODEL_ID(resource) {
  41. return resource.toString();
  42. }
  43. function computeModelSha1(model) {
  44. // compute the sha1
  45. const shaComputer = new StringSHA1();
  46. const snapshot = model.createSnapshot();
  47. let text;
  48. while ((text = snapshot.read())) {
  49. shaComputer.update(text);
  50. }
  51. return shaComputer.digest();
  52. }
  53. class ModelData {
  54. constructor(model, onWillDispose, onDidChangeLanguage) {
  55. this._modelEventListeners = new DisposableStore();
  56. this.model = model;
  57. this._languageSelection = null;
  58. this._languageSelectionListener = null;
  59. this._modelEventListeners.add(model.onWillDispose(() => onWillDispose(model)));
  60. this._modelEventListeners.add(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e)));
  61. }
  62. _disposeLanguageSelection() {
  63. if (this._languageSelectionListener) {
  64. this._languageSelectionListener.dispose();
  65. this._languageSelectionListener = null;
  66. }
  67. }
  68. dispose() {
  69. this._modelEventListeners.dispose();
  70. this._disposeLanguageSelection();
  71. }
  72. setLanguage(languageSelection) {
  73. this._disposeLanguageSelection();
  74. this._languageSelection = languageSelection;
  75. this._languageSelectionListener = this._languageSelection.onDidChange(() => this.model.setMode(languageSelection.languageId));
  76. this.model.setMode(languageSelection.languageId);
  77. }
  78. }
  79. const DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? 1 /* DefaultEndOfLine.LF */ : 2 /* DefaultEndOfLine.CRLF */;
  80. class DisposedModelInfo {
  81. constructor(uri, initialUndoRedoSnapshot, time, sharesUndoRedoStack, heapSize, sha1, versionId, alternativeVersionId) {
  82. this.uri = uri;
  83. this.initialUndoRedoSnapshot = initialUndoRedoSnapshot;
  84. this.time = time;
  85. this.sharesUndoRedoStack = sharesUndoRedoStack;
  86. this.heapSize = heapSize;
  87. this.sha1 = sha1;
  88. this.versionId = versionId;
  89. this.alternativeVersionId = alternativeVersionId;
  90. }
  91. }
  92. let ModelService = class ModelService extends Disposable {
  93. constructor(_configurationService, _resourcePropertiesService, _themeService, _logService, _undoRedoService, _languageService, _languageConfigurationService, _languageFeatureDebounceService, languageFeaturesService) {
  94. super();
  95. this._configurationService = _configurationService;
  96. this._resourcePropertiesService = _resourcePropertiesService;
  97. this._themeService = _themeService;
  98. this._logService = _logService;
  99. this._undoRedoService = _undoRedoService;
  100. this._languageService = _languageService;
  101. this._languageConfigurationService = _languageConfigurationService;
  102. this._languageFeatureDebounceService = _languageFeatureDebounceService;
  103. this._onModelAdded = this._register(new Emitter());
  104. this.onModelAdded = this._onModelAdded.event;
  105. this._onModelRemoved = this._register(new Emitter());
  106. this.onModelRemoved = this._onModelRemoved.event;
  107. this._onModelModeChanged = this._register(new Emitter());
  108. this.onModelLanguageChanged = this._onModelModeChanged.event;
  109. this._modelCreationOptionsByLanguageAndResource = Object.create(null);
  110. this._models = {};
  111. this._disposedModels = new Map();
  112. this._disposedModelsHeapSize = 0;
  113. this._semanticStyling = this._register(new SemanticStyling(this._themeService, this._languageService, this._logService));
  114. this._register(this._configurationService.onDidChangeConfiguration(() => this._updateModelOptions()));
  115. this._updateModelOptions();
  116. this._register(new SemanticColoringFeature(this._semanticStyling, this, this._themeService, this._configurationService, this._languageFeatureDebounceService, languageFeaturesService));
  117. }
  118. static _readModelOptions(config, isForSimpleWidget) {
  119. var _a;
  120. let tabSize = EDITOR_MODEL_DEFAULTS.tabSize;
  121. if (config.editor && typeof config.editor.tabSize !== 'undefined') {
  122. const parsedTabSize = parseInt(config.editor.tabSize, 10);
  123. if (!isNaN(parsedTabSize)) {
  124. tabSize = parsedTabSize;
  125. }
  126. if (tabSize < 1) {
  127. tabSize = 1;
  128. }
  129. }
  130. let indentSize = tabSize;
  131. if (config.editor && typeof config.editor.indentSize !== 'undefined' && config.editor.indentSize !== 'tabSize') {
  132. const parsedIndentSize = parseInt(config.editor.indentSize, 10);
  133. if (!isNaN(parsedIndentSize)) {
  134. indentSize = parsedIndentSize;
  135. }
  136. if (indentSize < 1) {
  137. indentSize = 1;
  138. }
  139. }
  140. let insertSpaces = EDITOR_MODEL_DEFAULTS.insertSpaces;
  141. if (config.editor && typeof config.editor.insertSpaces !== 'undefined') {
  142. insertSpaces = (config.editor.insertSpaces === 'false' ? false : Boolean(config.editor.insertSpaces));
  143. }
  144. let newDefaultEOL = DEFAULT_EOL;
  145. const eol = config.eol;
  146. if (eol === '\r\n') {
  147. newDefaultEOL = 2 /* DefaultEndOfLine.CRLF */;
  148. }
  149. else if (eol === '\n') {
  150. newDefaultEOL = 1 /* DefaultEndOfLine.LF */;
  151. }
  152. let trimAutoWhitespace = EDITOR_MODEL_DEFAULTS.trimAutoWhitespace;
  153. if (config.editor && typeof config.editor.trimAutoWhitespace !== 'undefined') {
  154. trimAutoWhitespace = (config.editor.trimAutoWhitespace === 'false' ? false : Boolean(config.editor.trimAutoWhitespace));
  155. }
  156. let detectIndentation = EDITOR_MODEL_DEFAULTS.detectIndentation;
  157. if (config.editor && typeof config.editor.detectIndentation !== 'undefined') {
  158. detectIndentation = (config.editor.detectIndentation === 'false' ? false : Boolean(config.editor.detectIndentation));
  159. }
  160. let largeFileOptimizations = EDITOR_MODEL_DEFAULTS.largeFileOptimizations;
  161. if (config.editor && typeof config.editor.largeFileOptimizations !== 'undefined') {
  162. largeFileOptimizations = (config.editor.largeFileOptimizations === 'false' ? false : Boolean(config.editor.largeFileOptimizations));
  163. }
  164. let bracketPairColorizationOptions = EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions;
  165. if (((_a = config.editor) === null || _a === void 0 ? void 0 : _a.bracketPairColorization) && typeof config.editor.bracketPairColorization === 'object') {
  166. bracketPairColorizationOptions = {
  167. enabled: !!config.editor.bracketPairColorization.enabled,
  168. independentColorPoolPerBracketType: !!config.editor.bracketPairColorization.independentColorPoolPerBracketType
  169. };
  170. }
  171. return {
  172. isForSimpleWidget: isForSimpleWidget,
  173. tabSize: tabSize,
  174. indentSize: indentSize,
  175. insertSpaces: insertSpaces,
  176. detectIndentation: detectIndentation,
  177. defaultEOL: newDefaultEOL,
  178. trimAutoWhitespace: trimAutoWhitespace,
  179. largeFileOptimizations: largeFileOptimizations,
  180. bracketPairColorizationOptions
  181. };
  182. }
  183. _getEOL(resource, language) {
  184. if (resource) {
  185. return this._resourcePropertiesService.getEOL(resource, language);
  186. }
  187. const eol = this._configurationService.getValue('files.eol', { overrideIdentifier: language });
  188. if (eol && typeof eol === 'string' && eol !== 'auto') {
  189. return eol;
  190. }
  191. return platform.OS === 3 /* platform.OperatingSystem.Linux */ || platform.OS === 2 /* platform.OperatingSystem.Macintosh */ ? '\n' : '\r\n';
  192. }
  193. _shouldRestoreUndoStack() {
  194. const result = this._configurationService.getValue('files.restoreUndoStack');
  195. if (typeof result === 'boolean') {
  196. return result;
  197. }
  198. return true;
  199. }
  200. getCreationOptions(language, resource, isForSimpleWidget) {
  201. let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource];
  202. if (!creationOptions) {
  203. const editor = this._configurationService.getValue('editor', { overrideIdentifier: language, resource });
  204. const eol = this._getEOL(resource, language);
  205. creationOptions = ModelService._readModelOptions({ editor, eol }, isForSimpleWidget);
  206. this._modelCreationOptionsByLanguageAndResource[language + resource] = creationOptions;
  207. }
  208. return creationOptions;
  209. }
  210. _updateModelOptions() {
  211. const oldOptionsByLanguageAndResource = this._modelCreationOptionsByLanguageAndResource;
  212. this._modelCreationOptionsByLanguageAndResource = Object.create(null);
  213. // Update options on all models
  214. const keys = Object.keys(this._models);
  215. for (let i = 0, len = keys.length; i < len; i++) {
  216. const modelId = keys[i];
  217. const modelData = this._models[modelId];
  218. const language = modelData.model.getLanguageId();
  219. const uri = modelData.model.uri;
  220. const oldOptions = oldOptionsByLanguageAndResource[language + uri];
  221. const newOptions = this.getCreationOptions(language, uri, modelData.model.isForSimpleWidget);
  222. ModelService._setModelOptionsForModel(modelData.model, newOptions, oldOptions);
  223. }
  224. }
  225. static _setModelOptionsForModel(model, newOptions, currentOptions) {
  226. if (currentOptions && currentOptions.defaultEOL !== newOptions.defaultEOL && model.getLineCount() === 1) {
  227. model.setEOL(newOptions.defaultEOL === 1 /* DefaultEndOfLine.LF */ ? 0 /* EndOfLineSequence.LF */ : 1 /* EndOfLineSequence.CRLF */);
  228. }
  229. if (currentOptions
  230. && (currentOptions.detectIndentation === newOptions.detectIndentation)
  231. && (currentOptions.insertSpaces === newOptions.insertSpaces)
  232. && (currentOptions.tabSize === newOptions.tabSize)
  233. && (currentOptions.indentSize === newOptions.indentSize)
  234. && (currentOptions.trimAutoWhitespace === newOptions.trimAutoWhitespace)
  235. && equals(currentOptions.bracketPairColorizationOptions, newOptions.bracketPairColorizationOptions)) {
  236. // Same indent opts, no need to touch the model
  237. return;
  238. }
  239. if (newOptions.detectIndentation) {
  240. model.detectIndentation(newOptions.insertSpaces, newOptions.tabSize);
  241. model.updateOptions({
  242. trimAutoWhitespace: newOptions.trimAutoWhitespace,
  243. bracketColorizationOptions: newOptions.bracketPairColorizationOptions
  244. });
  245. }
  246. else {
  247. model.updateOptions({
  248. insertSpaces: newOptions.insertSpaces,
  249. tabSize: newOptions.tabSize,
  250. indentSize: newOptions.indentSize,
  251. trimAutoWhitespace: newOptions.trimAutoWhitespace,
  252. bracketColorizationOptions: newOptions.bracketPairColorizationOptions
  253. });
  254. }
  255. }
  256. // --- begin IModelService
  257. _insertDisposedModel(disposedModelData) {
  258. this._disposedModels.set(MODEL_ID(disposedModelData.uri), disposedModelData);
  259. this._disposedModelsHeapSize += disposedModelData.heapSize;
  260. }
  261. _removeDisposedModel(resource) {
  262. const disposedModelData = this._disposedModels.get(MODEL_ID(resource));
  263. if (disposedModelData) {
  264. this._disposedModelsHeapSize -= disposedModelData.heapSize;
  265. }
  266. this._disposedModels.delete(MODEL_ID(resource));
  267. return disposedModelData;
  268. }
  269. _ensureDisposedModelsHeapSize(maxModelsHeapSize) {
  270. if (this._disposedModelsHeapSize > maxModelsHeapSize) {
  271. // we must remove some old undo stack elements to free up some memory
  272. const disposedModels = [];
  273. this._disposedModels.forEach(entry => {
  274. if (!entry.sharesUndoRedoStack) {
  275. disposedModels.push(entry);
  276. }
  277. });
  278. disposedModels.sort((a, b) => a.time - b.time);
  279. while (disposedModels.length > 0 && this._disposedModelsHeapSize > maxModelsHeapSize) {
  280. const disposedModel = disposedModels.shift();
  281. this._removeDisposedModel(disposedModel.uri);
  282. if (disposedModel.initialUndoRedoSnapshot !== null) {
  283. this._undoRedoService.restoreSnapshot(disposedModel.initialUndoRedoSnapshot);
  284. }
  285. }
  286. }
  287. }
  288. _createModelData(value, languageId, resource, isForSimpleWidget) {
  289. // create & save the model
  290. const options = this.getCreationOptions(languageId, resource, isForSimpleWidget);
  291. const model = new TextModel(value, languageId, options, resource, this._undoRedoService, this._languageService, this._languageConfigurationService);
  292. if (resource && this._disposedModels.has(MODEL_ID(resource))) {
  293. const disposedModelData = this._removeDisposedModel(resource);
  294. const elements = this._undoRedoService.getElements(resource);
  295. const sha1IsEqual = (computeModelSha1(model) === disposedModelData.sha1);
  296. if (sha1IsEqual || disposedModelData.sharesUndoRedoStack) {
  297. for (const element of elements.past) {
  298. if (isEditStackElement(element) && element.matchesResource(resource)) {
  299. element.setModel(model);
  300. }
  301. }
  302. for (const element of elements.future) {
  303. if (isEditStackElement(element) && element.matchesResource(resource)) {
  304. element.setModel(model);
  305. }
  306. }
  307. this._undoRedoService.setElementsValidFlag(resource, true, (element) => (isEditStackElement(element) && element.matchesResource(resource)));
  308. if (sha1IsEqual) {
  309. model._overwriteVersionId(disposedModelData.versionId);
  310. model._overwriteAlternativeVersionId(disposedModelData.alternativeVersionId);
  311. model._overwriteInitialUndoRedoSnapshot(disposedModelData.initialUndoRedoSnapshot);
  312. }
  313. }
  314. else {
  315. if (disposedModelData.initialUndoRedoSnapshot !== null) {
  316. this._undoRedoService.restoreSnapshot(disposedModelData.initialUndoRedoSnapshot);
  317. }
  318. }
  319. }
  320. const modelId = MODEL_ID(model.uri);
  321. if (this._models[modelId]) {
  322. // There already exists a model with this id => this is a programmer error
  323. throw new Error('ModelService: Cannot add model because it already exists!');
  324. }
  325. const modelData = new ModelData(model, (model) => this._onWillDispose(model), (model, e) => this._onDidChangeLanguage(model, e));
  326. this._models[modelId] = modelData;
  327. return modelData;
  328. }
  329. createModel(value, languageSelection, resource, isForSimpleWidget = false) {
  330. let modelData;
  331. if (languageSelection) {
  332. modelData = this._createModelData(value, languageSelection.languageId, resource, isForSimpleWidget);
  333. this.setMode(modelData.model, languageSelection);
  334. }
  335. else {
  336. modelData = this._createModelData(value, PLAINTEXT_LANGUAGE_ID, resource, isForSimpleWidget);
  337. }
  338. this._onModelAdded.fire(modelData.model);
  339. return modelData.model;
  340. }
  341. setMode(model, languageSelection) {
  342. if (!languageSelection) {
  343. return;
  344. }
  345. const modelData = this._models[MODEL_ID(model.uri)];
  346. if (!modelData) {
  347. return;
  348. }
  349. modelData.setLanguage(languageSelection);
  350. }
  351. getModels() {
  352. const ret = [];
  353. const keys = Object.keys(this._models);
  354. for (let i = 0, len = keys.length; i < len; i++) {
  355. const modelId = keys[i];
  356. ret.push(this._models[modelId].model);
  357. }
  358. return ret;
  359. }
  360. getModel(resource) {
  361. const modelId = MODEL_ID(resource);
  362. const modelData = this._models[modelId];
  363. if (!modelData) {
  364. return null;
  365. }
  366. return modelData.model;
  367. }
  368. getSemanticTokensProviderStyling(provider) {
  369. return this._semanticStyling.get(provider);
  370. }
  371. // --- end IModelService
  372. _schemaShouldMaintainUndoRedoElements(resource) {
  373. return (resource.scheme === Schemas.file
  374. || resource.scheme === Schemas.vscodeRemote
  375. || resource.scheme === Schemas.vscodeUserData
  376. || resource.scheme === Schemas.vscodeNotebookCell
  377. || resource.scheme === 'fake-fs' // for tests
  378. );
  379. }
  380. _onWillDispose(model) {
  381. const modelId = MODEL_ID(model.uri);
  382. const modelData = this._models[modelId];
  383. const sharesUndoRedoStack = (this._undoRedoService.getUriComparisonKey(model.uri) !== model.uri.toString());
  384. let maintainUndoRedoStack = false;
  385. let heapSize = 0;
  386. if (sharesUndoRedoStack || (this._shouldRestoreUndoStack() && this._schemaShouldMaintainUndoRedoElements(model.uri))) {
  387. const elements = this._undoRedoService.getElements(model.uri);
  388. if (elements.past.length > 0 || elements.future.length > 0) {
  389. for (const element of elements.past) {
  390. if (isEditStackElement(element) && element.matchesResource(model.uri)) {
  391. maintainUndoRedoStack = true;
  392. heapSize += element.heapSize(model.uri);
  393. element.setModel(model.uri); // remove reference from text buffer instance
  394. }
  395. }
  396. for (const element of elements.future) {
  397. if (isEditStackElement(element) && element.matchesResource(model.uri)) {
  398. maintainUndoRedoStack = true;
  399. heapSize += element.heapSize(model.uri);
  400. element.setModel(model.uri); // remove reference from text buffer instance
  401. }
  402. }
  403. }
  404. }
  405. const maxMemory = ModelService.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK;
  406. if (!maintainUndoRedoStack) {
  407. if (!sharesUndoRedoStack) {
  408. const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
  409. if (initialUndoRedoSnapshot !== null) {
  410. this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
  411. }
  412. }
  413. }
  414. else if (!sharesUndoRedoStack && heapSize > maxMemory) {
  415. // the undo stack for this file would never fit in the configured memory, so don't bother with it.
  416. const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
  417. if (initialUndoRedoSnapshot !== null) {
  418. this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
  419. }
  420. }
  421. else {
  422. this._ensureDisposedModelsHeapSize(maxMemory - heapSize);
  423. // We only invalidate the elements, but they remain in the undo-redo service.
  424. this._undoRedoService.setElementsValidFlag(model.uri, false, (element) => (isEditStackElement(element) && element.matchesResource(model.uri)));
  425. this._insertDisposedModel(new DisposedModelInfo(model.uri, modelData.model.getInitialUndoRedoSnapshot(), Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
  426. }
  427. delete this._models[modelId];
  428. modelData.dispose();
  429. // clean up cache
  430. delete this._modelCreationOptionsByLanguageAndResource[model.getLanguageId() + model.uri];
  431. this._onModelRemoved.fire(model);
  432. }
  433. _onDidChangeLanguage(model, e) {
  434. const oldLanguageId = e.oldLanguage;
  435. const newLanguageId = model.getLanguageId();
  436. const oldOptions = this.getCreationOptions(oldLanguageId, model.uri, model.isForSimpleWidget);
  437. const newOptions = this.getCreationOptions(newLanguageId, model.uri, model.isForSimpleWidget);
  438. ModelService._setModelOptionsForModel(model, newOptions, oldOptions);
  439. this._onModelModeChanged.fire({ model, oldLanguageId: oldLanguageId });
  440. }
  441. };
  442. ModelService.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK = 20 * 1024 * 1024;
  443. ModelService = __decorate([
  444. __param(0, IConfigurationService),
  445. __param(1, ITextResourcePropertiesService),
  446. __param(2, IThemeService),
  447. __param(3, ILogService),
  448. __param(4, IUndoRedoService),
  449. __param(5, ILanguageService),
  450. __param(6, ILanguageConfigurationService),
  451. __param(7, ILanguageFeatureDebounceService),
  452. __param(8, ILanguageFeaturesService)
  453. ], ModelService);
  454. export { ModelService };
  455. export const SEMANTIC_HIGHLIGHTING_SETTING_ID = 'editor.semanticHighlighting';
  456. export function isSemanticColoringEnabled(model, themeService, configurationService) {
  457. var _a;
  458. const setting = (_a = configurationService.getValue(SEMANTIC_HIGHLIGHTING_SETTING_ID, { overrideIdentifier: model.getLanguageId(), resource: model.uri })) === null || _a === void 0 ? void 0 : _a.enabled;
  459. if (typeof setting === 'boolean') {
  460. return setting;
  461. }
  462. return themeService.getColorTheme().semanticHighlighting;
  463. }
  464. let SemanticColoringFeature = class SemanticColoringFeature extends Disposable {
  465. constructor(semanticStyling, modelService, themeService, configurationService, languageFeatureDebounceService, languageFeaturesService) {
  466. super();
  467. this._watchers = Object.create(null);
  468. this._semanticStyling = semanticStyling;
  469. const register = (model) => {
  470. this._watchers[model.uri.toString()] = new ModelSemanticColoring(model, this._semanticStyling, themeService, languageFeatureDebounceService, languageFeaturesService);
  471. };
  472. const deregister = (model, modelSemanticColoring) => {
  473. modelSemanticColoring.dispose();
  474. delete this._watchers[model.uri.toString()];
  475. };
  476. const handleSettingOrThemeChange = () => {
  477. for (const model of modelService.getModels()) {
  478. const curr = this._watchers[model.uri.toString()];
  479. if (isSemanticColoringEnabled(model, themeService, configurationService)) {
  480. if (!curr) {
  481. register(model);
  482. }
  483. }
  484. else {
  485. if (curr) {
  486. deregister(model, curr);
  487. }
  488. }
  489. }
  490. };
  491. this._register(modelService.onModelAdded((model) => {
  492. if (isSemanticColoringEnabled(model, themeService, configurationService)) {
  493. register(model);
  494. }
  495. }));
  496. this._register(modelService.onModelRemoved((model) => {
  497. const curr = this._watchers[model.uri.toString()];
  498. if (curr) {
  499. deregister(model, curr);
  500. }
  501. }));
  502. this._register(configurationService.onDidChangeConfiguration(e => {
  503. if (e.affectsConfiguration(SEMANTIC_HIGHLIGHTING_SETTING_ID)) {
  504. handleSettingOrThemeChange();
  505. }
  506. }));
  507. this._register(themeService.onDidColorThemeChange(handleSettingOrThemeChange));
  508. }
  509. dispose() {
  510. // Dispose all watchers
  511. for (const watcher of Object.values(this._watchers)) {
  512. watcher.dispose();
  513. }
  514. super.dispose();
  515. }
  516. };
  517. SemanticColoringFeature = __decorate([
  518. __param(1, IModelService),
  519. __param(2, IThemeService),
  520. __param(3, IConfigurationService),
  521. __param(4, ILanguageFeatureDebounceService),
  522. __param(5, ILanguageFeaturesService)
  523. ], SemanticColoringFeature);
  524. class SemanticStyling extends Disposable {
  525. constructor(_themeService, _languageService, _logService) {
  526. super();
  527. this._themeService = _themeService;
  528. this._languageService = _languageService;
  529. this._logService = _logService;
  530. this._caches = new WeakMap();
  531. this._register(this._themeService.onDidColorThemeChange(() => {
  532. this._caches = new WeakMap();
  533. }));
  534. }
  535. get(provider) {
  536. if (!this._caches.has(provider)) {
  537. this._caches.set(provider, new SemanticTokensProviderStyling(provider.getLegend(), this._themeService, this._languageService, this._logService));
  538. }
  539. return this._caches.get(provider);
  540. }
  541. }
  542. class SemanticTokensResponse {
  543. constructor(provider, resultId, data) {
  544. this.provider = provider;
  545. this.resultId = resultId;
  546. this.data = data;
  547. }
  548. dispose() {
  549. this.provider.releaseDocumentSemanticTokens(this.resultId);
  550. }
  551. }
  552. let ModelSemanticColoring = class ModelSemanticColoring extends Disposable {
  553. constructor(model, stylingProvider, themeService, languageFeatureDebounceService, languageFeaturesService) {
  554. super();
  555. this._isDisposed = false;
  556. this._model = model;
  557. this._semanticStyling = stylingProvider;
  558. this._provider = languageFeaturesService.documentSemanticTokensProvider;
  559. this._debounceInformation = languageFeatureDebounceService.for(this._provider, 'DocumentSemanticTokens', { min: ModelSemanticColoring.REQUEST_MIN_DELAY, max: ModelSemanticColoring.REQUEST_MAX_DELAY });
  560. this._fetchDocumentSemanticTokens = this._register(new RunOnceScheduler(() => this._fetchDocumentSemanticTokensNow(), ModelSemanticColoring.REQUEST_MIN_DELAY));
  561. this._currentDocumentResponse = null;
  562. this._currentDocumentRequestCancellationTokenSource = null;
  563. this._documentProvidersChangeListeners = [];
  564. this._register(this._model.onDidChangeContent(() => {
  565. if (!this._fetchDocumentSemanticTokens.isScheduled()) {
  566. this._fetchDocumentSemanticTokens.schedule(this._debounceInformation.get(this._model));
  567. }
  568. }));
  569. this._register(this._model.onDidChangeLanguage(() => {
  570. // clear any outstanding state
  571. if (this._currentDocumentResponse) {
  572. this._currentDocumentResponse.dispose();
  573. this._currentDocumentResponse = null;
  574. }
  575. if (this._currentDocumentRequestCancellationTokenSource) {
  576. this._currentDocumentRequestCancellationTokenSource.cancel();
  577. this._currentDocumentRequestCancellationTokenSource = null;
  578. }
  579. this._setDocumentSemanticTokens(null, null, null, []);
  580. this._fetchDocumentSemanticTokens.schedule(0);
  581. }));
  582. const bindDocumentChangeListeners = () => {
  583. dispose(this._documentProvidersChangeListeners);
  584. this._documentProvidersChangeListeners = [];
  585. for (const provider of this._provider.all(model)) {
  586. if (typeof provider.onDidChange === 'function') {
  587. this._documentProvidersChangeListeners.push(provider.onDidChange(() => this._fetchDocumentSemanticTokens.schedule(0)));
  588. }
  589. }
  590. };
  591. bindDocumentChangeListeners();
  592. this._register(this._provider.onDidChange(() => {
  593. bindDocumentChangeListeners();
  594. this._fetchDocumentSemanticTokens.schedule(this._debounceInformation.get(this._model));
  595. }));
  596. this._register(themeService.onDidColorThemeChange(_ => {
  597. // clear out existing tokens
  598. this._setDocumentSemanticTokens(null, null, null, []);
  599. this._fetchDocumentSemanticTokens.schedule(this._debounceInformation.get(this._model));
  600. }));
  601. this._fetchDocumentSemanticTokens.schedule(0);
  602. }
  603. dispose() {
  604. if (this._currentDocumentResponse) {
  605. this._currentDocumentResponse.dispose();
  606. this._currentDocumentResponse = null;
  607. }
  608. if (this._currentDocumentRequestCancellationTokenSource) {
  609. this._currentDocumentRequestCancellationTokenSource.cancel();
  610. this._currentDocumentRequestCancellationTokenSource = null;
  611. }
  612. this._setDocumentSemanticTokens(null, null, null, []);
  613. this._isDisposed = true;
  614. super.dispose();
  615. }
  616. _fetchDocumentSemanticTokensNow() {
  617. if (this._currentDocumentRequestCancellationTokenSource) {
  618. // there is already a request running, let it finish...
  619. return;
  620. }
  621. if (!hasDocumentSemanticTokensProvider(this._provider, this._model)) {
  622. // there is no provider
  623. if (this._currentDocumentResponse) {
  624. // there are semantic tokens set
  625. this._model.tokenization.setSemanticTokens(null, false);
  626. }
  627. return;
  628. }
  629. const cancellationTokenSource = new CancellationTokenSource();
  630. const lastProvider = this._currentDocumentResponse ? this._currentDocumentResponse.provider : null;
  631. const lastResultId = this._currentDocumentResponse ? this._currentDocumentResponse.resultId || null : null;
  632. const request = getDocumentSemanticTokens(this._provider, this._model, lastProvider, lastResultId, cancellationTokenSource.token);
  633. this._currentDocumentRequestCancellationTokenSource = cancellationTokenSource;
  634. const pendingChanges = [];
  635. const contentChangeListener = this._model.onDidChangeContent((e) => {
  636. pendingChanges.push(e);
  637. });
  638. const sw = new StopWatch(false);
  639. request.then((res) => {
  640. this._debounceInformation.update(this._model, sw.elapsed());
  641. this._currentDocumentRequestCancellationTokenSource = null;
  642. contentChangeListener.dispose();
  643. if (!res) {
  644. this._setDocumentSemanticTokens(null, null, null, pendingChanges);
  645. }
  646. else {
  647. const { provider, tokens } = res;
  648. const styling = this._semanticStyling.get(provider);
  649. this._setDocumentSemanticTokens(provider, tokens || null, styling, pendingChanges);
  650. }
  651. }, (err) => {
  652. const isExpectedError = err && (errors.isCancellationError(err) || (typeof err.message === 'string' && err.message.indexOf('busy') !== -1));
  653. if (!isExpectedError) {
  654. errors.onUnexpectedError(err);
  655. }
  656. // Semantic tokens eats up all errors and considers errors to mean that the result is temporarily not available
  657. // The API does not have a special error kind to express this...
  658. this._currentDocumentRequestCancellationTokenSource = null;
  659. contentChangeListener.dispose();
  660. if (pendingChanges.length > 0) {
  661. // More changes occurred while the request was running
  662. if (!this._fetchDocumentSemanticTokens.isScheduled()) {
  663. this._fetchDocumentSemanticTokens.schedule(this._debounceInformation.get(this._model));
  664. }
  665. }
  666. });
  667. }
  668. static _copy(src, srcOffset, dest, destOffset, length) {
  669. // protect against overflows
  670. length = Math.min(length, dest.length - destOffset, src.length - srcOffset);
  671. for (let i = 0; i < length; i++) {
  672. dest[destOffset + i] = src[srcOffset + i];
  673. }
  674. }
  675. _setDocumentSemanticTokens(provider, tokens, styling, pendingChanges) {
  676. const currentResponse = this._currentDocumentResponse;
  677. const rescheduleIfNeeded = () => {
  678. if (pendingChanges.length > 0 && !this._fetchDocumentSemanticTokens.isScheduled()) {
  679. this._fetchDocumentSemanticTokens.schedule(this._debounceInformation.get(this._model));
  680. }
  681. };
  682. if (this._currentDocumentResponse) {
  683. this._currentDocumentResponse.dispose();
  684. this._currentDocumentResponse = null;
  685. }
  686. if (this._isDisposed) {
  687. // disposed!
  688. if (provider && tokens) {
  689. provider.releaseDocumentSemanticTokens(tokens.resultId);
  690. }
  691. return;
  692. }
  693. if (!provider || !styling) {
  694. this._model.tokenization.setSemanticTokens(null, false);
  695. return;
  696. }
  697. if (!tokens) {
  698. this._model.tokenization.setSemanticTokens(null, true);
  699. rescheduleIfNeeded();
  700. return;
  701. }
  702. if (isSemanticTokensEdits(tokens)) {
  703. if (!currentResponse) {
  704. // not possible!
  705. this._model.tokenization.setSemanticTokens(null, true);
  706. return;
  707. }
  708. if (tokens.edits.length === 0) {
  709. // nothing to do!
  710. tokens = {
  711. resultId: tokens.resultId,
  712. data: currentResponse.data
  713. };
  714. }
  715. else {
  716. let deltaLength = 0;
  717. for (const edit of tokens.edits) {
  718. deltaLength += (edit.data ? edit.data.length : 0) - edit.deleteCount;
  719. }
  720. const srcData = currentResponse.data;
  721. const destData = new Uint32Array(srcData.length + deltaLength);
  722. let srcLastStart = srcData.length;
  723. let destLastStart = destData.length;
  724. for (let i = tokens.edits.length - 1; i >= 0; i--) {
  725. const edit = tokens.edits[i];
  726. if (edit.start > srcData.length) {
  727. styling.warnInvalidEditStart(currentResponse.resultId, tokens.resultId, i, edit.start, srcData.length);
  728. // The edits are invalid and there's no way to recover
  729. this._model.tokenization.setSemanticTokens(null, true);
  730. return;
  731. }
  732. const copyCount = srcLastStart - (edit.start + edit.deleteCount);
  733. if (copyCount > 0) {
  734. ModelSemanticColoring._copy(srcData, srcLastStart - copyCount, destData, destLastStart - copyCount, copyCount);
  735. destLastStart -= copyCount;
  736. }
  737. if (edit.data) {
  738. ModelSemanticColoring._copy(edit.data, 0, destData, destLastStart - edit.data.length, edit.data.length);
  739. destLastStart -= edit.data.length;
  740. }
  741. srcLastStart = edit.start;
  742. }
  743. if (srcLastStart > 0) {
  744. ModelSemanticColoring._copy(srcData, 0, destData, 0, srcLastStart);
  745. }
  746. tokens = {
  747. resultId: tokens.resultId,
  748. data: destData
  749. };
  750. }
  751. }
  752. if (isSemanticTokens(tokens)) {
  753. this._currentDocumentResponse = new SemanticTokensResponse(provider, tokens.resultId, tokens.data);
  754. const result = toMultilineTokens2(tokens, styling, this._model.getLanguageId());
  755. // Adjust incoming semantic tokens
  756. if (pendingChanges.length > 0) {
  757. // More changes occurred while the request was running
  758. // We need to:
  759. // 1. Adjust incoming semantic tokens
  760. // 2. Request them again
  761. for (const change of pendingChanges) {
  762. for (const area of result) {
  763. for (const singleChange of change.changes) {
  764. area.applyEdit(singleChange.range, singleChange.text);
  765. }
  766. }
  767. }
  768. }
  769. this._model.tokenization.setSemanticTokens(result, true);
  770. }
  771. else {
  772. this._model.tokenization.setSemanticTokens(null, true);
  773. }
  774. rescheduleIfNeeded();
  775. }
  776. };
  777. ModelSemanticColoring.REQUEST_MIN_DELAY = 300;
  778. ModelSemanticColoring.REQUEST_MAX_DELAY = 2000;
  779. ModelSemanticColoring = __decorate([
  780. __param(2, IThemeService),
  781. __param(3, ILanguageFeatureDebounceService),
  782. __param(4, ILanguageFeaturesService)
  783. ], ModelSemanticColoring);
  784. export { ModelSemanticColoring };