"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const cancellation = require("../../../base/common/cancellation.js");
const errors = require("../../../base/common/errors.js");
const uri = require("../../../base/common/uri.js");
const model = require("./model.js");
const commands = require("../../../platform/commands/common/commands.js");
const types = require("../../../base/common/types.js");
const semanticTokensDto = require("./semanticTokensDto.js");
const range = require("../core/range.js");
const languageFeatures = require("./languageFeatures.js");
var __awaiter = globalThis && globalThis.__awaiter || function(thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function(resolve) {
      resolve(value);
    });
  }
  return new (P || (P = Promise))(function(resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }
    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }
    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }
    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};
function isSemanticTokens(v) {
  return v && !!v.data;
}
function isSemanticTokensEdits(v) {
  return v && Array.isArray(v.edits);
}
class DocumentSemanticTokensResult {
  constructor(provider, tokens, error) {
    this.provider = provider;
    this.tokens = tokens;
    this.error = error;
  }
}
function hasDocumentSemanticTokensProvider(registry, model2) {
  return registry.has(model2);
}
function getDocumentSemanticTokensProviders(registry, model2) {
  const groups = registry.orderedGroups(model2);
  return groups.length > 0 ? groups[0] : [];
}
function getDocumentSemanticTokens(registry, model2, lastProvider, lastResultId, token) {
  return __awaiter(this, void 0, void 0, function* () {
    const providers = getDocumentSemanticTokensProviders(registry, model2);
    const results = yield Promise.all(providers.map((provider) => __awaiter(this, void 0, void 0, function* () {
      let result;
      let error = null;
      try {
        result = yield provider.provideDocumentSemanticTokens(model2, provider === lastProvider ? lastResultId : null, token);
      } catch (err) {
        error = err;
        result = null;
      }
      if (!result || !isSemanticTokens(result) && !isSemanticTokensEdits(result)) {
        result = null;
      }
      return new DocumentSemanticTokensResult(provider, result, error);
    })));
    for (const result of results) {
      if (result.error) {
        throw result.error;
      }
      if (result.tokens) {
        return result;
      }
    }
    if (results.length > 0) {
      return results[0];
    }
    return null;
  });
}
function _getDocumentSemanticTokensProviderHighestGroup(registry, model2) {
  const result = registry.orderedGroups(model2);
  return result.length > 0 ? result[0] : null;
}
class DocumentRangeSemanticTokensResult {
  constructor(provider, tokens) {
    this.provider = provider;
    this.tokens = tokens;
  }
}
function hasDocumentRangeSemanticTokensProvider(providers, model2) {
  return providers.has(model2);
}
function getDocumentRangeSemanticTokensProviders(providers, model2) {
  const groups = providers.orderedGroups(model2);
  return groups.length > 0 ? groups[0] : [];
}
function getDocumentRangeSemanticTokens(registry, model2, range2, token) {
  return __awaiter(this, void 0, void 0, function* () {
    const providers = getDocumentRangeSemanticTokensProviders(registry, model2);
    const results = yield Promise.all(providers.map((provider) => __awaiter(this, void 0, void 0, function* () {
      let result;
      try {
        result = yield provider.provideDocumentRangeSemanticTokens(model2, range2, token);
      } catch (err) {
        errors.onUnexpectedExternalError(err);
        result = null;
      }
      if (!result || !isSemanticTokens(result)) {
        result = null;
      }
      return new DocumentRangeSemanticTokensResult(provider, result);
    })));
    for (const result of results) {
      if (result.tokens) {
        return result;
      }
    }
    if (results.length > 0) {
      return results[0];
    }
    return null;
  });
}
commands.CommandsRegistry.registerCommand("_provideDocumentSemanticTokensLegend", (accessor, ...args) => __awaiter(void 0, void 0, void 0, function* () {
  const [uri$1] = args;
  types.assertType(uri$1 instanceof uri.URI);
  const model$1 = accessor.get(model.IModelService).getModel(uri$1);
  if (!model$1) {
    return void 0;
  }
  const { documentSemanticTokensProvider } = accessor.get(languageFeatures.ILanguageFeaturesService);
  const providers = _getDocumentSemanticTokensProviderHighestGroup(documentSemanticTokensProvider, model$1);
  if (!providers) {
    return accessor.get(commands.ICommandService).executeCommand("_provideDocumentRangeSemanticTokensLegend", uri$1);
  }
  return providers[0].getLegend();
}));
commands.CommandsRegistry.registerCommand("_provideDocumentSemanticTokens", (accessor, ...args) => __awaiter(void 0, void 0, void 0, function* () {
  const [uri$1] = args;
  types.assertType(uri$1 instanceof uri.URI);
  const model$1 = accessor.get(model.IModelService).getModel(uri$1);
  if (!model$1) {
    return void 0;
  }
  const { documentSemanticTokensProvider } = accessor.get(languageFeatures.ILanguageFeaturesService);
  if (!hasDocumentSemanticTokensProvider(documentSemanticTokensProvider, model$1)) {
    return accessor.get(commands.ICommandService).executeCommand("_provideDocumentRangeSemanticTokens", uri$1, model$1.getFullModelRange());
  }
  const r = yield getDocumentSemanticTokens(documentSemanticTokensProvider, model$1, null, null, cancellation.CancellationToken.None);
  if (!r) {
    return void 0;
  }
  const { provider, tokens } = r;
  if (!tokens || !isSemanticTokens(tokens)) {
    return void 0;
  }
  const buff = semanticTokensDto.encodeSemanticTokensDto({
    id: 0,
    type: "full",
    data: tokens.data
  });
  if (tokens.resultId) {
    provider.releaseDocumentSemanticTokens(tokens.resultId);
  }
  return buff;
}));
commands.CommandsRegistry.registerCommand("_provideDocumentRangeSemanticTokensLegend", (accessor, ...args) => __awaiter(void 0, void 0, void 0, function* () {
  const [uri$1, range$1] = args;
  types.assertType(uri$1 instanceof uri.URI);
  const model$1 = accessor.get(model.IModelService).getModel(uri$1);
  if (!model$1) {
    return void 0;
  }
  const { documentRangeSemanticTokensProvider } = accessor.get(languageFeatures.ILanguageFeaturesService);
  const providers = getDocumentRangeSemanticTokensProviders(documentRangeSemanticTokensProvider, model$1);
  if (providers.length === 0) {
    return void 0;
  }
  if (providers.length === 1) {
    return providers[0].getLegend();
  }
  if (!range$1 || !range.Range.isIRange(range$1)) {
    console.warn(`provideDocumentRangeSemanticTokensLegend might be out-of-sync with provideDocumentRangeSemanticTokens unless a range argument is passed in`);
    return providers[0].getLegend();
  }
  const result = yield getDocumentRangeSemanticTokens(documentRangeSemanticTokensProvider, model$1, range.Range.lift(range$1), cancellation.CancellationToken.None);
  if (!result) {
    return void 0;
  }
  return result.provider.getLegend();
}));
commands.CommandsRegistry.registerCommand("_provideDocumentRangeSemanticTokens", (accessor, ...args) => __awaiter(void 0, void 0, void 0, function* () {
  const [uri$1, range$1] = args;
  types.assertType(uri$1 instanceof uri.URI);
  types.assertType(range.Range.isIRange(range$1));
  const model$1 = accessor.get(model.IModelService).getModel(uri$1);
  if (!model$1) {
    return void 0;
  }
  const { documentRangeSemanticTokensProvider } = accessor.get(languageFeatures.ILanguageFeaturesService);
  const result = yield getDocumentRangeSemanticTokens(documentRangeSemanticTokensProvider, model$1, range.Range.lift(range$1), cancellation.CancellationToken.None);
  if (!result || !result.tokens) {
    return void 0;
  }
  return semanticTokensDto.encodeSemanticTokensDto({
    id: 0,
    type: "full",
    data: result.tokens.data
  });
}));
exports.DocumentSemanticTokensResult = DocumentSemanticTokensResult;
exports.getDocumentRangeSemanticTokens = getDocumentRangeSemanticTokens;
exports.getDocumentSemanticTokens = getDocumentSemanticTokens;
exports.hasDocumentRangeSemanticTokensProvider = hasDocumentRangeSemanticTokensProvider;
exports.hasDocumentSemanticTokensProvider = hasDocumentSemanticTokensProvider;
exports.isSemanticTokens = isSemanticTokens;
exports.isSemanticTokensEdits = isSemanticTokensEdits;
