text: /*---------------------------------------------------------------------------------------------
   *  Copyright (c) Microsoft Corporation. All rights reserved.
   *  Licensed under the MIT License. See License.txt in the project root for license information.
   *--------------------------------------------------------------------------------------------*/
  import * as strings from '../../../base/common/strings.js';
  import { ReplaceCommand } from '../commands/replaceCommand.js';
  import { CursorColumns, EditOperationResult, isQuote } from './cursorCommon.js';
  import { MoveOperations } from './cursorMoveOperations.js';
  import { Range } from '../core/range.js';
  import { Position } from '../core/position.js';
  export class DeleteOperations {
      static deleteRight(prevEditOperationType, config, model, selections) {
          let commands = [];
          let shouldPushStackElementBefore = (prevEditOperationType !== 3 /* DeletingRight */);
          for (let i = 0, len = selections.length; i < len; i++) {
              const selection = selections[i];
              let deleteSelection = selection;
              if (deleteSelection.isEmpty()) {
                  let position = selection.getPosition();
                  let rightOfPosition = MoveOperations.right(config, model, position);
                  deleteSelection = new Range(rightOfPosition.lineNumber, rightOfPosition.column, position.lineNumber, position.column);
              }
              if (deleteSelection.isEmpty()) {
                  // Probably at end of file => ignore
                  commands[i] = null;
                  continue;
              }
              if (deleteSelection.startLineNumber !== deleteSelection.endLineNumber) {
                  shouldPushStackElementBefore = true;
              }
              commands[i] = new ReplaceCommand(deleteSelection, '');
          }
          return [shouldPushStackElementBefore, commands];
      }
      static isAutoClosingPairDelete(autoClosingDelete, autoClosingBrackets, autoClosingQuotes, autoClosingPairsOpen, model, selections, autoClosedCharacters) {
          if (autoClosingBrackets === 'never' && autoClosingQuotes === 'never') {
              return false;
          }
          if (autoClosingDelete === 'never') {
              return false;
          }
          for (let i = 0, len = selections.length; i < len; i++) {
              const selection = selections[i];
              const position = selection.getPosition();
              if (!selection.isEmpty()) {
                  return false;
              }
              const lineText = model.getLineContent(position.lineNumber);
              if (position.column < 2 || position.column >= lineText.length + 1) {
                  return false;
              }
              const character = lineText.charAt(position.column - 2);
              const autoClosingPairCandidates = autoClosingPairsOpen.get(character);
              if (!autoClosingPairCandidates) {
                  return false;
              }
              if (isQuote(character)) {
                  if (autoClosingQuotes === 'never') {
                      return false;
                  }
              }
              else {
                  if (autoClosingBrackets === 'never') {
                      return false;
                  }
              }
              const afterCharacter = lineText.charAt(position.column - 1);
              let foundAutoClosingPair = false;
              for (const autoClosingPairCandidate of autoClosingPairCandidates) {
                  if (autoClosingPairCandidate.open === character && autoClosingPairCandidate.close === afterCharacter) {
                      foundAutoClosingPair = true;
                  }
              }
              if (!foundAutoClosingPair) {
                  return false;
              }
              // Must delete the pair only if it was automatically inserted by the editor
              if (autoClosingDelete === 'auto') {
                  let found = false;
                  for (let j = 0, lenJ = autoClosedCharacters.length; j < lenJ; j++) {
                      const autoClosedCharacter = autoClosedCharacters[j];
                      if (position.lineNumber === autoClosedCharacter.startLineNumber && position.column === autoClosedCharacter.startColumn) {
                          found = true;
                          break;
                      }
                  }
                  if (!found) {
                      return false;
                  }
              }
          }
          return true;
      }
      static _runAutoClosingPairDelete(config, model, selections) {
          let commands = [];
          for (let i = 0, len = selections.length; i < len; i++) {
              const position = selections[i].getPosition();
              const deleteSelection = new Range(position.lineNumber, position.column - 1, position.lineNumber, position.column + 1);
              commands[i] = new ReplaceCommand(deleteSelection, '');
          }
          return [true, commands];
      }
      static deleteLeft(prevEditOperationType, config, model, selections, autoClosedCharacters) {
          if (this.isAutoClosingPairDelete(config.autoClosingDelete, config.autoClosingBrackets, config.autoClosingQuotes, config.autoClosingPairs.autoClosingPairsOpenByEnd, model, selections, autoClosedCharacters)) {
              return this._runAutoClosingPairDelete(config, model, selections);
          }
          const commands = [];
          let shouldPushStackElementBefore = (prevEditOperationType !== 2 /* DeletingLeft */);
          for (let i = 0, len = selections.length; i < len; i++) {
              let deleteRange = DeleteOperations.getDeleteRange(selections[i], model, config);
              // Ignore empty delete ranges, as they have no effect
              // They happen if the cursor is at the beginning of the file.
              if (deleteRange.isEmpty()) {
                  commands[i] = null;
                  continue;
              }
              if (deleteRange.startLineNumber !== deleteRange.endLineNumber) {
                  shouldPushStackElementBefore = true;
              }
              commands[i] = new ReplaceCommand(deleteRange, '');
          }
          return [shouldPushStackElementBefore, commands];
      }
      static getDeleteRange(selection, model, config) {
          if (!selection.isEmpty()) {
              return selection;
          }
          const position = selection.getPosition();
          // Unintend when using tab stops and cursor is within indentation
          if (config.useTabStops && position.column > 1) {
              const lineContent = model.getLineContent(position.lineNumber);
              const firstNonWhitespaceIndex = strings.firstNonWhitespaceIndex(lineContent);
              const lastIndentationColumn = (firstNonWhitespaceIndex === -1
                  ? /* entire string is whitespace */ lineContent.length + 1
                  : firstNonWhitespaceIndex + 1);
              if (position.column <= lastIndentationColumn) {
                  const fromVisibleColumn = CursorColumns.visibleColumnFromColumn2(config, model, position);
                  const toVisibleColumn = CursorColumns.prevIndentTabStop(fromVisibleColumn, config.indentSize);
                  const toColumn = CursorColumns.columnFromVisibleColumn2(config, model, position.lineNumber, toVisibleColumn);
                  return new Range(position.lineNumber, toColumn, position.lineNumber, position.column);
              }
          }
          return Range.fromPositions(DeleteOperations.getPositionAfterDeleteLeft(position, model), position);
      }
      static getPositionAfterDeleteLeft(position, model) {
          if (position.column > 1) {
              // Convert 1-based columns to 0-based offsets and back.
              const idx = strings.getLeftDeleteOffset(position.column - 1, model.getLineContent(position.lineNumber));
              return position.with(undefined, idx + 1);
          }
          else if (position.lineNumber > 1) {
              const newLine = position.lineNumber - 1;
              return new Position(newLine, model.getLineMaxColumn(newLine));
          }
          else {
              return position;
          }
      }
      static cut(config, model, selections) {
          let commands = [];
          for (let i = 0, len = selections.length; i < len; i++) {
              const selection = selections[i];
              if (selection.isEmpty()) {
                  if (config.emptySelectionClipboard) {
                      // This is a full line cut
                      let position = selection.getPosition();
                      let startLineNumber, startColumn, endLineNumber, endColumn;
                      if (position.lineNumber < model.getLineCount()) {
                          // Cutting a line in the middle of the model
                          startLineNumber = position.lineNumber;
                          startColumn = 1;
                          endLineNumber = position.lineNumber + 1;
                          endColumn = 1;
                      }
                      else if (position.lineNumber > 1) {
                          // Cutting the last line & there are more than 1 lines in the model
                          startLineNumber = position.lineNumber - 1;
                          startColumn = model.getLineMaxColumn(position.lineNumber - 1);
                          endLineNumber = position.lineNumber;
                          endColumn = model.getLineMaxColumn(position.lineNumber);
                      }
                      else {
                          // Cutting the single line that the model contains
                          startLineNumber = position.lineNumber;
                          startColumn = 1;
                          endLineNumber = position.lineNumber;
                          endColumn = model.getLineMaxColumn(position.lineNumber);
                      }
                      let deleteSelection = new Range(startLineNumber, startColumn, endLineNumber, endColumn);
                      if (!deleteSelection.isEmpty()) {
                          commands[i] = new ReplaceCommand(deleteSelection, '');
                      }
                      else {
                          commands[i] = null;
                      }
                  }
                  else {
                      // Cannot cut empty selection
                      commands[i] = null;
                  }
              }
              else {
                  commands[i] = new ReplaceCommand(selection, '');
              }
          }
          return new EditOperationResult(0 /* Other */, commands, {
              shouldPushStackElementBefore: true,
              shouldPushStackElementAfter: true
          });
      }
  }
  