Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/common/commands/replaceCommand.ts
3294 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Position } from '../core/position.js';
7
import { Range } from '../core/range.js';
8
import { Selection, SelectionDirection } from '../core/selection.js';
9
import { ICommand, ICursorStateComputerData, IEditOperationBuilder } from '../editorCommon.js';
10
import { ITextModel } from '../model.js';
11
12
export class ReplaceCommand implements ICommand {
13
14
private readonly _range: Range;
15
private readonly _text: string;
16
public readonly insertsAutoWhitespace: boolean;
17
18
constructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {
19
this._range = range;
20
this._text = text;
21
this.insertsAutoWhitespace = insertsAutoWhitespace;
22
}
23
24
public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {
25
builder.addTrackedEditOperation(this._range, this._text);
26
}
27
28
public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
29
const inverseEditOperations = helper.getInverseEditOperations();
30
const srcRange = inverseEditOperations[0].range;
31
return Selection.fromPositions(srcRange.getEndPosition());
32
}
33
}
34
35
export class ReplaceOvertypeCommand implements ICommand {
36
37
private readonly _range: Range;
38
private readonly _text: string;
39
public readonly insertsAutoWhitespace: boolean;
40
41
constructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {
42
this._range = range;
43
this._text = text;
44
this.insertsAutoWhitespace = insertsAutoWhitespace;
45
}
46
47
public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {
48
const intialStartPosition = this._range.getStartPosition();
49
const initialEndPosition = this._range.getEndPosition();
50
const initialEndLineNumber = initialEndPosition.lineNumber;
51
const offsetDelta = this._text.length + (this._range.isEmpty() ? 0 : -1);
52
let endPosition = addPositiveOffsetToModelPosition(model, initialEndPosition, offsetDelta);
53
if (endPosition.lineNumber > initialEndLineNumber) {
54
endPosition = new Position(initialEndLineNumber, model.getLineMaxColumn(initialEndLineNumber));
55
}
56
const replaceRange = Range.fromPositions(intialStartPosition, endPosition);
57
builder.addTrackedEditOperation(replaceRange, this._text);
58
}
59
60
public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
61
const inverseEditOperations = helper.getInverseEditOperations();
62
const srcRange = inverseEditOperations[0].range;
63
return Selection.fromPositions(srcRange.getEndPosition());
64
}
65
}
66
67
export class ReplaceCommandThatSelectsText implements ICommand {
68
69
private readonly _range: Range;
70
private readonly _text: string;
71
72
constructor(range: Range, text: string) {
73
this._range = range;
74
this._text = text;
75
}
76
77
public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {
78
builder.addTrackedEditOperation(this._range, this._text);
79
}
80
81
public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
82
const inverseEditOperations = helper.getInverseEditOperations();
83
const srcRange = inverseEditOperations[0].range;
84
return Selection.fromRange(srcRange, SelectionDirection.LTR);
85
}
86
}
87
88
export class ReplaceCommandWithoutChangingPosition implements ICommand {
89
90
private readonly _range: Range;
91
private readonly _text: string;
92
public readonly insertsAutoWhitespace: boolean;
93
94
constructor(range: Range, text: string, insertsAutoWhitespace: boolean = false) {
95
this._range = range;
96
this._text = text;
97
this.insertsAutoWhitespace = insertsAutoWhitespace;
98
}
99
100
public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {
101
builder.addTrackedEditOperation(this._range, this._text);
102
}
103
104
public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
105
const inverseEditOperations = helper.getInverseEditOperations();
106
const srcRange = inverseEditOperations[0].range;
107
return Selection.fromPositions(srcRange.getStartPosition());
108
}
109
}
110
111
export class ReplaceCommandWithOffsetCursorState implements ICommand {
112
113
private readonly _range: Range;
114
private readonly _text: string;
115
private readonly _columnDeltaOffset: number;
116
private readonly _lineNumberDeltaOffset: number;
117
public readonly insertsAutoWhitespace: boolean;
118
119
constructor(range: Range, text: string, lineNumberDeltaOffset: number, columnDeltaOffset: number, insertsAutoWhitespace: boolean = false) {
120
this._range = range;
121
this._text = text;
122
this._columnDeltaOffset = columnDeltaOffset;
123
this._lineNumberDeltaOffset = lineNumberDeltaOffset;
124
this.insertsAutoWhitespace = insertsAutoWhitespace;
125
}
126
127
public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {
128
builder.addTrackedEditOperation(this._range, this._text);
129
}
130
131
public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
132
const inverseEditOperations = helper.getInverseEditOperations();
133
const srcRange = inverseEditOperations[0].range;
134
return Selection.fromPositions(srcRange.getEndPosition().delta(this._lineNumberDeltaOffset, this._columnDeltaOffset));
135
}
136
}
137
138
export class ReplaceOvertypeCommandOnCompositionEnd implements ICommand {
139
140
private readonly _range: Range;
141
142
constructor(range: Range) {
143
this._range = range;
144
}
145
146
public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {
147
const text = model.getValueInRange(this._range);
148
const initialEndPosition = this._range.getEndPosition();
149
const initialEndLineNumber = initialEndPosition.lineNumber;
150
let endPosition = addPositiveOffsetToModelPosition(model, initialEndPosition, text.length);
151
if (endPosition.lineNumber > initialEndLineNumber) {
152
endPosition = new Position(initialEndLineNumber, model.getLineMaxColumn(initialEndLineNumber));
153
}
154
const replaceRange = Range.fromPositions(initialEndPosition, endPosition);
155
builder.addTrackedEditOperation(replaceRange, '');
156
}
157
158
public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
159
const inverseEditOperations = helper.getInverseEditOperations();
160
const srcRange = inverseEditOperations[0].range;
161
return Selection.fromPositions(srcRange.getEndPosition());
162
}
163
}
164
165
export class ReplaceCommandThatPreservesSelection implements ICommand {
166
167
private readonly _range: Range;
168
private readonly _text: string;
169
private readonly _initialSelection: Selection;
170
private readonly _forceMoveMarkers: boolean;
171
private _selectionId: string | null;
172
173
constructor(editRange: Range, text: string, initialSelection: Selection, forceMoveMarkers: boolean = false) {
174
this._range = editRange;
175
this._text = text;
176
this._initialSelection = initialSelection;
177
this._forceMoveMarkers = forceMoveMarkers;
178
this._selectionId = null;
179
}
180
181
public getEditOperations(model: ITextModel, builder: IEditOperationBuilder): void {
182
builder.addTrackedEditOperation(this._range, this._text, this._forceMoveMarkers);
183
this._selectionId = builder.trackSelection(this._initialSelection);
184
}
185
186
public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection {
187
return helper.getTrackedSelection(this._selectionId!);
188
}
189
}
190
191
function addPositiveOffsetToModelPosition(model: ITextModel, position: Position, offset: number): Position {
192
if (offset < 0) {
193
throw new Error('Unexpected negative delta');
194
}
195
const lineCount = model.getLineCount();
196
let endPosition = new Position(lineCount, model.getLineMaxColumn(lineCount));
197
for (let lineNumber = position.lineNumber; lineNumber <= lineCount; lineNumber++) {
198
if (lineNumber === position.lineNumber) {
199
const futureOffset = offset - model.getLineMaxColumn(position.lineNumber) + position.column;
200
if (futureOffset <= 0) {
201
endPosition = new Position(position.lineNumber, position.column + offset);
202
break;
203
}
204
offset = futureOffset;
205
} else {
206
const futureOffset = offset - model.getLineMaxColumn(lineNumber);
207
if (futureOffset <= 0) {
208
endPosition = new Position(lineNumber, offset);
209
break;
210
}
211
offset = futureOffset;
212
}
213
}
214
return endPosition;
215
}
216
217