Inline childFromLineNumber and childFromCharOffset (#17018)

* Inline childFromLineNumber and childFromCharOffset

* Handle empty document -- root node with 0 children

* Fix test
This commit is contained in:
Andy 2017-08-09 13:43:25 -07:00 committed by GitHub
parent bd68122821
commit b8c37bb50c
2 changed files with 27 additions and 57 deletions

View file

@ -49,6 +49,12 @@ var q:Point=<Point>p;`;
validateEditAtLineCharIndex = undefined;
});
it("handles empty lines array", () => {
const lineIndex = new server.LineIndex();
lineIndex.load([]);
assert.deepEqual(lineIndex.positionToLineOffset(0), { line: 1, offset: 1 });
});
it(`change 9 1 0 1 {"y"}`, () => {
validateEditAtLineCharIndex(9, 1, 0, "y");
});

View file

@ -675,45 +675,29 @@ namespace ts.server {
// Input position is relative to the start of this node.
// Output line number is absolute.
charOffsetToLineInfo(lineNumberAccumulator: number, relativePosition: number): { oneBasedLine: number, zeroBasedColumn: number, lineText: string | undefined } {
const childInfo = this.childFromCharOffset(lineNumberAccumulator, relativePosition);
if (!childInfo.child) {
return {
oneBasedLine: lineNumberAccumulator,
zeroBasedColumn: relativePosition,
lineText: undefined,
};
if (this.children.length === 0) {
// Root node might have no children if this is an empty document.
return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: undefined };
}
else if (childInfo.childIndex < this.children.length) {
if (childInfo.child.isLeaf()) {
return {
oneBasedLine: childInfo.lineNumberAccumulator,
zeroBasedColumn: childInfo.relativePosition,
lineText: childInfo.child.text,
};
for (const child of this.children) {
if (child.charCount() > relativePosition) {
if (child.isLeaf()) {
return { oneBasedLine: lineNumberAccumulator, zeroBasedColumn: relativePosition, lineText: child.text };
}
else {
return (<LineNode>child).charOffsetToLineInfo(lineNumberAccumulator, relativePosition);
}
}
else {
const lineNode = <LineNode>(childInfo.child);
return lineNode.charOffsetToLineInfo(childInfo.lineNumberAccumulator, childInfo.relativePosition);
relativePosition -= child.charCount();
lineNumberAccumulator += child.lineCount();
}
}
else {
const lineInfo = this.lineNumberToInfo(this.lineCount(), 0);
return { oneBasedLine: this.lineCount(), zeroBasedColumn: lineInfo.leaf.charCount(), lineText: undefined };
}
}
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
const childInfo = this.childFromLineNumber(relativeOneBasedLine, positionAccumulator);
if (!childInfo.child) {
return { position: positionAccumulator, leaf: undefined };
}
else if (childInfo.child.isLeaf()) {
return { position: childInfo.positionAccumulator, leaf: childInfo.child };
}
else {
const lineNode = <LineNode>(childInfo.child);
return lineNode.lineNumberToInfo(childInfo.relativeOneBasedLine, childInfo.positionAccumulator);
}
// Skipped all children
const { leaf } = this.lineNumberToInfo(this.lineCount(), 0);
return { oneBasedLine: this.lineCount(), zeroBasedColumn: leaf.charCount(), lineText: undefined };
}
/**
@ -721,39 +705,19 @@ namespace ts.server {
* Output line number is relative to the child.
* positionAccumulator will be an absolute position once relativeLineNumber reaches 0.
*/
private childFromLineNumber(relativeOneBasedLine: number, positionAccumulator: number): { child: LineCollection, relativeOneBasedLine: number, positionAccumulator: number } {
let child: LineCollection;
let i: number;
for (i = 0; i < this.children.length; i++) {
child = this.children[i];
lineNumberToInfo(relativeOneBasedLine: number, positionAccumulator: number): { position: number, leaf: LineLeaf | undefined } {
for (const child of this.children) {
const childLineCount = child.lineCount();
if (childLineCount >= relativeOneBasedLine) {
break;
return child.isLeaf() ? { position: positionAccumulator, leaf: child } : (<LineNode>child).lineNumberToInfo(relativeOneBasedLine, positionAccumulator);
}
else {
relativeOneBasedLine -= childLineCount;
positionAccumulator += child.charCount();
}
}
return { child, relativeOneBasedLine, positionAccumulator };
}
private childFromCharOffset(lineNumberAccumulator: number, relativePosition: number
): { child: LineCollection, childIndex: number, relativePosition: number, lineNumberAccumulator: number } {
let child: LineCollection;
let i: number;
let len: number;
for (i = 0, len = this.children.length; i < len; i++) {
child = this.children[i];
if (child.charCount() > relativePosition) {
break;
}
else {
relativePosition -= child.charCount();
lineNumberAccumulator += child.lineCount();
}
}
return { child, childIndex: i, relativePosition, lineNumberAccumulator };
return { position: positionAccumulator, leaf: undefined };
}
private splitAfter(childIndex: number) {