"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const dom = require("../../../../base/browser/dom.js");
const aria = require("../../../../base/browser/ui/aria/aria.js");
const scrollableElement = require("../../../../base/browser/ui/scrollbar/scrollableElement.js");
const codicons = require("../../../../base/common/codicons.js");
const event = require("../../../../base/common/event.js");
const lifecycle = require("../../../../base/common/lifecycle.js");
const strings = require("../../../../base/common/strings.js");
const types = require("../../../../base/common/types.js");
require("./parameterHints.css.js");
const markdownRenderer = require("../../markdownRenderer/browser/markdownRenderer.js");
const language = require("../../../common/languages/language.js");
const parameterHintsModel = require("./parameterHintsModel.js");
const provideSignatureHelp = require("./provideSignatureHelp.js");
const nls = require("../../../../nls.js");
const contextkey = require("../../../../platform/contextkey/common/contextkey.js");
const opener = require("../../../../platform/opener/common/opener.js");
const colorRegistry = require("../../../../platform/theme/common/colorRegistry.js");
const iconRegistry = require("../../../../platform/theme/common/iconRegistry.js");
const theme = require("../../../../platform/theme/common/theme.js");
const themeService = require("../../../../platform/theme/common/themeService.js");
const languageFeatures = require("../../../common/services/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);
  };
};
const $ = dom.$;
const parameterHintsNextIcon = iconRegistry.registerIcon("parameter-hints-next", codicons.Codicon.chevronDown, nls.localize("parameterHintsNextIcon", "Icon for show next parameter hint."));
const parameterHintsPreviousIcon = iconRegistry.registerIcon("parameter-hints-previous", codicons.Codicon.chevronUp, nls.localize("parameterHintsPreviousIcon", "Icon for show previous parameter hint."));
exports.ParameterHintsWidget = class ParameterHintsWidget extends lifecycle.Disposable {
  constructor(editor, contextKeyService, openerService, languageService, languageFeaturesService) {
    super();
    this.editor = editor;
    this.renderDisposeables = this._register(new lifecycle.DisposableStore());
    this.visible = false;
    this.announcedLabel = null;
    this.allowEditorOverflow = true;
    this.markdownRenderer = this._register(new markdownRenderer.MarkdownRenderer({ editor }, languageService, openerService));
    this.model = this._register(new parameterHintsModel.ParameterHintsModel(editor, languageFeaturesService.signatureHelpProvider));
    this.keyVisible = provideSignatureHelp.Context.Visible.bindTo(contextKeyService);
    this.keyMultipleSignatures = provideSignatureHelp.Context.MultipleSignatures.bindTo(contextKeyService);
    this._register(this.model.onChangedHints((newParameterHints) => {
      if (newParameterHints) {
        this.show();
        this.render(newParameterHints);
      } else {
        this.hide();
      }
    }));
  }
  createParameterHintDOMNodes() {
    const element = $(".editor-widget.parameter-hints-widget");
    const wrapper = dom.append(element, $(".phwrapper"));
    wrapper.tabIndex = -1;
    const controls = dom.append(wrapper, $(".controls"));
    const previous = dom.append(controls, $(".button" + themeService.ThemeIcon.asCSSSelector(parameterHintsPreviousIcon)));
    const overloads = dom.append(controls, $(".overloads"));
    const next = dom.append(controls, $(".button" + themeService.ThemeIcon.asCSSSelector(parameterHintsNextIcon)));
    this._register(dom.addDisposableListener(previous, "click", (e) => {
      dom.EventHelper.stop(e);
      this.previous();
    }));
    this._register(dom.addDisposableListener(next, "click", (e) => {
      dom.EventHelper.stop(e);
      this.next();
    }));
    const body = $(".body");
    const scrollbar = new scrollableElement.DomScrollableElement(body, {});
    this._register(scrollbar);
    wrapper.appendChild(scrollbar.getDomNode());
    const signature = dom.append(body, $(".signature"));
    const docs = dom.append(body, $(".docs"));
    element.style.userSelect = "text";
    this.domNodes = {
      element,
      signature,
      overloads,
      docs,
      scrollbar
    };
    this.editor.addContentWidget(this);
    this.hide();
    this._register(this.editor.onDidChangeCursorSelection((e) => {
      if (this.visible) {
        this.editor.layoutContentWidget(this);
      }
    }));
    const updateFont = () => {
      if (!this.domNodes) {
        return;
      }
      const fontInfo = this.editor.getOption(
        44
        /* fontInfo */
      );
      this.domNodes.element.style.fontSize = `${fontInfo.fontSize}px`;
      this.domNodes.element.style.lineHeight = `${fontInfo.lineHeight / fontInfo.fontSize}`;
    };
    updateFont();
    this._register(event.Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)).filter((e) => e.hasChanged(
      44
      /* fontInfo */
    )).on(updateFont, null));
    this._register(this.editor.onDidLayoutChange((e) => this.updateMaxHeight()));
    this.updateMaxHeight();
  }
  show() {
    if (this.visible) {
      return;
    }
    if (!this.domNodes) {
      this.createParameterHintDOMNodes();
    }
    this.keyVisible.set(true);
    this.visible = true;
    setTimeout(() => {
      if (this.domNodes) {
        this.domNodes.element.classList.add("visible");
      }
    }, 100);
    this.editor.layoutContentWidget(this);
  }
  hide() {
    this.renderDisposeables.clear();
    if (!this.visible) {
      return;
    }
    this.keyVisible.reset();
    this.visible = false;
    this.announcedLabel = null;
    if (this.domNodes) {
      this.domNodes.element.classList.remove("visible");
    }
    this.editor.layoutContentWidget(this);
  }
  getPosition() {
    if (this.visible) {
      return {
        position: this.editor.getPosition(),
        preference: [
          1,
          2
          /* BELOW */
        ]
      };
    }
    return null;
  }
  render(hints) {
    var _a;
    this.renderDisposeables.clear();
    if (!this.domNodes) {
      return;
    }
    const multiple = hints.signatures.length > 1;
    this.domNodes.element.classList.toggle("multiple", multiple);
    this.keyMultipleSignatures.set(multiple);
    this.domNodes.signature.innerText = "";
    this.domNodes.docs.innerText = "";
    const signature = hints.signatures[hints.activeSignature];
    if (!signature) {
      return;
    }
    const code = dom.append(this.domNodes.signature, $(".code"));
    const fontInfo = this.editor.getOption(
      44
      /* fontInfo */
    );
    code.style.fontSize = `${fontInfo.fontSize}px`;
    code.style.fontFamily = fontInfo.fontFamily;
    const hasParameters = signature.parameters.length > 0;
    const activeParameterIndex = (_a = signature.activeParameter) !== null && _a !== void 0 ? _a : hints.activeParameter;
    if (!hasParameters) {
      const label = dom.append(code, $("span"));
      label.textContent = signature.label;
    } else {
      this.renderParameters(code, signature, activeParameterIndex);
    }
    const activeParameter = signature.parameters[activeParameterIndex];
    if (activeParameter === null || activeParameter === void 0 ? void 0 : activeParameter.documentation) {
      const documentation = $("span.documentation");
      if (typeof activeParameter.documentation === "string") {
        documentation.textContent = activeParameter.documentation;
      } else {
        const renderedContents = this.renderMarkdownDocs(activeParameter.documentation);
        documentation.appendChild(renderedContents.element);
      }
      dom.append(this.domNodes.docs, $("p", {}, documentation));
    }
    if (signature.documentation === void 0)
      ;
    else if (typeof signature.documentation === "string") {
      dom.append(this.domNodes.docs, $("p", {}, signature.documentation));
    } else {
      const renderedContents = this.renderMarkdownDocs(signature.documentation);
      dom.append(this.domNodes.docs, renderedContents.element);
    }
    const hasDocs = this.hasDocs(signature, activeParameter);
    this.domNodes.signature.classList.toggle("has-docs", hasDocs);
    this.domNodes.docs.classList.toggle("empty", !hasDocs);
    this.domNodes.overloads.textContent = String(hints.activeSignature + 1).padStart(hints.signatures.length.toString().length, "0") + "/" + hints.signatures.length;
    if (activeParameter) {
      let labelToAnnounce = "";
      const param = signature.parameters[activeParameterIndex];
      if (Array.isArray(param.label)) {
        labelToAnnounce = signature.label.substring(param.label[0], param.label[1]);
      } else {
        labelToAnnounce = param.label;
      }
      if (param.documentation) {
        labelToAnnounce += typeof param.documentation === "string" ? `, ${param.documentation}` : `, ${param.documentation.value}`;
      }
      if (signature.documentation) {
        labelToAnnounce += typeof signature.documentation === "string" ? `, ${signature.documentation}` : `, ${signature.documentation.value}`;
      }
      if (this.announcedLabel !== labelToAnnounce) {
        aria.alert(nls.localize("hint", "{0}, hint", labelToAnnounce));
        this.announcedLabel = labelToAnnounce;
      }
    }
    this.editor.layoutContentWidget(this);
    this.domNodes.scrollbar.scanDomNode();
  }
  renderMarkdownDocs(markdown) {
    const renderedContents = this.renderDisposeables.add(this.markdownRenderer.render(markdown, {
      asyncRenderCallback: () => {
        var _a;
        (_a = this.domNodes) === null || _a === void 0 ? void 0 : _a.scrollbar.scanDomNode();
      }
    }));
    renderedContents.element.classList.add("markdown-docs");
    return renderedContents;
  }
  hasDocs(signature, activeParameter) {
    if (activeParameter && typeof activeParameter.documentation === "string" && types.assertIsDefined(activeParameter.documentation).length > 0) {
      return true;
    }
    if (activeParameter && typeof activeParameter.documentation === "object" && types.assertIsDefined(activeParameter.documentation).value.length > 0) {
      return true;
    }
    if (signature.documentation && typeof signature.documentation === "string" && types.assertIsDefined(signature.documentation).length > 0) {
      return true;
    }
    if (signature.documentation && typeof signature.documentation === "object" && types.assertIsDefined(signature.documentation.value).length > 0) {
      return true;
    }
    return false;
  }
  renderParameters(parent, signature, activeParameterIndex) {
    const [start, end] = this.getParameterLabelOffsets(signature, activeParameterIndex);
    const beforeSpan = document.createElement("span");
    beforeSpan.textContent = signature.label.substring(0, start);
    const paramSpan = document.createElement("span");
    paramSpan.textContent = signature.label.substring(start, end);
    paramSpan.className = "parameter active";
    const afterSpan = document.createElement("span");
    afterSpan.textContent = signature.label.substring(end);
    dom.append(parent, beforeSpan, paramSpan, afterSpan);
  }
  getParameterLabelOffsets(signature, paramIdx) {
    const param = signature.parameters[paramIdx];
    if (!param) {
      return [0, 0];
    } else if (Array.isArray(param.label)) {
      return param.label;
    } else if (!param.label.length) {
      return [0, 0];
    } else {
      const regex = new RegExp(`(\\W|^)${strings.escapeRegExpCharacters(param.label)}(?=\\W|$)`, "g");
      regex.test(signature.label);
      const idx = regex.lastIndex - param.label.length;
      return idx >= 0 ? [idx, regex.lastIndex] : [0, 0];
    }
  }
  next() {
    this.editor.focus();
    this.model.next();
  }
  previous() {
    this.editor.focus();
    this.model.previous();
  }
  cancel() {
    this.model.cancel();
  }
  getDomNode() {
    if (!this.domNodes) {
      this.createParameterHintDOMNodes();
    }
    return this.domNodes.element;
  }
  getId() {
    return ParameterHintsWidget.ID;
  }
  trigger(context) {
    this.model.trigger(context, 0);
  }
  updateMaxHeight() {
    if (!this.domNodes) {
      return;
    }
    const height = Math.max(this.editor.getLayoutInfo().height / 4, 250);
    const maxHeight = `${height}px`;
    this.domNodes.element.style.maxHeight = maxHeight;
    const wrapper = this.domNodes.element.getElementsByClassName("phwrapper");
    if (wrapper.length) {
      wrapper[0].style.maxHeight = maxHeight;
    }
  }
};
exports.ParameterHintsWidget.ID = "editor.widget.parameterHintsWidget";
exports.ParameterHintsWidget = __decorate([
  __param(1, contextkey.IContextKeyService),
  __param(2, opener.IOpenerService),
  __param(3, language.ILanguageService),
  __param(4, languageFeatures.ILanguageFeaturesService)
], exports.ParameterHintsWidget);
const editorHoverWidgetHighlightForeground = colorRegistry.registerColor("editorHoverWidget.highlightForeground", { dark: colorRegistry.listHighlightForeground, light: colorRegistry.listHighlightForeground, hc: colorRegistry.listHighlightForeground }, nls.localize("editorHoverWidgetHighlightForeground", "Foreground color of the active item in the parameter hint."));
themeService.registerThemingParticipant((theme$1, collector) => {
  const border = theme$1.getColor(colorRegistry.editorHoverBorder);
  if (border) {
    const borderWidth = theme$1.type === theme.ColorScheme.HIGH_CONTRAST ? 2 : 1;
    collector.addRule(`.monaco-editor .parameter-hints-widget { border: ${borderWidth}px solid ${border}; }`);
    collector.addRule(`.monaco-editor .parameter-hints-widget.multiple .body { border-left: 1px solid ${border.transparent(0.5)}; }`);
    collector.addRule(`.monaco-editor .parameter-hints-widget .signature.has-docs { border-bottom: 1px solid ${border.transparent(0.5)}; }`);
  }
  const background = theme$1.getColor(colorRegistry.editorHoverBackground);
  if (background) {
    collector.addRule(`.monaco-editor .parameter-hints-widget { background-color: ${background}; }`);
  }
  const link = theme$1.getColor(colorRegistry.textLinkForeground);
  if (link) {
    collector.addRule(`.monaco-editor .parameter-hints-widget a { color: ${link}; }`);
  }
  const linkHover = theme$1.getColor(colorRegistry.textLinkActiveForeground);
  if (linkHover) {
    collector.addRule(`.monaco-editor .parameter-hints-widget a:hover { color: ${linkHover}; }`);
  }
  const foreground = theme$1.getColor(colorRegistry.editorHoverForeground);
  if (foreground) {
    collector.addRule(`.monaco-editor .parameter-hints-widget { color: ${foreground}; }`);
  }
  const codeBackground = theme$1.getColor(colorRegistry.textCodeBlockBackground);
  if (codeBackground) {
    collector.addRule(`.monaco-editor .parameter-hints-widget code { background-color: ${codeBackground}; }`);
  }
  const parameterHighlightColor = theme$1.getColor(editorHoverWidgetHighlightForeground);
  if (parameterHighlightColor) {
    collector.addRule(`.monaco-editor .parameter-hints-widget .parameter.active { color: ${parameterHighlightColor}}`);
  }
});
exports.editorHoverWidgetHighlightForeground = editorHoverWidgetHighlightForeground;
