"use strict";
const arrays = require("../../../../base/common/arrays.js");
const cancellation = require("../../../../base/common/cancellation.js");
const errors = require("../../../../base/common/errors.js");
const keyCodes = require("../../../../base/common/keyCodes.js");
const lifecycle = require("../../../../base/common/lifecycle.js");
const editorExtensions = require("../../../browser/editorExtensions.js");
const codeEditorService = require("../../../browser/services/codeEditorService.js");
const characterClassifier = require("../../../common/core/characterClassifier.js");
const range = require("../../../common/core/range.js");
const editorContextKeys = require("../../../common/editorContextKeys.js");
const editorWorker = require("../../../common/services/editorWorker.js");
const languageFeatures = require("../../../common/services/languageFeatures.js");
const format = require("./format.js");
const formattingEdit = require("./formattingEdit.js");
const nls = require("../../../../nls.js");
const commands = require("../../../../platform/commands/common/commands.js");
const contextkey = require("../../../../platform/contextkey/common/contextkey.js");
const instantiation = require("../../../../platform/instantiation/common/instantiation.js");
const progress = require("../../../../platform/progress/common/progress.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());
  });
};
let FormatOnType = class FormatOnType2 {
  constructor(_editor, _languageFeaturesService, _workerService) {
    this._editor = _editor;
    this._languageFeaturesService = _languageFeaturesService;
    this._workerService = _workerService;
    this._disposables = new lifecycle.DisposableStore();
    this._sessionDisposables = new lifecycle.DisposableStore();
    this._disposables.add(_languageFeaturesService.onTypeFormattingEditProvider.onDidChange(this._update, this));
    this._disposables.add(_editor.onDidChangeModel(() => this._update()));
    this._disposables.add(_editor.onDidChangeModelLanguage(() => this._update()));
    this._disposables.add(_editor.onDidChangeConfiguration((e) => {
      if (e.hasChanged(
        49
        /* formatOnType */
      )) {
        this._update();
      }
    }));
  }
  dispose() {
    this._disposables.dispose();
    this._sessionDisposables.dispose();
  }
  _update() {
    this._sessionDisposables.clear();
    if (!this._editor.getOption(
      49
      /* formatOnType */
    )) {
      return;
    }
    if (!this._editor.hasModel()) {
      return;
    }
    const model = this._editor.getModel();
    const [support] = this._languageFeaturesService.onTypeFormattingEditProvider.ordered(model);
    if (!support || !support.autoFormatTriggerCharacters) {
      return;
    }
    let triggerChars = new characterClassifier.CharacterSet();
    for (let ch of support.autoFormatTriggerCharacters) {
      triggerChars.add(ch.charCodeAt(0));
    }
    this._sessionDisposables.add(this._editor.onDidType((text) => {
      let lastCharCode = text.charCodeAt(text.length - 1);
      if (triggerChars.has(lastCharCode)) {
        this._trigger(String.fromCharCode(lastCharCode));
      }
    }));
  }
  _trigger(ch) {
    if (!this._editor.hasModel()) {
      return;
    }
    if (this._editor.getSelections().length > 1 || !this._editor.getSelection().isEmpty()) {
      return;
    }
    const model = this._editor.getModel();
    const position = this._editor.getPosition();
    const cts = new cancellation.CancellationTokenSource();
    const unbind = this._editor.onDidChangeModelContent((e) => {
      if (e.isFlush) {
        cts.cancel();
        unbind.dispose();
        return;
      }
      for (let i = 0, len = e.changes.length; i < len; i++) {
        const change = e.changes[i];
        if (change.range.endLineNumber <= position.lineNumber) {
          cts.cancel();
          unbind.dispose();
          return;
        }
      }
    });
    format.getOnTypeFormattingEdits(this._workerService, this._languageFeaturesService, model, position, ch, model.getFormattingOptions(), cts.token).then((edits) => {
      if (cts.token.isCancellationRequested) {
        return;
      }
      if (arrays.isNonEmptyArray(edits)) {
        formattingEdit.FormattingEdit.execute(this._editor, edits, true);
        format.alertFormattingEdits(edits);
      }
    }).finally(() => {
      unbind.dispose();
    });
  }
};
FormatOnType.ID = "editor.contrib.autoFormat";
FormatOnType = __decorate([
  __param(1, languageFeatures.ILanguageFeaturesService),
  __param(2, editorWorker.IEditorWorkerService)
], FormatOnType);
let FormatOnPaste = class FormatOnPaste2 {
  constructor(editor, _languageFeaturesService, _instantiationService) {
    this.editor = editor;
    this._languageFeaturesService = _languageFeaturesService;
    this._instantiationService = _instantiationService;
    this._callOnDispose = new lifecycle.DisposableStore();
    this._callOnModel = new lifecycle.DisposableStore();
    this._callOnDispose.add(editor.onDidChangeConfiguration(() => this._update()));
    this._callOnDispose.add(editor.onDidChangeModel(() => this._update()));
    this._callOnDispose.add(editor.onDidChangeModelLanguage(() => this._update()));
    this._callOnDispose.add(_languageFeaturesService.documentRangeFormattingEditProvider.onDidChange(this._update, this));
  }
  dispose() {
    this._callOnDispose.dispose();
    this._callOnModel.dispose();
  }
  _update() {
    this._callOnModel.clear();
    if (!this.editor.getOption(
      48
      /* formatOnPaste */
    )) {
      return;
    }
    if (!this.editor.hasModel()) {
      return;
    }
    if (!this._languageFeaturesService.documentRangeFormattingEditProvider.has(this.editor.getModel())) {
      return;
    }
    this._callOnModel.add(this.editor.onDidPaste(({ range: range2 }) => this._trigger(range2)));
  }
  _trigger(range2) {
    if (!this.editor.hasModel()) {
      return;
    }
    if (this.editor.getSelections().length > 1) {
      return;
    }
    this._instantiationService.invokeFunction(format.formatDocumentRangesWithSelectedProvider, this.editor, range2, 2, progress.Progress.None, cancellation.CancellationToken.None).catch(errors.onUnexpectedError);
  }
};
FormatOnPaste.ID = "editor.contrib.formatOnPaste";
FormatOnPaste = __decorate([
  __param(1, languageFeatures.ILanguageFeaturesService),
  __param(2, instantiation.IInstantiationService)
], FormatOnPaste);
class FormatDocumentAction extends editorExtensions.EditorAction {
  constructor() {
    super({
      id: "editor.action.formatDocument",
      label: nls.localize("formatDocument.label", "Format Document"),
      alias: "Format Document",
      precondition: contextkey.ContextKeyExpr.and(editorContextKeys.EditorContextKeys.notInCompositeEditor, editorContextKeys.EditorContextKeys.writable, editorContextKeys.EditorContextKeys.hasDocumentFormattingProvider),
      kbOpts: {
        kbExpr: editorContextKeys.EditorContextKeys.editorTextFocus,
        primary: 1024 | 512 | 36,
        linux: {
          primary: 2048 | 1024 | 39
          /* KeyI */
        },
        weight: 100
        /* EditorContrib */
      },
      contextMenuOpts: {
        group: "1_modification",
        order: 1.3
      }
    });
  }
  run(accessor, editor) {
    return __awaiter(this, void 0, void 0, function* () {
      if (editor.hasModel()) {
        const instaService = accessor.get(instantiation.IInstantiationService);
        const progressService = accessor.get(progress.IEditorProgressService);
        yield progressService.showWhile(instaService.invokeFunction(format.formatDocumentWithSelectedProvider, editor, 1, progress.Progress.None, cancellation.CancellationToken.None), 250);
      }
    });
  }
}
class FormatSelectionAction extends editorExtensions.EditorAction {
  constructor() {
    super({
      id: "editor.action.formatSelection",
      label: nls.localize("formatSelection.label", "Format Selection"),
      alias: "Format Selection",
      precondition: contextkey.ContextKeyExpr.and(editorContextKeys.EditorContextKeys.writable, editorContextKeys.EditorContextKeys.hasDocumentSelectionFormattingProvider),
      kbOpts: {
        kbExpr: editorContextKeys.EditorContextKeys.editorTextFocus,
        primary: keyCodes.KeyChord(
          2048 | 41,
          2048 | 36
          /* KeyF */
        ),
        weight: 100
        /* EditorContrib */
      },
      contextMenuOpts: {
        when: editorContextKeys.EditorContextKeys.hasNonEmptySelection,
        group: "1_modification",
        order: 1.31
      }
    });
  }
  run(accessor, editor) {
    return __awaiter(this, void 0, void 0, function* () {
      if (!editor.hasModel()) {
        return;
      }
      const instaService = accessor.get(instantiation.IInstantiationService);
      const model = editor.getModel();
      const ranges = editor.getSelections().map((range$1) => {
        return range$1.isEmpty() ? new range.Range(range$1.startLineNumber, 1, range$1.startLineNumber, model.getLineMaxColumn(range$1.startLineNumber)) : range$1;
      });
      const progressService = accessor.get(progress.IEditorProgressService);
      yield progressService.showWhile(instaService.invokeFunction(format.formatDocumentRangesWithSelectedProvider, editor, ranges, 1, progress.Progress.None, cancellation.CancellationToken.None), 250);
    });
  }
}
editorExtensions.registerEditorContribution(FormatOnType.ID, FormatOnType);
editorExtensions.registerEditorContribution(FormatOnPaste.ID, FormatOnPaste);
editorExtensions.registerEditorAction(FormatDocumentAction);
editorExtensions.registerEditorAction(FormatSelectionAction);
commands.CommandsRegistry.registerCommand("editor.action.format", (accessor) => __awaiter(void 0, void 0, void 0, function* () {
  const editor = accessor.get(codeEditorService.ICodeEditorService).getFocusedCodeEditor();
  if (!editor || !editor.hasModel()) {
    return;
  }
  const commandService = accessor.get(commands.ICommandService);
  if (editor.getSelection().isEmpty()) {
    yield commandService.executeCommand("editor.action.formatDocument");
  } else {
    yield commandService.executeCommand("editor.action.formatSelection");
  }
}));
