text: /*---------------------------------------------------------------------------------------------
   *  Copyright (c) Microsoft Corporation. All rights reserved.
   *  Licensed under the MIT License. See License.txt in the project root for license information.
   *--------------------------------------------------------------------------------------------*/
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
      var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
      if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
      else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
      return c > 3 && r && Object.defineProperty(target, key, r), r;
  };
  var __param = (this && this.__param) || function (paramIndex, decorator) {
      return function (target, key) { decorator(target, key, paramIndex); }
  };
  import { Emitter } from '../../../base/common/event';
  import { Disposable, DisposableStore, dispose } from '../../../base/common/lifecycle';
  import * as platform from '../../../base/common/platform';
  import * as errors from '../../../base/common/errors';
  import { EDITOR_MODEL_DEFAULTS } from '../config/editorOptions';
  import { TextModel } from '../model/textModel';
  import { DocumentSemanticTokensProviderRegistry } from '../modes';
  import { PLAINTEXT_LANGUAGE_IDENTIFIER } from '../modes/modesRegistry';
  import { ITextResourcePropertiesService } from './textResourceConfigurationService';
  import { IConfigurationService } from '../../../platform/configuration/common/configuration';
  import { RunOnceScheduler } from '../../../base/common/async';
  import { CancellationTokenSource } from '../../../base/common/cancellation';
  import { IThemeService } from '../../../platform/theme/common/themeService';
  import { ILogService } from '../../../platform/log/common/log';
  import { IUndoRedoService } from '../../../platform/undoRedo/common/undoRedo';
  import { StringSHA1 } from '../../../base/common/hash';
  import { isEditStackElement } from '../model/editStack';
  import { Schemas } from '../../../base/common/network';
  import { SemanticTokensProviderStyling, toMultilineTokens2 } from './semanticTokensProviderStyling';
  import { getDocumentSemanticTokens, isSemanticTokens, isSemanticTokensEdits } from './getSemanticTokens';
  function MODEL_ID(resource) {
      return resource.toString();
  }
  function computeModelSha1(model) {
      // compute the sha1
      const shaComputer = new StringSHA1();
      const snapshot = model.createSnapshot();
      let text;
      while ((text = snapshot.read())) {
          shaComputer.update(text);
      }
      return shaComputer.digest();
  }
  class ModelData {
      constructor(model, onWillDispose, onDidChangeLanguage) {
          this._modelEventListeners = new DisposableStore();
          this.model = model;
          this._languageSelection = null;
          this._languageSelectionListener = null;
          this._modelEventListeners.add(model.onWillDispose(() => onWillDispose(model)));
          this._modelEventListeners.add(model.onDidChangeLanguage((e) => onDidChangeLanguage(model, e)));
      }
      _disposeLanguageSelection() {
          if (this._languageSelectionListener) {
              this._languageSelectionListener.dispose();
              this._languageSelectionListener = null;
          }
      }
      dispose() {
          this._modelEventListeners.dispose();
          this._disposeLanguageSelection();
      }
      setLanguage(languageSelection) {
          this._disposeLanguageSelection();
          this._languageSelection = languageSelection;
          this._languageSelectionListener = this._languageSelection.onDidChange(() => this.model.setMode(languageSelection.languageIdentifier));
          this.model.setMode(languageSelection.languageIdentifier);
      }
  }
  const DEFAULT_EOL = (platform.isLinux || platform.isMacintosh) ? 1 /* LF */ : 2 /* CRLF */;
  class DisposedModelInfo {
      constructor(uri, initialUndoRedoSnapshot, time, sharesUndoRedoStack, heapSize, sha1, versionId, alternativeVersionId) {
          this.uri = uri;
          this.initialUndoRedoSnapshot = initialUndoRedoSnapshot;
          this.time = time;
          this.sharesUndoRedoStack = sharesUndoRedoStack;
          this.heapSize = heapSize;
          this.sha1 = sha1;
          this.versionId = versionId;
          this.alternativeVersionId = alternativeVersionId;
      }
  }
  function schemaShouldMaintainUndoRedoElements(resource) {
      return (resource.scheme === Schemas.file
          || resource.scheme === Schemas.vscodeRemote
          || resource.scheme === Schemas.userData
          || resource.scheme === 'fake-fs' // for tests
      );
  }
  let ModelServiceImpl = class ModelServiceImpl extends Disposable {
      constructor(_configurationService, _resourcePropertiesService, _themeService, _logService, _undoRedoService) {
          super();
          this._configurationService = _configurationService;
          this._resourcePropertiesService = _resourcePropertiesService;
          this._themeService = _themeService;
          this._logService = _logService;
          this._undoRedoService = _undoRedoService;
          this._onModelAdded = this._register(new Emitter());
          this.onModelAdded = this._onModelAdded.event;
          this._onModelRemoved = this._register(new Emitter());
          this.onModelRemoved = this._onModelRemoved.event;
          this._onModelModeChanged = this._register(new Emitter());
          this.onModelModeChanged = this._onModelModeChanged.event;
          this._modelCreationOptionsByLanguageAndResource = Object.create(null);
          this._models = {};
          this._disposedModels = new Map();
          this._disposedModelsHeapSize = 0;
          this._semanticStyling = this._register(new SemanticStyling(this._themeService, this._logService));
          this._register(this._configurationService.onDidChangeConfiguration(() => this._updateModelOptions()));
          this._updateModelOptions();
          this._register(new SemanticColoringFeature(this, this._themeService, this._configurationService, this._semanticStyling));
      }
      static _readModelOptions(config, isForSimpleWidget) {
          let tabSize = EDITOR_MODEL_DEFAULTS.tabSize;
          if (config.editor && typeof config.editor.tabSize !== 'undefined') {
              const parsedTabSize = parseInt(config.editor.tabSize, 10);
              if (!isNaN(parsedTabSize)) {
                  tabSize = parsedTabSize;
              }
              if (tabSize < 1) {
                  tabSize = 1;
              }
          }
          let indentSize = tabSize;
          if (config.editor && typeof config.editor.indentSize !== 'undefined' && config.editor.indentSize !== 'tabSize') {
              const parsedIndentSize = parseInt(config.editor.indentSize, 10);
              if (!isNaN(parsedIndentSize)) {
                  indentSize = parsedIndentSize;
              }
              if (indentSize < 1) {
                  indentSize = 1;
              }
          }
          let insertSpaces = EDITOR_MODEL_DEFAULTS.insertSpaces;
          if (config.editor && typeof config.editor.insertSpaces !== 'undefined') {
              insertSpaces = (config.editor.insertSpaces === 'false' ? false : Boolean(config.editor.insertSpaces));
          }
          let newDefaultEOL = DEFAULT_EOL;
          const eol = config.eol;
          if (eol === '\r\n') {
              newDefaultEOL = 2 /* CRLF */;
          }
          else if (eol === '\n') {
              newDefaultEOL = 1 /* LF */;
          }
          let trimAutoWhitespace = EDITOR_MODEL_DEFAULTS.trimAutoWhitespace;
          if (config.editor && typeof config.editor.trimAutoWhitespace !== 'undefined') {
              trimAutoWhitespace = (config.editor.trimAutoWhitespace === 'false' ? false : Boolean(config.editor.trimAutoWhitespace));
          }
          let detectIndentation = EDITOR_MODEL_DEFAULTS.detectIndentation;
          if (config.editor && typeof config.editor.detectIndentation !== 'undefined') {
              detectIndentation = (config.editor.detectIndentation === 'false' ? false : Boolean(config.editor.detectIndentation));
          }
          let largeFileOptimizations = EDITOR_MODEL_DEFAULTS.largeFileOptimizations;
          if (config.editor && typeof config.editor.largeFileOptimizations !== 'undefined') {
              largeFileOptimizations = (config.editor.largeFileOptimizations === 'false' ? false : Boolean(config.editor.largeFileOptimizations));
          }
          return {
              isForSimpleWidget: isForSimpleWidget,
              tabSize: tabSize,
              indentSize: indentSize,
              insertSpaces: insertSpaces,
              detectIndentation: detectIndentation,
              defaultEOL: newDefaultEOL,
              trimAutoWhitespace: trimAutoWhitespace,
              largeFileOptimizations: largeFileOptimizations
          };
      }
      _getEOL(resource, language) {
          if (resource) {
              return this._resourcePropertiesService.getEOL(resource, language);
          }
          const eol = this._configurationService.getValue('files.eol', { overrideIdentifier: language });
          if (eol && eol !== 'auto') {
              return eol;
          }
          return platform.OS === 3 /* Linux */ || platform.OS === 2 /* Macintosh */ ? '\n' : '\r\n';
      }
      _shouldRestoreUndoStack() {
          const result = this._configurationService.getValue('files.restoreUndoStack');
          if (typeof result === 'boolean') {
              return result;
          }
          return true;
      }
      getCreationOptions(language, resource, isForSimpleWidget) {
          let creationOptions = this._modelCreationOptionsByLanguageAndResource[language + resource];
          if (!creationOptions) {
              const editor = this._configurationService.getValue('editor', { overrideIdentifier: language, resource });
              const eol = this._getEOL(resource, language);
              creationOptions = ModelServiceImpl._readModelOptions({ editor, eol }, isForSimpleWidget);
              this._modelCreationOptionsByLanguageAndResource[language + resource] = creationOptions;
          }
          return creationOptions;
      }
      _updateModelOptions() {
          const oldOptionsByLanguageAndResource = this._modelCreationOptionsByLanguageAndResource;
          this._modelCreationOptionsByLanguageAndResource = Object.create(null);
          // Update options on all models
          const keys = Object.keys(this._models);
          for (let i = 0, len = keys.length; i < len; i++) {
              const modelId = keys[i];
              const modelData = this._models[modelId];
              const language = modelData.model.getLanguageIdentifier().language;
              const uri = modelData.model.uri;
              const oldOptions = oldOptionsByLanguageAndResource[language + uri];
              const newOptions = this.getCreationOptions(language, uri, modelData.model.isForSimpleWidget);
              ModelServiceImpl._setModelOptionsForModel(modelData.model, newOptions, oldOptions);
          }
      }
      static _setModelOptionsForModel(model, newOptions, currentOptions) {
          if (currentOptions && currentOptions.defaultEOL !== newOptions.defaultEOL && model.getLineCount() === 1) {
              model.setEOL(newOptions.defaultEOL === 1 /* LF */ ? 0 /* LF */ : 1 /* CRLF */);
          }
          if (currentOptions
              && (currentOptions.detectIndentation === newOptions.detectIndentation)
              && (currentOptions.insertSpaces === newOptions.insertSpaces)
              && (currentOptions.tabSize === newOptions.tabSize)
              && (currentOptions.indentSize === newOptions.indentSize)
              && (currentOptions.trimAutoWhitespace === newOptions.trimAutoWhitespace)) {
              // Same indent opts, no need to touch the model
              return;
          }
          if (newOptions.detectIndentation) {
              model.detectIndentation(newOptions.insertSpaces, newOptions.tabSize);
              model.updateOptions({
                  trimAutoWhitespace: newOptions.trimAutoWhitespace
              });
          }
          else {
              model.updateOptions({
                  insertSpaces: newOptions.insertSpaces,
                  tabSize: newOptions.tabSize,
                  indentSize: newOptions.indentSize,
                  trimAutoWhitespace: newOptions.trimAutoWhitespace
              });
          }
      }
      // --- begin IModelService
      _insertDisposedModel(disposedModelData) {
          this._disposedModels.set(MODEL_ID(disposedModelData.uri), disposedModelData);
          this._disposedModelsHeapSize += disposedModelData.heapSize;
      }
      _removeDisposedModel(resource) {
          const disposedModelData = this._disposedModels.get(MODEL_ID(resource));
          if (disposedModelData) {
              this._disposedModelsHeapSize -= disposedModelData.heapSize;
          }
          this._disposedModels.delete(MODEL_ID(resource));
          return disposedModelData;
      }
      _ensureDisposedModelsHeapSize(maxModelsHeapSize) {
          if (this._disposedModelsHeapSize > maxModelsHeapSize) {
              // we must remove some old undo stack elements to free up some memory
              const disposedModels = [];
              this._disposedModels.forEach(entry => {
                  if (!entry.sharesUndoRedoStack) {
                      disposedModels.push(entry);
                  }
              });
              disposedModels.sort((a, b) => a.time - b.time);
              while (disposedModels.length > 0 && this._disposedModelsHeapSize > maxModelsHeapSize) {
                  const disposedModel = disposedModels.shift();
                  this._removeDisposedModel(disposedModel.uri);
                  if (disposedModel.initialUndoRedoSnapshot !== null) {
                      this._undoRedoService.restoreSnapshot(disposedModel.initialUndoRedoSnapshot);
                  }
              }
          }
      }
      _createModelData(value, languageIdentifier, resource, isForSimpleWidget) {
          // create & save the model
          const options = this.getCreationOptions(languageIdentifier.language, resource, isForSimpleWidget);
          const model = new TextModel(value, options, languageIdentifier, resource, this._undoRedoService);
          if (resource && this._disposedModels.has(MODEL_ID(resource))) {
              const disposedModelData = this._removeDisposedModel(resource);
              const elements = this._undoRedoService.getElements(resource);
              const sha1IsEqual = (computeModelSha1(model) === disposedModelData.sha1);
              if (sha1IsEqual || disposedModelData.sharesUndoRedoStack) {
                  for (const element of elements.past) {
                      if (isEditStackElement(element) && element.matchesResource(resource)) {
                          element.setModel(model);
                      }
                  }
                  for (const element of elements.future) {
                      if (isEditStackElement(element) && element.matchesResource(resource)) {
                          element.setModel(model);
                      }
                  }
                  this._undoRedoService.setElementsValidFlag(resource, true, (element) => (isEditStackElement(element) && element.matchesResource(resource)));
                  if (sha1IsEqual) {
                      model._overwriteVersionId(disposedModelData.versionId);
                      model._overwriteAlternativeVersionId(disposedModelData.alternativeVersionId);
                      model._overwriteInitialUndoRedoSnapshot(disposedModelData.initialUndoRedoSnapshot);
                  }
              }
              else {
                  if (disposedModelData.initialUndoRedoSnapshot !== null) {
                      this._undoRedoService.restoreSnapshot(disposedModelData.initialUndoRedoSnapshot);
                  }
              }
          }
          const modelId = MODEL_ID(model.uri);
          if (this._models[modelId]) {
              // There already exists a model with this id => this is a programmer error
              throw new Error('ModelService: Cannot add model because it already exists!');
          }
          const modelData = new ModelData(model, (model) => this._onWillDispose(model), (model, e) => this._onDidChangeLanguage(model, e));
          this._models[modelId] = modelData;
          return modelData;
      }
      createModel(value, languageSelection, resource, isForSimpleWidget = false) {
          let modelData;
          if (languageSelection) {
              modelData = this._createModelData(value, languageSelection.languageIdentifier, resource, isForSimpleWidget);
              this.setMode(modelData.model, languageSelection);
          }
          else {
              modelData = this._createModelData(value, PLAINTEXT_LANGUAGE_IDENTIFIER, resource, isForSimpleWidget);
          }
          this._onModelAdded.fire(modelData.model);
          return modelData.model;
      }
      setMode(model, languageSelection) {
          if (!languageSelection) {
              return;
          }
          const modelData = this._models[MODEL_ID(model.uri)];
          if (!modelData) {
              return;
          }
          modelData.setLanguage(languageSelection);
      }
      getModels() {
          const ret = [];
          const keys = Object.keys(this._models);
          for (let i = 0, len = keys.length; i < len; i++) {
              const modelId = keys[i];
              ret.push(this._models[modelId].model);
          }
          return ret;
      }
      getModel(resource) {
          const modelId = MODEL_ID(resource);
          const modelData = this._models[modelId];
          if (!modelData) {
              return null;
          }
          return modelData.model;
      }
      getSemanticTokensProviderStyling(provider) {
          return this._semanticStyling.get(provider);
      }
      // --- end IModelService
      _onWillDispose(model) {
          const modelId = MODEL_ID(model.uri);
          const modelData = this._models[modelId];
          const sharesUndoRedoStack = (this._undoRedoService.getUriComparisonKey(model.uri) !== model.uri.toString());
          let maintainUndoRedoStack = false;
          let heapSize = 0;
          if (sharesUndoRedoStack || (this._shouldRestoreUndoStack() && schemaShouldMaintainUndoRedoElements(model.uri))) {
              const elements = this._undoRedoService.getElements(model.uri);
              if (elements.past.length > 0 || elements.future.length > 0) {
                  for (const element of elements.past) {
                      if (isEditStackElement(element) && element.matchesResource(model.uri)) {
                          maintainUndoRedoStack = true;
                          heapSize += element.heapSize(model.uri);
                          element.setModel(model.uri); // remove reference from text buffer instance
                      }
                  }
                  for (const element of elements.future) {
                      if (isEditStackElement(element) && element.matchesResource(model.uri)) {
                          maintainUndoRedoStack = true;
                          heapSize += element.heapSize(model.uri);
                          element.setModel(model.uri); // remove reference from text buffer instance
                      }
                  }
              }
          }
          const maxMemory = ModelServiceImpl.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK;
          if (!maintainUndoRedoStack) {
              if (!sharesUndoRedoStack) {
                  const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
                  if (initialUndoRedoSnapshot !== null) {
                      this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
                  }
              }
          }
          else if (!sharesUndoRedoStack && heapSize > maxMemory) {
              // the undo stack for this file would never fit in the configured memory, so don't bother with it.
              const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
              if (initialUndoRedoSnapshot !== null) {
                  this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
              }
          }
          else {
              this._ensureDisposedModelsHeapSize(maxMemory - heapSize);
              // We only invalidate the elements, but they remain in the undo-redo service.
              this._undoRedoService.setElementsValidFlag(model.uri, false, (element) => (isEditStackElement(element) && element.matchesResource(model.uri)));
              this._insertDisposedModel(new DisposedModelInfo(model.uri, modelData.model.getInitialUndoRedoSnapshot(), Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model), model.getVersionId(), model.getAlternativeVersionId()));
          }
          delete this._models[modelId];
          modelData.dispose();
          // clean up cache
          delete this._modelCreationOptionsByLanguageAndResource[model.getLanguageIdentifier().language + model.uri];
          this._onModelRemoved.fire(model);
      }
      _onDidChangeLanguage(model, e) {
          const oldModeId = e.oldLanguage;
          const newModeId = model.getLanguageIdentifier().language;
          const oldOptions = this.getCreationOptions(oldModeId, model.uri, model.isForSimpleWidget);
          const newOptions = this.getCreationOptions(newModeId, model.uri, model.isForSimpleWidget);
          ModelServiceImpl._setModelOptionsForModel(model, newOptions, oldOptions);
          this._onModelModeChanged.fire({ model, oldModeId });
      }
  };
  ModelServiceImpl.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK = 20 * 1024 * 1024;
  ModelServiceImpl = __decorate([
      __param(0, IConfigurationService),
      __param(1, ITextResourcePropertiesService),
      __param(2, IThemeService),
      __param(3, ILogService),
      __param(4, IUndoRedoService)
  ], ModelServiceImpl);
  export { ModelServiceImpl };
  export const SEMANTIC_HIGHLIGHTING_SETTING_ID = 'editor.semanticHighlighting';
  export function isSemanticColoringEnabled(model, themeService, configurationService) {
      var _a;
      const setting = (_a = configurationService.getValue(SEMANTIC_HIGHLIGHTING_SETTING_ID, { overrideIdentifier: model.getLanguageIdentifier().language, resource: model.uri })) === null || _a === void 0 ? void 0 : _a.enabled;
      if (typeof setting === 'boolean') {
          return setting;
      }
      return themeService.getColorTheme().semanticHighlighting;
  }
  class SemanticColoringFeature extends Disposable {
      constructor(modelService, themeService, configurationService, semanticStyling) {
          super();
          this._watchers = Object.create(null);
          this._semanticStyling = semanticStyling;
          const register = (model) => {
              this._watchers[model.uri.toString()] = new ModelSemanticColoring(model, themeService, this._semanticStyling);
          };
          const deregister = (model, modelSemanticColoring) => {
              modelSemanticColoring.dispose();
              delete this._watchers[model.uri.toString()];
          };
          const handleSettingOrThemeChange = () => {
              for (let model of modelService.getModels()) {
                  const curr = this._watchers[model.uri.toString()];
                  if (isSemanticColoringEnabled(model, themeService, configurationService)) {
                      if (!curr) {
                          register(model);
                      }
                  }
                  else {
                      if (curr) {
                          deregister(model, curr);
                      }
                  }
              }
          };
          this._register(modelService.onModelAdded((model) => {
              if (isSemanticColoringEnabled(model, themeService, configurationService)) {
                  register(model);
              }
          }));
          this._register(modelService.onModelRemoved((model) => {
              const curr = this._watchers[model.uri.toString()];
              if (curr) {
                  deregister(model, curr);
              }
          }));
          this._register(configurationService.onDidChangeConfiguration(e => {
              if (e.affectsConfiguration(SEMANTIC_HIGHLIGHTING_SETTING_ID)) {
                  handleSettingOrThemeChange();
              }
          }));
          this._register(themeService.onDidColorThemeChange(handleSettingOrThemeChange));
      }
  }
  class SemanticStyling extends Disposable {
      constructor(_themeService, _logService) {
          super();
          this._themeService = _themeService;
          this._logService = _logService;
          this._caches = new WeakMap();
          this._register(this._themeService.onDidColorThemeChange(() => {
              this._caches = new WeakMap();
          }));
      }
      get(provider) {
          if (!this._caches.has(provider)) {
              this._caches.set(provider, new SemanticTokensProviderStyling(provider.getLegend(), this._themeService, this._logService));
          }
          return this._caches.get(provider);
      }
  }
  class SemanticTokensResponse {
      constructor(_provider, resultId, data) {
          this._provider = _provider;
          this.resultId = resultId;
          this.data = data;
      }
      dispose() {
          this._provider.releaseDocumentSemanticTokens(this.resultId);
      }
  }
  export class ModelSemanticColoring extends Disposable {
      constructor(model, themeService, stylingProvider) {
          super();
          this._isDisposed = false;
          this._model = model;
          this._semanticStyling = stylingProvider;
          this._fetchDocumentSemanticTokens = this._register(new RunOnceScheduler(() => this._fetchDocumentSemanticTokensNow(), ModelSemanticColoring.FETCH_DOCUMENT_SEMANTIC_TOKENS_DELAY));
          this._currentDocumentResponse = null;
          this._currentDocumentRequestCancellationTokenSource = null;
          this._documentProvidersChangeListeners = [];
          this._register(this._model.onDidChangeContent(() => {
              if (!this._fetchDocumentSemanticTokens.isScheduled()) {
                  this._fetchDocumentSemanticTokens.schedule();
              }
          }));
          this._register(this._model.onDidChangeLanguage(() => {
              // clear any outstanding state
              if (this._currentDocumentResponse) {
                  this._currentDocumentResponse.dispose();
                  this._currentDocumentResponse = null;
              }
              if (this._currentDocumentRequestCancellationTokenSource) {
                  this._currentDocumentRequestCancellationTokenSource.cancel();
                  this._currentDocumentRequestCancellationTokenSource = null;
              }
              this._setDocumentSemanticTokens(null, null, null, []);
              this._fetchDocumentSemanticTokens.schedule(0);
          }));
          const bindDocumentChangeListeners = () => {
              dispose(this._documentProvidersChangeListeners);
              this._documentProvidersChangeListeners = [];
              for (const provider of DocumentSemanticTokensProviderRegistry.all(model)) {
                  if (typeof provider.onDidChange === 'function') {
                      this._documentProvidersChangeListeners.push(provider.onDidChange(() => this._fetchDocumentSemanticTokens.schedule(0)));
                  }
              }
          };
          bindDocumentChangeListeners();
          this._register(DocumentSemanticTokensProviderRegistry.onDidChange(() => {
              bindDocumentChangeListeners();
              this._fetchDocumentSemanticTokens.schedule();
          }));
          this._register(themeService.onDidColorThemeChange(_ => {
              // clear out existing tokens
              this._setDocumentSemanticTokens(null, null, null, []);
              this._fetchDocumentSemanticTokens.schedule();
          }));
          this._fetchDocumentSemanticTokens.schedule(0);
      }
      dispose() {
          if (this._currentDocumentResponse) {
              this._currentDocumentResponse.dispose();
              this._currentDocumentResponse = null;
          }
          if (this._currentDocumentRequestCancellationTokenSource) {
              this._currentDocumentRequestCancellationTokenSource.cancel();
              this._currentDocumentRequestCancellationTokenSource = null;
          }
          this._setDocumentSemanticTokens(null, null, null, []);
          this._isDisposed = true;
          super.dispose();
      }
      _fetchDocumentSemanticTokensNow() {
          if (this._currentDocumentRequestCancellationTokenSource) {
              // there is already a request running, let it finish...
              return;
          }
          const cancellationTokenSource = new CancellationTokenSource();
          const lastResultId = this._currentDocumentResponse ? this._currentDocumentResponse.resultId || null : null;
          const r = getDocumentSemanticTokens(this._model, lastResultId, cancellationTokenSource.token);
          if (!r) {
              // there is no provider
              if (this._currentDocumentResponse) {
                  // there are semantic tokens set
                  this._model.setSemanticTokens(null, false);
              }
              return;
          }
          const { provider, request } = r;
          this._currentDocumentRequestCancellationTokenSource = cancellationTokenSource;
          const pendingChanges = [];
          const contentChangeListener = this._model.onDidChangeContent((e) => {
              pendingChanges.push(e);
          });
          const styling = this._semanticStyling.get(provider);
          request.then((res) => {
              this._currentDocumentRequestCancellationTokenSource = null;
              contentChangeListener.dispose();
              this._setDocumentSemanticTokens(provider, res || null, styling, pendingChanges);
          }, (err) => {
              const isExpectedError = err && (errors.isPromiseCanceledError(err) || (typeof err.message === 'string' && err.message.indexOf('busy') !== -1));
              if (!isExpectedError) {
                  errors.onUnexpectedError(err);
              }
              // Semantic tokens eats up all errors and considers errors to mean that the result is temporarily not available
              // The API does not have a special error kind to express this...
              this._currentDocumentRequestCancellationTokenSource = null;
              contentChangeListener.dispose();
              if (pendingChanges.length > 0) {
                  // More changes occurred while the request was running
                  if (!this._fetchDocumentSemanticTokens.isScheduled()) {
                      this._fetchDocumentSemanticTokens.schedule();
                  }
              }
          });
      }
      static _copy(src, srcOffset, dest, destOffset, length) {
          for (let i = 0; i < length; i++) {
              dest[destOffset + i] = src[srcOffset + i];
          }
      }
      _setDocumentSemanticTokens(provider, tokens, styling, pendingChanges) {
          const currentResponse = this._currentDocumentResponse;
          const rescheduleIfNeeded = () => {
              if (pendingChanges.length > 0 && !this._fetchDocumentSemanticTokens.isScheduled()) {
                  this._fetchDocumentSemanticTokens.schedule();
              }
          };
          if (this._currentDocumentResponse) {
              this._currentDocumentResponse.dispose();
              this._currentDocumentResponse = null;
          }
          if (this._isDisposed) {
              // disposed!
              if (provider && tokens) {
                  provider.releaseDocumentSemanticTokens(tokens.resultId);
              }
              return;
          }
          if (!provider || !styling) {
              this._model.setSemanticTokens(null, false);
              return;
          }
          if (!tokens) {
              this._model.setSemanticTokens(null, true);
              rescheduleIfNeeded();
              return;
          }
          if (isSemanticTokensEdits(tokens)) {
              if (!currentResponse) {
                  // not possible!
                  this._model.setSemanticTokens(null, true);
                  return;
              }
              if (tokens.edits.length === 0) {
                  // nothing to do!
                  tokens = {
                      resultId: tokens.resultId,
                      data: currentResponse.data
                  };
              }
              else {
                  let deltaLength = 0;
                  for (const edit of tokens.edits) {
                      deltaLength += (edit.data ? edit.data.length : 0) - edit.deleteCount;
                  }
                  const srcData = currentResponse.data;
                  const destData = new Uint32Array(srcData.length + deltaLength);
                  let srcLastStart = srcData.length;
                  let destLastStart = destData.length;
                  for (let i = tokens.edits.length - 1; i >= 0; i--) {
                      const edit = tokens.edits[i];
                      const copyCount = srcLastStart - (edit.start + edit.deleteCount);
                      if (copyCount > 0) {
                          ModelSemanticColoring._copy(srcData, srcLastStart - copyCount, destData, destLastStart - copyCount, copyCount);
                          destLastStart -= copyCount;
                      }
                      if (edit.data) {
                          ModelSemanticColoring._copy(edit.data, 0, destData, destLastStart - edit.data.length, edit.data.length);
                          destLastStart -= edit.data.length;
                      }
                      srcLastStart = edit.start;
                  }
                  if (srcLastStart > 0) {
                      ModelSemanticColoring._copy(srcData, 0, destData, 0, srcLastStart);
                  }
                  tokens = {
                      resultId: tokens.resultId,
                      data: destData
                  };
              }
          }
          if (isSemanticTokens(tokens)) {
              this._currentDocumentResponse = new SemanticTokensResponse(provider, tokens.resultId, tokens.data);
              const result = toMultilineTokens2(tokens, styling, this._model.getLanguageIdentifier());
              // Adjust incoming semantic tokens
              if (pendingChanges.length > 0) {
                  // More changes occurred while the request was running
                  // We need to:
                  // 1. Adjust incoming semantic tokens
                  // 2. Request them again
                  for (const change of pendingChanges) {
                      for (const area of result) {
                          for (const singleChange of change.changes) {
                              area.applyEdit(singleChange.range, singleChange.text);
                          }
                      }
                  }
              }
              this._model.setSemanticTokens(result, true);
          }
          else {
              this._model.setSemanticTokens(null, true);
          }
          rescheduleIfNeeded();
      }
  }
  ModelSemanticColoring.FETCH_DOCUMENT_SEMANTIC_TOKENS_DELAY = 300;
  