import { alert } from "../../../../base/browser/ui/aria/aria.mjs";
import { isNonEmptyArray } from "../../../../base/common/arrays.mjs";
import { IdleValue } from "../../../../base/common/async.mjs";
import { CancellationTokenSource } from "../../../../base/common/cancellation.mjs";
import { onUnexpectedError } from "../../../../base/common/errors.mjs";
import { Event } from "../../../../base/common/event.mjs";
import { SimpleKeybinding } from "../../../../base/common/keybindings.mjs";
import { MutableDisposable, DisposableStore, toDisposable, dispose } from "../../../../base/common/lifecycle.mjs";
import { isMacintosh } from "../../../../base/common/platform.mjs";
import { StopWatch } from "../../../../base/common/stopwatch.mjs";
import { isObject, assertType } from "../../../../base/common/types.mjs";
import { StableEditorScrollState } from "../../../browser/stableEditorScroll.mjs";
import { registerEditorContribution, registerEditorAction, EditorCommand, registerEditorCommand, EditorAction } from "../../../browser/editorExtensions.mjs";
import { EditOperation } from "../../../common/core/editOperation.mjs";
import { Position } from "../../../common/core/position.mjs";
import { Range } from "../../../common/core/range.mjs";
import { EditorContextKeys } from "../../../common/editorContextKeys.mjs";
import { SnippetController2 } from "../../snippet/browser/snippetController2.mjs";
import { SnippetParser } from "../../snippet/browser/snippetParser.mjs";
import { ISuggestMemoryService } from "./suggestMemory.mjs";
import { WordContextKey } from "./wordContextKey.mjs";
import { localize } from "../../../../nls.mjs";
import { MenuRegistry } from "../../../../platform/actions/common/actions.mjs";
import { ICommandService, CommandsRegistry } from "../../../../platform/commands/common/commands.mjs";
import { IContextKeyService, ContextKeyExpr } from "../../../../platform/contextkey/common/contextkey.mjs";
import { IInstantiationService } from "../../../../platform/instantiation/common/instantiation.mjs";
import { KeybindingsRegistry } from "../../../../platform/keybinding/common/keybindingsRegistry.mjs";
import { ILogService } from "../../../../platform/log/common/log.mjs";
import { Context, suggestWidgetStatusbarMenu } from "./suggest.mjs";
import { SuggestAlternatives } from "./suggestAlternatives.mjs";
import { CommitCharacterController } from "./suggestCommitCharacters.mjs";
import { SuggestModel } from "./suggestModel.mjs";
import { OvertypingCapturer } from "./suggestOvertypingCapturer.mjs";
import { SuggestWidget } from "./suggestWidget.mjs";
import { ITelemetryService } from "../../../../platform/telemetry/common/telemetry.mjs";
import { basename, extname } from "../../../../base/common/resources.mjs";
import { hash } from "../../../../base/common/hash.mjs";
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);
  };
};
class LineSuffix {
  constructor(_model, _position) {
    this._model = _model;
    this._position = _position;
    const maxColumn = _model.getLineMaxColumn(_position.lineNumber);
    if (maxColumn !== _position.column) {
      const offset = _model.getOffsetAt(_position);
      const end = _model.getPositionAt(offset + 1);
      this._marker = _model.deltaDecorations([], [{
        range: Range.fromPositions(_position, end),
        options: {
          description: "suggest-line-suffix",
          stickiness: 1
          /* NeverGrowsWhenTypingAtEdges */
        }
      }]);
    }
  }
  dispose() {
    if (this._marker && !this._model.isDisposed()) {
      this._model.deltaDecorations(this._marker, []);
    }
  }
  delta(position) {
    if (this._model.isDisposed() || this._position.lineNumber !== position.lineNumber) {
      return 0;
    }
    if (this._marker) {
      const range = this._model.getDecorationRange(this._marker[0]);
      const end = this._model.getOffsetAt(range.getStartPosition());
      return end - this._model.getOffsetAt(position);
    } else {
      return this._model.getLineMaxColumn(position.lineNumber) - position.column;
    }
  }
}
let SuggestController = class SuggestController2 {
  constructor(editor, _memoryService, _commandService, _contextKeyService, _instantiationService, _logService, _telemetryService) {
    this._memoryService = _memoryService;
    this._commandService = _commandService;
    this._contextKeyService = _contextKeyService;
    this._instantiationService = _instantiationService;
    this._logService = _logService;
    this._telemetryService = _telemetryService;
    this._lineSuffix = new MutableDisposable();
    this._toDispose = new DisposableStore();
    this._selectors = new PriorityRegistry((s) => s.priority);
    this._telemetryGate = 0;
    this.editor = editor;
    this.model = _instantiationService.createInstance(SuggestModel, this.editor);
    const ctxInsertMode = Context.InsertMode.bindTo(_contextKeyService);
    ctxInsertMode.set(editor.getOption(
      106
      /* suggest */
    ).insertMode);
    this.model.onDidTrigger(() => ctxInsertMode.set(editor.getOption(
      106
      /* suggest */
    ).insertMode));
    this.widget = this._toDispose.add(new IdleValue(() => {
      const widget = this._instantiationService.createInstance(SuggestWidget, this.editor);
      this._toDispose.add(widget);
      this._toDispose.add(widget.onDidSelect((item) => this._insertSuggestion(item, 0), this));
      const commitCharacterController = new CommitCharacterController(this.editor, widget, (item) => this._insertSuggestion(
        item,
        2
        /* NoAfterUndoStop */
      ));
      this._toDispose.add(commitCharacterController);
      this._toDispose.add(this.model.onDidSuggest((e) => {
        if (e.completionModel.items.length === 0) {
          commitCharacterController.reset();
        }
      }));
      const ctxMakesTextEdit = Context.MakesTextEdit.bindTo(this._contextKeyService);
      const ctxHasInsertAndReplace = Context.HasInsertAndReplaceRange.bindTo(this._contextKeyService);
      const ctxCanResolve = Context.CanResolve.bindTo(this._contextKeyService);
      this._toDispose.add(toDisposable(() => {
        ctxMakesTextEdit.reset();
        ctxHasInsertAndReplace.reset();
        ctxCanResolve.reset();
      }));
      this._toDispose.add(widget.onDidFocus(({ item }) => {
        const position = this.editor.getPosition();
        const startColumn = item.editStart.column;
        const endColumn = position.column;
        let value = true;
        if (this.editor.getOption(
          1
          /* acceptSuggestionOnEnter */
        ) === "smart" && this.model.state === 2 && !item.completion.additionalTextEdits && !(item.completion.insertTextRules & 4) && endColumn - startColumn === item.completion.insertText.length) {
          const oldText = this.editor.getModel().getValueInRange({
            startLineNumber: position.lineNumber,
            startColumn,
            endLineNumber: position.lineNumber,
            endColumn
          });
          value = oldText !== item.completion.insertText;
        }
        ctxMakesTextEdit.set(value);
        ctxHasInsertAndReplace.set(!Position.equals(item.editInsertEnd, item.editReplaceEnd));
        ctxCanResolve.set(Boolean(item.provider.resolveCompletionItem) || Boolean(item.completion.documentation) || item.completion.detail !== item.completion.label);
      }));
      this._toDispose.add(widget.onDetailsKeyDown((e) => {
        if (e.toKeybinding().equals(new SimpleKeybinding(
          true,
          false,
          false,
          false,
          33
          /* KeyC */
        )) || isMacintosh && e.toKeybinding().equals(new SimpleKeybinding(
          false,
          false,
          false,
          true,
          33
          /* KeyC */
        ))) {
          e.stopPropagation();
          return;
        }
        if (!e.toKeybinding().isModifierKey()) {
          this.editor.focus();
        }
      }));
      return widget;
    }));
    this._overtypingCapturer = this._toDispose.add(new IdleValue(() => {
      return this._toDispose.add(new OvertypingCapturer(this.editor, this.model));
    }));
    this._alternatives = this._toDispose.add(new IdleValue(() => {
      return this._toDispose.add(new SuggestAlternatives(this.editor, this._contextKeyService));
    }));
    this._toDispose.add(_instantiationService.createInstance(WordContextKey, editor));
    this._toDispose.add(this.model.onDidTrigger((e) => {
      this.widget.value.showTriggered(e.auto, e.shy ? 250 : 50);
      this._lineSuffix.value = new LineSuffix(this.editor.getModel(), e.position);
    }));
    this._toDispose.add(this.model.onDidSuggest((e) => {
      if (!e.shy) {
        let index = -1;
        for (const selector of this._selectors.itemsOrderedByPriorityDesc) {
          index = selector.select(this.editor.getModel(), this.editor.getPosition(), e.completionModel.items);
          if (index !== -1) {
            break;
          }
        }
        if (index === -1) {
          index = this._memoryService.select(this.editor.getModel(), this.editor.getPosition(), e.completionModel.items);
        }
        this.widget.value.showSuggestions(e.completionModel, index, e.isFrozen, e.auto);
      }
    }));
    this._toDispose.add(this.model.onDidCancel((e) => {
      if (!e.retrigger) {
        this.widget.value.hideWidget();
      }
    }));
    this._toDispose.add(this.editor.onDidBlurEditorWidget(() => {
      {
        this.model.cancel();
        this.model.clear();
      }
    }));
    let acceptSuggestionsOnEnter = Context.AcceptSuggestionsOnEnter.bindTo(_contextKeyService);
    let updateFromConfig = () => {
      const acceptSuggestionOnEnter = this.editor.getOption(
        1
        /* acceptSuggestionOnEnter */
      );
      acceptSuggestionsOnEnter.set(acceptSuggestionOnEnter === "on" || acceptSuggestionOnEnter === "smart");
    };
    this._toDispose.add(this.editor.onDidChangeConfiguration(() => updateFromConfig()));
    updateFromConfig();
  }
  static get(editor) {
    return editor.getContribution(SuggestController2.ID);
  }
  dispose() {
    this._alternatives.dispose();
    this._toDispose.dispose();
    this.widget.dispose();
    this.model.dispose();
    this._lineSuffix.dispose();
  }
  _insertSuggestion(event, flags) {
    if (!event || !event.item) {
      this._alternatives.value.reset();
      this.model.cancel();
      this.model.clear();
      return;
    }
    if (!this.editor.hasModel()) {
      return;
    }
    const snippetController = SnippetController2.get(this.editor);
    if (!snippetController) {
      return;
    }
    const model = this.editor.getModel();
    const modelVersionNow = model.getAlternativeVersionId();
    const { item } = event;
    const tasks = [];
    const cts = new CancellationTokenSource();
    if (!(flags & 1)) {
      this.editor.pushUndoStop();
    }
    const info = this.getOverwriteInfo(item, Boolean(
      flags & 8
      /* AlternativeOverwriteConfig */
    ));
    this._memoryService.memorize(model, this.editor.getPosition(), item);
    if (Array.isArray(item.completion.additionalTextEdits)) {
      const scrollState = StableEditorScrollState.capture(this.editor);
      this.editor.executeEdits("suggestController.additionalTextEdits.sync", item.completion.additionalTextEdits.map((edit) => EditOperation.replace(Range.lift(edit.range), edit.text)));
      scrollState.restoreRelativeVerticalPositionOfCursor(this.editor);
    } else if (!item.isResolved) {
      const sw = new StopWatch(true);
      let position;
      const docListener = model.onDidChangeContent((e) => {
        if (e.isFlush) {
          cts.cancel();
          docListener.dispose();
          return;
        }
        for (let change of e.changes) {
          const thisPosition = Range.getEndPosition(change.range);
          if (!position || Position.isBefore(thisPosition, position)) {
            position = thisPosition;
          }
        }
      });
      let oldFlags = flags;
      flags |= 2;
      let didType = false;
      let typeListener = this.editor.onWillType(() => {
        typeListener.dispose();
        didType = true;
        if (!(oldFlags & 2)) {
          this.editor.pushUndoStop();
        }
      });
      tasks.push(item.resolve(cts.token).then(() => {
        if (!item.completion.additionalTextEdits || cts.token.isCancellationRequested) {
          return false;
        }
        if (position && item.completion.additionalTextEdits.some((edit) => Position.isBefore(position, Range.getStartPosition(edit.range)))) {
          return false;
        }
        if (didType) {
          this.editor.pushUndoStop();
        }
        const scrollState = StableEditorScrollState.capture(this.editor);
        this.editor.executeEdits("suggestController.additionalTextEdits.async", item.completion.additionalTextEdits.map((edit) => EditOperation.replace(Range.lift(edit.range), edit.text)));
        scrollState.restoreRelativeVerticalPositionOfCursor(this.editor);
        if (didType || !(oldFlags & 2)) {
          this.editor.pushUndoStop();
        }
        return true;
      }).then((applied) => {
        this._logService.trace("[suggest] async resolving of edits DONE (ms, applied?)", sw.elapsed(), applied);
        docListener.dispose();
        typeListener.dispose();
      }));
    }
    let { insertText } = item.completion;
    if (!(item.completion.insertTextRules & 4)) {
      insertText = SnippetParser.escape(insertText);
    }
    snippetController.insert(insertText, {
      overwriteBefore: info.overwriteBefore,
      overwriteAfter: info.overwriteAfter,
      undoStopBefore: false,
      undoStopAfter: false,
      adjustWhitespace: !(item.completion.insertTextRules & 1),
      clipboardText: event.model.clipboardText,
      overtypingCapturer: this._overtypingCapturer.value
    });
    if (!(flags & 2)) {
      this.editor.pushUndoStop();
    }
    if (!item.completion.command) {
      this.model.cancel();
    } else if (item.completion.command.id === TriggerSuggestAction.id) {
      this.model.trigger({ auto: true, shy: false }, true);
    } else {
      tasks.push(this._commandService.executeCommand(item.completion.command.id, ...item.completion.command.arguments ? [...item.completion.command.arguments] : []).catch(onUnexpectedError));
      this.model.cancel();
    }
    if (flags & 4) {
      this._alternatives.value.set(event, (next) => {
        cts.cancel();
        while (model.canUndo()) {
          if (modelVersionNow !== model.getAlternativeVersionId()) {
            model.undo();
          }
          this._insertSuggestion(next, 1 | 2 | (flags & 8 ? 8 : 0));
          break;
        }
      });
    }
    this._alertCompletionItem(item);
    Promise.all(tasks).finally(() => {
      this._reportSuggestionAcceptedTelemetry(model, event);
      this.model.clear();
      cts.dispose();
    });
  }
  _reportSuggestionAcceptedTelemetry(model, acceptedSuggestion) {
    var _a;
    if (this._telemetryGate++ % 100 !== 0) {
      return;
    }
    const providerId = ((_a = acceptedSuggestion.item.provider._debugDisplayName) !== null && _a !== void 0 ? _a : "unknown").split("(", 1)[0].toLowerCase();
    this._telemetryService.publicLog2("suggest.acceptedSuggestion", {
      providerId,
      basenameHash: hash(basename(model.uri)).toString(16),
      languageId: model.getLanguageId(),
      fileExtension: extname(model.uri)
    });
  }
  getOverwriteInfo(item, toggleMode) {
    assertType(this.editor.hasModel());
    let replace = this.editor.getOption(
      106
      /* suggest */
    ).insertMode === "replace";
    if (toggleMode) {
      replace = !replace;
    }
    const overwriteBefore = item.position.column - item.editStart.column;
    const overwriteAfter = (replace ? item.editReplaceEnd.column : item.editInsertEnd.column) - item.position.column;
    const columnDelta = this.editor.getPosition().column - item.position.column;
    const suffixDelta = this._lineSuffix.value ? this._lineSuffix.value.delta(this.editor.getPosition()) : 0;
    return {
      overwriteBefore: overwriteBefore + columnDelta,
      overwriteAfter: overwriteAfter + suffixDelta
    };
  }
  _alertCompletionItem(item) {
    if (isNonEmptyArray(item.completion.additionalTextEdits)) {
      let msg = localize("aria.alert.snippet", "Accepting '{0}' made {1} additional edits", item.textLabel, item.completion.additionalTextEdits.length);
      alert(msg);
    }
  }
  triggerSuggest(onlyFrom, auto) {
    if (this.editor.hasModel()) {
      this.model.trigger({ auto: auto !== null && auto !== void 0 ? auto : false, shy: false }, false, onlyFrom);
      this.editor.revealPosition(
        this.editor.getPosition(),
        0
        /* Smooth */
      );
      this.editor.focus();
    }
  }
  triggerSuggestAndAcceptBest(arg) {
    if (!this.editor.hasModel()) {
      return;
    }
    const positionNow = this.editor.getPosition();
    const fallback = () => {
      if (positionNow.equals(this.editor.getPosition())) {
        this._commandService.executeCommand(arg.fallback);
      }
    };
    const makesTextEdit = (item) => {
      if (item.completion.insertTextRules & 4 || item.completion.additionalTextEdits) {
        return true;
      }
      const position = this.editor.getPosition();
      const startColumn = item.editStart.column;
      const endColumn = position.column;
      if (endColumn - startColumn !== item.completion.insertText.length) {
        return true;
      }
      const textNow = this.editor.getModel().getValueInRange({
        startLineNumber: position.lineNumber,
        startColumn,
        endLineNumber: position.lineNumber,
        endColumn
      });
      return textNow !== item.completion.insertText;
    };
    Event.once(this.model.onDidTrigger)((_) => {
      let listener = [];
      Event.any(this.model.onDidTrigger, this.model.onDidCancel)(() => {
        dispose(listener);
        fallback();
      }, void 0, listener);
      this.model.onDidSuggest(({ completionModel }) => {
        dispose(listener);
        if (completionModel.items.length === 0) {
          fallback();
          return;
        }
        const index = this._memoryService.select(this.editor.getModel(), this.editor.getPosition(), completionModel.items);
        const item = completionModel.items[index];
        if (!makesTextEdit(item)) {
          fallback();
          return;
        }
        this.editor.pushUndoStop();
        this._insertSuggestion(
          { index, item, model: completionModel },
          4 | 1 | 2
          /* NoAfterUndoStop */
        );
      }, void 0, listener);
    });
    this.model.trigger({ auto: false, shy: true });
    this.editor.revealPosition(
      positionNow,
      0
      /* Smooth */
    );
    this.editor.focus();
  }
  acceptSelectedSuggestion(keepAlternativeSuggestions, alternativeOverwriteConfig) {
    const item = this.widget.value.getFocusedItem();
    let flags = 0;
    if (keepAlternativeSuggestions) {
      flags |= 4;
    }
    if (alternativeOverwriteConfig) {
      flags |= 8;
    }
    this._insertSuggestion(item, flags);
  }
  acceptNextSuggestion() {
    this._alternatives.value.next();
  }
  acceptPrevSuggestion() {
    this._alternatives.value.prev();
  }
  cancelSuggestWidget() {
    this.model.cancel();
    this.model.clear();
    this.widget.value.hideWidget();
  }
  selectNextSuggestion() {
    this.widget.value.selectNext();
  }
  selectNextPageSuggestion() {
    this.widget.value.selectNextPage();
  }
  selectLastSuggestion() {
    this.widget.value.selectLast();
  }
  selectPrevSuggestion() {
    this.widget.value.selectPrevious();
  }
  selectPrevPageSuggestion() {
    this.widget.value.selectPreviousPage();
  }
  selectFirstSuggestion() {
    this.widget.value.selectFirst();
  }
  toggleSuggestionDetails() {
    this.widget.value.toggleDetails();
  }
  toggleExplainMode() {
    this.widget.value.toggleExplainMode();
  }
  toggleSuggestionFocus() {
    this.widget.value.toggleDetailsFocus();
  }
  resetWidgetSize() {
    this.widget.value.resetPersistedSize();
  }
  forceRenderingAbove() {
    this.widget.value.forceRenderingAbove();
  }
  stopForceRenderingAbove() {
    if (!this.widget.isInitialized) {
      return;
    }
    this.widget.value.stopForceRenderingAbove();
  }
  registerSelector(selector) {
    return this._selectors.register(selector);
  }
};
SuggestController.ID = "editor.contrib.suggestController";
SuggestController = __decorate([
  __param(1, ISuggestMemoryService),
  __param(2, ICommandService),
  __param(3, IContextKeyService),
  __param(4, IInstantiationService),
  __param(5, ILogService),
  __param(6, ITelemetryService)
], SuggestController);
class PriorityRegistry {
  constructor(prioritySelector) {
    this.prioritySelector = prioritySelector;
    this._items = new Array();
  }
  register(value) {
    if (this._items.indexOf(value) !== -1) {
      throw new Error("Value is already registered");
    }
    this._items.push(value);
    this._items.sort((s1, s2) => this.prioritySelector(s2) - this.prioritySelector(s1));
    return {
      dispose: () => {
        const idx = this._items.indexOf(value);
        if (idx >= 0) {
          this._items.splice(idx, 1);
        }
      }
    };
  }
  get itemsOrderedByPriorityDesc() {
    return this._items;
  }
}
class TriggerSuggestAction extends EditorAction {
  constructor() {
    super({
      id: TriggerSuggestAction.id,
      label: localize("suggest.trigger.label", "Trigger Suggest"),
      alias: "Trigger Suggest",
      precondition: ContextKeyExpr.and(EditorContextKeys.writable, EditorContextKeys.hasCompletionItemProvider),
      kbOpts: {
        kbExpr: EditorContextKeys.textInputFocus,
        primary: 2048 | 10,
        secondary: [
          2048 | 39
          /* KeyI */
        ],
        mac: { primary: 256 | 10, secondary: [
          512 | 9,
          2048 | 39
          /* KeyI */
        ] },
        weight: 100
        /* EditorContrib */
      }
    });
  }
  run(_accessor, editor, args) {
    const controller = SuggestController.get(editor);
    if (!controller) {
      return;
    }
    let auto;
    if (args && typeof args === "object") {
      if (args.auto === true) {
        auto = true;
      }
    }
    controller.triggerSuggest(void 0, auto);
  }
}
TriggerSuggestAction.id = "editor.action.triggerSuggest";
registerEditorContribution(SuggestController.ID, SuggestController);
registerEditorAction(TriggerSuggestAction);
const weight = 100 + 90;
const SuggestCommand = EditorCommand.bindToContribution(SuggestController.get);
registerEditorCommand(new SuggestCommand({
  id: "acceptSelectedSuggestion",
  precondition: Context.Visible,
  handler(x) {
    x.acceptSelectedSuggestion(true, false);
  }
}));
KeybindingsRegistry.registerKeybindingRule({
  id: "acceptSelectedSuggestion",
  when: ContextKeyExpr.and(Context.Visible, EditorContextKeys.textInputFocus),
  primary: 2,
  weight
});
KeybindingsRegistry.registerKeybindingRule({
  id: "acceptSelectedSuggestion",
  when: ContextKeyExpr.and(Context.Visible, EditorContextKeys.textInputFocus, Context.AcceptSuggestionsOnEnter, Context.MakesTextEdit),
  primary: 3,
  weight
});
MenuRegistry.appendMenuItem(suggestWidgetStatusbarMenu, {
  command: { id: "acceptSelectedSuggestion", title: localize("accept.insert", "Insert") },
  group: "left",
  order: 1,
  when: Context.HasInsertAndReplaceRange.toNegated()
});
MenuRegistry.appendMenuItem(suggestWidgetStatusbarMenu, {
  command: { id: "acceptSelectedSuggestion", title: localize("accept.insert", "Insert") },
  group: "left",
  order: 1,
  when: ContextKeyExpr.and(Context.HasInsertAndReplaceRange, Context.InsertMode.isEqualTo("insert"))
});
MenuRegistry.appendMenuItem(suggestWidgetStatusbarMenu, {
  command: { id: "acceptSelectedSuggestion", title: localize("accept.replace", "Replace") },
  group: "left",
  order: 1,
  when: ContextKeyExpr.and(Context.HasInsertAndReplaceRange, Context.InsertMode.isEqualTo("replace"))
});
registerEditorCommand(new SuggestCommand({
  id: "acceptAlternativeSelectedSuggestion",
  precondition: ContextKeyExpr.and(Context.Visible, EditorContextKeys.textInputFocus),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 1024 | 3,
    secondary: [
      1024 | 2
      /* Tab */
    ]
  },
  handler(x) {
    x.acceptSelectedSuggestion(false, true);
  },
  menuOpts: [{
    menuId: suggestWidgetStatusbarMenu,
    group: "left",
    order: 2,
    when: ContextKeyExpr.and(Context.HasInsertAndReplaceRange, Context.InsertMode.isEqualTo("insert")),
    title: localize("accept.replace", "Replace")
  }, {
    menuId: suggestWidgetStatusbarMenu,
    group: "left",
    order: 2,
    when: ContextKeyExpr.and(Context.HasInsertAndReplaceRange, Context.InsertMode.isEqualTo("replace")),
    title: localize("accept.insert", "Insert")
  }]
}));
CommandsRegistry.registerCommandAlias("acceptSelectedSuggestionOnEnter", "acceptSelectedSuggestion");
registerEditorCommand(new SuggestCommand({
  id: "hideSuggestWidget",
  precondition: Context.Visible,
  handler: (x) => x.cancelSuggestWidget(),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 9,
    secondary: [
      1024 | 9
      /* Escape */
    ]
  }
}));
registerEditorCommand(new SuggestCommand({
  id: "selectNextSuggestion",
  precondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSuggestions),
  handler: (c) => c.selectNextSuggestion(),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 18,
    secondary: [
      2048 | 18
      /* DownArrow */
    ],
    mac: { primary: 18, secondary: [
      2048 | 18,
      256 | 44
      /* KeyN */
    ] }
  }
}));
registerEditorCommand(new SuggestCommand({
  id: "selectNextPageSuggestion",
  precondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSuggestions),
  handler: (c) => c.selectNextPageSuggestion(),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 12,
    secondary: [
      2048 | 12
      /* PageDown */
    ]
  }
}));
registerEditorCommand(new SuggestCommand({
  id: "selectLastSuggestion",
  precondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSuggestions),
  handler: (c) => c.selectLastSuggestion()
}));
registerEditorCommand(new SuggestCommand({
  id: "selectPrevSuggestion",
  precondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSuggestions),
  handler: (c) => c.selectPrevSuggestion(),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 16,
    secondary: [
      2048 | 16
      /* UpArrow */
    ],
    mac: { primary: 16, secondary: [
      2048 | 16,
      256 | 46
      /* KeyP */
    ] }
  }
}));
registerEditorCommand(new SuggestCommand({
  id: "selectPrevPageSuggestion",
  precondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSuggestions),
  handler: (c) => c.selectPrevPageSuggestion(),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 11,
    secondary: [
      2048 | 11
      /* PageUp */
    ]
  }
}));
registerEditorCommand(new SuggestCommand({
  id: "selectFirstSuggestion",
  precondition: ContextKeyExpr.and(Context.Visible, Context.MultipleSuggestions),
  handler: (c) => c.selectFirstSuggestion()
}));
registerEditorCommand(new SuggestCommand({
  id: "toggleSuggestionDetails",
  precondition: Context.Visible,
  handler: (x) => x.toggleSuggestionDetails(),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 2048 | 10,
    secondary: [
      2048 | 39
      /* KeyI */
    ],
    mac: { primary: 256 | 10, secondary: [
      2048 | 39
      /* KeyI */
    ] }
  },
  menuOpts: [{
    menuId: suggestWidgetStatusbarMenu,
    group: "right",
    order: 1,
    when: ContextKeyExpr.and(Context.DetailsVisible, Context.CanResolve),
    title: localize("detail.more", "show less")
  }, {
    menuId: suggestWidgetStatusbarMenu,
    group: "right",
    order: 1,
    when: ContextKeyExpr.and(Context.DetailsVisible.toNegated(), Context.CanResolve),
    title: localize("detail.less", "show more")
  }]
}));
registerEditorCommand(new SuggestCommand({
  id: "toggleExplainMode",
  precondition: Context.Visible,
  handler: (x) => x.toggleExplainMode(),
  kbOpts: {
    weight: 100,
    primary: 2048 | 85
  }
}));
registerEditorCommand(new SuggestCommand({
  id: "toggleSuggestionFocus",
  precondition: Context.Visible,
  handler: (x) => x.toggleSuggestionFocus(),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 2048 | 512 | 10,
    mac: {
      primary: 256 | 512 | 10
      /* Space */
    }
  }
}));
registerEditorCommand(new SuggestCommand({
  id: "insertBestCompletion",
  precondition: ContextKeyExpr.and(EditorContextKeys.textInputFocus, ContextKeyExpr.equals("config.editor.tabCompletion", "on"), WordContextKey.AtEnd, Context.Visible.toNegated(), SuggestAlternatives.OtherSuggestions.toNegated(), SnippetController2.InSnippetMode.toNegated()),
  handler: (x, arg) => {
    x.triggerSuggestAndAcceptBest(isObject(arg) ? Object.assign({ fallback: "tab" }, arg) : { fallback: "tab" });
  },
  kbOpts: {
    weight,
    primary: 2
    /* Tab */
  }
}));
registerEditorCommand(new SuggestCommand({
  id: "insertNextSuggestion",
  precondition: ContextKeyExpr.and(EditorContextKeys.textInputFocus, ContextKeyExpr.equals("config.editor.tabCompletion", "on"), SuggestAlternatives.OtherSuggestions, Context.Visible.toNegated(), SnippetController2.InSnippetMode.toNegated()),
  handler: (x) => x.acceptNextSuggestion(),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 2
    /* Tab */
  }
}));
registerEditorCommand(new SuggestCommand({
  id: "insertPrevSuggestion",
  precondition: ContextKeyExpr.and(EditorContextKeys.textInputFocus, ContextKeyExpr.equals("config.editor.tabCompletion", "on"), SuggestAlternatives.OtherSuggestions, Context.Visible.toNegated(), SnippetController2.InSnippetMode.toNegated()),
  handler: (x) => x.acceptPrevSuggestion(),
  kbOpts: {
    weight,
    kbExpr: EditorContextKeys.textInputFocus,
    primary: 1024 | 2
    /* Tab */
  }
}));
registerEditorAction(class extends EditorAction {
  constructor() {
    super({
      id: "editor.action.resetSuggestSize",
      label: localize("suggest.reset.label", "Reset Suggest Widget Size"),
      alias: "Reset Suggest Widget Size",
      precondition: void 0
    });
  }
  run(_accessor, editor) {
    var _a;
    (_a = SuggestController.get(editor)) === null || _a === void 0 ? void 0 : _a.resetWidgetSize();
  }
});
export {
  SuggestController,
  TriggerSuggestAction
};
