"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const event = require("../../../base/common/event.js");
const lifecycle = require("../../../base/common/lifecycle.js");
const platform = require("../../../base/common/platform.js");
const errors = require("../../../base/common/errors.js");
const textModel = require("../model/textModel.js");
const textModelDefaults = require("../core/textModelDefaults.js");
const modesRegistry = require("../languages/modesRegistry.js");
const language = require("../languages/language.js");
const model = require("./model.js");
const textResourceConfiguration = require("./textResourceConfiguration.js");
const configuration = require("../../../platform/configuration/common/configuration.js");
const async = require("../../../base/common/async.js");
const cancellation = require("../../../base/common/cancellation.js");
const themeService = require("../../../platform/theme/common/themeService.js");
const log = require("../../../platform/log/common/log.js");
const undoRedo = require("../../../platform/undoRedo/common/undoRedo.js");
const hash = require("../../../base/common/hash.js");
const editStack = require("../model/editStack.js");
const network = require("../../../base/common/network.js");
const semanticTokensProviderStyling = require("./semanticTokensProviderStyling.js");
const getSemanticTokens = require("./getSemanticTokens.js");
const objects = require("../../../base/common/objects.js");
const languageConfigurationRegistry = require("../languages/languageConfigurationRegistry.js");
const languageFeatureDebounce = require("./languageFeatureDebounce.js");
const stopwatch = require("../../../base/common/stopwatch.js");
const languageFeatures = require("./languageFeatures.js");
var __decorate = globalThis && globalThis.__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 = globalThis && globalThis.__param || function(paramIndex, decorator) {
  return function(target, key) {
    decorator(target, key, paramIndex);
  };
};
function MODEL_ID(resource) {
  return resource.toString();
}
function computeModelSha1(model2) {
  const shaComputer = new hash.StringSHA1();
  const snapshot = model2.createSnapshot();
  let text;
  while (text = snapshot.read()) {
    shaComputer.update(text);
  }
  return shaComputer.digest();
}
class ModelData {
  constructor(model2, onWillDispose, onDidChangeLanguage) {
    this._modelEventListeners = new lifecycle.DisposableStore();
    this.model = model2;
    this._languageSelection = null;
    this._languageSelectionListener = null;
    this._modelEventListeners.add(model2.onWillDispose(() => onWillDispose(model2)));
    this._modelEventListeners.add(model2.onDidChangeLanguage((e) => onDidChangeLanguage(model2, 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.languageId));
    this.model.setMode(languageSelection.languageId);
  }
}
const DEFAULT_EOL = platform.isLinux || platform.isMacintosh ? 1 : 2;
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;
  }
}
exports.ModelService = class ModelService extends lifecycle.Disposable {
  constructor(_configurationService, _resourcePropertiesService, _themeService, _logService, _undoRedoService, _languageService, _languageConfigurationService, _languageFeatureDebounceService, languageFeaturesService) {
    super();
    this._configurationService = _configurationService;
    this._resourcePropertiesService = _resourcePropertiesService;
    this._themeService = _themeService;
    this._logService = _logService;
    this._undoRedoService = _undoRedoService;
    this._languageService = _languageService;
    this._languageConfigurationService = _languageConfigurationService;
    this._languageFeatureDebounceService = _languageFeatureDebounceService;
    this._onModelAdded = this._register(new event.Emitter());
    this.onModelAdded = this._onModelAdded.event;
    this._onModelRemoved = this._register(new event.Emitter());
    this.onModelRemoved = this._onModelRemoved.event;
    this._onModelModeChanged = this._register(new event.Emitter());
    this.onModelLanguageChanged = this._onModelModeChanged.event;
    this._modelCreationOptionsByLanguageAndResource = /* @__PURE__ */ Object.create(null);
    this._models = {};
    this._disposedModels = /* @__PURE__ */ new Map();
    this._disposedModelsHeapSize = 0;
    this._semanticStyling = this._register(new SemanticStyling(this._themeService, this._languageService, this._logService));
    this._register(this._configurationService.onDidChangeConfiguration(() => this._updateModelOptions()));
    this._updateModelOptions();
    this._register(new SemanticColoringFeature(this._semanticStyling, this, this._themeService, this._configurationService, this._languageFeatureDebounceService, languageFeaturesService));
  }
  static _readModelOptions(config, isForSimpleWidget) {
    var _a;
    let tabSize = textModelDefaults.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 = textModelDefaults.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;
    } else if (eol === "\n") {
      newDefaultEOL = 1;
    }
    let trimAutoWhitespace = textModelDefaults.EDITOR_MODEL_DEFAULTS.trimAutoWhitespace;
    if (config.editor && typeof config.editor.trimAutoWhitespace !== "undefined") {
      trimAutoWhitespace = config.editor.trimAutoWhitespace === "false" ? false : Boolean(config.editor.trimAutoWhitespace);
    }
    let detectIndentation = textModelDefaults.EDITOR_MODEL_DEFAULTS.detectIndentation;
    if (config.editor && typeof config.editor.detectIndentation !== "undefined") {
      detectIndentation = config.editor.detectIndentation === "false" ? false : Boolean(config.editor.detectIndentation);
    }
    let largeFileOptimizations = textModelDefaults.EDITOR_MODEL_DEFAULTS.largeFileOptimizations;
    if (config.editor && typeof config.editor.largeFileOptimizations !== "undefined") {
      largeFileOptimizations = config.editor.largeFileOptimizations === "false" ? false : Boolean(config.editor.largeFileOptimizations);
    }
    let bracketPairColorizationOptions = textModelDefaults.EDITOR_MODEL_DEFAULTS.bracketPairColorizationOptions;
    if (((_a = config.editor) === null || _a === void 0 ? void 0 : _a.bracketPairColorization) && typeof config.editor.bracketPairColorization === "object") {
      bracketPairColorizationOptions = {
        enabled: !!config.editor.bracketPairColorization.enabled
      };
    }
    return {
      isForSimpleWidget,
      tabSize,
      indentSize,
      insertSpaces,
      detectIndentation,
      defaultEOL: newDefaultEOL,
      trimAutoWhitespace,
      largeFileOptimizations,
      bracketPairColorizationOptions
    };
  }
  _getEOL(resource, language2) {
    if (resource) {
      return this._resourcePropertiesService.getEOL(resource, language2);
    }
    const eol = this._configurationService.getValue("files.eol", { overrideIdentifier: language2 });
    if (eol && typeof eol === "string" && eol !== "auto") {
      return eol;
    }
    return platform.OS === 3 || platform.OS === 2 ? "\n" : "\r\n";
  }
  _shouldRestoreUndoStack() {
    const result = this._configurationService.getValue("files.restoreUndoStack");
    if (typeof result === "boolean") {
      return result;
    }
    return true;
  }
  getCreationOptions(language2, resource, isForSimpleWidget) {
    let creationOptions = this._modelCreationOptionsByLanguageAndResource[language2 + resource];
    if (!creationOptions) {
      const editor = this._configurationService.getValue("editor", { overrideIdentifier: language2, resource });
      const eol = this._getEOL(resource, language2);
      creationOptions = ModelService._readModelOptions({ editor, eol }, isForSimpleWidget);
      this._modelCreationOptionsByLanguageAndResource[language2 + resource] = creationOptions;
    }
    return creationOptions;
  }
  _updateModelOptions() {
    const oldOptionsByLanguageAndResource = this._modelCreationOptionsByLanguageAndResource;
    this._modelCreationOptionsByLanguageAndResource = /* @__PURE__ */ Object.create(null);
    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 language2 = modelData.model.getLanguageId();
      const uri = modelData.model.uri;
      const oldOptions = oldOptionsByLanguageAndResource[language2 + uri];
      const newOptions = this.getCreationOptions(language2, uri, modelData.model.isForSimpleWidget);
      ModelService._setModelOptionsForModel(modelData.model, newOptions, oldOptions);
    }
  }
  static _setModelOptionsForModel(model2, newOptions, currentOptions) {
    if (currentOptions && currentOptions.defaultEOL !== newOptions.defaultEOL && model2.getLineCount() === 1) {
      model2.setEOL(
        newOptions.defaultEOL === 1 ? 0 : 1
        /* CRLF */
      );
    }
    if (currentOptions && currentOptions.detectIndentation === newOptions.detectIndentation && currentOptions.insertSpaces === newOptions.insertSpaces && currentOptions.tabSize === newOptions.tabSize && currentOptions.indentSize === newOptions.indentSize && currentOptions.trimAutoWhitespace === newOptions.trimAutoWhitespace && objects.equals(currentOptions.bracketPairColorizationOptions, newOptions.bracketPairColorizationOptions)) {
      return;
    }
    if (newOptions.detectIndentation) {
      model2.detectIndentation(newOptions.insertSpaces, newOptions.tabSize);
      model2.updateOptions({
        trimAutoWhitespace: newOptions.trimAutoWhitespace,
        bracketColorizationOptions: newOptions.bracketPairColorizationOptions
      });
    } else {
      model2.updateOptions({
        insertSpaces: newOptions.insertSpaces,
        tabSize: newOptions.tabSize,
        indentSize: newOptions.indentSize,
        trimAutoWhitespace: newOptions.trimAutoWhitespace,
        bracketColorizationOptions: newOptions.bracketPairColorizationOptions
      });
    }
  }
  // --- 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) {
      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, languageId, resource, isForSimpleWidget) {
    const options = this.getCreationOptions(languageId, resource, isForSimpleWidget);
    const model2 = new textModel.TextModel(value, languageId, options, resource, this._undoRedoService, this._languageService, this._languageConfigurationService);
    if (resource && this._disposedModels.has(MODEL_ID(resource))) {
      const disposedModelData = this._removeDisposedModel(resource);
      const elements = this._undoRedoService.getElements(resource);
      const sha1IsEqual = computeModelSha1(model2) === disposedModelData.sha1;
      if (sha1IsEqual || disposedModelData.sharesUndoRedoStack) {
        for (const element of elements.past) {
          if (editStack.isEditStackElement(element) && element.matchesResource(resource)) {
            element.setModel(model2);
          }
        }
        for (const element of elements.future) {
          if (editStack.isEditStackElement(element) && element.matchesResource(resource)) {
            element.setModel(model2);
          }
        }
        this._undoRedoService.setElementsValidFlag(resource, true, (element) => editStack.isEditStackElement(element) && element.matchesResource(resource));
        if (sha1IsEqual) {
          model2._overwriteVersionId(disposedModelData.versionId);
          model2._overwriteAlternativeVersionId(disposedModelData.alternativeVersionId);
          model2._overwriteInitialUndoRedoSnapshot(disposedModelData.initialUndoRedoSnapshot);
        }
      } else {
        if (disposedModelData.initialUndoRedoSnapshot !== null) {
          this._undoRedoService.restoreSnapshot(disposedModelData.initialUndoRedoSnapshot);
        }
      }
    }
    const modelId = MODEL_ID(model2.uri);
    if (this._models[modelId]) {
      throw new Error("ModelService: Cannot add model because it already exists!");
    }
    const modelData = new ModelData(model2, (model3) => this._onWillDispose(model3), (model3, e) => this._onDidChangeLanguage(model3, e));
    this._models[modelId] = modelData;
    return modelData;
  }
  createModel(value, languageSelection, resource, isForSimpleWidget = false) {
    let modelData;
    if (languageSelection) {
      modelData = this._createModelData(value, languageSelection.languageId, resource, isForSimpleWidget);
      this.setMode(modelData.model, languageSelection);
    } else {
      modelData = this._createModelData(value, modesRegistry.PLAINTEXT_LANGUAGE_ID, resource, isForSimpleWidget);
    }
    this._onModelAdded.fire(modelData.model);
    return modelData.model;
  }
  setMode(model2, languageSelection) {
    if (!languageSelection) {
      return;
    }
    const modelData = this._models[MODEL_ID(model2.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
  _schemaShouldMaintainUndoRedoElements(resource) {
    return resource.scheme === network.Schemas.file || resource.scheme === network.Schemas.vscodeRemote || resource.scheme === network.Schemas.userData || resource.scheme === network.Schemas.vscodeNotebookCell || resource.scheme === "fake-fs";
  }
  _onWillDispose(model2) {
    const modelId = MODEL_ID(model2.uri);
    const modelData = this._models[modelId];
    const sharesUndoRedoStack = this._undoRedoService.getUriComparisonKey(model2.uri) !== model2.uri.toString();
    let maintainUndoRedoStack = false;
    let heapSize = 0;
    if (sharesUndoRedoStack || this._shouldRestoreUndoStack() && this._schemaShouldMaintainUndoRedoElements(model2.uri)) {
      const elements = this._undoRedoService.getElements(model2.uri);
      if (elements.past.length > 0 || elements.future.length > 0) {
        for (const element of elements.past) {
          if (editStack.isEditStackElement(element) && element.matchesResource(model2.uri)) {
            maintainUndoRedoStack = true;
            heapSize += element.heapSize(model2.uri);
            element.setModel(model2.uri);
          }
        }
        for (const element of elements.future) {
          if (editStack.isEditStackElement(element) && element.matchesResource(model2.uri)) {
            maintainUndoRedoStack = true;
            heapSize += element.heapSize(model2.uri);
            element.setModel(model2.uri);
          }
        }
      }
    }
    const maxMemory = ModelService.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) {
      const initialUndoRedoSnapshot = modelData.model.getInitialUndoRedoSnapshot();
      if (initialUndoRedoSnapshot !== null) {
        this._undoRedoService.restoreSnapshot(initialUndoRedoSnapshot);
      }
    } else {
      this._ensureDisposedModelsHeapSize(maxMemory - heapSize);
      this._undoRedoService.setElementsValidFlag(model2.uri, false, (element) => editStack.isEditStackElement(element) && element.matchesResource(model2.uri));
      this._insertDisposedModel(new DisposedModelInfo(model2.uri, modelData.model.getInitialUndoRedoSnapshot(), Date.now(), sharesUndoRedoStack, heapSize, computeModelSha1(model2), model2.getVersionId(), model2.getAlternativeVersionId()));
    }
    delete this._models[modelId];
    modelData.dispose();
    delete this._modelCreationOptionsByLanguageAndResource[model2.getLanguageId() + model2.uri];
    this._onModelRemoved.fire(model2);
  }
  _onDidChangeLanguage(model2, e) {
    const oldLanguageId = e.oldLanguage;
    const newLanguageId = model2.getLanguageId();
    const oldOptions = this.getCreationOptions(oldLanguageId, model2.uri, model2.isForSimpleWidget);
    const newOptions = this.getCreationOptions(newLanguageId, model2.uri, model2.isForSimpleWidget);
    ModelService._setModelOptionsForModel(model2, newOptions, oldOptions);
    this._onModelModeChanged.fire({ model: model2, oldLanguageId });
  }
};
exports.ModelService.MAX_MEMORY_FOR_CLOSED_FILES_UNDO_STACK = 20 * 1024 * 1024;
exports.ModelService = __decorate([
  __param(0, configuration.IConfigurationService),
  __param(1, textResourceConfiguration.ITextResourcePropertiesService),
  __param(2, themeService.IThemeService),
  __param(3, log.ILogService),
  __param(4, undoRedo.IUndoRedoService),
  __param(5, language.ILanguageService),
  __param(6, languageConfigurationRegistry.ILanguageConfigurationService),
  __param(7, languageFeatureDebounce.ILanguageFeatureDebounceService),
  __param(8, languageFeatures.ILanguageFeaturesService)
], exports.ModelService);
const SEMANTIC_HIGHLIGHTING_SETTING_ID = "editor.semanticHighlighting";
function isSemanticColoringEnabled(model2, themeService2, configurationService) {
  var _a;
  const setting = (_a = configurationService.getValue(SEMANTIC_HIGHLIGHTING_SETTING_ID, { overrideIdentifier: model2.getLanguageId(), resource: model2.uri })) === null || _a === void 0 ? void 0 : _a.enabled;
  if (typeof setting === "boolean") {
    return setting;
  }
  return themeService2.getColorTheme().semanticHighlighting;
}
let SemanticColoringFeature = class SemanticColoringFeature2 extends lifecycle.Disposable {
  constructor(semanticStyling, modelService, themeService2, configurationService, languageFeatureDebounceService, languageFeaturesService) {
    super();
    this._watchers = /* @__PURE__ */ Object.create(null);
    this._semanticStyling = semanticStyling;
    const register = (model2) => {
      this._watchers[model2.uri.toString()] = new exports.ModelSemanticColoring(model2, this._semanticStyling, themeService2, languageFeatureDebounceService, languageFeaturesService);
    };
    const deregister = (model2, modelSemanticColoring) => {
      modelSemanticColoring.dispose();
      delete this._watchers[model2.uri.toString()];
    };
    const handleSettingOrThemeChange = () => {
      for (let model2 of modelService.getModels()) {
        const curr = this._watchers[model2.uri.toString()];
        if (isSemanticColoringEnabled(model2, themeService2, configurationService)) {
          if (!curr) {
            register(model2);
          }
        } else {
          if (curr) {
            deregister(model2, curr);
          }
        }
      }
    };
    this._register(modelService.onModelAdded((model2) => {
      if (isSemanticColoringEnabled(model2, themeService2, configurationService)) {
        register(model2);
      }
    }));
    this._register(modelService.onModelRemoved((model2) => {
      const curr = this._watchers[model2.uri.toString()];
      if (curr) {
        deregister(model2, curr);
      }
    }));
    this._register(configurationService.onDidChangeConfiguration((e) => {
      if (e.affectsConfiguration(SEMANTIC_HIGHLIGHTING_SETTING_ID)) {
        handleSettingOrThemeChange();
      }
    }));
    this._register(themeService2.onDidColorThemeChange(handleSettingOrThemeChange));
  }
};
SemanticColoringFeature = __decorate([
  __param(1, model.IModelService),
  __param(2, themeService.IThemeService),
  __param(3, configuration.IConfigurationService),
  __param(4, languageFeatureDebounce.ILanguageFeatureDebounceService),
  __param(5, languageFeatures.ILanguageFeaturesService)
], SemanticColoringFeature);
class SemanticStyling extends lifecycle.Disposable {
  constructor(_themeService, _languageService, _logService) {
    super();
    this._themeService = _themeService;
    this._languageService = _languageService;
    this._logService = _logService;
    this._caches = /* @__PURE__ */ new WeakMap();
    this._register(this._themeService.onDidColorThemeChange(() => {
      this._caches = /* @__PURE__ */ new WeakMap();
    }));
  }
  get(provider) {
    if (!this._caches.has(provider)) {
      this._caches.set(provider, new semanticTokensProviderStyling.SemanticTokensProviderStyling(provider.getLegend(), this._themeService, this._languageService, 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);
  }
}
exports.ModelSemanticColoring = class ModelSemanticColoring extends lifecycle.Disposable {
  constructor(model2, stylingProvider, themeService2, languageFeatureDebounceService, languageFeaturesService) {
    super();
    this._isDisposed = false;
    this._model = model2;
    this._semanticStyling = stylingProvider;
    this._provider = languageFeaturesService.documentSemanticTokensProvider;
    this._debounceInformation = languageFeatureDebounceService.for(this._provider, "DocumentSemanticTokens", { min: ModelSemanticColoring.REQUEST_MIN_DELAY, max: ModelSemanticColoring.REQUEST_MAX_DELAY });
    this._fetchDocumentSemanticTokens = this._register(new async.RunOnceScheduler(() => this._fetchDocumentSemanticTokensNow(), ModelSemanticColoring.REQUEST_MIN_DELAY));
    this._currentDocumentResponse = null;
    this._currentDocumentRequestCancellationTokenSource = null;
    this._documentProvidersChangeListeners = [];
    this._register(this._model.onDidChangeContent(() => {
      if (!this._fetchDocumentSemanticTokens.isScheduled()) {
        this._fetchDocumentSemanticTokens.schedule(this._debounceInformation.get(this._model));
      }
    }));
    this._register(this._model.onDidChangeLanguage(() => {
      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 = () => {
      lifecycle.dispose(this._documentProvidersChangeListeners);
      this._documentProvidersChangeListeners = [];
      for (const provider of this._provider.all(model2)) {
        if (typeof provider.onDidChange === "function") {
          this._documentProvidersChangeListeners.push(provider.onDidChange(() => this._fetchDocumentSemanticTokens.schedule(0)));
        }
      }
    };
    bindDocumentChangeListeners();
    this._register(this._provider.onDidChange(() => {
      bindDocumentChangeListeners();
      this._fetchDocumentSemanticTokens.schedule(this._debounceInformation.get(this._model));
    }));
    this._register(themeService2.onDidColorThemeChange((_) => {
      this._setDocumentSemanticTokens(null, null, null, []);
      this._fetchDocumentSemanticTokens.schedule(this._debounceInformation.get(this._model));
    }));
    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) {
      return;
    }
    if (!getSemanticTokens.hasDocumentSemanticTokensProvider(this._provider, this._model)) {
      if (this._currentDocumentResponse) {
        this._model.setSemanticTokens(null, false);
      }
      return;
    }
    const cancellationTokenSource = new cancellation.CancellationTokenSource();
    const lastProvider = this._currentDocumentResponse ? this._currentDocumentResponse.provider : null;
    const lastResultId = this._currentDocumentResponse ? this._currentDocumentResponse.resultId || null : null;
    const request = getSemanticTokens.getDocumentSemanticTokens(this._provider, this._model, lastProvider, lastResultId, cancellationTokenSource.token);
    this._currentDocumentRequestCancellationTokenSource = cancellationTokenSource;
    const pendingChanges = [];
    const contentChangeListener = this._model.onDidChangeContent((e) => {
      pendingChanges.push(e);
    });
    const sw = new stopwatch.StopWatch(false);
    request.then((res) => {
      this._debounceInformation.update(this._model, sw.elapsed());
      this._currentDocumentRequestCancellationTokenSource = null;
      contentChangeListener.dispose();
      if (!res) {
        this._setDocumentSemanticTokens(null, null, null, pendingChanges);
      } else {
        const { provider, tokens } = res;
        const styling = this._semanticStyling.get(provider);
        this._setDocumentSemanticTokens(provider, tokens || null, styling, pendingChanges);
      }
    }, (err) => {
      const isExpectedError = err && (errors.isCancellationError(err) || typeof err.message === "string" && err.message.indexOf("busy") !== -1);
      if (!isExpectedError) {
        errors.onUnexpectedError(err);
      }
      this._currentDocumentRequestCancellationTokenSource = null;
      contentChangeListener.dispose();
      if (pendingChanges.length > 0) {
        if (!this._fetchDocumentSemanticTokens.isScheduled()) {
          this._fetchDocumentSemanticTokens.schedule(this._debounceInformation.get(this._model));
        }
      }
    });
  }
  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(this._debounceInformation.get(this._model));
      }
    };
    if (this._currentDocumentResponse) {
      this._currentDocumentResponse.dispose();
      this._currentDocumentResponse = null;
    }
    if (this._isDisposed) {
      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 (getSemanticTokens.isSemanticTokensEdits(tokens)) {
      if (!currentResponse) {
        this._model.setSemanticTokens(null, true);
        return;
      }
      if (tokens.edits.length === 0) {
        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 (getSemanticTokens.isSemanticTokens(tokens)) {
      this._currentDocumentResponse = new SemanticTokensResponse(provider, tokens.resultId, tokens.data);
      const result = semanticTokensProviderStyling.toMultilineTokens2(tokens, styling, this._model.getLanguageId());
      if (pendingChanges.length > 0) {
        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();
  }
};
exports.ModelSemanticColoring.REQUEST_MIN_DELAY = 300;
exports.ModelSemanticColoring.REQUEST_MAX_DELAY = 2e3;
exports.ModelSemanticColoring = __decorate([
  __param(2, themeService.IThemeService),
  __param(3, languageFeatureDebounce.ILanguageFeatureDebounceService),
  __param(4, languageFeatures.ILanguageFeaturesService)
], exports.ModelSemanticColoring);
exports.SEMANTIC_HIGHLIGHTING_SETTING_ID = SEMANTIC_HIGHLIGHTING_SETTING_ID;
exports.isSemanticColoringEnabled = isSemanticColoringEnabled;
