Skip to content

Commit b8c37bb

Browse files
author
Andy
authored
Inline childFromLineNumber and childFromCharOffset (microsoft#17018)
* Inline childFromLineNumber and childFromCharOffset * Handle empty document -- root node with 0 children * Fix test
1 parent bd68122 commit b8c37bb

File tree

2 files changed

+28
-58
lines changed

2 files changed

+28
-58
lines changed

src/harness/unittests/versionCache.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ var q:Point=<Point>p;`;
4949
validateEditAtLineCharIndex = undefined;
5050
});
5151

52+
it("handles empty lines array", () => {
53+
const lineIndex = new server.LineIndex();
54+
lineIndex.load([]);
55+
assert.deepEqual(lineIndex.positionToLineOffset(0), { line: 1, offset: 1 });
56+
});
57+
5258
it(`change 9 1 0 1 {"y"}`, () => {
5359
validateEditAtLineCharIndex(9, 1, 0, "y");
5460
});

src/server/scriptVersionCache.ts

Lines changed: 22 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -675,85 +675,49 @@ namespace ts.server {
675675
// Input position is relative to the start of this node.
676676
// Output line number is absolute.
677677
charOffsetToLineInfo(lineNumberAccumulator: number, relativePosition: number): { oneBasedLine: number, zeroBasedColumn: number, lineText: string | undefined } {
678-
const childInfo = this.childFromCharOffset(lineNumberAccumulator, relativePosition);
679-
if (!childInfo.child) {
680-
return {
681-
oneBasedLine: lineNumberAccumulator,
682-
zeroBasedColumn: relativePosition,
683-
lineText: undefined,
684-
};
685-
}
686-
else if (childInfo.childIndex < this.children.length) {
687-
if (childInfo.child.isLeaf()) {
688-
return {
689-
oneBasedLine: childInfo.lineNumberAccumulator,
690-
zeroBasedColumn: childInfo.relativePosition,
691-
lineText: childInfo.child.text,
692-
};
678+
if (this.children.length === 0) {
679+
// Root node might have no children if this is an empty document.
680+
return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: undefined };
681+
}
682+
683+
for (const child of this.children) {
684+
if (child.charCount() > relativePosition) {
685+
if (child.isLeaf()) {
686+
return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: child.text };
687+
}
688+
else {
689+
return (<LineNode>child).charOffsetToLineInfo(lineNumberAccumulator, relativePosition);
690+
}
693691
}
694692
else {
695-
const lineNode = <LineNode>(childInfo.child);
696-
return lineNode.charOffsetToLineInfo(childInfo.lineNumberAccumulator, childInfo.relativePosition);
693+
relativePosition -= child.charCount();
694+
lineNumberAccumulator += child.lineCount();
697695
}
698696
}
699-
else {
700-
const lineInfo = this.lineNumberToInfo(this.lineCount(), 0);
701-
return { oneBasedLine: this.lineCount(), zeroBasedColumn: lineInfo.leaf.charCount(), lineText: undefined };
702-
}
703-
}
704697

705-
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
706-
const childInfo = this.childFromLineNumber(relativeOneBasedLine, positionAccumulator);
707-
if (!childInfo.child) {
708-
return { position: positionAccumulator, leaf: undefined };
709-
}
710-
else if (childInfo.child.isLeaf()) {
711-
return { position: childInfo.positionAccumulator, leaf: childInfo.child };
712-
}
713-
else {
714-
const lineNode = <LineNode>(childInfo.child);
715-
return lineNode.lineNumberToInfo(childInfo.relativeOneBasedLine, childInfo.positionAccumulator);
716-
}
698+
// Skipped all children
699+
const { leaf } = this.lineNumberToInfo(this.lineCount(), 0);
700+
return { oneBasedLine: this.lineCount(), zeroBasedColumn: leaf.charCount(), lineText: undefined };
717701
}
718702

719703
/**
720704
* Input line number is relative to the start of this node.
721705
* Output line number is relative to the child.
722706
* positionAccumulator will be an absolute position once relativeLineNumber reaches 0.
723707
*/
724-
private childFromLineNumber(relativeOneBasedLine: number, positionAccumulator: number): { child: LineCollection, relativeOneBasedLine: number, positionAccumulator: number } {
725-
let child: LineCollection;
726-
let i: number;
727-
for (i = 0; i < this.children.length; i++) {
728-
child = this.children[i];
708+
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
709+
for (const child of this.children) {
729710
const childLineCount = child.lineCount();
730711
if (childLineCount >= relativeOneBasedLine) {
731-
break;
712+
return child.isLeaf() ? { position: positionAccumulator, leaf: child } : (<LineNode>child).lineNumberToInfo(relativeOneBasedLine, positionAccumulator);
732713
}
733714
else {
734715
relativeOneBasedLine -= childLineCount;
735716
positionAccumulator += child.charCount();
736717
}
737718
}
738-
return { child, relativeOneBasedLine, positionAccumulator };
739-
}
740719

741-
private childFromCharOffset(lineNumberAccumulator: number, relativePosition: number
742-
): { child: LineCollection, childIndex: number, relativePosition: number, lineNumberAccumulator: number } {
743-
let child: LineCollection;
744-
let i: number;
745-
let len: number;
746-
for (i = 0, len = this.children.length; i < len; i++) {
747-
child = this.children[i];
748-
if (child.charCount() > relativePosition) {
749-
break;
750-
}
751-
else {
752-
relativePosition -= child.charCount();
753-
lineNumberAccumulator += child.lineCount();
754-
}
755-
}
756-
return { child, childIndex: i, relativePosition, lineNumberAccumulator };
720+
return { position: positionAccumulator, leaf: undefined };
757721
}
758722

759723
private splitAfter(childIndex: number) {

0 commit comments

Comments
 (0)