Skip to content

Commit

Permalink
Make TS completion item more efficent to compute
Browse files Browse the repository at this point in the history
For #95324

- Removes repeated calls to `getWordRangeAtPosition`
- Only use our fuzzy string logic when using TS 3.8 or older
  • Loading branch information
mjbvz committed Apr 15, 2020
1 parent 6c06845 commit 948aa4a
Showing 1 changed file with 37 additions and 28 deletions.
65 changes: 37 additions & 28 deletions extensions/typescript-language-features/src/features/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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));
Expand All @@ -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),
Expand All @@ -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,
Expand Down Expand Up @@ -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.#')) {
Expand Down Expand Up @@ -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),
Expand All @@ -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 {
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 948aa4a

Please sign in to comment.