"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const event = require("../../../../base/common/event.js");
const lifecycle = require("../../../../base/common/lifecycle.js");
const strings = require("../../../../base/common/strings.js");
const editorExtensions = require("../../../browser/editorExtensions.js");
const cursorColumns = require("../../../common/core/cursorColumns.js");
const editorContextKeys = require("../../../common/editorContextKeys.js");
const consts = require("./consts.js");
const ghostTextModel = require("./ghostTextModel.js");
const ghostTextWidget = require("./ghostTextWidget.js");
const nls = require("../../../../nls.js");
const contextkey = require("../../../../platform/contextkey/common/contextkey.js");
const instantiation = require("../../../../platform/instantiation/common/instantiation.js");
const keybindingsRegistry = require("../../../../platform/keybinding/common/keybindingsRegistry.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);
  };
};
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());
  });
};
exports.GhostTextController = class GhostTextController extends lifecycle.Disposable {
  constructor(editor, instantiationService) {
    super();
    this.editor = editor;
    this.instantiationService = instantiationService;
    this.triggeredExplicitly = false;
    this.activeController = this._register(new lifecycle.MutableDisposable());
    this.activeModelDidChangeEmitter = this._register(new event.Emitter());
    this._register(this.editor.onDidChangeModel(() => {
      this.updateModelController();
    }));
    this._register(this.editor.onDidChangeConfiguration((e) => {
      if (e.hasChanged(
        106
        /* suggest */
      )) {
        this.updateModelController();
      }
      if (e.hasChanged(
        55
        /* inlineSuggest */
      )) {
        this.updateModelController();
      }
    }));
    this.updateModelController();
  }
  static get(editor) {
    return editor.getContribution(GhostTextController.ID);
  }
  get activeModel() {
    var _a;
    return (_a = this.activeController.value) === null || _a === void 0 ? void 0 : _a.model;
  }
  // Don't call this method when not necessary. It will recreate the activeController.
  updateModelController() {
    const suggestOptions = this.editor.getOption(
      106
      /* suggest */
    );
    const inlineSuggestOptions = this.editor.getOption(
      55
      /* inlineSuggest */
    );
    this.activeController.value = void 0;
    this.activeController.value = this.editor.hasModel() && (suggestOptions.preview || inlineSuggestOptions.enabled || this.triggeredExplicitly) ? this.instantiationService.createInstance(exports.ActiveGhostTextController, this.editor) : void 0;
    this.activeModelDidChangeEmitter.fire();
  }
  shouldShowHoverAt(hoverRange) {
    var _a;
    return ((_a = this.activeModel) === null || _a === void 0 ? void 0 : _a.shouldShowHoverAt(hoverRange)) || false;
  }
  shouldShowHoverAtViewZone(viewZoneId) {
    var _a, _b;
    return ((_b = (_a = this.activeController.value) === null || _a === void 0 ? void 0 : _a.widget) === null || _b === void 0 ? void 0 : _b.shouldShowHoverAtViewZone(viewZoneId)) || false;
  }
  trigger() {
    var _a;
    this.triggeredExplicitly = true;
    if (!this.activeController.value) {
      this.updateModelController();
    }
    (_a = this.activeModel) === null || _a === void 0 ? void 0 : _a.triggerInlineCompletion();
  }
  commit() {
    var _a;
    (_a = this.activeModel) === null || _a === void 0 ? void 0 : _a.commitInlineCompletion();
  }
  hide() {
    var _a;
    (_a = this.activeModel) === null || _a === void 0 ? void 0 : _a.hideInlineCompletion();
  }
  showNextInlineCompletion() {
    var _a;
    (_a = this.activeModel) === null || _a === void 0 ? void 0 : _a.showNextInlineCompletion();
  }
  showPreviousInlineCompletion() {
    var _a;
    (_a = this.activeModel) === null || _a === void 0 ? void 0 : _a.showPreviousInlineCompletion();
  }
  hasMultipleInlineCompletions() {
    var _a;
    return __awaiter(this, void 0, void 0, function* () {
      const result = yield (_a = this.activeModel) === null || _a === void 0 ? void 0 : _a.hasMultipleInlineCompletions();
      return result !== void 0 ? result : false;
    });
  }
};
exports.GhostTextController.inlineSuggestionVisible = new contextkey.RawContextKey("inlineSuggestionVisible", false, nls.localize("inlineSuggestionVisible", "Whether an inline suggestion is visible"));
exports.GhostTextController.inlineSuggestionHasIndentation = new contextkey.RawContextKey("inlineSuggestionHasIndentation", false, nls.localize("inlineSuggestionHasIndentation", "Whether the inline suggestion starts with whitespace"));
exports.GhostTextController.inlineSuggestionHasIndentationLessThanTabSize = new contextkey.RawContextKey("inlineSuggestionHasIndentationLessThanTabSize", true, nls.localize("inlineSuggestionHasIndentationLessThanTabSize", "Whether the inline suggestion starts with whitespace that is less than what would be inserted by tab"));
exports.GhostTextController.ID = "editor.contrib.ghostTextController";
exports.GhostTextController = __decorate([
  __param(1, instantiation.IInstantiationService)
], exports.GhostTextController);
class GhostTextContextKeys {
  constructor(contextKeyService) {
    this.contextKeyService = contextKeyService;
    this.inlineCompletionVisible = exports.GhostTextController.inlineSuggestionVisible.bindTo(this.contextKeyService);
    this.inlineCompletionSuggestsIndentation = exports.GhostTextController.inlineSuggestionHasIndentation.bindTo(this.contextKeyService);
    this.inlineCompletionSuggestsIndentationLessThanTabSize = exports.GhostTextController.inlineSuggestionHasIndentationLessThanTabSize.bindTo(this.contextKeyService);
  }
}
exports.ActiveGhostTextController = class ActiveGhostTextController extends lifecycle.Disposable {
  constructor(editor, instantiationService, contextKeyService) {
    super();
    this.editor = editor;
    this.instantiationService = instantiationService;
    this.contextKeyService = contextKeyService;
    this.contextKeys = new GhostTextContextKeys(this.contextKeyService);
    this.model = this._register(this.instantiationService.createInstance(ghostTextModel.GhostTextModel, this.editor));
    this.widget = this._register(this.instantiationService.createInstance(ghostTextWidget.GhostTextWidget, this.editor, this.model));
    this._register(lifecycle.toDisposable(() => {
      this.contextKeys.inlineCompletionVisible.set(false);
      this.contextKeys.inlineCompletionSuggestsIndentation.set(false);
      this.contextKeys.inlineCompletionSuggestsIndentationLessThanTabSize.set(true);
    }));
    this._register(this.model.onDidChange(() => {
      this.updateContextKeys();
    }));
    this.updateContextKeys();
  }
  updateContextKeys() {
    var _a;
    this.contextKeys.inlineCompletionVisible.set(((_a = this.model.activeInlineCompletionsModel) === null || _a === void 0 ? void 0 : _a.ghostText) !== void 0);
    let startsWithIndentation = false;
    let startsWithIndentationLessThanTabSize = true;
    const ghostText = this.model.inlineCompletionsModel.ghostText;
    if (!!this.model.activeInlineCompletionsModel && ghostText && ghostText.parts.length > 0) {
      const { column, lines } = ghostText.parts[0];
      const firstLine = lines[0];
      const indentationEndColumn = this.editor.getModel().getLineIndentColumn(ghostText.lineNumber);
      const inIndentation = column <= indentationEndColumn;
      if (inIndentation) {
        let firstNonWsIdx = strings.firstNonWhitespaceIndex(firstLine);
        if (firstNonWsIdx === -1) {
          firstNonWsIdx = firstLine.length - 1;
        }
        startsWithIndentation = firstNonWsIdx > 0;
        const tabSize = this.editor.getModel().getOptions().tabSize;
        const visibleColumnIndentation = cursorColumns.CursorColumns.visibleColumnFromColumn(firstLine, firstNonWsIdx + 1, tabSize);
        startsWithIndentationLessThanTabSize = visibleColumnIndentation < tabSize;
      }
    }
    this.contextKeys.inlineCompletionSuggestsIndentation.set(startsWithIndentation);
    this.contextKeys.inlineCompletionSuggestsIndentationLessThanTabSize.set(startsWithIndentationLessThanTabSize);
  }
};
exports.ActiveGhostTextController = __decorate([
  __param(1, instantiation.IInstantiationService),
  __param(2, contextkey.IContextKeyService)
], exports.ActiveGhostTextController);
const GhostTextCommand = editorExtensions.EditorCommand.bindToContribution(exports.GhostTextController.get);
const commitInlineSuggestionAction = new GhostTextCommand({
  id: consts.inlineSuggestCommitId,
  precondition: exports.GhostTextController.inlineSuggestionVisible,
  handler(x) {
    x.commit();
    x.editor.focus();
  }
});
editorExtensions.registerEditorCommand(commitInlineSuggestionAction);
keybindingsRegistry.KeybindingsRegistry.registerKeybindingRule({
  primary: 2,
  weight: 200,
  id: commitInlineSuggestionAction.id,
  when: contextkey.ContextKeyExpr.and(commitInlineSuggestionAction.precondition, editorContextKeys.EditorContextKeys.tabMovesFocus.toNegated(), exports.GhostTextController.inlineSuggestionHasIndentationLessThanTabSize)
});
editorExtensions.registerEditorCommand(new GhostTextCommand({
  id: "editor.action.inlineSuggest.hide",
  precondition: exports.GhostTextController.inlineSuggestionVisible,
  kbOpts: {
    weight: 100,
    primary: 9
  },
  handler(x) {
    x.hide();
  }
}));
class ShowNextInlineSuggestionAction extends editorExtensions.EditorAction {
  constructor() {
    super({
      id: ShowNextInlineSuggestionAction.ID,
      label: nls.localize("action.inlineSuggest.showNext", "Show Next Inline Suggestion"),
      alias: "Show Next Inline Suggestion",
      precondition: contextkey.ContextKeyExpr.and(editorContextKeys.EditorContextKeys.writable, exports.GhostTextController.inlineSuggestionVisible),
      kbOpts: {
        weight: 100,
        primary: 512 | 89
      }
    });
  }
  run(accessor, editor) {
    return __awaiter(this, void 0, void 0, function* () {
      const controller = exports.GhostTextController.get(editor);
      if (controller) {
        controller.showNextInlineCompletion();
        editor.focus();
      }
    });
  }
}
ShowNextInlineSuggestionAction.ID = "editor.action.inlineSuggest.showNext";
class ShowPreviousInlineSuggestionAction extends editorExtensions.EditorAction {
  constructor() {
    super({
      id: ShowPreviousInlineSuggestionAction.ID,
      label: nls.localize("action.inlineSuggest.showPrevious", "Show Previous Inline Suggestion"),
      alias: "Show Previous Inline Suggestion",
      precondition: contextkey.ContextKeyExpr.and(editorContextKeys.EditorContextKeys.writable, exports.GhostTextController.inlineSuggestionVisible),
      kbOpts: {
        weight: 100,
        primary: 512 | 87
      }
    });
  }
  run(accessor, editor) {
    return __awaiter(this, void 0, void 0, function* () {
      const controller = exports.GhostTextController.get(editor);
      if (controller) {
        controller.showPreviousInlineCompletion();
        editor.focus();
      }
    });
  }
}
ShowPreviousInlineSuggestionAction.ID = "editor.action.inlineSuggest.showPrevious";
class TriggerInlineSuggestionAction extends editorExtensions.EditorAction {
  constructor() {
    super({
      id: "editor.action.inlineSuggest.trigger",
      label: nls.localize("action.inlineSuggest.trigger", "Trigger Inline Suggestion"),
      alias: "Trigger Inline Suggestion",
      precondition: editorContextKeys.EditorContextKeys.writable
    });
  }
  run(accessor, editor) {
    return __awaiter(this, void 0, void 0, function* () {
      const controller = exports.GhostTextController.get(editor);
      if (controller) {
        controller.trigger();
      }
    });
  }
}
exports.ShowNextInlineSuggestionAction = ShowNextInlineSuggestionAction;
exports.ShowPreviousInlineSuggestionAction = ShowPreviousInlineSuggestionAction;
exports.TriggerInlineSuggestionAction = TriggerInlineSuggestionAction;
exports.commitInlineSuggestionAction = commitInlineSuggestionAction;
