"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const lifecycle = require("../../../../base/common/lifecycle.js");
const editorExtensions = require("../../../browser/editorExtensions.js");
const range = require("../../../common/core/range.js");
const selection = require("../../../common/core/selection.js");
const editorContextKeys = require("../../../common/editorContextKeys.js");
const suggest = require("../../suggest/browser/suggest.js");
const nls = require("../../../../nls.js");
const contextkey = require("../../../../platform/contextkey/common/contextkey.js");
const instantiation = require("../../../../platform/instantiation/common/instantiation.js");
const log = require("../../../../platform/log/common/log.js");
const snippetSession = require("./snippetSession.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 _defaultOptions = {
  overwriteBefore: 0,
  overwriteAfter: 0,
  undoStopBefore: true,
  undoStopAfter: true,
  adjustWhitespace: true,
  clipboardText: void 0,
  overtypingCapturer: void 0
};
exports.SnippetController2 = class SnippetController2 {
  constructor(_editor, _instantiationService, _logService, contextKeyService) {
    this._editor = _editor;
    this._instantiationService = _instantiationService;
    this._logService = _logService;
    this._snippetListener = new lifecycle.DisposableStore();
    this._modelVersionId = -1;
    this._inSnippet = SnippetController2.InSnippetMode.bindTo(contextKeyService);
    this._hasNextTabstop = SnippetController2.HasNextTabstop.bindTo(contextKeyService);
    this._hasPrevTabstop = SnippetController2.HasPrevTabstop.bindTo(contextKeyService);
  }
  static get(editor) {
    return editor.getContribution(SnippetController2.ID);
  }
  dispose() {
    var _a;
    this._inSnippet.reset();
    this._hasPrevTabstop.reset();
    this._hasNextTabstop.reset();
    (_a = this._session) === null || _a === void 0 ? void 0 : _a.dispose();
    this._snippetListener.dispose();
  }
  insert(template, opts) {
    try {
      this._doInsert(template, typeof opts === "undefined" ? _defaultOptions : Object.assign(Object.assign({}, _defaultOptions), opts));
    } catch (e) {
      this.cancel();
      this._logService.error(e);
      this._logService.error("snippet_error");
      this._logService.error("insert_template=", template);
      this._logService.error("existing_template=", this._session ? this._session._logInfo() : "<no_session>");
    }
  }
  _doInsert(template, opts) {
    if (!this._editor.hasModel()) {
      return;
    }
    this._snippetListener.clear();
    if (opts.undoStopBefore) {
      this._editor.getModel().pushStackElement();
    }
    if (!this._session) {
      this._modelVersionId = this._editor.getModel().getAlternativeVersionId();
      this._session = new snippetSession.SnippetSession(this._editor, template, opts);
      this._session.insert();
    } else {
      this._session.merge(template, opts);
    }
    if (opts.undoStopAfter) {
      this._editor.getModel().pushStackElement();
    }
    this._updateState();
    this._snippetListener.add(this._editor.onDidChangeModelContent((e) => e.isFlush && this.cancel()));
    this._snippetListener.add(this._editor.onDidChangeModel(() => this.cancel()));
    this._snippetListener.add(this._editor.onDidChangeCursorSelection(() => this._updateState()));
  }
  _updateState() {
    if (!this._session || !this._editor.hasModel()) {
      return;
    }
    if (this._modelVersionId === this._editor.getModel().getAlternativeVersionId()) {
      return this.cancel();
    }
    if (!this._session.hasPlaceholder) {
      return this.cancel();
    }
    if (this._session.isAtLastPlaceholder || !this._session.isSelectionWithinPlaceholders()) {
      this._editor.getModel().pushStackElement();
      return this.cancel();
    }
    this._inSnippet.set(true);
    this._hasPrevTabstop.set(!this._session.isAtFirstPlaceholder);
    this._hasNextTabstop.set(!this._session.isAtLastPlaceholder);
    this._handleChoice();
  }
  _handleChoice() {
    if (!this._session || !this._editor.hasModel()) {
      this._currentChoice = void 0;
      return;
    }
    const { choice } = this._session;
    if (!choice) {
      this._currentChoice = void 0;
      return;
    }
    if (this._currentChoice !== choice) {
      this._currentChoice = choice;
      this._editor.setSelections(this._editor.getSelections().map((s) => selection.Selection.fromPositions(s.getStartPosition())));
      const [first] = choice.options;
      this._instantiationService.invokeFunction(suggest.showSimpleSuggestions, this._editor, choice.options.map((option, i) => {
        return {
          kind: 13,
          label: option.value,
          insertText: option.value,
          // insertText: `\${1|${after.concat(before).join(',')}|}$0`,
          // snippetType: 'textmate',
          sortText: "a".repeat(i + 1),
          range: range.Range.fromPositions(this._editor.getPosition(), this._editor.getPosition().delta(0, first.value.length))
        };
      }));
    }
  }
  finish() {
    while (this._inSnippet.get()) {
      this.next();
    }
  }
  cancel(resetSelection = false) {
    var _a;
    this._inSnippet.reset();
    this._hasPrevTabstop.reset();
    this._hasNextTabstop.reset();
    this._snippetListener.clear();
    (_a = this._session) === null || _a === void 0 ? void 0 : _a.dispose();
    this._session = void 0;
    this._modelVersionId = -1;
    if (resetSelection) {
      this._editor.setSelections([this._editor.getSelection()]);
    }
  }
  prev() {
    if (this._session) {
      this._session.prev();
    }
    this._updateState();
  }
  next() {
    if (this._session) {
      this._session.next();
    }
    this._updateState();
  }
  isInSnippet() {
    return Boolean(this._inSnippet.get());
  }
};
exports.SnippetController2.ID = "snippetController2";
exports.SnippetController2.InSnippetMode = new contextkey.RawContextKey("inSnippetMode", false, nls.localize("inSnippetMode", "Whether the editor in current in snippet mode"));
exports.SnippetController2.HasNextTabstop = new contextkey.RawContextKey("hasNextTabstop", false, nls.localize("hasNextTabstop", "Whether there is a next tab stop when in snippet mode"));
exports.SnippetController2.HasPrevTabstop = new contextkey.RawContextKey("hasPrevTabstop", false, nls.localize("hasPrevTabstop", "Whether there is a previous tab stop when in snippet mode"));
exports.SnippetController2 = __decorate([
  __param(1, instantiation.IInstantiationService),
  __param(2, log.ILogService),
  __param(3, contextkey.IContextKeyService)
], exports.SnippetController2);
editorExtensions.registerEditorContribution(exports.SnippetController2.ID, exports.SnippetController2);
const CommandCtor = editorExtensions.EditorCommand.bindToContribution(exports.SnippetController2.get);
editorExtensions.registerEditorCommand(new CommandCtor({
  id: "jumpToNextSnippetPlaceholder",
  precondition: contextkey.ContextKeyExpr.and(exports.SnippetController2.InSnippetMode, exports.SnippetController2.HasNextTabstop),
  handler: (ctrl) => ctrl.next(),
  kbOpts: {
    weight: 100 + 30,
    kbExpr: editorContextKeys.EditorContextKeys.editorTextFocus,
    primary: 2
    /* Tab */
  }
}));
editorExtensions.registerEditorCommand(new CommandCtor({
  id: "jumpToPrevSnippetPlaceholder",
  precondition: contextkey.ContextKeyExpr.and(exports.SnippetController2.InSnippetMode, exports.SnippetController2.HasPrevTabstop),
  handler: (ctrl) => ctrl.prev(),
  kbOpts: {
    weight: 100 + 30,
    kbExpr: editorContextKeys.EditorContextKeys.editorTextFocus,
    primary: 1024 | 2
    /* Tab */
  }
}));
editorExtensions.registerEditorCommand(new CommandCtor({
  id: "leaveSnippet",
  precondition: exports.SnippetController2.InSnippetMode,
  handler: (ctrl) => ctrl.cancel(true),
  kbOpts: {
    weight: 100 + 30,
    kbExpr: editorContextKeys.EditorContextKeys.editorTextFocus,
    primary: 9,
    secondary: [
      1024 | 9
      /* Escape */
    ]
  }
}));
editorExtensions.registerEditorCommand(new CommandCtor({
  id: "acceptSnippet",
  precondition: exports.SnippetController2.InSnippetMode,
  handler: (ctrl) => ctrl.finish()
  // kbOpts: {
  // 	weight: KeybindingWeight.EditorContrib + 30,
  // 	kbExpr: EditorContextKeys.textFocus,
  // 	primary: KeyCode.Enter,
  // }
}));
