"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const aria = require("../../../../base/browser/ui/aria/aria.js");
const async = require("../../../../base/common/async.js");
const cancellation = require("../../../../base/common/cancellation.js");
const errors = require("../../../../base/common/errors.js");
const lifecycle = require("../../../../base/common/lifecycle.js");
const types = require("../../../../base/common/types.js");
const uri = require("../../../../base/common/uri.js");
const editorState = require("../../editorState/browser/editorState.js");
const editorExtensions = require("../../../browser/editorExtensions.js");
const bulkEditService = require("../../../browser/services/bulkEditService.js");
const codeEditorService = require("../../../browser/services/codeEditorService.js");
const position = require("../../../common/core/position.js");
const range = require("../../../common/core/range.js");
const editorContextKeys = require("../../../common/editorContextKeys.js");
const textResourceConfiguration = require("../../../common/services/textResourceConfiguration.js");
const messageController = require("../../message/browser/messageController.js");
const nls = require("../../../../nls.js");
const configurationRegistry = require("../../../../platform/configuration/common/configurationRegistry.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 notification = require("../../../../platform/notification/common/notification.js");
const progress = require("../../../../platform/progress/common/progress.js");
const platform = require("../../../../platform/registry/common/platform.js");
const renameInputField = require("./renameInputField.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);
  };
};
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());
  });
};
class RenameSkeleton {
  constructor(model, position2, registry) {
    this.model = model;
    this.position = position2;
    this._providerRenameIdx = 0;
    this._providers = registry.ordered(model);
  }
  hasProvider() {
    return this._providers.length > 0;
  }
  resolveRenameLocation(token) {
    return __awaiter(this, void 0, void 0, function* () {
      const rejects = [];
      for (this._providerRenameIdx = 0; this._providerRenameIdx < this._providers.length; this._providerRenameIdx++) {
        const provider = this._providers[this._providerRenameIdx];
        if (!provider.resolveRenameLocation) {
          break;
        }
        let res = yield provider.resolveRenameLocation(this.model, this.position, token);
        if (!res) {
          continue;
        }
        if (res.rejectReason) {
          rejects.push(res.rejectReason);
          continue;
        }
        return res;
      }
      const word = this.model.getWordAtPosition(this.position);
      if (!word) {
        return {
          range: range.Range.fromPositions(this.position),
          text: "",
          rejectReason: rejects.length > 0 ? rejects.join("\n") : void 0
        };
      }
      return {
        range: new range.Range(this.position.lineNumber, word.startColumn, this.position.lineNumber, word.endColumn),
        text: word.word,
        rejectReason: rejects.length > 0 ? rejects.join("\n") : void 0
      };
    });
  }
  provideRenameEdits(newName, token) {
    return __awaiter(this, void 0, void 0, function* () {
      return this._provideRenameEdits(newName, this._providerRenameIdx, [], token);
    });
  }
  _provideRenameEdits(newName, i, rejects, token) {
    return __awaiter(this, void 0, void 0, function* () {
      const provider = this._providers[i];
      if (!provider) {
        return {
          edits: [],
          rejectReason: rejects.join("\n")
        };
      }
      const result = yield provider.provideRenameEdits(this.model, this.position, newName, token);
      if (!result) {
        return this._provideRenameEdits(newName, i + 1, rejects.concat(nls.localize("no result", "No result.")), token);
      } else if (result.rejectReason) {
        return this._provideRenameEdits(newName, i + 1, rejects.concat(result.rejectReason), token);
      }
      return result;
    });
  }
}
function rename(registry, model, position2, newName) {
  return __awaiter(this, void 0, void 0, function* () {
    const skeleton = new RenameSkeleton(model, position2, registry);
    const loc = yield skeleton.resolveRenameLocation(cancellation.CancellationToken.None);
    if (loc === null || loc === void 0 ? void 0 : loc.rejectReason) {
      return { edits: [], rejectReason: loc.rejectReason };
    }
    return skeleton.provideRenameEdits(newName, cancellation.CancellationToken.None);
  });
}
let RenameController = class RenameController2 {
  constructor(editor, _instaService, _notificationService, _bulkEditService, _progressService, _logService, _configService, _languageFeaturesService) {
    this.editor = editor;
    this._instaService = _instaService;
    this._notificationService = _notificationService;
    this._bulkEditService = _bulkEditService;
    this._progressService = _progressService;
    this._logService = _logService;
    this._configService = _configService;
    this._languageFeaturesService = _languageFeaturesService;
    this._dispoableStore = new lifecycle.DisposableStore();
    this._cts = new cancellation.CancellationTokenSource();
    this._renameInputField = this._dispoableStore.add(new async.IdleValue(() => this._dispoableStore.add(this._instaService.createInstance(renameInputField.RenameInputField, this.editor, ["acceptRenameInput", "acceptRenameInputWithPreview"]))));
  }
  static get(editor) {
    return editor.getContribution(RenameController2.ID);
  }
  dispose() {
    this._dispoableStore.dispose();
    this._cts.dispose(true);
  }
  run() {
    var _a, _b;
    return __awaiter(this, void 0, void 0, function* () {
      this._cts.dispose(true);
      if (!this.editor.hasModel()) {
        return void 0;
      }
      const position2 = this.editor.getPosition();
      const skeleton = new RenameSkeleton(this.editor.getModel(), position2, this._languageFeaturesService.renameProvider);
      if (!skeleton.hasProvider()) {
        return void 0;
      }
      this._cts = new editorState.EditorStateCancellationTokenSource(
        this.editor,
        4 | 1
        /* Value */
      );
      let loc;
      try {
        const resolveLocationOperation = skeleton.resolveRenameLocation(this._cts.token);
        this._progressService.showWhile(resolveLocationOperation, 250);
        loc = yield resolveLocationOperation;
      } catch (e) {
        (_a = messageController.MessageController.get(this.editor)) === null || _a === void 0 ? void 0 : _a.showMessage(e || nls.localize("resolveRenameLocationFailed", "An unknown error occurred while resolving rename location"), position2);
        return void 0;
      }
      if (!loc) {
        return void 0;
      }
      if (loc.rejectReason) {
        (_b = messageController.MessageController.get(this.editor)) === null || _b === void 0 ? void 0 : _b.showMessage(loc.rejectReason, position2);
        return void 0;
      }
      if (this._cts.token.isCancellationRequested) {
        return void 0;
      }
      this._cts.dispose();
      this._cts = new editorState.EditorStateCancellationTokenSource(this.editor, 4 | 1, loc.range);
      let selection = this.editor.getSelection();
      let selectionStart = 0;
      let selectionEnd = loc.text.length;
      if (!range.Range.isEmpty(selection) && !range.Range.spansMultipleLines(selection) && range.Range.containsRange(loc.range, selection)) {
        selectionStart = Math.max(0, selection.startColumn - loc.range.startColumn);
        selectionEnd = Math.min(loc.range.endColumn, selection.endColumn) - loc.range.startColumn;
      }
      const supportPreview = this._bulkEditService.hasPreviewHandler() && this._configService.getValue(this.editor.getModel().uri, "editor.rename.enablePreview");
      const inputFieldResult = yield this._renameInputField.value.getInput(loc.range, loc.text, selectionStart, selectionEnd, supportPreview, this._cts.token);
      if (typeof inputFieldResult === "boolean") {
        if (inputFieldResult) {
          this.editor.focus();
        }
        return void 0;
      }
      this.editor.focus();
      const renameOperation = async.raceCancellation(skeleton.provideRenameEdits(inputFieldResult.newName, this._cts.token), this._cts.token).then((renameResult) => __awaiter(this, void 0, void 0, function* () {
        if (!renameResult || !this.editor.hasModel()) {
          return;
        }
        if (renameResult.rejectReason) {
          this._notificationService.info(renameResult.rejectReason);
          return;
        }
        this.editor.setSelection(range.Range.fromPositions(this.editor.getSelection().getPosition()));
        this._bulkEditService.apply(bulkEditService.ResourceEdit.convert(renameResult), {
          editor: this.editor,
          showPreview: inputFieldResult.wantsPreview,
          label: nls.localize("label", "Renaming '{0}'", loc === null || loc === void 0 ? void 0 : loc.text),
          quotableLabel: nls.localize("quotableLabel", "Renaming {0}", loc === null || loc === void 0 ? void 0 : loc.text)
        }).then((result) => {
          if (result.ariaSummary) {
            aria.alert(nls.localize("aria", "Successfully renamed '{0}' to '{1}'. Summary: {2}", loc.text, inputFieldResult.newName, result.ariaSummary));
          }
        }).catch((err) => {
          this._notificationService.error(nls.localize("rename.failedApply", "Rename failed to apply edits"));
          this._logService.error(err);
        });
      }), (err) => {
        this._notificationService.error(nls.localize("rename.failed", "Rename failed to compute edits"));
        this._logService.error(err);
      });
      this._progressService.showWhile(renameOperation, 250);
      return renameOperation;
    });
  }
  acceptRenameInput(wantsPreview) {
    this._renameInputField.value.acceptInput(wantsPreview);
  }
  cancelRenameInput() {
    this._renameInputField.value.cancelInput(true);
  }
};
RenameController.ID = "editor.contrib.renameController";
RenameController = __decorate([
  __param(1, instantiation.IInstantiationService),
  __param(2, notification.INotificationService),
  __param(3, bulkEditService.IBulkEditService),
  __param(4, progress.IEditorProgressService),
  __param(5, log.ILogService),
  __param(6, textResourceConfiguration.ITextResourceConfigurationService),
  __param(7, languageFeatures.ILanguageFeaturesService)
], RenameController);
class RenameAction extends editorExtensions.EditorAction {
  constructor() {
    super({
      id: "editor.action.rename",
      label: nls.localize("rename.label", "Rename Symbol"),
      alias: "Rename Symbol",
      precondition: contextkey.ContextKeyExpr.and(editorContextKeys.EditorContextKeys.writable, editorContextKeys.EditorContextKeys.hasRenameProvider),
      kbOpts: {
        kbExpr: editorContextKeys.EditorContextKeys.editorTextFocus,
        primary: 60,
        weight: 100
        /* EditorContrib */
      },
      contextMenuOpts: {
        group: "1_modification",
        order: 1.1
      }
    });
  }
  runCommand(accessor, args) {
    const editorService = accessor.get(codeEditorService.ICodeEditorService);
    const [uri$1, pos] = Array.isArray(args) && args || [void 0, void 0];
    if (uri.URI.isUri(uri$1) && position.Position.isIPosition(pos)) {
      return editorService.openCodeEditor({ resource: uri$1 }, editorService.getActiveCodeEditor()).then((editor) => {
        if (!editor) {
          return;
        }
        editor.setPosition(pos);
        editor.invokeWithinContext((accessor2) => {
          this.reportTelemetry(accessor2, editor);
          return this.run(accessor2, editor);
        });
      }, errors.onUnexpectedError);
    }
    return super.runCommand(accessor, args);
  }
  run(accessor, editor) {
    const controller = RenameController.get(editor);
    if (controller) {
      return controller.run();
    }
    return Promise.resolve();
  }
}
editorExtensions.registerEditorContribution(RenameController.ID, RenameController);
editorExtensions.registerEditorAction(RenameAction);
const RenameCommand = editorExtensions.EditorCommand.bindToContribution(RenameController.get);
editorExtensions.registerEditorCommand(new RenameCommand({
  id: "acceptRenameInput",
  precondition: renameInputField.CONTEXT_RENAME_INPUT_VISIBLE,
  handler: (x) => x.acceptRenameInput(false),
  kbOpts: {
    weight: 100 + 99,
    kbExpr: editorContextKeys.EditorContextKeys.focus,
    primary: 3
    /* Enter */
  }
}));
editorExtensions.registerEditorCommand(new RenameCommand({
  id: "acceptRenameInputWithPreview",
  precondition: contextkey.ContextKeyExpr.and(renameInputField.CONTEXT_RENAME_INPUT_VISIBLE, contextkey.ContextKeyExpr.has("config.editor.rename.enablePreview")),
  handler: (x) => x.acceptRenameInput(true),
  kbOpts: {
    weight: 100 + 99,
    kbExpr: editorContextKeys.EditorContextKeys.focus,
    primary: 1024 + 3
    /* Enter */
  }
}));
editorExtensions.registerEditorCommand(new RenameCommand({
  id: "cancelRenameInput",
  precondition: renameInputField.CONTEXT_RENAME_INPUT_VISIBLE,
  handler: (x) => x.cancelRenameInput(),
  kbOpts: {
    weight: 100 + 99,
    kbExpr: editorContextKeys.EditorContextKeys.focus,
    primary: 9,
    secondary: [
      1024 | 9
      /* Escape */
    ]
  }
}));
editorExtensions.registerModelAndPositionCommand("_executeDocumentRenameProvider", function(accessor, model, position2, ...args) {
  const [newName] = args;
  types.assertType(typeof newName === "string");
  const { renameProvider } = accessor.get(languageFeatures.ILanguageFeaturesService);
  return rename(renameProvider, model, position2, newName);
});
editorExtensions.registerModelAndPositionCommand("_executePrepareRename", function(accessor, model, position2) {
  return __awaiter(this, void 0, void 0, function* () {
    const { renameProvider } = accessor.get(languageFeatures.ILanguageFeaturesService);
    const skeleton = new RenameSkeleton(model, position2, renameProvider);
    const loc = yield skeleton.resolveRenameLocation(cancellation.CancellationToken.None);
    if (loc === null || loc === void 0 ? void 0 : loc.rejectReason) {
      throw new Error(loc.rejectReason);
    }
    return loc;
  });
});
platform.Registry.as(configurationRegistry.Extensions.Configuration).registerConfiguration({
  id: "editor",
  properties: {
    "editor.rename.enablePreview": {
      scope: 5,
      description: nls.localize("enablePreview", "Enable/disable the ability to preview changes before renaming"),
      default: true,
      type: "boolean"
    }
  }
});
exports.RenameAction = RenameAction;
exports.rename = rename;
