"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const async = require("../../../../../base/common/async.js");
const errors = require("../../../../../base/common/errors.js");
const htmlContent = require("../../../../../base/common/htmlContent.js");
const lifecycle = require("../../../../../base/common/lifecycle.js");
const types = require("../../../../../base/common/types.js");
require("./goToDefinitionAtPosition.css.js");
const editorState = require("../../../editorState/browser/editorState.js");
const editorExtensions = require("../../../../browser/editorExtensions.js");
const position = require("../../../../common/core/position.js");
const range = require("../../../../common/core/range.js");
const language = require("../../../../common/languages/language.js");
const resolverService = require("../../../../common/services/resolverService.js");
const clickLinkGesture = require("./clickLinkGesture.js");
const peekView = require("../../../peekView/browser/peekView.js");
const nls = require("../../../../../nls.js");
const contextkey = require("../../../../../platform/contextkey/common/contextkey.js");
const colorRegistry = require("../../../../../platform/theme/common/colorRegistry.js");
const themeService = require("../../../../../platform/theme/common/themeService.js");
const goToCommands = require("../goToCommands.js");
const goToSymbol = require("../goToSymbol.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);
  };
};
exports.GotoDefinitionAtPositionEditorContribution = class GotoDefinitionAtPositionEditorContribution {
  constructor(editor, textModelResolverService, languageService, languageFeaturesService) {
    this.textModelResolverService = textModelResolverService;
    this.languageService = languageService;
    this.languageFeaturesService = languageFeaturesService;
    this.toUnhook = new lifecycle.DisposableStore();
    this.toUnhookForKeyboard = new lifecycle.DisposableStore();
    this.linkDecorations = [];
    this.currentWordAtPosition = null;
    this.previousPromise = null;
    this.editor = editor;
    let linkGesture = new clickLinkGesture.ClickLinkGesture(editor);
    this.toUnhook.add(linkGesture);
    this.toUnhook.add(linkGesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, keyboardEvent]) => {
      this.startFindDefinitionFromMouse(mouseEvent, types.withNullAsUndefined(keyboardEvent));
    }));
    this.toUnhook.add(linkGesture.onExecute((mouseEvent) => {
      if (this.isEnabled(mouseEvent)) {
        this.gotoDefinition(mouseEvent.target.position, mouseEvent.hasSideBySideModifier).then(() => {
          this.removeLinkDecorations();
        }, (error) => {
          this.removeLinkDecorations();
          errors.onUnexpectedError(error);
        });
      }
    }));
    this.toUnhook.add(linkGesture.onCancel(() => {
      this.removeLinkDecorations();
      this.currentWordAtPosition = null;
    }));
  }
  static get(editor) {
    return editor.getContribution(GotoDefinitionAtPositionEditorContribution.ID);
  }
  startFindDefinitionFromCursor(position2) {
    return this.startFindDefinition(position2).then(() => {
      this.toUnhookForKeyboard.add(this.editor.onDidChangeCursorPosition(() => {
        this.currentWordAtPosition = null;
        this.removeLinkDecorations();
        this.toUnhookForKeyboard.clear();
      }));
      this.toUnhookForKeyboard.add(this.editor.onKeyDown((e) => {
        if (e) {
          this.currentWordAtPosition = null;
          this.removeLinkDecorations();
          this.toUnhookForKeyboard.clear();
        }
      }));
    });
  }
  startFindDefinitionFromMouse(mouseEvent, withKey) {
    if (mouseEvent.target.type === 9 && this.linkDecorations.length > 0) {
      return;
    }
    if (!this.editor.hasModel() || !this.isEnabled(mouseEvent, withKey)) {
      this.currentWordAtPosition = null;
      this.removeLinkDecorations();
      return;
    }
    const position2 = mouseEvent.target.position;
    this.startFindDefinition(position2);
  }
  startFindDefinition(position2) {
    var _a;
    this.toUnhookForKeyboard.clear();
    const word = position2 ? (_a = this.editor.getModel()) === null || _a === void 0 ? void 0 : _a.getWordAtPosition(position2) : null;
    if (!word) {
      this.currentWordAtPosition = null;
      this.removeLinkDecorations();
      return Promise.resolve(0);
    }
    if (this.currentWordAtPosition && this.currentWordAtPosition.startColumn === word.startColumn && this.currentWordAtPosition.endColumn === word.endColumn && this.currentWordAtPosition.word === word.word) {
      return Promise.resolve(0);
    }
    this.currentWordAtPosition = word;
    let state = new editorState.EditorState(
      this.editor,
      4 | 1 | 2 | 8
      /* Scroll */
    );
    if (this.previousPromise) {
      this.previousPromise.cancel();
      this.previousPromise = null;
    }
    this.previousPromise = async.createCancelablePromise((token) => this.findDefinition(position2, token));
    return this.previousPromise.then((results) => {
      if (!results || !results.length || !state.validate(this.editor)) {
        this.removeLinkDecorations();
        return;
      }
      if (results.length > 1) {
        this.addDecoration(new range.Range(position2.lineNumber, word.startColumn, position2.lineNumber, word.endColumn), new htmlContent.MarkdownString().appendText(nls.localize("multipleResults", "Click to show {0} definitions.", results.length)));
      } else {
        let result = results[0];
        if (!result.uri) {
          return;
        }
        this.textModelResolverService.createModelReference(result.uri).then((ref) => {
          if (!ref.object || !ref.object.textEditorModel) {
            ref.dispose();
            return;
          }
          const { object: { textEditorModel } } = ref;
          const { startLineNumber } = result.range;
          if (startLineNumber < 1 || startLineNumber > textEditorModel.getLineCount()) {
            ref.dispose();
            return;
          }
          const previewValue = this.getPreviewValue(textEditorModel, startLineNumber, result);
          let wordRange;
          if (result.originSelectionRange) {
            wordRange = range.Range.lift(result.originSelectionRange);
          } else {
            wordRange = new range.Range(position2.lineNumber, word.startColumn, position2.lineNumber, word.endColumn);
          }
          const languageId = this.languageService.guessLanguageIdByFilepathOrFirstLine(textEditorModel.uri);
          this.addDecoration(wordRange, new htmlContent.MarkdownString().appendCodeblock(languageId ? languageId : "", previewValue));
          ref.dispose();
        });
      }
    }).then(void 0, errors.onUnexpectedError);
  }
  getPreviewValue(textEditorModel, startLineNumber, result) {
    let rangeToUse = result.targetSelectionRange ? result.range : this.getPreviewRangeBasedOnBrackets(textEditorModel, startLineNumber);
    const numberOfLinesInRange = rangeToUse.endLineNumber - rangeToUse.startLineNumber;
    if (numberOfLinesInRange >= GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES) {
      rangeToUse = this.getPreviewRangeBasedOnIndentation(textEditorModel, startLineNumber);
    }
    const previewValue = this.stripIndentationFromPreviewRange(textEditorModel, startLineNumber, rangeToUse);
    return previewValue;
  }
  stripIndentationFromPreviewRange(textEditorModel, startLineNumber, previewRange) {
    const startIndent = textEditorModel.getLineFirstNonWhitespaceColumn(startLineNumber);
    let minIndent = startIndent;
    for (let endLineNumber = startLineNumber + 1; endLineNumber < previewRange.endLineNumber; endLineNumber++) {
      const endIndent = textEditorModel.getLineFirstNonWhitespaceColumn(endLineNumber);
      minIndent = Math.min(minIndent, endIndent);
    }
    const previewValue = textEditorModel.getValueInRange(previewRange).replace(new RegExp(`^\\s{${minIndent - 1}}`, "gm"), "").trim();
    return previewValue;
  }
  getPreviewRangeBasedOnIndentation(textEditorModel, startLineNumber) {
    const startIndent = textEditorModel.getLineFirstNonWhitespaceColumn(startLineNumber);
    const maxLineNumber = Math.min(textEditorModel.getLineCount(), startLineNumber + GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES);
    let endLineNumber = startLineNumber + 1;
    for (; endLineNumber < maxLineNumber; endLineNumber++) {
      let endIndent = textEditorModel.getLineFirstNonWhitespaceColumn(endLineNumber);
      if (startIndent === endIndent) {
        break;
      }
    }
    return new range.Range(startLineNumber, 1, endLineNumber + 1, 1);
  }
  getPreviewRangeBasedOnBrackets(textEditorModel, startLineNumber) {
    const maxLineNumber = Math.min(textEditorModel.getLineCount(), startLineNumber + GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES);
    const brackets = [];
    let ignoreFirstEmpty = true;
    let currentBracket = textEditorModel.bracketPairs.findNextBracket(new position.Position(startLineNumber, 1));
    while (currentBracket !== null) {
      if (brackets.length === 0) {
        brackets.push(currentBracket);
      } else {
        const lastBracket = brackets[brackets.length - 1];
        if (lastBracket.open[0] === currentBracket.open[0] && lastBracket.isOpen && !currentBracket.isOpen) {
          brackets.pop();
        } else {
          brackets.push(currentBracket);
        }
        if (brackets.length === 0) {
          if (ignoreFirstEmpty) {
            ignoreFirstEmpty = false;
          } else {
            return new range.Range(startLineNumber, 1, currentBracket.range.endLineNumber + 1, 1);
          }
        }
      }
      const maxColumn = textEditorModel.getLineMaxColumn(startLineNumber);
      let nextLineNumber = currentBracket.range.endLineNumber;
      let nextColumn = currentBracket.range.endColumn;
      if (maxColumn === currentBracket.range.endColumn) {
        nextLineNumber++;
        nextColumn = 1;
      }
      if (nextLineNumber > maxLineNumber) {
        return new range.Range(startLineNumber, 1, maxLineNumber + 1, 1);
      }
      currentBracket = textEditorModel.bracketPairs.findNextBracket(new position.Position(nextLineNumber, nextColumn));
    }
    return new range.Range(startLineNumber, 1, maxLineNumber + 1, 1);
  }
  addDecoration(range2, hoverMessage) {
    const newDecorations = {
      range: range2,
      options: {
        description: "goto-definition-link",
        inlineClassName: "goto-definition-link",
        hoverMessage
      }
    };
    this.linkDecorations = this.editor.deltaDecorations(this.linkDecorations, [newDecorations]);
  }
  removeLinkDecorations() {
    if (this.linkDecorations.length > 0) {
      this.linkDecorations = this.editor.deltaDecorations(this.linkDecorations, []);
    }
  }
  isEnabled(mouseEvent, withKey) {
    return this.editor.hasModel() && mouseEvent.isNoneOrSingleMouseDown && mouseEvent.target.type === 6 && (mouseEvent.hasTriggerModifier || (withKey ? withKey.keyCodeIsTriggerKey : false)) && this.languageFeaturesService.definitionProvider.has(this.editor.getModel());
  }
  findDefinition(position2, token) {
    const model = this.editor.getModel();
    if (!model) {
      return Promise.resolve(null);
    }
    return goToSymbol.getDefinitionsAtPosition(this.languageFeaturesService.definitionProvider, model, position2, token);
  }
  gotoDefinition(position2, openToSide) {
    this.editor.setPosition(position2);
    return this.editor.invokeWithinContext((accessor) => {
      const canPeek = !openToSide && this.editor.getOption(
        78
        /* definitionLinkOpensInPeek */
      ) && !this.isInPeekEditor(accessor);
      const action = new goToCommands.DefinitionAction({ openToSide, openInPeek: canPeek, muteMessage: true }, { alias: "", label: "", id: "", precondition: void 0 });
      return action.run(accessor, this.editor);
    });
  }
  isInPeekEditor(accessor) {
    const contextKeyService = accessor.get(contextkey.IContextKeyService);
    return peekView.PeekContext.inPeekEditor.getValue(contextKeyService);
  }
  dispose() {
    this.toUnhook.dispose();
  }
};
exports.GotoDefinitionAtPositionEditorContribution.ID = "editor.contrib.gotodefinitionatposition";
exports.GotoDefinitionAtPositionEditorContribution.MAX_SOURCE_PREVIEW_LINES = 8;
exports.GotoDefinitionAtPositionEditorContribution = __decorate([
  __param(1, resolverService.ITextModelService),
  __param(2, language.ILanguageService),
  __param(3, languageFeatures.ILanguageFeaturesService)
], exports.GotoDefinitionAtPositionEditorContribution);
editorExtensions.registerEditorContribution(exports.GotoDefinitionAtPositionEditorContribution.ID, exports.GotoDefinitionAtPositionEditorContribution);
themeService.registerThemingParticipant((theme, collector) => {
  const activeLinkForeground = theme.getColor(colorRegistry.editorActiveLinkForeground);
  if (activeLinkForeground) {
    collector.addRule(`.monaco-editor .goto-definition-link { color: ${activeLinkForeground} !important; }`);
  }
});
