Skip to content

Commit

Permalink
Sets a hard limit of number of scopes to check for completions (#1244)
Browse files Browse the repository at this point in the history
* Sets a hard limit of number of scopes to check for completions

* Update src/bscPlugin/completions/CompletionsProcessor.ts

Co-authored-by: Bronley Plumb <bronley@gmail.com>

* Fixes from PR comments

---------

Co-authored-by: Bronley Plumb <bronley@gmail.com>
  • Loading branch information
markwpearce and TwitchBronBron committed Jul 8, 2024
1 parent 050a191 commit 0b04e82
Showing 1 changed file with 31 additions and 6 deletions.
37 changes: 31 additions & 6 deletions src/bscPlugin/completions/CompletionsProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import { createIdentifier } from '../../astUtils/creators';
import type { FunctionExpression } from '../../parser/Expression';
import { LogLevel } from '../../Logger';


const SCOPES_FOR_COMPLETION = 3;

export class CompletionsProcessor {
constructor(
private event: ProvideCompletionsEvent
Expand All @@ -34,11 +37,9 @@ export class CompletionsProcessor {
public process() {
let file = this.event.file;
this.event.program.logger.time(LogLevel.log, ['Processing completions'], () => {
//find the scopes for this file
let scopesForFile = this.event.program.getScopesForFile(file);

//if there are no scopes, include the global scope so we at least get the built-in functions
scopesForFile = scopesForFile.length > 0 ? scopesForFile : [this.event.program.globalScope];
// Find the scopes for this file - Only process the first few scopes
const scopesToProcess = this.getScopesForCompletion(file);

//get the completions from all scopes for this file
let completionResults: CompletionItem[] = [];
Expand All @@ -53,6 +54,7 @@ export class CompletionsProcessor {
this.event.completions.push(...this.getScriptImportCompletions(file.program, file.pkgPath, scriptImport));
return;
}

const results = this.getBrsFileCompletions(this.event.position, file);
completionResults = results.scoped;
globalResults = results.global;
Expand All @@ -67,13 +69,35 @@ export class CompletionsProcessor {
for (let completion of allCompletions) {
let key = `${completion.label}-${completion.kind}`;
keyCounts.set(key, keyCounts.has(key) ? keyCounts.get(key) + 1 : 1);
if (keyCounts.get(key) === scopesForFile.length) {
if (keyCounts.get(key) === scopesToProcess.length) {
this.event.completions.push(completion);
}
}
});
}

private getScopesForCompletion(file: BscFile) {
//find the scopes for this file
let scopesForFile = this.event.program?.getScopesForFile(file) ?? [];

//if there are no scopes, include the global scope so we at least get the built-in functions
if (this.event.program) {
scopesForFile = scopesForFile.length > 0 ? scopesForFile : [this.event.program.globalScope];
}

// Only process the first few scopes. This might result in missing completions,
// but it's better than wasting TONS of cycles building essentially the same completions over and over
const scopesToProcess = scopesForFile.slice(0, SCOPES_FOR_COMPLETION);

// always include the source scope if applicable to this file
let sourceScope = scopesForFile.find(x => x.name === 'source');
if (sourceScope && !scopesToProcess.includes(sourceScope)) {
//replace the first scope with the source scope so we process a consistent number of scopes if possible
scopesToProcess[0] = sourceScope;
}
return scopesToProcess;
}


/**
* Get all available completions for the specified position
Expand Down Expand Up @@ -265,7 +289,8 @@ export class CompletionsProcessor {
globalCompletions.push(...this.getSymbolsCompletion(globalSymbols));
}

for (const scope of this.event.scopes) {
const scopesToProcess = this.getScopesForCompletion(file);
for (const scope of scopesToProcess) {
if (tokenKind === TokenKind.StringLiteral || tokenKind === TokenKind.TemplateStringQuasi) {
result.push(...this.getStringLiteralCompletions(scope, currentToken));
continue;
Expand Down

0 comments on commit 0b04e82

Please sign in to comment.