tree-sitter/lib/binding_web/src/edit.ts
2025-09-19 17:40:26 -04:00

125 lines
4.3 KiB
TypeScript

import { Point, Range } from "./constants";
export class Edit {
/** The start position of the change. */
startPosition: Point;
/** The end position of the change before the edit. */
oldEndPosition: Point;
/** The end position of the change after the edit. */
newEndPosition: Point;
/** The start index of the change. */
startIndex: number;
/** The end index of the change before the edit. */
oldEndIndex: number;
/** The end index of the change after the edit. */
newEndIndex: number;
constructor({
startIndex,
oldEndIndex,
newEndIndex,
startPosition,
oldEndPosition,
newEndPosition,
}: {
startIndex: number;
oldEndIndex: number;
newEndIndex: number;
startPosition: Point;
oldEndPosition: Point;
newEndPosition: Point;
}) {
this.startIndex = startIndex >>> 0;
this.oldEndIndex = oldEndIndex >>> 0;
this.newEndIndex = newEndIndex >>> 0;
this.startPosition = startPosition;
this.oldEndPosition = oldEndPosition;
this.newEndPosition = newEndPosition;
}
/**
* Edit a point and index to keep it in-sync with source code that has been edited.
*
* This function updates a single point's byte offset and row/column position
* based on an edit operation. This is useful for editing points without
* requiring a tree or node instance.
*/
editPoint(point: Point, index: number): { point: Point; index: number } {
let newIndex = index;
const newPoint = { ...point };
if (index >= this.oldEndIndex) {
newIndex = this.newEndIndex + (index - this.oldEndIndex);
const originalRow = point.row;
newPoint.row = this.newEndPosition.row + (point.row - this.oldEndPosition.row);
newPoint.column = originalRow === this.oldEndPosition.row
? this.newEndPosition.column + (point.column - this.oldEndPosition.column)
: point.column;
} else if (index > this.startIndex) {
newIndex = this.newEndIndex;
newPoint.row = this.newEndPosition.row;
newPoint.column = this.newEndPosition.column;
}
return { point: newPoint, index: newIndex };
}
/**
* Edit a range to keep it in-sync with source code that has been edited.
*
* This function updates a range's start and end positions based on an edit
* operation. This is useful for editing ranges without requiring a tree
* or node instance.
*/
editRange(range: Range): Range {
const newRange: Range = {
startIndex: range.startIndex,
startPosition: { ...range.startPosition },
endIndex: range.endIndex,
endPosition: { ...range.endPosition }
};
if (range.endIndex >= this.oldEndIndex) {
if (range.endIndex !== Number.MAX_SAFE_INTEGER) {
newRange.endIndex = this.newEndIndex + (range.endIndex - this.oldEndIndex);
newRange.endPosition = {
row: this.newEndPosition.row + (range.endPosition.row - this.oldEndPosition.row),
column: range.endPosition.row === this.oldEndPosition.row
? this.newEndPosition.column + (range.endPosition.column - this.oldEndPosition.column)
: range.endPosition.column,
};
if (newRange.endIndex < this.newEndIndex) {
newRange.endIndex = Number.MAX_SAFE_INTEGER;
newRange.endPosition = { row: Number.MAX_SAFE_INTEGER, column: Number.MAX_SAFE_INTEGER };
}
}
} else if (range.endIndex > this.startIndex) {
newRange.endIndex = this.startIndex;
newRange.endPosition = { ...this.startPosition };
}
if (range.startIndex >= this.oldEndIndex) {
newRange.startIndex = this.newEndIndex + (range.startIndex - this.oldEndIndex);
newRange.startPosition = {
row: this.newEndPosition.row + (range.startPosition.row - this.oldEndPosition.row),
column: range.startPosition.row === this.oldEndPosition.row
? this.newEndPosition.column + (range.startPosition.column - this.oldEndPosition.column)
: range.startPosition.column,
};
if (newRange.startIndex < this.newEndIndex) {
newRange.startIndex = Number.MAX_SAFE_INTEGER;
newRange.startPosition = { row: Number.MAX_SAFE_INTEGER, column: Number.MAX_SAFE_INTEGER };
}
} else if (range.startIndex > this.startIndex) {
newRange.startIndex = this.startIndex;
newRange.startPosition = { ...this.startPosition };
}
return newRange;
}
}