mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-11 02:32:35 -05:00
Merge from vscode 073a24de05773f2261f89172987002dc0ae2f1cd (#9711)
This commit is contained in:
@@ -269,7 +269,7 @@ export class PieceTreeBase {
|
||||
protected _buffers!: StringBuffer[]; // 0 is change buffer, others are readonly original buffer.
|
||||
protected _lineCnt!: number;
|
||||
protected _length!: number;
|
||||
protected _EOL!: string;
|
||||
protected _EOL!: '\r\n' | '\n';
|
||||
protected _EOLLength!: number;
|
||||
protected _EOLNormalized!: boolean;
|
||||
private _lastChangeBufferPos!: BufferCursor;
|
||||
@@ -351,7 +351,7 @@ export class PieceTreeBase {
|
||||
}
|
||||
|
||||
// #region Buffer API
|
||||
public getEOL(): string {
|
||||
public getEOL(): '\r\n' | '\n' {
|
||||
return this._EOL;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ import { Range } from 'vs/editor/common/core/range';
|
||||
import { ApplyEditsResult, EndOfLinePreference, FindMatch, IInternalModelContentChange, ISingleEditOperationIdentifier, ITextBuffer, ITextSnapshot, ValidAnnotatedEditOperation, IValidEditOperation } from 'vs/editor/common/model';
|
||||
import { PieceTreeBase, StringBuffer } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeBase';
|
||||
import { SearchData } from 'vs/editor/common/model/textModelSearch';
|
||||
import { countEOL, StringEOL } from 'vs/editor/common/model/tokensStore';
|
||||
import { TextChange } from 'vs/editor/common/model/textChange';
|
||||
|
||||
export interface IValidatedEditOperation {
|
||||
sortIndex: number;
|
||||
@@ -16,7 +18,10 @@ export interface IValidatedEditOperation {
|
||||
range: Range;
|
||||
rangeOffset: number;
|
||||
rangeLength: number;
|
||||
lines: string[] | null;
|
||||
text: string;
|
||||
eolCount: number;
|
||||
firstLineLength: number;
|
||||
lastLineLength: number;
|
||||
forceMoveMarkers: boolean;
|
||||
isAutoWhitespaceEdit: boolean;
|
||||
}
|
||||
@@ -60,7 +65,7 @@ export class PieceTreeTextBuffer implements ITextBuffer {
|
||||
public getBOM(): string {
|
||||
return this._BOM;
|
||||
}
|
||||
public getEOL(): string {
|
||||
public getEOL(): '\r\n' | '\n' {
|
||||
return this._pieceTree.getEOL();
|
||||
}
|
||||
|
||||
@@ -201,7 +206,7 @@ export class PieceTreeTextBuffer implements ITextBuffer {
|
||||
this._pieceTree.setEOL(newEOL);
|
||||
}
|
||||
|
||||
public applyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean): ApplyEditsResult {
|
||||
public applyEdits(rawOperations: ValidAnnotatedEditOperation[], recordTrimAutoWhitespace: boolean, computeUndoEdits: boolean): ApplyEditsResult {
|
||||
let mightContainRTL = this._mightContainRTL;
|
||||
let mightContainNonBasicASCII = this._mightContainNonBasicASCII;
|
||||
let canReduceOperations = true;
|
||||
@@ -220,13 +225,34 @@ export class PieceTreeTextBuffer implements ITextBuffer {
|
||||
if (!mightContainNonBasicASCII && op.text) {
|
||||
mightContainNonBasicASCII = !strings.isBasicASCII(op.text);
|
||||
}
|
||||
|
||||
let validText = '';
|
||||
let eolCount = 0;
|
||||
let firstLineLength = 0;
|
||||
let lastLineLength = 0;
|
||||
if (op.text) {
|
||||
let strEOL: StringEOL;
|
||||
[eolCount, firstLineLength, lastLineLength, strEOL] = countEOL(op.text);
|
||||
|
||||
const bufferEOL = this.getEOL();
|
||||
const expectedStrEOL = (bufferEOL === '\r\n' ? StringEOL.CRLF : StringEOL.LF);
|
||||
if (strEOL === StringEOL.Unknown || strEOL === expectedStrEOL) {
|
||||
validText = op.text;
|
||||
} else {
|
||||
validText = op.text.replace(/\r\n|\r|\n/g, bufferEOL);
|
||||
}
|
||||
}
|
||||
|
||||
operations[i] = {
|
||||
sortIndex: i,
|
||||
identifier: op.identifier || null,
|
||||
range: validatedRange,
|
||||
rangeOffset: this.getOffsetAt(validatedRange.startLineNumber, validatedRange.startColumn),
|
||||
rangeLength: this.getValueLengthInRange(validatedRange),
|
||||
lines: op.text ? op.text.split(/\r\n|\r|\n/) : null,
|
||||
text: validText,
|
||||
eolCount: eolCount,
|
||||
firstLineLength: firstLineLength,
|
||||
lastLineLength: lastLineLength,
|
||||
forceMoveMarkers: Boolean(op.forceMoveMarkers),
|
||||
isAutoWhitespaceEdit: op.isAutoWhitespaceEdit || false
|
||||
};
|
||||
@@ -254,46 +280,56 @@ export class PieceTreeTextBuffer implements ITextBuffer {
|
||||
}
|
||||
|
||||
// Delta encode operations
|
||||
let reverseRanges = PieceTreeTextBuffer._getInverseEditRanges(operations);
|
||||
let reverseRanges = (computeUndoEdits || recordTrimAutoWhitespace ? PieceTreeTextBuffer._getInverseEditRanges(operations) : []);
|
||||
let newTrimAutoWhitespaceCandidates: { lineNumber: number, oldContent: string }[] = [];
|
||||
if (recordTrimAutoWhitespace) {
|
||||
for (let i = 0; i < operations.length; i++) {
|
||||
let op = operations[i];
|
||||
let reverseRange = reverseRanges[i];
|
||||
|
||||
for (let i = 0; i < operations.length; i++) {
|
||||
let op = operations[i];
|
||||
let reverseRange = reverseRanges[i];
|
||||
|
||||
if (recordTrimAutoWhitespace && op.isAutoWhitespaceEdit && op.range.isEmpty()) {
|
||||
// Record already the future line numbers that might be auto whitespace removal candidates on next edit
|
||||
for (let lineNumber = reverseRange.startLineNumber; lineNumber <= reverseRange.endLineNumber; lineNumber++) {
|
||||
let currentLineContent = '';
|
||||
if (lineNumber === reverseRange.startLineNumber) {
|
||||
currentLineContent = this.getLineContent(op.range.startLineNumber);
|
||||
if (strings.firstNonWhitespaceIndex(currentLineContent) !== -1) {
|
||||
continue;
|
||||
if (op.isAutoWhitespaceEdit && op.range.isEmpty()) {
|
||||
// Record already the future line numbers that might be auto whitespace removal candidates on next edit
|
||||
for (let lineNumber = reverseRange.startLineNumber; lineNumber <= reverseRange.endLineNumber; lineNumber++) {
|
||||
let currentLineContent = '';
|
||||
if (lineNumber === reverseRange.startLineNumber) {
|
||||
currentLineContent = this.getLineContent(op.range.startLineNumber);
|
||||
if (strings.firstNonWhitespaceIndex(currentLineContent) !== -1) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
newTrimAutoWhitespaceCandidates.push({ lineNumber: lineNumber, oldContent: currentLineContent });
|
||||
}
|
||||
newTrimAutoWhitespaceCandidates.push({ lineNumber: lineNumber, oldContent: currentLineContent });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let reverseOperations: IReverseSingleEditOperation[] = [];
|
||||
for (let i = 0; i < operations.length; i++) {
|
||||
let op = operations[i];
|
||||
let reverseRange = reverseRanges[i];
|
||||
let reverseOperations: IReverseSingleEditOperation[] | null = null;
|
||||
if (computeUndoEdits) {
|
||||
|
||||
reverseOperations[i] = {
|
||||
sortIndex: op.sortIndex,
|
||||
identifier: op.identifier,
|
||||
range: reverseRange,
|
||||
text: this.getValueInRange(op.range),
|
||||
forceMoveMarkers: op.forceMoveMarkers
|
||||
};
|
||||
let reverseRangeDeltaOffset = 0;
|
||||
reverseOperations = [];
|
||||
for (let i = 0; i < operations.length; i++) {
|
||||
const op = operations[i];
|
||||
const reverseRange = reverseRanges[i];
|
||||
const bufferText = this.getValueInRange(op.range);
|
||||
const reverseRangeOffset = op.rangeOffset + reverseRangeDeltaOffset;
|
||||
reverseRangeDeltaOffset += (op.text.length - bufferText.length);
|
||||
|
||||
reverseOperations[i] = {
|
||||
sortIndex: op.sortIndex,
|
||||
identifier: op.identifier,
|
||||
range: reverseRange,
|
||||
text: bufferText,
|
||||
textChange: new TextChange(op.rangeOffset, bufferText, reverseRangeOffset, op.text)
|
||||
};
|
||||
}
|
||||
|
||||
// Can only sort reverse operations when the order is not significant
|
||||
if (!hasTouchingRanges) {
|
||||
reverseOperations.sort((a, b) => a.sortIndex - b.sortIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// Can only sort reverse operations when the order is not significant
|
||||
if (!hasTouchingRanges) {
|
||||
reverseOperations.sort((a, b) => a.sortIndex - b.sortIndex);
|
||||
}
|
||||
|
||||
this._mightContainRTL = mightContainRTL;
|
||||
this._mightContainNonBasicASCII = mightContainNonBasicASCII;
|
||||
@@ -350,58 +386,45 @@ export class PieceTreeTextBuffer implements ITextBuffer {
|
||||
}
|
||||
|
||||
_toSingleEditOperation(operations: IValidatedEditOperation[]): IValidatedEditOperation {
|
||||
let forceMoveMarkers = false,
|
||||
firstEditRange = operations[0].range,
|
||||
lastEditRange = operations[operations.length - 1].range,
|
||||
entireEditRange = new Range(firstEditRange.startLineNumber, firstEditRange.startColumn, lastEditRange.endLineNumber, lastEditRange.endColumn),
|
||||
lastEndLineNumber = firstEditRange.startLineNumber,
|
||||
lastEndColumn = firstEditRange.startColumn,
|
||||
result: string[] = [];
|
||||
let forceMoveMarkers = false;
|
||||
const firstEditRange = operations[0].range;
|
||||
const lastEditRange = operations[operations.length - 1].range;
|
||||
const entireEditRange = new Range(firstEditRange.startLineNumber, firstEditRange.startColumn, lastEditRange.endLineNumber, lastEditRange.endColumn);
|
||||
let lastEndLineNumber = firstEditRange.startLineNumber;
|
||||
let lastEndColumn = firstEditRange.startColumn;
|
||||
const result: string[] = [];
|
||||
|
||||
for (let i = 0, len = operations.length; i < len; i++) {
|
||||
let operation = operations[i],
|
||||
range = operation.range;
|
||||
const operation = operations[i];
|
||||
const range = operation.range;
|
||||
|
||||
forceMoveMarkers = forceMoveMarkers || operation.forceMoveMarkers;
|
||||
|
||||
// (1) -- Push old text
|
||||
for (let lineNumber = lastEndLineNumber; lineNumber < range.startLineNumber; lineNumber++) {
|
||||
if (lineNumber === lastEndLineNumber) {
|
||||
result.push(this.getLineContent(lineNumber).substring(lastEndColumn - 1));
|
||||
} else {
|
||||
result.push('\n');
|
||||
result.push(this.getLineContent(lineNumber));
|
||||
}
|
||||
}
|
||||
|
||||
if (range.startLineNumber === lastEndLineNumber) {
|
||||
result.push(this.getLineContent(range.startLineNumber).substring(lastEndColumn - 1, range.startColumn - 1));
|
||||
} else {
|
||||
result.push('\n');
|
||||
result.push(this.getLineContent(range.startLineNumber).substring(0, range.startColumn - 1));
|
||||
}
|
||||
result.push(this.getValueInRange(new Range(lastEndLineNumber, lastEndColumn, range.startLineNumber, range.startColumn)));
|
||||
|
||||
// (2) -- Push new text
|
||||
if (operation.lines) {
|
||||
for (let j = 0, lenJ = operation.lines.length; j < lenJ; j++) {
|
||||
if (j !== 0) {
|
||||
result.push('\n');
|
||||
}
|
||||
result.push(operation.lines[j]);
|
||||
}
|
||||
if (operation.text.length > 0) {
|
||||
result.push(operation.text);
|
||||
}
|
||||
|
||||
lastEndLineNumber = operation.range.endLineNumber;
|
||||
lastEndColumn = operation.range.endColumn;
|
||||
lastEndLineNumber = range.endLineNumber;
|
||||
lastEndColumn = range.endColumn;
|
||||
}
|
||||
|
||||
const text = result.join('');
|
||||
const [eolCount, firstLineLength, lastLineLength] = countEOL(text);
|
||||
|
||||
return {
|
||||
sortIndex: 0,
|
||||
identifier: operations[0].identifier,
|
||||
range: entireEditRange,
|
||||
rangeOffset: this.getOffsetAt(entireEditRange.startLineNumber, entireEditRange.startColumn),
|
||||
rangeLength: this.getValueLengthInRange(entireEditRange, EndOfLinePreference.TextDefined),
|
||||
lines: result.join('').split('\n'),
|
||||
text: text,
|
||||
eolCount: eolCount,
|
||||
firstLineLength: firstLineLength,
|
||||
lastLineLength: lastLineLength,
|
||||
forceMoveMarkers: forceMoveMarkers,
|
||||
isAutoWhitespaceEdit: false
|
||||
};
|
||||
@@ -421,41 +444,26 @@ export class PieceTreeTextBuffer implements ITextBuffer {
|
||||
const endLineNumber = op.range.endLineNumber;
|
||||
const endColumn = op.range.endColumn;
|
||||
|
||||
if (startLineNumber === endLineNumber && startColumn === endColumn && (!op.lines || op.lines.length === 0)) {
|
||||
if (startLineNumber === endLineNumber && startColumn === endColumn && op.text.length === 0) {
|
||||
// no-op
|
||||
continue;
|
||||
}
|
||||
|
||||
const deletingLinesCnt = endLineNumber - startLineNumber;
|
||||
const insertingLinesCnt = (op.lines ? op.lines.length - 1 : 0);
|
||||
const editingLinesCnt = Math.min(deletingLinesCnt, insertingLinesCnt);
|
||||
|
||||
const text = (op.lines ? op.lines.join(this.getEOL()) : '');
|
||||
|
||||
if (text) {
|
||||
if (op.text) {
|
||||
// replacement
|
||||
this._pieceTree.delete(op.rangeOffset, op.rangeLength);
|
||||
this._pieceTree.insert(op.rangeOffset, text, true);
|
||||
this._pieceTree.insert(op.rangeOffset, op.text, true);
|
||||
|
||||
} else {
|
||||
// deletion
|
||||
this._pieceTree.delete(op.rangeOffset, op.rangeLength);
|
||||
}
|
||||
|
||||
if (editingLinesCnt < insertingLinesCnt) {
|
||||
let newLinesContent: string[] = [];
|
||||
for (let j = editingLinesCnt + 1; j <= insertingLinesCnt; j++) {
|
||||
newLinesContent.push(op.lines![j]);
|
||||
}
|
||||
|
||||
newLinesContent[newLinesContent.length - 1] = this.getLineContent(startLineNumber + insertingLinesCnt - 1);
|
||||
}
|
||||
|
||||
const contentChangeRange = new Range(startLineNumber, startColumn, endLineNumber, endColumn);
|
||||
contentChanges.push({
|
||||
range: contentChangeRange,
|
||||
rangeLength: op.rangeLength,
|
||||
text: text,
|
||||
text: op.text,
|
||||
rangeOffset: op.rangeOffset,
|
||||
forceMoveMarkers: op.forceMoveMarkers
|
||||
});
|
||||
@@ -504,18 +512,16 @@ export class PieceTreeTextBuffer implements ITextBuffer {
|
||||
|
||||
let resultRange: Range;
|
||||
|
||||
if (op.lines && op.lines.length > 0) {
|
||||
if (op.text.length > 0) {
|
||||
// the operation inserts something
|
||||
let lineCount = op.lines.length;
|
||||
let firstLine = op.lines[0];
|
||||
let lastLine = op.lines[lineCount - 1];
|
||||
const lineCount = op.eolCount + 1;
|
||||
|
||||
if (lineCount === 1) {
|
||||
// single line insert
|
||||
resultRange = new Range(startLineNumber, startColumn, startLineNumber, startColumn + firstLine.length);
|
||||
resultRange = new Range(startLineNumber, startColumn, startLineNumber, startColumn + op.firstLineLength);
|
||||
} else {
|
||||
// multi line insert
|
||||
resultRange = new Range(startLineNumber, startColumn, startLineNumber + lineCount - 1, lastLine.length + 1);
|
||||
resultRange = new Range(startLineNumber, startColumn, startLineNumber + lineCount - 1, op.lastLineLength + 1);
|
||||
}
|
||||
} else {
|
||||
// There is nothing to insert
|
||||
|
||||
Reference in New Issue
Block a user