Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reindex replacements spans for completions to be 0-indexed #12332

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3816,6 +3816,11 @@ namespace ts {
export type Transformer = (context: TransformationContext) => (node: SourceFile) => SourceFile;

export interface TextSpan {
/**
* 0-indexed position in the file.
*
* ie: the first position in the file has start === 0.
*/
start: number;
length: number;
}
Expand Down
6 changes: 4 additions & 2 deletions src/server/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,10 @@ namespace ts.server {
if (entry.replacementSpan !== undefined) {
const { name, kind, kindModifiers, sortText, replacementSpan} = entry;

const convertedSpan = createTextSpanFromBounds(this.lineOffsetToPosition(fileName, replacementSpan.start),
this.lineOffsetToPosition(fileName, replacementSpan.end));
const startBound = this.lineOffsetToPosition(fileName, replacementSpan.start)
const endBound = this.lineOffsetToPosition(fileName, replacementSpan.end)

const convertedSpan = createTextSpanFromBounds(startBound, endBound);
return { name, kind, kindModifiers, sortText, replacementSpan: convertedSpan };
}

Expand Down
16 changes: 13 additions & 3 deletions src/server/scriptInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,23 @@ namespace ts.server {
}

/**
* @param line 1-based index
* @param offset 1-based index
* @param position 0-based position index
* @return ILineInfo with 1-based indexing for line numbers and offsets.
*/
positionToLineOffset(position: number): ILineInfo {
positionToOneIndexedLineOffset(position: number): ILineInfo {
const index = this.snap().index;
const lineOffset = index.charOffsetToLineNumberAndPos(position);
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
}

/**
* @param position 0-based position index
* @return ILineInfo with 0-based indexing for line numbers and offsets.
*/
positionToZeroIndexedLineOffset(position: number): ILineInfo {
const index = this.snap().index;
const lineOffset = index.charOffsetToLineNumberAndPos(position);
return { line: lineOffset.line - 1, offset: lineOffset.offset };
}
}
}
94 changes: 54 additions & 40 deletions src/server/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ namespace ts.server {
function formatDiag(fileName: NormalizedPath, project: Project, diag: ts.Diagnostic): protocol.Diagnostic {
const scriptInfo = project.getScriptInfoForNormalizedPath(fileName);
return {
start: scriptInfo.positionToLineOffset(diag.start),
end: scriptInfo.positionToLineOffset(diag.start + diag.length),
start: scriptInfo.positionToOneIndexedLineOffset(diag.start),
end: scriptInfo.positionToOneIndexedLineOffset(diag.start + diag.length),
text: ts.flattenDiagnosticMessageText(diag.messageText, "\n"),
code: diag.code
};
Expand Down Expand Up @@ -396,8 +396,8 @@ namespace ts.server {
length: d.length,
category: DiagnosticCategory[d.category].toLowerCase(),
code: d.code,
startLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start),
endLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start + d.length)
startLocation: scriptInfo && scriptInfo.positionToOneIndexedLineOffset(d.start),
endLocation: scriptInfo && scriptInfo.positionToOneIndexedLineOffset(d.start + d.length)
});
}

Expand Down Expand Up @@ -428,8 +428,8 @@ namespace ts.server {
const defScriptInfo = project.getScriptInfo(def.fileName);
return {
file: def.fileName,
start: defScriptInfo.positionToLineOffset(def.textSpan.start),
end: defScriptInfo.positionToLineOffset(ts.textSpanEnd(def.textSpan))
start: defScriptInfo.positionToOneIndexedLineOffset(def.textSpan.start),
end: defScriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(def.textSpan))
};
});
}
Expand All @@ -452,8 +452,8 @@ namespace ts.server {
const defScriptInfo = project.getScriptInfo(def.fileName);
return {
file: def.fileName,
start: defScriptInfo.positionToLineOffset(def.textSpan.start),
end: defScriptInfo.positionToLineOffset(ts.textSpanEnd(def.textSpan))
start: defScriptInfo.positionToOneIndexedLineOffset(def.textSpan.start),
end: defScriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(def.textSpan))
};
});
}
Expand All @@ -469,8 +469,8 @@ namespace ts.server {
if (simplifiedResult) {
return implementations.map(impl => ({
file: impl.fileName,
start: scriptInfo.positionToLineOffset(impl.textSpan.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(impl.textSpan))
start: scriptInfo.positionToOneIndexedLineOffset(impl.textSpan.start),
end: scriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(impl.textSpan))
}));
}
else {
Expand All @@ -492,8 +492,8 @@ namespace ts.server {
return occurrences.map(occurrence => {
const { fileName, isWriteAccess, textSpan } = occurrence;
const scriptInfo = project.getScriptInfo(fileName);
const start = scriptInfo.positionToLineOffset(textSpan.start);
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan));
const start = scriptInfo.positionToOneIndexedLineOffset(textSpan.start);
const end = scriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(textSpan));
return {
start,
end,
Expand Down Expand Up @@ -539,8 +539,8 @@ namespace ts.server {

function convertHighlightSpan(highlightSpan: ts.HighlightSpan): ts.server.protocol.HighlightSpan {
const { textSpan, kind } = highlightSpan;
const start = scriptInfo.positionToLineOffset(textSpan.start);
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(textSpan));
const start = scriptInfo.positionToOneIndexedLineOffset(textSpan.start);
const end = scriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(textSpan));
return { start, end, kind };
}
}
Expand Down Expand Up @@ -624,8 +624,8 @@ namespace ts.server {
const locationScriptInfo = project.getScriptInfo(location.fileName);
return <protocol.FileSpan>{
file: location.fileName,
start: locationScriptInfo.positionToLineOffset(location.textSpan.start),
end: locationScriptInfo.positionToLineOffset(ts.textSpanEnd(location.textSpan)),
start: locationScriptInfo.positionToOneIndexedLineOffset(location.textSpan.start),
end: locationScriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(location.textSpan)),
};
});
},
Expand Down Expand Up @@ -708,7 +708,7 @@ namespace ts.server {

const displayString = ts.displayPartsToString(nameInfo.displayParts);
const nameSpan = nameInfo.textSpan;
const nameColStart = scriptInfo.positionToLineOffset(nameSpan.start).offset;
const nameColStart = scriptInfo.positionToOneIndexedLineOffset(nameSpan.start).offset;
const nameText = scriptInfo.snap().getText(nameSpan.start, ts.textSpanEnd(nameSpan));
const refs = combineProjectOutput<protocol.ReferencesResponseItem>(
projects,
Expand All @@ -720,14 +720,14 @@ namespace ts.server {

return references.map(ref => {
const refScriptInfo = project.getScriptInfo(ref.fileName);
const start = refScriptInfo.positionToLineOffset(ref.textSpan.start);
const start = refScriptInfo.positionToOneIndexedLineOffset(ref.textSpan.start);
const refLineSpan = refScriptInfo.lineToTextSpan(start.line - 1);
const lineText = refScriptInfo.snap().getText(refLineSpan.start, ts.textSpanEnd(refLineSpan)).replace(/\r|\n/g, "");
return {
file: ref.fileName,
start: start,
lineText: lineText,
end: refScriptInfo.positionToLineOffset(ts.textSpanEnd(ref.textSpan)),
end: refScriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(ref.textSpan)),
isWriteAccess: ref.isWriteAccess,
isDefinition: ref.isDefinition
};
Expand Down Expand Up @@ -856,8 +856,8 @@ namespace ts.server {
return {
kind: quickInfo.kind,
kindModifiers: quickInfo.kindModifiers,
start: scriptInfo.positionToLineOffset(quickInfo.textSpan.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(quickInfo.textSpan)),
start: scriptInfo.positionToOneIndexedLineOffset(quickInfo.textSpan.start),
end: scriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(quickInfo.textSpan)),
displayString: displayString,
documentation: docString,
};
Expand Down Expand Up @@ -952,8 +952,8 @@ namespace ts.server {

return edits.map((edit) => {
return {
start: scriptInfo.positionToLineOffset(edit.span.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(edit.span)),
start: scriptInfo.positionToOneIndexedLineOffset(edit.span.start),
end: scriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(edit.span)),
newText: edit.newText ? edit.newText : ""
};
});
Expand All @@ -966,24 +966,31 @@ namespace ts.server {
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
const position = this.getPosition(args, scriptInfo);

const completions = project.getLanguageService().getCompletionsAtPosition(file, position);
const completions: ts.CompletionInfo = project.getLanguageService().getCompletionsAtPosition(file, position);
if (!completions) {
return undefined;
}

if (simplifiedResult) {
return completions.entries.reduce((result: protocol.CompletionEntry[], entry: ts.CompletionEntry) => {
if (completions.isMemberCompletion || (entry.name.toLowerCase().indexOf(prefix.toLowerCase()) === 0)) {
const { name, kind, kindModifiers, sortText, replacementSpan } = entry;
const convertedSpan: protocol.TextSpan =
replacementSpan ? this.decorateSpan(replacementSpan, scriptInfo) : undefined;
result.push({ name, kind, kindModifiers, sortText, replacementSpan: convertedSpan });
const convertedSpan: protocol.TextSpan | undefined = entry.replacementSpan ?
this.toZeroIndexedProtocolSpan(entry.replacementSpan, scriptInfo) :
undefined;

result.push(toProtocolCompletionEntry(entry, convertedSpan));
}
return result;
}, []).sort((a, b) => ts.compareStrings(a.name, b.name));
}
else {
return completions;
}

function toProtocolCompletionEntry(entry: ts.CompletionEntry | protocol.CompletionEntry, replacementSpan?: protocol.TextSpan): protocol.CompletionEntry {
entry.replacementSpan = replacementSpan;
return <protocol.CompletionEntry>entry;
}
}

private getCompletionEntryDetails(args: protocol.CompletionDetailsRequestArgs): protocol.CompletionEntryDetails[] {
Expand Down Expand Up @@ -1044,8 +1051,8 @@ namespace ts.server {
return {
items: helpItems.items,
applicableSpan: {
start: scriptInfo.positionToLineOffset(span.start),
end: scriptInfo.positionToLineOffset(span.start + span.length)
start: scriptInfo.positionToOneIndexedLineOffset(span.start),
end: scriptInfo.positionToOneIndexedLineOffset(span.start + span.length)
},
selectedItemIndex: helpItems.selectedItemIndex,
argumentIndex: helpItems.argumentIndex,
Expand Down Expand Up @@ -1119,7 +1126,7 @@ namespace ts.server {
text: item.text,
kind: item.kind,
kindModifiers: item.kindModifiers,
spans: item.spans.map(span => this.decorateSpan(span, scriptInfo)),
spans: item.spans.map(span => this.toOneIndexedProtocolSpan(span, scriptInfo)),
childItems: this.decorateNavigationBarItems(item.childItems, scriptInfo),
indent: item.indent
}));
Expand All @@ -1140,15 +1147,22 @@ namespace ts.server {
text: tree.text,
kind: tree.kind,
kindModifiers: tree.kindModifiers,
spans: tree.spans.map(span => this.decorateSpan(span, scriptInfo)),
spans: tree.spans.map(span => this.toOneIndexedProtocolSpan(span, scriptInfo)),
childItems: map(tree.childItems, item => this.decorateNavigationTree(item, scriptInfo))
};
}

private decorateSpan(span: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
private toOneIndexedProtocolSpan(span: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
return {
start: scriptInfo.positionToOneIndexedLineOffset(span.start),
end: scriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(span))
};
}

private toZeroIndexedProtocolSpan(span: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan {
return {
start: scriptInfo.positionToLineOffset(span.start),
end: scriptInfo.positionToLineOffset(ts.textSpanEnd(span))
start: scriptInfo.positionToZeroIndexedLineOffset(span.start),
end: scriptInfo.positionToZeroIndexedLineOffset(ts.textSpanEnd(span))
};
}

Expand Down Expand Up @@ -1177,8 +1191,8 @@ namespace ts.server {

return navItems.map((navItem) => {
const scriptInfo = project.getScriptInfo(navItem.fileName);
const start = scriptInfo.positionToLineOffset(navItem.textSpan.start);
const end = scriptInfo.positionToLineOffset(ts.textSpanEnd(navItem.textSpan));
const start = scriptInfo.positionToOneIndexedLineOffset(navItem.textSpan.start);
const end = scriptInfo.positionToOneIndexedLineOffset(ts.textSpanEnd(navItem.textSpan));
const bakedItem: protocol.NavtoItem = {
name: navItem.name,
kind: navItem.kind,
Expand Down Expand Up @@ -1285,8 +1299,8 @@ namespace ts.server {

private convertTextChangeToCodeEdit(change: ts.TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit {
return {
start: scriptInfo.positionToLineOffset(change.span.start),
end: scriptInfo.positionToLineOffset(change.span.start + change.span.length),
start: scriptInfo.positionToOneIndexedLineOffset(change.span.start),
end: scriptInfo.positionToOneIndexedLineOffset(change.span.start + change.span.length),
newText: change.newText ? change.newText : ""
};
}
Expand All @@ -1301,7 +1315,7 @@ namespace ts.server {
return !spans
? undefined
: simplifiedResult
? spans.map(span => this.decorateSpan(span, scriptInfo))
? spans.map(span => this.toOneIndexedProtocolSpan(span, scriptInfo))
: spans;
}

Expand Down