Path: blob/main/src/vs/editor/common/commands/replaceCommand.ts
3294 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Position } from '../core/position.js';6import { Range } from '../core/range.js';7import { Selection, SelectionDirection } from '../core/selection.js';8import { ICommand, ICursorStateComputerData, IEditOperationBuilder } from '../editorCommon.js';9import { ITextModel } from '../model.js';1011export class ReplaceCommand implements ICommand {1213private readonly _range: Range;14private readonly _text: string;15public readonly insertsAutoWhitespace: boolean;1617constructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {18this._range = range;19this._text = text;20this.insertsAutoWhitespace = insertsAutoWhitespace;21}2223public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {24builder.addTrackedEditOperation(this._range, this._text);25}2627public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {28const inverseEditOperations = helper.getInverseEditOperations();29const srcRange = inverseEditOperations[0].range;30return Selection.fromPositions(srcRange.getEndPosition());31}32}3334export class ReplaceOvertypeCommand implements ICommand {3536private readonly _range: Range;37private readonly _text: string;38public readonly insertsAutoWhitespace: boolean;3940constructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {41this._range = range;42this._text = text;43this.insertsAutoWhitespace = insertsAutoWhitespace;44}4546public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {47const intialStartPosition = this._range.getStartPosition();48const initialEndPosition = this._range.getEndPosition();49const initialEndLineNumber = initialEndPosition.lineNumber;50const offsetDelta = this._text.length + (this._range.isEmpty() ? 0 : -1);51let endPosition = addPositiveOffsetToModelPosition(model, initialEndPosition, offsetDelta);52if (endPosition.lineNumber > initialEndLineNumber) {53endPosition = new Position(initialEndLineNumber, model.getLineMaxColumn(initialEndLineNumber));54}55const replaceRange = Range.fromPositions(intialStartPosition, endPosition);56builder.addTrackedEditOperation(replaceRange, this._text);57}5859public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {60const inverseEditOperations = helper.getInverseEditOperations();61const srcRange = inverseEditOperations[0].range;62return Selection.fromPositions(srcRange.getEndPosition());63}64}6566export class ReplaceCommandThatSelectsText implements ICommand {6768private readonly _range: Range;69private readonly _text: string;7071constructor(range: Range, text: string) {72this._range = range;73this._text = text;74}7576public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {77builder.addTrackedEditOperation(this._range, this._text);78}7980public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {81const inverseEditOperations = helper.getInverseEditOperations();82const srcRange = inverseEditOperations[0].range;83return Selection.fromRange(srcRange, SelectionDirection.LTR);84}85}8687export class ReplaceCommandWithoutChangingPosition implements ICommand {8889private readonly _range: Range;90private readonly _text: string;91public readonly insertsAutoWhitespace: boolean;9293constructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {94this._range = range;95this._text = text;96this.insertsAutoWhitespace = insertsAutoWhitespace;97}9899public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {100builder.addTrackedEditOperation(this._range, this._text);101}102103public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {104const inverseEditOperations = helper.getInverseEditOperations();105const srcRange = inverseEditOperations[0].range;106return Selection.fromPositions(srcRange.getStartPosition());107}108}109110export class ReplaceCommandWithOffsetCursorState implements ICommand {111112private readonly _range: Range;113private readonly _text: string;114private readonly _columnDeltaOffset: number;115private readonly _lineNumberDeltaOffset: number;116public readonly insertsAutoWhitespace: boolean;117118constructor(range: Range, text: string, lineNumberDeltaOffset: number, columnDeltaOffset: number, insertsAutoWhitespace: boolean = false) {119this._range = range;120this._text = text;121this._columnDeltaOffset = columnDeltaOffset;122this._lineNumberDeltaOffset = lineNumberDeltaOffset;123this.insertsAutoWhitespace = insertsAutoWhitespace;124}125126public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {127builder.addTrackedEditOperation(this._range, this._text);128}129130public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {131const inverseEditOperations = helper.getInverseEditOperations();132const srcRange = inverseEditOperations[0].range;133return Selection.fromPositions(srcRange.getEndPosition().delta(this._lineNumberDeltaOffset, this._columnDeltaOffset));134}135}136137export class ReplaceOvertypeCommandOnCompositionEnd implements ICommand {138139private readonly _range: Range;140141constructor(range: Range) {142this._range = range;143}144145public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {146const text = model.getValueInRange(this._range);147const initialEndPosition = this._range.getEndPosition();148const initialEndLineNumber = initialEndPosition.lineNumber;149let endPosition = addPositiveOffsetToModelPosition(model, initialEndPosition, text.length);150if (endPosition.lineNumber > initialEndLineNumber) {151endPosition = new Position(initialEndLineNumber, model.getLineMaxColumn(initialEndLineNumber));152}153const replaceRange = Range.fromPositions(initialEndPosition, endPosition);154builder.addTrackedEditOperation(replaceRange, '');155}156157public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {158const inverseEditOperations = helper.getInverseEditOperations();159const srcRange = inverseEditOperations[0].range;160return Selection.fromPositions(srcRange.getEndPosition());161}162}163164export class ReplaceCommandThatPreservesSelection implements ICommand {165166private readonly _range: Range;167private readonly _text: string;168private readonly _initialSelection: Selection;169private readonly _forceMoveMarkers: boolean;170private _selectionId: string | null;171172constructor(editRange: Range, text: string, initialSelection: Selection, forceMoveMarkers: boolean = false) {173this._range = editRange;174this._text = text;175this._initialSelection = initialSelection;176this._forceMoveMarkers = forceMoveMarkers;177this._selectionId = null;178}179180public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {181builder.addTrackedEditOperation(this._range, this._text, this._forceMoveMarkers);182this._selectionId = builder.trackSelection(this._initialSelection);183}184185public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {186return helper.getTrackedSelection(this._selectionId!);187}188}189190function addPositiveOffsetToModelPosition(model: ITextModel, position: Position, offset: number): Position {191if (offset < 0) {192throw new Error('Unexpected negative delta');193}194const lineCount = model.getLineCount();195let endPosition = new Position(lineCount, model.getLineMaxColumn(lineCount));196for (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {197if (lineNumber === position.lineNumber) {198const futureOffset = offset - model.getLineMaxColumn(position.lineNumber) + position.column;199if (futureOffset <= 0) {200endPosition = new Position(position.lineNumber, position.column + offset);201break;202}203offset = futureOffset;204} else {205const futureOffset = offset - model.getLineMaxColumn(lineNumber);206if (futureOffset <= 0) {207endPosition = new Position(lineNumber, offset);208break;209}210offset = futureOffset;211}212}213return endPosition;214}215216217