"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const async = require("../../../../base/common/async.js");
const lifecycle = require("../../../../base/common/lifecycle.js");
require("./bracketMatching.css.js");
const editorExtensions = require("../../../browser/editorExtensions.js");
const position = require("../../../common/core/position.js");
const range = require("../../../common/core/range.js");
const selection = require("../../../common/core/selection.js");
const editorContextKeys = require("../../../common/editorContextKeys.js");
const model = require("../../../common/model.js");
const textModel = require("../../../common/model/textModel.js");
const editorColorRegistry = require("../../../common/core/editorColorRegistry.js");
const nls = require("../../../../nls.js");
const actions = require("../../../../platform/actions/common/actions.js");
const colorRegistry = require("../../../../platform/theme/common/colorRegistry.js");
const themeService = require("../../../../platform/theme/common/themeService.js");
const overviewRulerBracketMatchForeground = colorRegistry.registerColor("editorOverviewRuler.bracketMatchForeground", { dark: "#A0A0A0", light: "#A0A0A0", hc: "#A0A0A0" }, nls.localize("overviewRulerBracketMatchForeground", "Overview ruler marker color for matching brackets."));
class JumpToBracketAction extends editorExtensions.EditorAction {
  constructor() {
    super({
      id: "editor.action.jumpToBracket",
      label: nls.localize("smartSelect.jumpBracket", "Go to Bracket"),
      alias: "Go to Bracket",
      precondition: void 0,
      kbOpts: {
        kbExpr: editorContextKeys.EditorContextKeys.editorTextFocus,
        primary: 2048 | 1024 | 88,
        weight: 100
        /* EditorContrib */
      }
    });
  }
  run(accessor, editor) {
    var _a;
    (_a = BracketMatchingController.get(editor)) === null || _a === void 0 ? void 0 : _a.jumpToBracket();
  }
}
class SelectToBracketAction extends editorExtensions.EditorAction {
  constructor() {
    super({
      id: "editor.action.selectToBracket",
      label: nls.localize("smartSelect.selectToBracket", "Select to Bracket"),
      alias: "Select to Bracket",
      precondition: void 0,
      description: {
        description: `Select to Bracket`,
        args: [{
          name: "args",
          schema: {
            type: "object",
            properties: {
              "selectBrackets": {
                type: "boolean",
                default: true
              }
            }
          }
        }]
      }
    });
  }
  run(accessor, editor, args) {
    var _a;
    let selectBrackets = true;
    if (args && args.selectBrackets === false) {
      selectBrackets = false;
    }
    (_a = BracketMatchingController.get(editor)) === null || _a === void 0 ? void 0 : _a.selectToBracket(selectBrackets);
  }
}
class BracketsData {
  constructor(position2, brackets, options) {
    this.position = position2;
    this.brackets = brackets;
    this.options = options;
  }
}
class BracketMatchingController extends lifecycle.Disposable {
  constructor(editor) {
    super();
    this._editor = editor;
    this._lastBracketsData = [];
    this._lastVersionId = 0;
    this._decorations = [];
    this._updateBracketsSoon = this._register(new async.RunOnceScheduler(() => this._updateBrackets(), 50));
    this._matchBrackets = this._editor.getOption(
      64
      /* matchBrackets */
    );
    this._updateBracketsSoon.schedule();
    this._register(editor.onDidChangeCursorPosition((e) => {
      if (this._matchBrackets === "never") {
        return;
      }
      this._updateBracketsSoon.schedule();
    }));
    this._register(editor.onDidChangeModelContent((e) => {
      this._updateBracketsSoon.schedule();
    }));
    this._register(editor.onDidChangeModel((e) => {
      this._lastBracketsData = [];
      this._decorations = [];
      this._updateBracketsSoon.schedule();
    }));
    this._register(editor.onDidChangeModelLanguageConfiguration((e) => {
      this._lastBracketsData = [];
      this._updateBracketsSoon.schedule();
    }));
    this._register(editor.onDidChangeConfiguration((e) => {
      if (e.hasChanged(
        64
        /* matchBrackets */
      )) {
        this._matchBrackets = this._editor.getOption(
          64
          /* matchBrackets */
        );
        this._decorations = this._editor.deltaDecorations(this._decorations, []);
        this._lastBracketsData = [];
        this._lastVersionId = 0;
        this._updateBracketsSoon.schedule();
      }
    }));
    this._register(editor.onDidBlurEditorWidget(() => {
      this._updateBracketsSoon.schedule();
    }));
    this._register(editor.onDidFocusEditorWidget(() => {
      this._updateBracketsSoon.schedule();
    }));
  }
  static get(editor) {
    return editor.getContribution(BracketMatchingController.ID);
  }
  jumpToBracket() {
    if (!this._editor.hasModel()) {
      return;
    }
    const model2 = this._editor.getModel();
    const newSelections = this._editor.getSelections().map((selection$1) => {
      const position2 = selection$1.getStartPosition();
      const brackets = model2.bracketPairs.matchBracket(position2);
      let newCursorPosition = null;
      if (brackets) {
        if (brackets[0].containsPosition(position2)) {
          newCursorPosition = brackets[1].getStartPosition();
        } else if (brackets[1].containsPosition(position2)) {
          newCursorPosition = brackets[0].getStartPosition();
        }
      } else {
        const enclosingBrackets = model2.bracketPairs.findEnclosingBrackets(position2);
        if (enclosingBrackets) {
          newCursorPosition = enclosingBrackets[0].getStartPosition();
        } else {
          const nextBracket = model2.bracketPairs.findNextBracket(position2);
          if (nextBracket && nextBracket.range) {
            newCursorPosition = nextBracket.range.getStartPosition();
          }
        }
      }
      if (newCursorPosition) {
        return new selection.Selection(newCursorPosition.lineNumber, newCursorPosition.column, newCursorPosition.lineNumber, newCursorPosition.column);
      }
      return new selection.Selection(position2.lineNumber, position2.column, position2.lineNumber, position2.column);
    });
    this._editor.setSelections(newSelections);
    this._editor.revealRange(newSelections[0]);
  }
  selectToBracket(selectBrackets) {
    if (!this._editor.hasModel()) {
      return;
    }
    const model2 = this._editor.getModel();
    const newSelections = [];
    this._editor.getSelections().forEach((selection$1) => {
      const position2 = selection$1.getStartPosition();
      let brackets = model2.bracketPairs.matchBracket(position2);
      if (!brackets) {
        brackets = model2.bracketPairs.findEnclosingBrackets(position2);
        if (!brackets) {
          const nextBracket = model2.bracketPairs.findNextBracket(position2);
          if (nextBracket && nextBracket.range) {
            brackets = model2.bracketPairs.matchBracket(nextBracket.range.getStartPosition());
          }
        }
      }
      let selectFrom = null;
      let selectTo = null;
      if (brackets) {
        brackets.sort(range.Range.compareRangesUsingStarts);
        const [open, close] = brackets;
        selectFrom = selectBrackets ? open.getStartPosition() : open.getEndPosition();
        selectTo = selectBrackets ? close.getEndPosition() : close.getStartPosition();
        if (close.containsPosition(position2)) {
          const tmp = selectFrom;
          selectFrom = selectTo;
          selectTo = tmp;
        }
      }
      if (selectFrom && selectTo) {
        newSelections.push(new selection.Selection(selectFrom.lineNumber, selectFrom.column, selectTo.lineNumber, selectTo.column));
      }
    });
    if (newSelections.length > 0) {
      this._editor.setSelections(newSelections);
      this._editor.revealRange(newSelections[0]);
    }
  }
  _updateBrackets() {
    if (this._matchBrackets === "never") {
      return;
    }
    this._recomputeBrackets();
    let newDecorations = [], newDecorationsLen = 0;
    for (const bracketData of this._lastBracketsData) {
      let brackets = bracketData.brackets;
      if (brackets) {
        newDecorations[newDecorationsLen++] = { range: brackets[0], options: bracketData.options };
        newDecorations[newDecorationsLen++] = { range: brackets[1], options: bracketData.options };
      }
    }
    this._decorations = this._editor.deltaDecorations(this._decorations, newDecorations);
  }
  _recomputeBrackets() {
    if (!this._editor.hasModel() || !this._editor.hasWidgetFocus()) {
      this._lastBracketsData = [];
      this._lastVersionId = 0;
      return;
    }
    const selections = this._editor.getSelections();
    if (selections.length > 100) {
      this._lastBracketsData = [];
      this._lastVersionId = 0;
      return;
    }
    const model2 = this._editor.getModel();
    const versionId = model2.getVersionId();
    let previousData = [];
    if (this._lastVersionId === versionId) {
      previousData = this._lastBracketsData;
    }
    let positions = [], positionsLen = 0;
    for (let i = 0, len = selections.length; i < len; i++) {
      let selection2 = selections[i];
      if (selection2.isEmpty()) {
        positions[positionsLen++] = selection2.getStartPosition();
      }
    }
    if (positions.length > 1) {
      positions.sort(position.Position.compare);
    }
    let newData = [], newDataLen = 0;
    let previousIndex = 0, previousLen = previousData.length;
    for (let i = 0, len = positions.length; i < len; i++) {
      let position2 = positions[i];
      while (previousIndex < previousLen && previousData[previousIndex].position.isBefore(position2)) {
        previousIndex++;
      }
      if (previousIndex < previousLen && previousData[previousIndex].position.equals(position2)) {
        newData[newDataLen++] = previousData[previousIndex];
      } else {
        let brackets = model2.bracketPairs.matchBracket(
          position2,
          20
          /* give at most 20ms to compute */
        );
        let options = BracketMatchingController._DECORATION_OPTIONS_WITH_OVERVIEW_RULER;
        if (!brackets && this._matchBrackets === "always") {
          brackets = model2.bracketPairs.findEnclosingBrackets(
            position2,
            20
            /* give at most 20ms to compute */
          );
          options = BracketMatchingController._DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER;
        }
        newData[newDataLen++] = new BracketsData(position2, brackets, options);
      }
    }
    this._lastBracketsData = newData;
    this._lastVersionId = versionId;
  }
}
BracketMatchingController.ID = "editor.contrib.bracketMatchingController";
BracketMatchingController._DECORATION_OPTIONS_WITH_OVERVIEW_RULER = textModel.ModelDecorationOptions.register({
  description: "bracket-match-overview",
  stickiness: 1,
  className: "bracket-match",
  overviewRuler: {
    color: themeService.themeColorFromId(overviewRulerBracketMatchForeground),
    position: model.OverviewRulerLane.Center
  }
});
BracketMatchingController._DECORATION_OPTIONS_WITHOUT_OVERVIEW_RULER = textModel.ModelDecorationOptions.register({
  description: "bracket-match-no-overview",
  stickiness: 1,
  className: "bracket-match"
});
editorExtensions.registerEditorContribution(BracketMatchingController.ID, BracketMatchingController);
editorExtensions.registerEditorAction(SelectToBracketAction);
editorExtensions.registerEditorAction(JumpToBracketAction);
themeService.registerThemingParticipant((theme, collector) => {
  const bracketMatchBackground = theme.getColor(editorColorRegistry.editorBracketMatchBackground);
  if (bracketMatchBackground) {
    collector.addRule(`.monaco-editor .bracket-match { background-color: ${bracketMatchBackground}; }`);
  }
  const bracketMatchBorder = theme.getColor(editorColorRegistry.editorBracketMatchBorder);
  if (bracketMatchBorder) {
    collector.addRule(`.monaco-editor .bracket-match { border: 1px solid ${bracketMatchBorder}; }`);
  }
});
actions.MenuRegistry.appendMenuItem(actions.MenuId.MenubarGoMenu, {
  group: "5_infile_nav",
  command: {
    id: "editor.action.jumpToBracket",
    title: nls.localize({ key: "miGoToBracket", comment: ["&& denotes a mnemonic"] }, "Go to &&Bracket")
  },
  order: 2
});
exports.BracketMatchingController = BracketMatchingController;
