Skip to content

Commit eee7724

Browse files
committed
Async calls to reduce server workload
1 parent 43167cf commit eee7724

File tree

4 files changed

+54
-51
lines changed

4 files changed

+54
-51
lines changed

server/src/project/document.ts

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Diagnostic, SemanticTokens, SymbolInformation, SymbolKind } from 'vscode-languageserver';
1+
import { CancellationToken, Diagnostic, LSPErrorCodes, ResponseError, SemanticTokens, SymbolInformation, SymbolKind } from 'vscode-languageserver';
22
import { Workspace } from './workspace';
33
import { FoldableElement } from './elements/special';
44
import { BaseSyntaxElement, HasAttribute, HasSemanticToken, HasSymbolInformation } from './elements/base';
@@ -9,17 +9,7 @@ import { SemanticTokensManager } from '../capabilities/semanticTokens';
99
import { sleep } from '../utils/helpers';
1010

1111

12-
export interface ProjectDocument {
13-
name: string;
14-
textDocument: TextDocument;
15-
languageServerSemanticTokens: (range?: Range) => SemanticTokens | null;
16-
languageServerSymbolInformationAsync(): Promise<SymbolInformation[]>;
17-
get foldableElements(): FoldingRange[];
18-
parseAsync(): Promise<void>;
19-
}
20-
21-
22-
export abstract class BaseProjectDocument implements ProjectDocument {
12+
export abstract class BaseProjectDocument {
2313
readonly workspace: Workspace;
2414
readonly textDocument: TextDocument;
2515
readonly name: string;
@@ -36,13 +26,8 @@ export abstract class BaseProjectDocument implements ProjectDocument {
3626
protected _semanticTokens: SemanticTokensManager = new SemanticTokensManager();
3727

3828
isBusy = false;
39-
private _requestId = 0;
4029
abstract symbolKind: SymbolKind
4130

42-
get foldableElements() {
43-
return this._foldableElements;
44-
}
45-
4631
get activeAttributeElement() {
4732
return this._attributeElements?.at(-1);
4833
}
@@ -53,7 +38,7 @@ export abstract class BaseProjectDocument implements ProjectDocument {
5338
this.name = name;
5439
}
5540

56-
static create(workspace: Workspace, document: TextDocument): VbaClassDocument | VbaModuleDocument {
41+
static create(workspace: Workspace, document: TextDocument): BaseProjectDocument {
5742
const slashParts = document.uri.split('/').at(-1);
5843
const dotParts = slashParts?.split('.');
5944
const extension = dotParts?.at(-1);
@@ -77,24 +62,21 @@ export abstract class BaseProjectDocument implements ProjectDocument {
7762
return this._semanticTokens.getSemanticTokens(range);
7863
};
7964

80-
async languageServerSymbolInformationAsync(): Promise<SymbolInformation[]> {
81-
this._requestId += 1;
82-
const requestId = this._requestId;
65+
async languageServerSymbolInformationAsync(token: CancellationToken): Promise<SymbolInformation[]> {
8366
while (this.isBusy) {
8467
await sleep(5);
85-
if (requestId < this._requestId) {
68+
if (token.isCancellationRequested) {
8669
return [];
8770
}
8871
}
89-
this._requestId = 0;
9072
return this._symbolInformations;
9173
}
9274

93-
parseAsync = async (): Promise<void> => {
75+
parseAsync = async (token: CancellationToken): Promise<void> => {
9476
this.isBusy = true;
95-
console.log('Parsing document');
96-
await (new SyntaxParser()).parseAsync(this);
97-
this.isBusy = false;
77+
if (await (new SyntaxParser()).parseAsync(this, token)) {
78+
this.isBusy = false;
79+
}
9880
};
9981

10082
registerNamedElementDeclaration(element: any) {
@@ -177,6 +159,18 @@ export abstract class BaseProjectDocument implements ProjectDocument {
177159
registerSymbolInformation = (element: HasSymbolInformation): number => {
178160
return this._symbolInformations.push(element.symbolInformation);
179161
};
162+
163+
/** Get document information */
164+
async getFoldingRanges(token: CancellationToken): Promise<FoldingRange[]> {
165+
while (this.isBusy) {
166+
await sleep(5);
167+
if (token.isCancellationRequested) {
168+
return [];
169+
}
170+
}
171+
this.workspace.connection.console.info('Processing request for Folding Range');
172+
return this._foldableElements;
173+
}
180174
}
181175

182176

server/src/project/elements/module.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ export class ModuleElement extends BaseContextSyntaxElement implements HasSymbol
2222
}
2323

2424
get symbolInformation(): SymbolInformation {
25-
console.warn(`Creating symbol with name ${this._name}`);
2625
return SymbolInformationFactory.create(
2726
this, this.symbolKind
2827
);

server/src/project/parser/vbaSyntaxParser.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { FoldableElement } from '../elements/special';
1414
import { ConstDeclarationsElement, EnumBlockDeclarationElement, EnumMemberDeclarationElement, MethodBlockDeclarationElement, VariableDeclarationsElement } from '../elements/memory';
1515
import { ModuleElement } from '../elements/module';
1616
import { sleep } from '../../utils/helpers';
17+
import { CancellationToken } from 'vscode-languageserver';
1718

1819
export class SyntaxParser {
1920
private static _lockIdentifier = 0;
@@ -31,25 +32,34 @@ export class SyntaxParser {
3132
this._lockIdentifier = 0;
3233
}
3334

34-
async parseAsync(document: VbaClassDocument | VbaModuleDocument) {
35+
async parseAsync(document: VbaClassDocument | VbaModuleDocument, token: CancellationToken): Promise<boolean> {
36+
// token.onCancellationRequested(e => {
37+
// throw new Error("No");
38+
// });
39+
3540
// Refuse to do anything that seems like too much work.
3641
if (document.textDocument.lineCount > 1000) {
3742
// TODO: Make this an option that people can increase or decrease.
3843
console.log(`Document oversize: ${document.textDocument.lineCount} lines.`);
3944
console.warn(`Syntax parsing has been disabled to prevent crashing.`);
40-
return;
45+
return false;
4146
}
4247

4348
// Wait a few seconds to see if any other input has ocurred.
4449
const lock = SyntaxParser._acquireLock();
4550
await sleep(1000);
4651
if (!SyntaxParser._hasLock(lock)) {
4752
console.info('Newer lock detected. Cancelling parse.');
48-
return;
53+
return false;
4954
}
5055
SyntaxParser._releaseLock();
5156

5257
// Parse the document.
58+
this.parse(document);
59+
return true;
60+
}
61+
62+
parse(document: VbaClassDocument | VbaModuleDocument) {
5363
console.info('Parsing the document.');
5464
const listener = new VbaTreeWalkListener(document);
5565
const parser = this.createParser(document.textDocument);

server/src/project/workspace.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { CompletionItem, CompletionParams, DidChangeConfigurationNotification, DidChangeConfigurationParams, DidChangeWatchedFilesParams, DocumentSymbolParams, FoldingRange, FoldingRangeParams, Hover, HoverParams, SemanticTokensParams, SemanticTokensRangeParams, SymbolInformation, TextDocuments, WorkspaceFoldersChangeEvent, _Connection } from 'vscode-languageserver';
2-
import { BaseProjectDocument, ProjectDocument } from './document';
1+
import { CancellationToken, CancellationTokenSource, CompletionItem, CompletionParams, DidChangeConfigurationNotification, DidChangeConfigurationParams, DidChangeWatchedFilesParams, DocumentSymbolParams, FoldingRange, FoldingRangeParams, Hover, HoverParams, SemanticTokensParams, SemanticTokensRangeParams, SymbolInformation, TextDocuments, WorkspaceFoldersChangeEvent, _Connection } from 'vscode-languageserver';
2+
import { BaseProjectDocument } from './document';
33
import { LanguageServerConfiguration } from '../server';
44
import { hasConfigurationCapability } from '../capabilities/workspaceFolder';
55
import { TextDocument } from 'vscode-languageserver-textdocument';
@@ -11,13 +11,13 @@ import { TextDocument } from 'vscode-languageserver-textdocument';
1111
*/
1212
export class Workspace {
1313
private _events: WorkspaceEvents;
14-
private _documents: ProjectDocument[] = [];
15-
private _activeDocument?: ProjectDocument;
14+
private _documents: BaseProjectDocument[] = [];
15+
private _activeDocument?: BaseProjectDocument;
1616
private _publicScopeDeclarations: Map<string, any> = new Map();
1717

1818
readonly connection: _Connection;
1919

20-
activateDocument(document: ProjectDocument) {
20+
activateDocument(document: BaseProjectDocument) {
2121
this._activeDocument = document;
2222
}
2323

@@ -59,8 +59,9 @@ class WorkspaceEvents {
5959
private readonly _workspace: Workspace;
6060
private readonly _documents: TextDocuments<TextDocument>;
6161
private readonly _configuration: LanguageServerConfiguration;
62+
private _parseCancellationToken?: CancellationTokenSource;
6263

63-
activeDocument?: ProjectDocument;
64+
activeDocument?: BaseProjectDocument;
6465

6566
constructor(params: {connection: _Connection, workspace: Workspace, configuration: LanguageServerConfiguration}) {
6667
this._workspace = params.workspace;
@@ -72,17 +73,16 @@ class WorkspaceEvents {
7273
}
7374

7475
private initialiseConnectionEvents(connection: _Connection) {
75-
console.log('Initialising connection events...');
7676
connection.onInitialized(() => this.onInitialized());
7777
connection.onCompletion(params => this.onCompletion(params));
7878
connection.onCompletionResolve(item => this.onCompletionResolve(item));
7979
connection.onDidChangeConfiguration(params => this.onDidChangeConfiguration(params));
8080
connection.onDidChangeWatchedFiles(params => this.onDidChangeWatchedFiles(params));
81-
connection.onDocumentSymbol(async (params) => await this.onDocumentSymbolAsync(params));
81+
connection.onDocumentSymbol(async (params, token) => await this.onDocumentSymbolAsync(params, token));
8282
connection.onHover(params => this.onHover(params));
8383

8484
if (hasConfigurationCapability(this._configuration)) {
85-
connection.onFoldingRanges((params) => this.onFoldingRanges(params));
85+
connection.onFoldingRanges(async (params, token) => this.onFoldingRanges(params, token));
8686
}
8787

8888
connection.onRequest((method: string, params: object | object[] | any) => {
@@ -101,19 +101,16 @@ class WorkspaceEvents {
101101
}
102102

103103
private initialiseDocumentsEvents() {
104-
console.log('Initialising documents events...');
105104
this._documents.onDidChangeContent(async (e) => await this.onDidChangeContentAsync(e.document));
106105
}
107106

108107
/** Connection event handlers */
109108

110109
private onCompletion(params: CompletionParams): never[] {
111-
console.log(`onCompletion: ${params}`);
112110
return [];
113111
}
114112

115113
private onCompletionResolve(item: CompletionItem): CompletionItem {
116-
console.log(`onCompletionResolve: ${item.label}`);
117114
return item;
118115
}
119116

@@ -127,16 +124,15 @@ class WorkspaceEvents {
127124

128125
// TODO: Should trigger a full workspace refresh.
129126
private onDidChangeWorkspaceFolders(e: WorkspaceFoldersChangeEvent) {
130-
console.log(`onDidChangeWorkspaceFolders: ${e}`);
131127
this._workspace.connection.console.log(`Workspace folder change event received.\n${e}`);
132128
}
133129

134-
private async onDocumentSymbolAsync(params: DocumentSymbolParams): Promise<SymbolInformation[]> {
135-
return await this.activeDocument?.languageServerSymbolInformationAsync() ?? [];
130+
private async onDocumentSymbolAsync(params: DocumentSymbolParams, token: CancellationToken): Promise<SymbolInformation[]> {
131+
return await this.activeDocument?.languageServerSymbolInformationAsync(token) ?? [];
136132
}
137133

138-
private onFoldingRanges(params: FoldingRangeParams): FoldingRange[] {
139-
return this._workspace.activeDocument?.foldableElements ?? [];
134+
private async onFoldingRanges(params: FoldingRangeParams, token: CancellationToken): Promise<FoldingRange[]> {
135+
return await this._workspace.activeDocument?.getFoldingRanges(token) ?? [];
140136
}
141137

142138
private onHover(params: HoverParams): Hover {
@@ -163,9 +159,13 @@ class WorkspaceEvents {
163159
* @param doc The document that changed.
164160
*/
165161
async onDidChangeContentAsync(doc: TextDocument) {
162+
// this._parseCancellationToken?.cancel();
163+
// this._parseCancellationToken?.dispose();
164+
166165
this.activeDocument = BaseProjectDocument.create(this._workspace, doc);
167-
await this.activeDocument.parseAsync();
166+
this._parseCancellationToken = new CancellationTokenSource();
167+
await this.activeDocument.parseAsync(this._parseCancellationToken.token);
168+
this._parseCancellationToken = undefined;
168169
this._workspace.activateDocument(this.activeDocument);
169170
}
170-
171-
}
171+
}

0 commit comments

Comments
 (0)