Make TS completion item more efficent to compute

For #95324

- Removes repeated calls to `getWordRangeAtPosition`
- Only use our fuzzy string logic when using TS 3.8 or older
This commit is contained in:
Matt Bierner 2020-04-15 10:00:02 -07:00
parent 6c068456e3
commit 948aa4a214

View file

@ -32,8 +32,16 @@ interface CompletionContext {
readonly isNewIdentifierLocation: boolean;
readonly isMemberCompletion: boolean;
readonly isInValidCommitCharacterContext: boolean;
readonly enableCallCompletions: boolean;
readonly dotAccessorContext?: DotAccessorContext;
readonly enableCallCompletions: boolean;
readonly useCodeSnippetsOnMethodSuggest: boolean,
readonly wordRange: vscode.Range | undefined;
readonly line: string;
readonly useFuzzyWordRangeLogic: boolean,
}
class MyCompletionItem extends vscode.CompletionItem {
@ -42,10 +50,8 @@ class MyCompletionItem extends vscode.CompletionItem {
constructor(
public readonly position: vscode.Position,
public readonly document: vscode.TextDocument,
line: string,
public readonly tsEntry: Proto.CompletionEntry,
useCodeSnippetsOnMethodSuggest: boolean,
public readonly completionContext: CompletionContext,
private readonly completionContext: CompletionContext,
public readonly metadata: any | undefined,
) {
super(tsEntry.name, MyCompletionItem.convertKind(tsEntry.kind));
@ -63,13 +69,13 @@ class MyCompletionItem extends vscode.CompletionItem {
}
this.position = position;
this.useCodeSnippet = useCodeSnippetsOnMethodSuggest && (this.kind === vscode.CompletionItemKind.Function || this.kind === vscode.CompletionItemKind.Method);
this.useCodeSnippet = completionContext.useCodeSnippetsOnMethodSuggest && (this.kind === vscode.CompletionItemKind.Function || this.kind === vscode.CompletionItemKind.Method);
if (tsEntry.replacementSpan) {
let replaceRange = typeConverters.Range.fromTextSpan(tsEntry.replacementSpan);
// Make sure we only replace a single line at most
if (!replaceRange.isSingleLine) {
replaceRange = new vscode.Range(replaceRange.start.line, replaceRange.start.character, replaceRange.start.line, line.length);
replaceRange = new vscode.Range(replaceRange.start.line, replaceRange.start.character, replaceRange.start.line, completionContext.line.length);
}
this.range = {
inserting: new vscode.Range(replaceRange.start, position),
@ -78,12 +84,12 @@ class MyCompletionItem extends vscode.CompletionItem {
}
this.insertText = tsEntry.insertText;
this.filterText = this.getFilterText(line, tsEntry.insertText);
this.filterText = this.getFilterText(completionContext.line, tsEntry.insertText);
if (completionContext.isMemberCompletion && completionContext.dotAccessorContext) {
this.filterText = completionContext.dotAccessorContext.text + (this.insertText || this.label);
if (!this.range) {
const replacementRange = this.getReplaceRange(line);
const replacementRange = this.getFuzzyWordRange();
if (replacementRange) {
this.range = {
inserting: completionContext.dotAccessorContext.range,
@ -126,13 +132,13 @@ class MyCompletionItem extends vscode.CompletionItem {
}
}
}
this.resolveRange(line);
this.resolveRange();
}
private getFilterText(line: string, insertText: string | undefined): string | undefined {
// Handle private field completions
if (this.tsEntry.name.startsWith('#')) {
const wordRange = this.document.getWordRangeAtPosition(this.position);
const wordRange = this.completionContext.wordRange;
const wordStart = wordRange ? line.charAt(wordRange.start.character) : undefined;
if (insertText) {
if (insertText.startsWith('this.#')) {
@ -164,12 +170,12 @@ class MyCompletionItem extends vscode.CompletionItem {
return insertText;
}
private resolveRange(line: string): void {
private resolveRange(): void {
if (this.range) {
return;
}
const replaceRange = this.getReplaceRange(line);
const replaceRange = this.getFuzzyWordRange();
if (replaceRange) {
this.range = {
inserting: new vscode.Range(replaceRange.start, this.position),
@ -178,23 +184,21 @@ class MyCompletionItem extends vscode.CompletionItem {
}
}
private getReplaceRange(line: string) {
const wordRange = this.document.getWordRangeAtPosition(this.position);
let replaceRange = wordRange;
// Try getting longer, prefix based range for completions that span words
const text = line.slice(Math.max(0, this.position.character - this.label.length), this.position.character).toLowerCase();
const entryName = this.label.toLowerCase();
for (let i = entryName.length; i >= 0; --i) {
if (text.endsWith(entryName.substr(0, i)) && (!wordRange || wordRange.start.character > this.position.character - i)) {
replaceRange = new vscode.Range(
new vscode.Position(this.position.line, Math.max(0, this.position.character - i)),
this.position);
break;
private getFuzzyWordRange() {
if (this.completionContext.useFuzzyWordRangeLogic) {
// Try getting longer, prefix based range for completions that span words
const text = this.completionContext.line.slice(Math.max(0, this.position.character - this.label.length), this.position.character).toLowerCase();
const entryName = this.label.toLowerCase();
for (let i = entryName.length; i >= 0; --i) {
if (text.endsWith(entryName.substr(0, i)) && (!this.completionContext.wordRange || this.completionContext.wordRange.start.character > this.position.character - i)) {
return new vscode.Range(
new vscode.Position(this.position.line, Math.max(0, this.position.character - i)),
this.position);
}
}
}
return replaceRange;
return this.completionContext.wordRange;
}
private static convertKind(kind: string): vscode.CompletionItemKind {
@ -498,15 +502,20 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider
metadata = response.metadata;
}
const wordRange = document.getWordRangeAtPosition(position);
const isInValidCommitCharacterContext = this.isInValidCommitCharacterContext(document, position);
const items = entries
.filter(entry => !shouldExcludeCompletionEntry(entry, completionConfiguration))
.map(entry => new MyCompletionItem(position, document, line.text, entry, completionConfiguration.useCodeSnippetsOnMethodSuggest, {
.map(entry => new MyCompletionItem(position, document, entry, {
isNewIdentifierLocation,
isMemberCompletion,
dotAccessorContext,
isInValidCommitCharacterContext,
enableCallCompletions: !completionConfiguration.useCodeSnippetsOnMethodSuggest
enableCallCompletions: !completionConfiguration.useCodeSnippetsOnMethodSuggest,
wordRange,
line: line.text,
useCodeSnippetsOnMethodSuggest: completionConfiguration.useCodeSnippetsOnMethodSuggest,
useFuzzyWordRangeLogic: this.client.apiVersion.lt(API.v390),
}, metadata));
return new vscode.CompletionList(items, isIncomplete);
}