From b559eb64e2571cef06acd05568809edc43fbb354 Mon Sep 17 00:00:00 2001 From: sslinky Date: Thu, 23 May 2024 09:06:01 +0800 Subject: [PATCH 01/16] Get, Set, Let now work on variable assignment --- client/src/syntaxes/vba.tmLanguage.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/client/src/syntaxes/vba.tmLanguage.yaml b/client/src/syntaxes/vba.tmLanguage.yaml index 4b4fe16..9d19c4f 100644 --- a/client/src/syntaxes/vba.tmLanguage.yaml +++ b/client/src/syntaxes/vba.tmLanguage.yaml @@ -504,13 +504,15 @@ repository: - include: "#language" variableAssignment: - match: "(?i)([a-z][a-z0-9_]*)(\\s*=\\s*)(.*)" + match: "(?i)((Get|Let|Set)\\s+)?([a-z][a-z0-9_]*)(\\s*=\\s*)(.*)" captures: - 1: - name: variable.other.assignment.vba 2: - name: keyword.operator.assignment.vba + name: keyword.control.vba 3: + name: variable.other.assignment.vba + 4: + name: keyword.operator.assignment.vba + 5: patterns: - include: "#funcCall" - include: "#subCall" From 56ba4c6856ed75c57ccde5b31d1f2fead2762f67 Mon Sep 17 00:00:00 2001 From: sslinky Date: Thu, 23 May 2024 09:22:28 +0800 Subject: [PATCH 02/16] Removed testing --- client/src/syntaxes/vba.tmLanguage.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/client/src/syntaxes/vba.tmLanguage.yaml b/client/src/syntaxes/vba.tmLanguage.yaml index 9d19c4f..8c2a99d 100644 --- a/client/src/syntaxes/vba.tmLanguage.yaml +++ b/client/src/syntaxes/vba.tmLanguage.yaml @@ -19,7 +19,6 @@ repository: - include: "#mthdSig" - include: "#variableDeclarations" - include: "#block" - - include: "#testing" repository: moduleLines: match: '([^\n:]*)?:(?=([^"]*"[^"]*")*[^"]*$)' From a08c46ffc1a0b703863a2e5f480e93ebf9889164 Mon Sep 17 00:00:00 2001 From: sslinky Date: Thu, 23 May 2024 09:22:45 +0800 Subject: [PATCH 03/16] 1.2.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 030657e..ecb6c23 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vba-lsp", - "version": "1.2.0", + "version": "1.2.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vba-lsp", - "version": "1.2.0", + "version": "1.2.1", "hasInstallScript": true, "license": "MIT", "devDependencies": { diff --git a/package.json b/package.json index 76ad0e0..824d64c 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "icon": "images/vba-lsp-icon.png", "author": "SSlinky", "license": "MIT", - "version": "1.2.0", + "version": "1.2.1", "repository": { "type": "git", "url": "https://github.com/SSlinky/VBA-LanguageServer" From ab5415d6ef78d9c83ffa911e7b7f072682244951 Mon Sep 17 00:00:00 2001 From: sslinky Date: Thu, 23 May 2024 16:14:38 +0800 Subject: [PATCH 04/16] Fixed some On Error lines resolving as func or sub calls --- client/src/syntaxes/vba.tmLanguage.yaml | 8 ++++---- server/src/server.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/syntaxes/vba.tmLanguage.yaml b/client/src/syntaxes/vba.tmLanguage.yaml index 8c2a99d..b3e3e1c 100644 --- a/client/src/syntaxes/vba.tmLanguage.yaml +++ b/client/src/syntaxes/vba.tmLanguage.yaml @@ -137,7 +137,7 @@ repository: - include: "#flowBranchSimple" repository: flowBranchOnGos: - match: "(?i)\\b(on\\s+error|on)\\s+(.*\\s+)?(goto|gosub)\\s+([a-z][a-z0-9_]*|\\d+)\\b" + match: "(?i)\\b(on\\s+error|on)\\s+(.*\\s+)?(goto|gosub)\\s+([a-z][a-z0-9_]*|\\d+)\\b(.*)" captures: 1: name: keyword.control.flow.branch.vba @@ -148,6 +148,9 @@ repository: name: keyword.control.flow.branch.vba 4: name: variable.other.constant.label.vba + 5: + patterns: + - include: "#vbaLang" flowBranchSimple: name: keyword.control.flow.branch.vba @@ -442,8 +445,6 @@ repository: - include: "#blockLines" - include: "#variableDeclarations" - include: "#variableAssignment" - - include: "#funcCall" - - include: "#subCall" - include: "#mthdClose" - include: "#language" @@ -557,7 +558,6 @@ repository: - include: "#args" end: "\\n" - args: # The match gates an args list. It is not consumed by the # match immediately because it is passed through captures which diff --git a/server/src/server.ts b/server/src/server.ts index 38a1a65..eb3dc6b 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -56,8 +56,8 @@ export class LanguageServerConfiguration { hoverProvider: false, textDocumentSync: TextDocumentSyncKind.Incremental, completionProvider: { resolveProvider: false }, - foldingRangeProvider: true, - documentSymbolProvider: true, + foldingRangeProvider: false, + documentSymbolProvider: false, }; constructor(params: InitializeParams) { From de4c923bf539a5ff03a2cad7a9268b86de69f6f9 Mon Sep 17 00:00:00 2001 From: sslinky Date: Thu, 23 May 2024 16:15:06 +0800 Subject: [PATCH 05/16] 1.2.2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index ecb6c23..2dc0619 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vba-lsp", - "version": "1.2.1", + "version": "1.2.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vba-lsp", - "version": "1.2.1", + "version": "1.2.2", "hasInstallScript": true, "license": "MIT", "devDependencies": { diff --git a/package.json b/package.json index 824d64c..c0fcd5d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "icon": "images/vba-lsp-icon.png", "author": "SSlinky", "license": "MIT", - "version": "1.2.1", + "version": "1.2.2", "repository": { "type": "git", "url": "https://github.com/SSlinky/VBA-LanguageServer" From 713e8d98bce8b20d3f8303a834f67c3c8a262286 Mon Sep 17 00:00:00 2001 From: sslinky Date: Thu, 23 May 2024 21:33:05 +0800 Subject: [PATCH 06/16] Removed some logging and added request cancellation for long processes --- server/src/project/document.ts | 16 ++++++--- server/src/project/parser/vbaSyntaxParser.ts | 37 +++++++++++++++++++- server/src/project/workspace.ts | 16 +++------ 3 files changed, 52 insertions(+), 17 deletions(-) diff --git a/server/src/project/document.ts b/server/src/project/document.ts index 08b6377..bbd9419 100644 --- a/server/src/project/document.ts +++ b/server/src/project/document.ts @@ -15,7 +15,7 @@ export interface ProjectDocument { languageServerSemanticTokens: (range?: Range) => SemanticTokens | null; languageServerSymbolInformationAsync(): Promise; get foldableElements(): FoldingRange[]; - parse(): void; + parseAsync(): Promise; } @@ -36,6 +36,7 @@ export abstract class BaseProjectDocument implements ProjectDocument { protected _semanticTokens: SemanticTokensManager = new SemanticTokensManager(); isBusy = false; + private _requestId = 0; abstract symbolKind: SymbolKind get foldableElements() { @@ -76,18 +77,23 @@ export abstract class BaseProjectDocument implements ProjectDocument { return this._semanticTokens.getSemanticTokens(range); }; - async languageServerSymbolInformationAsync() { + async languageServerSymbolInformationAsync(): Promise { + this._requestId += 1; + const requestId = this._requestId; while (this.isBusy) { await sleep(5); + if (requestId < this._requestId) { + return []; + } } + this._requestId = 0; return this._symbolInformations; } - parse = (): void => { + parseAsync = async (): Promise => { this.isBusy = true; console.log('Parsing document'); - (new SyntaxParser()).parse(this); - console.log('Finished parsing document'); + await (new SyntaxParser()).parseAsync(this); this.isBusy = false; }; diff --git a/server/src/project/parser/vbaSyntaxParser.ts b/server/src/project/parser/vbaSyntaxParser.ts index c28c466..7bab51b 100644 --- a/server/src/project/parser/vbaSyntaxParser.ts +++ b/server/src/project/parser/vbaSyntaxParser.ts @@ -13,9 +13,44 @@ import { VbaClassDocument, VbaModuleDocument } from '../document'; import { FoldableElement } from '../elements/special'; import { ConstDeclarationsElement, EnumBlockDeclarationElement, EnumMemberDeclarationElement, MethodBlockDeclarationElement, VariableDeclarationsElement } from '../elements/memory'; import { ModuleElement } from '../elements/module'; +import { sleep } from '../../utils/helpers'; export class SyntaxParser { - parse(document: VbaClassDocument | VbaModuleDocument) { + private static _lockIdentifier = 0; + + private static _acquireLock(): number { + this._lockIdentifier += 1; + return this._lockIdentifier; + } + + private static _hasLock(lockIdentifier: number): boolean { + return this._lockIdentifier === lockIdentifier; + } + + private static _releaseLock(): void { + this._lockIdentifier = 0; + } + + async parseAsync(document: VbaClassDocument | VbaModuleDocument) { + // Refuse to do anything that seems like too much work. + if (document.textDocument.lineCount > 1000) { + // TODO: Make this an option that people can increase or decrease. + console.log(`Document oversize: ${document.textDocument.lineCount} lines.`); + console.warn(`Syntax parsing has been disabled to prevent crashing.`); + return; + } + + // Wait a few seconds to see if any other input has ocurred. + const lock = SyntaxParser._acquireLock(); + await sleep(1000); + if (!SyntaxParser._hasLock(lock)) { + console.info('Newer lock detected. Cancelling parse.'); + return; + } + SyntaxParser._releaseLock(); + + // Parse the document. + console.info('Parsing the document.'); const listener = new VbaTreeWalkListener(document); const parser = this.createParser(document.textDocument); diff --git a/server/src/project/workspace.ts b/server/src/project/workspace.ts index 52a2931..fdc1212 100644 --- a/server/src/project/workspace.ts +++ b/server/src/project/workspace.ts @@ -78,7 +78,7 @@ class WorkspaceEvents { connection.onCompletionResolve(item => this.onCompletionResolve(item)); connection.onDidChangeConfiguration(params => this.onDidChangeConfiguration(params)); connection.onDidChangeWatchedFiles(params => this.onDidChangeWatchedFiles(params)); - connection.onDocumentSymbol((params) => this.onDocumentSymbolAsync(params)); + connection.onDocumentSymbol(async (params) => await this.onDocumentSymbolAsync(params)); connection.onHover(params => this.onHover(params)); if (hasConfigurationCapability(this._configuration)) { @@ -102,7 +102,7 @@ class WorkspaceEvents { private initialiseDocumentsEvents() { console.log('Initialising documents events...'); - this._documents.onDidChangeContent(e => this.onDidChangeContent(e.document)); + this._documents.onDidChangeContent(async (e) => await this.onDidChangeContentAsync(e.document)); } /** Connection event handlers */ @@ -132,23 +132,18 @@ class WorkspaceEvents { } private async onDocumentSymbolAsync(params: DocumentSymbolParams): Promise { - console.log(`onDocumentSymbolAsync: ${params.textDocument.uri}`); return await this.activeDocument?.languageServerSymbolInformationAsync() ?? []; } private onFoldingRanges(params: FoldingRangeParams): FoldingRange[] { - const foldingRanges = this._workspace.activeDocument?.foldableElements ?? []; - console.log(`onFoldingRanges: ${params.textDocument.uri} (${foldingRanges.length} ranges)`); - return foldingRanges; + return this._workspace.activeDocument?.foldableElements ?? []; } private onHover(params: HoverParams): Hover { - console.log(`onHover: ${params.position.line},${params.position.character}`); return { contents: '' }; } private onInitialized(): void { - console.log('onInitialized:---'); const connection = this._workspace.connection; // Register for client configuration notification changes. connection.client.register(DidChangeConfigurationNotification.type, undefined); @@ -167,10 +162,9 @@ class WorkspaceEvents { * This event handler is called whenever a `TextDocuments` is changed. * @param doc The document that changed. */ - onDidChangeContent(doc: TextDocument) { - console.log('onDidChangeContent:--- ' + doc.uri); + async onDidChangeContentAsync(doc: TextDocument) { this.activeDocument = BaseProjectDocument.create(this._workspace, doc); - this.activeDocument.parse(); + await this.activeDocument.parseAsync(); this._workspace.activateDocument(this.activeDocument); } From d8959f6bc96dcd4778c9231a290d35e675976ccd Mon Sep 17 00:00:00 2001 From: sslinky Date: Thu, 23 May 2024 21:37:04 +0800 Subject: [PATCH 07/16] Deleted old project file --- syntaxes/vba.json | 258 ---------------------------------------------- 1 file changed, 258 deletions(-) delete mode 100644 syntaxes/vba.json diff --git a/syntaxes/vba.json b/syntaxes/vba.json deleted file mode 100644 index c673fad..0000000 --- a/syntaxes/vba.json +++ /dev/null @@ -1,258 +0,0 @@ -{ - "comment": - "Modified from the original ASP bundle. Originally modified by Thomas Aylott subtleGradient.com", - "fileTypes": ["bas", "cls", "frm", "sht", "wbk"], - "foldingStartMarker": - "(<(?i:(head|table|div|style|script|ul|ol|form|dl))\\b.*?>|\\{|^\\s*?|\\}|^\\s*|\\(|,))\\s*(?>(Not)\\s+)?\\b([a-zA-Z_xf-xff][a-zA-Z0-9_xf-xff]*?)?\\b(?!(\\(|\\.))|\\b([a-zA-Z_xf-xff][a-zA-Z0-9_xf-xff]*?)\\b(?=\\s*(\\+|=|-|\\&|\\\\|/|<|>|\\(|\\))))", - "captures": { - "2": {"name": "keyword.control.vba" }, - "3": {"name": "variable.other.vba" } - } - }, - { - "match": - "!|\\$|%|&|=|<=|>=|<>|<|>|!|^|&&|\\|\\b(mod|in|new|delete|typeof)\\b", - "name": "keyword.operator.js" - } - ], - "repository": { - "round-brackets": { - "begin": "\\(", - "beginCaptures": [ - { - "name": "punctuation.section.round-brackets.begin.vba" - } - ], - "end": "\\)", - "endCaptures": [ - { - "name": "punctuation.section.round-brackets.end.vba" - } - ], - "name": "meta.round-brackets", - "patterns": [ - { - "include": "source.vba" - } - ] - } - }, - "scopeName": "source.vba", - "uuid": "7F9C9343-D48E-4E7D-BFE8-F680714DCD3E" -} From 3c50dcac1e309d3f4dfbb166bf1f98b214a40aba Mon Sep 17 00:00:00 2001 From: sslinky Date: Thu, 23 May 2024 21:37:14 +0800 Subject: [PATCH 08/16] Remove debugging guff --- server/src/project/document.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/project/document.ts b/server/src/project/document.ts index bbd9419..3ab5751 100644 --- a/server/src/project/document.ts +++ b/server/src/project/document.ts @@ -175,7 +175,6 @@ export abstract class BaseProjectDocument implements ProjectDocument { * @returns a number for some reason. */ registerSymbolInformation = (element: HasSymbolInformation): number => { - console.debug(`Registering symbol for ${element.symbolInformation.name}`); return this._symbolInformations.push(element.symbolInformation); }; } From 6db28b94bce1ea70677e9c21fdbdb990a9104188 Mon Sep 17 00:00:00 2001 From: sslinky Date: Fri, 24 May 2024 01:29:11 +0800 Subject: [PATCH 09/16] Fixes : breaking comments --- client/src/syntaxes/vba.tmLanguage.yaml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/client/src/syntaxes/vba.tmLanguage.yaml b/client/src/syntaxes/vba.tmLanguage.yaml index b3e3e1c..fd963a0 100644 --- a/client/src/syntaxes/vba.tmLanguage.yaml +++ b/client/src/syntaxes/vba.tmLanguage.yaml @@ -12,6 +12,7 @@ repository: vbaLang: patterns: - include: "#comments" + - include: "#moduleLinesWithComment" - include: "#moduleLines" - include: "#moduleHeader" - include: "#enum" @@ -20,8 +21,17 @@ repository: - include: "#variableDeclarations" - include: "#block" repository: + moduleLinesWithComment: + match: ([^\n']*)?('.*(?=([^"]*"[^"]*")*[^"]*$)) + captures: + 1: + patterns: + - include: "#vbaLang" + 2: + patterns: + - include: "#comments" moduleLines: - match: '([^\n:]*)?:(?=([^"]*"[^"]*")*[^"]*$)' + match: ([^\n:]*)?:(?=([^"]*"[^"]*")*[^"]*$) captures: 1: patterns: From 3732004f6da12f6dd2286badea29f18abe926458 Mon Sep 17 00:00:00 2001 From: sslinky Date: Fri, 24 May 2024 02:41:18 +0800 Subject: [PATCH 10/16] Fix multiple issues with grammar --- client/src/syntaxes/vba.tmLanguage.yaml | 88 +++++++++++++++++++++---- 1 file changed, 75 insertions(+), 13 deletions(-) diff --git a/client/src/syntaxes/vba.tmLanguage.yaml b/client/src/syntaxes/vba.tmLanguage.yaml index fd963a0..d5751b4 100644 --- a/client/src/syntaxes/vba.tmLanguage.yaml +++ b/client/src/syntaxes/vba.tmLanguage.yaml @@ -17,6 +17,7 @@ repository: - include: "#moduleHeader" - include: "#enum" - include: "#struct" + - include: "#funcDeclareSig" - include: "#mthdSig" - include: "#variableDeclarations" - include: "#block" @@ -41,6 +42,7 @@ repository: name: source.language.vba patterns: - include: "#comments" + - include: "#vbaBuiltIns" - include: "#literals" - include: "#operators" - include: "#keywords" @@ -127,7 +129,7 @@ repository: repository: flowDecision: name: keyword.control.flow.decision.vba - match: "(?i)\\b(if|then|elseif|else|end if|select case|case|switch|end select)\\b" + match: '(?i)(^|\s+)([#]?if|then|[#]?elseif|[#]?else|[#]?end if|select case|case|switch|end select)\b' flowLoop: name: keyword.control.flow.loop.vba @@ -204,6 +206,18 @@ repository: name: variable.other.constant.label.vba match: "(?i)^([a-z][a-z0-9_]*|\\d+):" + vbaBuiltIns: + patterns: + - include: "#vbaEnum" + - include: "#vbaConstant" + repository: + vbaEnum: + match: (?i)(vba7|win64) + name: constant.numeric.enum.vba + vbaConstant: + match: (?i)(vbNewLine|vbCr|vbLf|vbCrLf) + name: constant.numeric.enum.vba + objectModel: patterns: - include: "#application" @@ -266,8 +280,13 @@ repository: name: support.type.primitive.vba match: "(?i)(?<=\\bAs)\\s+(boolean|byte|currency|date|decimal|double|integer|long(long|ptr)?|single|string|variant)\\b" objectType: - name: entity.name.type.vba - match: "(?i)(?<=\\bAs)\\s+([A-Z][A-Z0-9_]*)\\b" + name: support.type.object.vba + match: (?i)(?<=\bAs)(\s+New)?\s+([A-Z][A-Z0-9_]*)\b + captures: + 1: + name: keyword.storage.new.vba + 2: + name: support.type.object.vba arguments: name: source.args.vba @@ -275,13 +294,12 @@ repository: - include: "#lineContinuation" - include: "#paramArray" - include: "#funcCall" - - include: "#subCall" - include: "#argsVariable" - include: "#argsLiteral" - include: "#language" repository: argsVariable: - match: "(?i),?\\s*(Optional\\s+)?((?:ByVal|ByRef)\\s+)?([a-z][a-z0-9_]*)(?:\\s*(\\bas\\s+[a-z][a-z0-9_]*))?\\b(\\s+=\\s+[^,)]*)?" + match: (?i),?\s*(Optional\s+)?((?:ByVal|ByRef)\s+)?([a-z][a-z0-9_]*)(?:\s*(\bas\s+[a-z][a-z0-9_]*))?\b(\s+=\s+[^,)]*)? captures: 1: name: storage.type.modifier.vba @@ -422,10 +440,40 @@ repository: patterns: - include: "#types" + funcDeclareSig: + name: source.declare.signature.vba + begin: (?i)^\s*((?:Public|Private|Friend)?\b\s*Declare)\s+(PtrSafe\s+)?(Sub|Function)\s+([a-z][a-z0-9_]*)\s+(Lib)\s+("[a-z][a-z0-9._]*")(?:\s+(Alias)\s+("[a-z][a-z0-9_]*"))?\s+\( + end: '(?i)(?:\))\s+(as\s+[a-z][a-z0-9_]*)' + beginCaptures: + 1: # Public|Private|Friend Declare + name: storage.type.method.vba + 2: # PtrSafe + name: storage.type.method.vba + 3: # Sub|Function + name: storage.type.method.vba + 4: # Name + name: entity.name.function.vba + 5: # Lib + name: storage.type.method.vba + 6: # Lib name + patterns: + - include: "#literals" + 7: # Alias + name: storage.type.method.vba + 8: # Alias name + patterns: + - include: "#literals" + endCaptures: + 1: # return type + patterns: + - include: "#types" + patterns: + - include: "#arguments" + mthdSig: name: source.method.signature.vba - begin: "(?i)^\\s*((?:Public|Private)?\\b\\s*(?:(?:Sub|Function)|Property\\s+(?:Let|Get|Set)))\\s+([a-z][a-z0-9_]*)\\s*(\\()" - end: "(?i)(\\))\\s+(as\\s+[a-z][a-z0-9_]*)?" + begin: '(?i)^\s*((?:Public|Private)?\b\s*(?:(?:Sub|Function)|Property\s+(?:Let|Get|Set)))\s+([a-z][a-z0-9_]*)\s*(\()' + end: '(?i)(\))\s+(as\s+[a-z][a-z0-9_]*)?' beginCaptures: 1: name: storage.type.method.vba @@ -439,7 +487,6 @@ repository: 2: # return type patterns: - include: "#types" - patterns: - include: "#arguments" @@ -478,7 +525,7 @@ repository: repository: variableDeclaration: name: storage.var-declaration.vba - match: "(?i)^\\s*(Dim|Public|Private)\\s+([a-z][a-z0-9_]*)(\\(.*\\))?(\\s+As\\s+[A-Z][A-Z0-9_]*)?" + match: (?i)^\s*(Dim|Public|Private)\s+([a-z][a-z0-9_]*)(\(.*\))?(\s+As(?:\s+New)?\s+[A-Z][A-Z0-9_]*)? captures: 1: # Dim|Private @@ -513,8 +560,10 @@ repository: patterns: - include: "#language" + # TODO: Redo this so it can take into account chaining, e.g.: + # MyClass.MyProp = SomeObject.Foo(20) variableAssignment: - match: "(?i)((Get|Let|Set)\\s+)?([a-z][a-z0-9_]*)(\\s*=\\s*)(.*)" + match: (?i)((Get|Let|Set)\s+)?([a-z][a-z0-9._]*)(\s*=\s*)(.*) captures: 2: name: keyword.control.vba @@ -525,7 +574,7 @@ repository: 5: patterns: - include: "#funcCall" - - include: "#subCall" + # - include: "#subCall" # Why would a variable assignment ever have a sub call? - include: "#language" funcCall: @@ -543,10 +592,23 @@ repository: - include: "#lineContinuation" subCall: + begin: (?i)([a-z][a-z0-9._]*)\s+(.*,.*) + beginCaptures: + 1: + name: entity.name.function.call.vba + 2: + patterns: + - include: "#arguments" + end: \n + patterns: + # - include: "#subCallMultiLine" + - include: "#arguments" + + subCallOld: # TODO: Better way to do this. # Captures sub calls with two or more args. # Required because they break properties somehow. - begin: "(?i)([a-z][a-z0-9_]*)\\s+(.*,.*)" + begin: (?i)([a-z][a-z0-9_]*)\s+(.*,.*) beginCaptures: 1: name: entity.name.function.call.vba @@ -565,7 +627,7 @@ repository: 1: name: entity.name.function.call.vba patterns: - - include: "#args" + - include: "#arguments" end: "\\n" args: From 5596616d186be18a8b4bbcf95e666e3b9d43ae18 Mon Sep 17 00:00:00 2001 From: sslinky Date: Fri, 24 May 2024 02:47:13 +0800 Subject: [PATCH 11/16] 1.2.3 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2dc0619..02fd54b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vba-lsp", - "version": "1.2.2", + "version": "1.2.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vba-lsp", - "version": "1.2.2", + "version": "1.2.3", "hasInstallScript": true, "license": "MIT", "devDependencies": { diff --git a/package.json b/package.json index c0fcd5d..4fb8a12 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "icon": "images/vba-lsp-icon.png", "author": "SSlinky", "license": "MIT", - "version": "1.2.2", + "version": "1.2.3", "repository": { "type": "git", "url": "https://github.com/SSlinky/VBA-LanguageServer" From 347040199c8368eb0a3f2d8a198a956daa4ac9ad Mon Sep 17 00:00:00 2001 From: sslinky Date: Fri, 24 May 2024 14:19:51 +0800 Subject: [PATCH 12/16] Significant update - bug fixing --- client/src/syntaxes/vba.tmLanguage.yaml | 335 ++++++++++++++---------- 1 file changed, 190 insertions(+), 145 deletions(-) diff --git a/client/src/syntaxes/vba.tmLanguage.yaml b/client/src/syntaxes/vba.tmLanguage.yaml index d5751b4..d124c12 100644 --- a/client/src/syntaxes/vba.tmLanguage.yaml +++ b/client/src/syntaxes/vba.tmLanguage.yaml @@ -6,37 +6,67 @@ fileTypes: - .frm patterns: - - include: "#vbaLang" + - include: "#fileStructure" repository: - vbaLang: + fileStructure: + patterns: + - include: "#comments" # Handle comments here so they aren't broken by other stuff. + - include: "#strings" # Handle strings here so they aren't broken by other stuff. + - include: "#labels" # Handle labels first so they aren't handled by lines. + - include: "#methodSignature" + - include: "#continuations" # Consume continuations so they "continue" other matches. + - include: "#syntaxLines" # Split document lines into syntax lines. + + continuations: + name: meta.has-continuation.vba + begin: (?i)(.*)(\s_\s*) + end: \n + patterns: + - include: "#lineContinuation" + - include: "#fileStructure" + beginCaptures: + 1: + patterns: + - include: "#fileStructure" + 2: + patterns: + - include: "#lineContinuation" + + lineContinuation: + name: support.vba + match: \s*_\s*\n + + syntaxLines: + name: meta.syntax-lines.vba + match: ((?:[^\n":]|"(?:\\.|[^\n"\\])*")+|"(?:\\.|[^\n"\\])*") + captures: + 1: # Split line + # patterns: + # - include: "#strings" + # - include: "#syntaxLine" + # 2: # Single syntax line. + patterns: + - include: "#main" + # repository: + # syntaxLine: + # name: meta.syntax-line.vba + # match: (?:(.*):) + # captures: + # 1: + # patterns: + # - include: "main" + + main: patterns: - - include: "#comments" - - include: "#moduleLinesWithComment" - - include: "#moduleLines" - include: "#moduleHeader" - include: "#enum" - include: "#struct" - - include: "#funcDeclareSig" - - include: "#mthdSig" + - include: "#declareFunctionSignature" + - include: "#methodSignature" - include: "#variableDeclarations" - include: "#block" - repository: - moduleLinesWithComment: - match: ([^\n']*)?('.*(?=([^"]*"[^"]*")*[^"]*$)) - captures: - 1: - patterns: - - include: "#vbaLang" - 2: - patterns: - - include: "#comments" - moduleLines: - match: ([^\n:]*)?:(?=([^"]*"[^"]*")*[^"]*$) - captures: - 1: - patterns: - - include: "#vbaLang" + language: name: source.language.vba @@ -46,16 +76,14 @@ repository: - include: "#literals" - include: "#operators" - include: "#keywords" - - include: "#funcCall" + - include: "#functionCall" - include: "#subCall" - include: "#objectModel" - lineContinuation: - name: support.vba - match: "\\s*_\\s*\\n" literals: patterns: + - include: "#comments" - include: "#string" - include: "#boolean" - include: "#number" @@ -84,19 +112,19 @@ repository: repository: opsArithmetic: name: keyword.operator.arithmetic.vba - match: "(?i)([*&/\\+-]|\\bMod\\b)" + match: (?i)([*&/\+-]|\bMod\b) opsComparison: name: keyword.operator.comparison.vba - match: "(?i)([<>=]|\\b(is|like)\\b)" + match: (?i)([<>=]|\b(is|like)\b) opsConcatenation: name: keyword.operator.concatenation.vba - match: "(?i)[&+]" + match: (?i)[&+] opsLogical: name: keyword.operator.logical.vba - match: "(?i)\\b(and|eqv|imp|not|or|xor)\\b" + match: (?i)\b(and|eqv|imp|not|or|xor)\b opsOther: name: keyword.operator.concatenation.vba - match: "(?i)\\b(addressof|typeof)\\b" + match: (?i)\b(addressof|typeof)\b keywords: patterns: @@ -121,7 +149,10 @@ repository: kw-flow: patterns: + - include: "#inlineIfElse" + - include: "#inlineIf" - include: "#flowDecision" + - include: "#forEachLoop" - include: "#flowLoop" - include: "#flowCall" - include: "#flowPauseExit" @@ -129,11 +160,61 @@ repository: repository: flowDecision: name: keyword.control.flow.decision.vba - match: '(?i)(^|\s+)([#]?if|then|[#]?elseif|[#]?else|[#]?end if|select case|case|switch|end select)\b' + match: '(?i)(^|\s+)(#if|then|#elseif|#else|#end if|select case|case|switch|end select)\b' + # match: '(?i)(^|\s+)([#]?if|then|[#]?elseif|[#]?else|[#]?end if|select case|case|switch|end select)\b' flowLoop: name: keyword.control.flow.loop.vba - match: "(?i)\\b(do|exit\\s+do|while|until|loop|for|exit\\s+for|next|with)\\b" + match: "(?i)\\b(do|exit\\s+do|while|until|loop|for|each|in|to|exit\\s+for|next|with)\\b" + + forEachLoop: + name: meta.flow.foreach.vba + match: (?i)\b(for\s+each)\s+(.+?)\s+(in) + captures: + 1: + name: keyword.control.flow.loop.vba + 2: + patterns: + - include: "#expression" + - include: "#functionCall" + 3: + name: keyword.control.flow.loop.vba + + inlineIfElse: + name: meta.flow.inline-if-else.vba + match: (?i)\b(if)\s+(.*?)\s+(then)\s+(.*)\s+(else)\s+(.*) + captures: + 1: + name: keyword.control.flow.decision.vba + 2: + patterns: + - include: "#expression" + - include: "#functionCall" + 3: + name: keyword.control.flow.decision.vba + 4: + patterns: + - include: "#expression" + - include: "#functionCall" + 5: + name: keyword.control.flow.decision.vba + 6: + patterns: + - include: "#expression" + - include: "#functionCall" + + inlineIf: + name: meta.flow.inline-if.vba + match: (?i)\b(if)\s+(.*?)\s+(then) + captures: + 1: + name: keyword.control.flow.decision.vba + 2: + patterns: + - include: "#expression" + - include: "#functionCall" + 3: + name: keyword.control.flow.decision.vba flowCall: name: keyword.control.flow.call.vba @@ -162,7 +243,7 @@ repository: name: variable.other.constant.label.vba 5: patterns: - - include: "#vbaLang" + - include: "#main" flowBranchSimple: name: keyword.control.flow.branch.vba @@ -203,8 +284,11 @@ repository: match: "^#.*" labels: - name: variable.other.constant.label.vba - match: "(?i)^([a-z][a-z0-9_]*|\\d+):" + # name: variable.other.constant.label.vba + match: '(?i)^(\s*[a-z][a-z0-9_]*|\d+):' + captures: + 1: + name: variable.other.constant.label.vba vbaBuiltIns: patterns: @@ -259,7 +343,7 @@ repository: - include: "#objectModelDebugInvalid" repository: objectModelDebugValid: - match: "(?i)\\b(debug)(\\.(print|assert))" + match: (?i)\b(debug)(\.(print|assert)) captures: 1: name: entity.name.type.vba @@ -268,7 +352,7 @@ repository: objectModelDebugInvalid: name: invalid.unimplemented.vba - match: "(?i)\\b(debug)(\\.([a-z][a-z0-9_]*))" + match: (?i)\b(debug)(\.([a-z][a-z0-9_]*)) types: patterns: @@ -278,7 +362,7 @@ repository: repository: primativeType: name: support.type.primitive.vba - match: "(?i)(?<=\\bAs)\\s+(boolean|byte|currency|date|decimal|double|integer|long(long|ptr)?|single|string|variant)\\b" + match: (?i)(?<=\bAs)\s+(boolean|byte|currency|date|decimal|double|integer|long(long|ptr)?|single|string|variant)\b objectType: name: support.type.object.vba match: (?i)(?<=\bAs)(\s+New)?\s+([A-Z][A-Z0-9_]*)\b @@ -289,11 +373,13 @@ repository: name: support.type.object.vba arguments: + # Rules that have no match will never return a name in the hierarchy. + # This name doesn't do anything but leaving this as usage notes. name: source.args.vba patterns: - include: "#lineContinuation" - include: "#paramArray" - - include: "#funcCall" + - include: "#functionCall" - include: "#argsVariable" - include: "#argsLiteral" - include: "#language" @@ -315,20 +401,21 @@ repository: - include: "#language" argsLiteral: - match: "(?i),?\\s*([a-z0-9\"]*)\\b" + name: meta.arguments.argsLiteral.vba + match: ((?:[^\n",]|"(?:\\.|[^\n"\\])*")+|"(?:\\.|[^\n"\\])*") captures: 1: patterns: - - include: "#types" + - include: "#literals" paramArray: - match: "(?i)(ParamArray)\\s+([a-z][a-z0-9_]*)(\\(\\))(\\s+As\\s+Variant)" + match: (?i),?\s*(ParamArray)\s+([a-z][a-z0-9_]*)(?:\(\))(\s+As\s+Variant)? captures: 1: - name: storage.type.array.vba + name: storage.type.modifier.array.vba 2: - name: variable.other.readwrite.vba - 4: + name: variable.parameter.vba + 3: patterns: - include: "#types" @@ -342,20 +429,20 @@ repository: # The sub-pattern consumes the \n if preceded by line continuation. # Capturing it there prevents the end pattern being matched. name: comment.block.vba - begin: "'.*\\s_\\s*" - end: "\\n" + begin: (?i)'.*\s_\s* + end: \n patterns: - include: "#lineContinuation" apostropheComments: name: comment.line.apostrophe.vba - match: "'.*" + match: (?i)'.* remarkComments: name: comment.line.remark.vba - match: "(?i)(?<=^|:)\\s*Rem\\b.*" + match: (?i)(?<=^|:)\s*Rem\b.* attribute: name: entity.other.attribute-name.vba - match: "(?i)^Attribute(.*)" + match: (?i)^Attribute(.*) captures: 0: patterns: @@ -372,33 +459,33 @@ repository: - include: "#attribute" moduleAttributeBlock: name: entity.other.attribute-name.block.vba - begin: "(?i)^VERSION" - end: "^(?i)End" + begin: (?i)^VERSION + end: ^(?i)End patterns: - include: "#comments" - include: "#literals" moduleOption: name: keyword.control.vba - match: "(?i)^\\s*Option\\s+(Explicit|Base|Private\\s+Module)\\b" + match: (?i)^\s*Option\s+(Explicit|Base|Private\s+Module)\b enum: name: meta.enum.declaration.vba - begin: "(?i)^\\s*((?:(?:Public|Private) )?\\s*Enum)\\s+([a-z][a-z0-9_]*)" + begin: (?i)^\s*((?:(?:Public|Private) )?\s*Enum)\s+([a-z][a-z0-9_]*) beginCaptures: 1: name: storage.type.enum.vba 2: name: entity.name.type.enum.vba patterns: - - include: "#enumDeclaration" - end: "(?i)^\\s*End\\s+Enum\\b" + - include: "#enumMember" + end: (?i)^\s*End\s+Enum\b endCaptures: 0: name: storage.type.enum.vba - enumDeclaration: - match: "(?i)^\\s*([a-z][a-z0-9_]*)(\\s+=.*)?('.*)?$" + enumMember: + match: (?i)^\s*([a-z][a-z0-9_]*)(\s+=.*)?('.*)?$ captures: 1: name: constant.numeric.enum.vba @@ -440,7 +527,7 @@ repository: patterns: - include: "#types" - funcDeclareSig: + declareFunctionSignature: name: source.declare.signature.vba begin: (?i)^\s*((?:Public|Private|Friend)?\b\s*Declare)\s+(PtrSafe\s+)?(Sub|Function)\s+([a-z][a-z0-9_]*)\s+(Lib)\s+("[a-z][a-z0-9._]*")(?:\s+(Alias)\s+("[a-z][a-z0-9_]*"))?\s+\( end: '(?i)(?:\))\s+(as\s+[a-z][a-z0-9_]*)' @@ -470,7 +557,7 @@ repository: patterns: - include: "#arguments" - mthdSig: + methodSignature: name: source.method.signature.vba begin: '(?i)^\s*((?:Public|Private)?\b\s*(?:(?:Sub|Function)|Property\s+(?:Let|Get|Set)))\s+([a-z][a-z0-9_]*)\s*(\()' end: '(?i)(\))\s+(as\s+[a-z][a-z0-9_]*)?' @@ -490,33 +577,56 @@ repository: patterns: - include: "#arguments" - mthdClose: - name: storage.type.method.vba - match: "(?i)^\\s*End\\s+(Sub|Function|Property)" + methodClose: + name: storage.type.method.close.vba + match: (?i)^\s*End\s+(Sub|Function|Property) + + expression: + # (?:[*&/\+-]|\bMod\b)| + # (?:[<>=]|\b(is|like)\b)| + # (?:[&+])| + # (?:\b(and|eqv|imp|not|or|xor)\b)| + # (?:\b(addressof|typeof)\b) + + # This match just made up of the operators matchs. Don't look at it too hard. + match: (?i)(.*?)\s+((?:[*&/\+-]|\bMod\b)|(?:[<>=]|\b(is|like)\b)|(?:[&+])|(?:\b(and|eqv|imp|not|or|xor)\b)|(?:\b(addressof|typeof)\b))\s+(.*) + captures: + 1: # Left sided of expression + patterns: + - include: "#literal" + 2: # Operator + patterns: + - include: "#operators" + 3: # Operator + patterns: + - include: "#literals" + - include: "#functionCall" + - include: "#expression" block: patterns: - - include: "#labels" - - include: "#comments" - - include: "#blockAttribute" - - include: "#blockLines" - include: "#variableDeclarations" - include: "#variableAssignment" - - include: "#mthdClose" + - include: "#methodClose" - include: "#language" repository: blockLines: name: source.methodlines.vba - match: "(.*):" + match: (?:(^(?:\s*[a-z0-9]*?:\s*)(?:\s+'.*)?$)|(.*):) + # match: (?:(^(?:\s*[a-z0-9]*?:\s*)(?:\s+'.*)?$)|(.*):) captures: - 1: + 1: # label + name: source.methodlines.label.vba + # patterns: + # - include: "#labels" + 2: # colon separated line patterns: - include: "#block" - blockAttribute: - patterns: - - include: "#attribute" + # blockAttribute: + # patterns: + # - include: "#attribute" variableDeclarations: patterns: @@ -573,22 +683,20 @@ repository: name: keyword.operator.assignment.vba 5: patterns: - - include: "#funcCall" - # - include: "#subCall" # Why would a variable assignment ever have a sub call? + - include: "#functionCall" - include: "#language" - funcCall: + functionCall: name: meta.function.call.vba - begin: "(?i)([a-z][a-z0-9_]*)\\(" - end: "\\)" + begin: (?i)([a-z][a-z0-9_]*)\( + end: \) beginCaptures: 1: name: entity.name.function.call.vba patterns: # These calls need to be back to a top level group because # textMate does not seem to support a repository in a begin/end - - include: "#args" - - include: "#arg" + - include: "#arguments" - include: "#lineContinuation" subCall: @@ -604,69 +712,6 @@ repository: # - include: "#subCallMultiLine" - include: "#arguments" - subCallOld: - # TODO: Better way to do this. - # Captures sub calls with two or more args. - # Required because they break properties somehow. - begin: (?i)([a-z][a-z0-9_]*)\s+(.*,.*) - beginCaptures: - 1: - name: entity.name.function.call.vba - 2: - patterns: - - include: "#args" - - include: "#arg" - patterns: - - include: "#args" - - include: "#arg" - end: "\\n" - - subCallMultiLine: - begin: "(?i)([a-z][a-z0-9_]*)\\s+_\\s*['\\n]" - beginCaptures: - 1: - name: entity.name.function.call.vba - patterns: - - include: "#arguments" - end: "\\n" - - args: - # The match gates an args list. It is not consumed by the - # match immediately because it is passed through captures which - # handles args separately. - match: ".*,.*" - captures: - 0: - patterns: - - include: "#argsHandler" - repository: - argsHandler: - begin: "[^,]+" - beginCaptures: - 0: - name: variable.parameter.vba - patterns: - - include: "#arg" - end: "," - patterns: - - include: "#arg" - - arg: - patterns: - - include: "#kwarg" - - include: "#literals" - - include: "#lineConcat" - - include: "#language" - - kwarg: - match: "(?i)([a-z][a-z0-9_]*)(:=.*)" - captures: - 1: - name: variable.parameter.function-call.vba - 2: - patterns: - - include: "#arg" - testing: patterns: - name: keyword.control From a385bdbf18da399e359cdb25c25d5d74091b09af Mon Sep 17 00:00:00 2001 From: sslinky Date: Fri, 24 May 2024 14:22:33 +0800 Subject: [PATCH 13/16] Turn capabilties back on after performance update --- server/src/server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/server.ts b/server/src/server.ts index eb3dc6b..38a1a65 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -56,8 +56,8 @@ export class LanguageServerConfiguration { hoverProvider: false, textDocumentSync: TextDocumentSyncKind.Incremental, completionProvider: { resolveProvider: false }, - foldingRangeProvider: false, - documentSymbolProvider: false, + foldingRangeProvider: true, + documentSymbolProvider: true, }; constructor(params: InitializeParams) { From 43167cfb15fb8dfd5845d0129417e431f61a1145 Mon Sep 17 00:00:00 2001 From: sslinky Date: Fri, 24 May 2024 14:27:26 +0800 Subject: [PATCH 14/16] 1.2.4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 02fd54b..1b8b331 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vba-lsp", - "version": "1.2.3", + "version": "1.2.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vba-lsp", - "version": "1.2.3", + "version": "1.2.4", "hasInstallScript": true, "license": "MIT", "devDependencies": { diff --git a/package.json b/package.json index 4fb8a12..d792801 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "icon": "images/vba-lsp-icon.png", "author": "SSlinky", "license": "MIT", - "version": "1.2.3", + "version": "1.2.4", "repository": { "type": "git", "url": "https://github.com/SSlinky/VBA-LanguageServer" From eee77246a696a11e991842c23bf6c97d8add6be7 Mon Sep 17 00:00:00 2001 From: sslinky Date: Fri, 24 May 2024 20:49:17 +0800 Subject: [PATCH 15/16] Async calls to reduce server workload --- server/src/project/document.ts | 48 +++++++++----------- server/src/project/elements/module.ts | 1 - server/src/project/parser/vbaSyntaxParser.ts | 16 +++++-- server/src/project/workspace.ts | 40 ++++++++-------- 4 files changed, 54 insertions(+), 51 deletions(-) diff --git a/server/src/project/document.ts b/server/src/project/document.ts index 3ab5751..75eadd0 100644 --- a/server/src/project/document.ts +++ b/server/src/project/document.ts @@ -1,4 +1,4 @@ -import { Diagnostic, SemanticTokens, SymbolInformation, SymbolKind } from 'vscode-languageserver'; +import { CancellationToken, Diagnostic, LSPErrorCodes, ResponseError, SemanticTokens, SymbolInformation, SymbolKind } from 'vscode-languageserver'; import { Workspace } from './workspace'; import { FoldableElement } from './elements/special'; import { BaseSyntaxElement, HasAttribute, HasSemanticToken, HasSymbolInformation } from './elements/base'; @@ -9,17 +9,7 @@ import { SemanticTokensManager } from '../capabilities/semanticTokens'; import { sleep } from '../utils/helpers'; -export interface ProjectDocument { - name: string; - textDocument: TextDocument; - languageServerSemanticTokens: (range?: Range) => SemanticTokens | null; - languageServerSymbolInformationAsync(): Promise; - get foldableElements(): FoldingRange[]; - parseAsync(): Promise; -} - - -export abstract class BaseProjectDocument implements ProjectDocument { +export abstract class BaseProjectDocument { readonly workspace: Workspace; readonly textDocument: TextDocument; readonly name: string; @@ -36,13 +26,8 @@ export abstract class BaseProjectDocument implements ProjectDocument { protected _semanticTokens: SemanticTokensManager = new SemanticTokensManager(); isBusy = false; - private _requestId = 0; abstract symbolKind: SymbolKind - get foldableElements() { - return this._foldableElements; - } - get activeAttributeElement() { return this._attributeElements?.at(-1); } @@ -53,7 +38,7 @@ export abstract class BaseProjectDocument implements ProjectDocument { this.name = name; } - static create(workspace: Workspace, document: TextDocument): VbaClassDocument | VbaModuleDocument { + static create(workspace: Workspace, document: TextDocument): BaseProjectDocument { const slashParts = document.uri.split('/').at(-1); const dotParts = slashParts?.split('.'); const extension = dotParts?.at(-1); @@ -77,24 +62,21 @@ export abstract class BaseProjectDocument implements ProjectDocument { return this._semanticTokens.getSemanticTokens(range); }; - async languageServerSymbolInformationAsync(): Promise { - this._requestId += 1; - const requestId = this._requestId; + async languageServerSymbolInformationAsync(token: CancellationToken): Promise { while (this.isBusy) { await sleep(5); - if (requestId < this._requestId) { + if (token.isCancellationRequested) { return []; } } - this._requestId = 0; return this._symbolInformations; } - parseAsync = async (): Promise => { + parseAsync = async (token: CancellationToken): Promise => { this.isBusy = true; - console.log('Parsing document'); - await (new SyntaxParser()).parseAsync(this); - this.isBusy = false; + if (await (new SyntaxParser()).parseAsync(this, token)) { + this.isBusy = false; + } }; registerNamedElementDeclaration(element: any) { @@ -177,6 +159,18 @@ export abstract class BaseProjectDocument implements ProjectDocument { registerSymbolInformation = (element: HasSymbolInformation): number => { return this._symbolInformations.push(element.symbolInformation); }; + + /** Get document information */ + async getFoldingRanges(token: CancellationToken): Promise { + while (this.isBusy) { + await sleep(5); + if (token.isCancellationRequested) { + return []; + } + } + this.workspace.connection.console.info('Processing request for Folding Range'); + return this._foldableElements; + } } diff --git a/server/src/project/elements/module.ts b/server/src/project/elements/module.ts index 4b97af0..ae50968 100644 --- a/server/src/project/elements/module.ts +++ b/server/src/project/elements/module.ts @@ -22,7 +22,6 @@ export class ModuleElement extends BaseContextSyntaxElement implements HasSymbol } get symbolInformation(): SymbolInformation { - console.warn(`Creating symbol with name ${this._name}`); return SymbolInformationFactory.create( this, this.symbolKind ); diff --git a/server/src/project/parser/vbaSyntaxParser.ts b/server/src/project/parser/vbaSyntaxParser.ts index 7bab51b..bcb11da 100644 --- a/server/src/project/parser/vbaSyntaxParser.ts +++ b/server/src/project/parser/vbaSyntaxParser.ts @@ -14,6 +14,7 @@ import { FoldableElement } from '../elements/special'; import { ConstDeclarationsElement, EnumBlockDeclarationElement, EnumMemberDeclarationElement, MethodBlockDeclarationElement, VariableDeclarationsElement } from '../elements/memory'; import { ModuleElement } from '../elements/module'; import { sleep } from '../../utils/helpers'; +import { CancellationToken } from 'vscode-languageserver'; export class SyntaxParser { private static _lockIdentifier = 0; @@ -31,13 +32,17 @@ export class SyntaxParser { this._lockIdentifier = 0; } - async parseAsync(document: VbaClassDocument | VbaModuleDocument) { + async parseAsync(document: VbaClassDocument | VbaModuleDocument, token: CancellationToken): Promise { + // token.onCancellationRequested(e => { + // throw new Error("No"); + // }); + // Refuse to do anything that seems like too much work. if (document.textDocument.lineCount > 1000) { // TODO: Make this an option that people can increase or decrease. console.log(`Document oversize: ${document.textDocument.lineCount} lines.`); console.warn(`Syntax parsing has been disabled to prevent crashing.`); - return; + return false; } // Wait a few seconds to see if any other input has ocurred. @@ -45,11 +50,16 @@ export class SyntaxParser { await sleep(1000); if (!SyntaxParser._hasLock(lock)) { console.info('Newer lock detected. Cancelling parse.'); - return; + return false; } SyntaxParser._releaseLock(); // Parse the document. + this.parse(document); + return true; + } + + parse(document: VbaClassDocument | VbaModuleDocument) { console.info('Parsing the document.'); const listener = new VbaTreeWalkListener(document); const parser = this.createParser(document.textDocument); diff --git a/server/src/project/workspace.ts b/server/src/project/workspace.ts index fdc1212..6c7fc4b 100644 --- a/server/src/project/workspace.ts +++ b/server/src/project/workspace.ts @@ -1,5 +1,5 @@ -import { CompletionItem, CompletionParams, DidChangeConfigurationNotification, DidChangeConfigurationParams, DidChangeWatchedFilesParams, DocumentSymbolParams, FoldingRange, FoldingRangeParams, Hover, HoverParams, SemanticTokensParams, SemanticTokensRangeParams, SymbolInformation, TextDocuments, WorkspaceFoldersChangeEvent, _Connection } from 'vscode-languageserver'; -import { BaseProjectDocument, ProjectDocument } from './document'; +import { CancellationToken, CancellationTokenSource, CompletionItem, CompletionParams, DidChangeConfigurationNotification, DidChangeConfigurationParams, DidChangeWatchedFilesParams, DocumentSymbolParams, FoldingRange, FoldingRangeParams, Hover, HoverParams, SemanticTokensParams, SemanticTokensRangeParams, SymbolInformation, TextDocuments, WorkspaceFoldersChangeEvent, _Connection } from 'vscode-languageserver'; +import { BaseProjectDocument } from './document'; import { LanguageServerConfiguration } from '../server'; import { hasConfigurationCapability } from '../capabilities/workspaceFolder'; import { TextDocument } from 'vscode-languageserver-textdocument'; @@ -11,13 +11,13 @@ import { TextDocument } from 'vscode-languageserver-textdocument'; */ export class Workspace { private _events: WorkspaceEvents; - private _documents: ProjectDocument[] = []; - private _activeDocument?: ProjectDocument; + private _documents: BaseProjectDocument[] = []; + private _activeDocument?: BaseProjectDocument; private _publicScopeDeclarations: Map = new Map(); readonly connection: _Connection; - activateDocument(document: ProjectDocument) { + activateDocument(document: BaseProjectDocument) { this._activeDocument = document; } @@ -59,8 +59,9 @@ class WorkspaceEvents { private readonly _workspace: Workspace; private readonly _documents: TextDocuments; private readonly _configuration: LanguageServerConfiguration; + private _parseCancellationToken?: CancellationTokenSource; - activeDocument?: ProjectDocument; + activeDocument?: BaseProjectDocument; constructor(params: {connection: _Connection, workspace: Workspace, configuration: LanguageServerConfiguration}) { this._workspace = params.workspace; @@ -72,17 +73,16 @@ class WorkspaceEvents { } private initialiseConnectionEvents(connection: _Connection) { - console.log('Initialising connection events...'); connection.onInitialized(() => this.onInitialized()); connection.onCompletion(params => this.onCompletion(params)); connection.onCompletionResolve(item => this.onCompletionResolve(item)); connection.onDidChangeConfiguration(params => this.onDidChangeConfiguration(params)); connection.onDidChangeWatchedFiles(params => this.onDidChangeWatchedFiles(params)); - connection.onDocumentSymbol(async (params) => await this.onDocumentSymbolAsync(params)); + connection.onDocumentSymbol(async (params, token) => await this.onDocumentSymbolAsync(params, token)); connection.onHover(params => this.onHover(params)); if (hasConfigurationCapability(this._configuration)) { - connection.onFoldingRanges((params) => this.onFoldingRanges(params)); + connection.onFoldingRanges(async (params, token) => this.onFoldingRanges(params, token)); } connection.onRequest((method: string, params: object | object[] | any) => { @@ -101,19 +101,16 @@ class WorkspaceEvents { } private initialiseDocumentsEvents() { - console.log('Initialising documents events...'); this._documents.onDidChangeContent(async (e) => await this.onDidChangeContentAsync(e.document)); } /** Connection event handlers */ private onCompletion(params: CompletionParams): never[] { - console.log(`onCompletion: ${params}`); return []; } private onCompletionResolve(item: CompletionItem): CompletionItem { - console.log(`onCompletionResolve: ${item.label}`); return item; } @@ -127,16 +124,15 @@ class WorkspaceEvents { // TODO: Should trigger a full workspace refresh. private onDidChangeWorkspaceFolders(e: WorkspaceFoldersChangeEvent) { - console.log(`onDidChangeWorkspaceFolders: ${e}`); this._workspace.connection.console.log(`Workspace folder change event received.\n${e}`); } - private async onDocumentSymbolAsync(params: DocumentSymbolParams): Promise { - return await this.activeDocument?.languageServerSymbolInformationAsync() ?? []; + private async onDocumentSymbolAsync(params: DocumentSymbolParams, token: CancellationToken): Promise { + return await this.activeDocument?.languageServerSymbolInformationAsync(token) ?? []; } - private onFoldingRanges(params: FoldingRangeParams): FoldingRange[] { - return this._workspace.activeDocument?.foldableElements ?? []; + private async onFoldingRanges(params: FoldingRangeParams, token: CancellationToken): Promise { + return await this._workspace.activeDocument?.getFoldingRanges(token) ?? []; } private onHover(params: HoverParams): Hover { @@ -163,9 +159,13 @@ class WorkspaceEvents { * @param doc The document that changed. */ async onDidChangeContentAsync(doc: TextDocument) { + // this._parseCancellationToken?.cancel(); + // this._parseCancellationToken?.dispose(); + this.activeDocument = BaseProjectDocument.create(this._workspace, doc); - await this.activeDocument.parseAsync(); + this._parseCancellationToken = new CancellationTokenSource(); + await this.activeDocument.parseAsync(this._parseCancellationToken.token); + this._parseCancellationToken = undefined; this._workspace.activateDocument(this.activeDocument); } - -} \ No newline at end of file +} From 694a6ac085f445f1b4637300c14f05fdeefba7c8 Mon Sep 17 00:00:00 2001 From: sslinky Date: Fri, 24 May 2024 20:49:37 +0800 Subject: [PATCH 16/16] 1.3.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1b8b331..19cac30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vba-lsp", - "version": "1.2.4", + "version": "1.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vba-lsp", - "version": "1.2.4", + "version": "1.3.0", "hasInstallScript": true, "license": "MIT", "devDependencies": { diff --git a/package.json b/package.json index d792801..26e3403 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "icon": "images/vba-lsp-icon.png", "author": "SSlinky", "license": "MIT", - "version": "1.2.4", + "version": "1.3.0", "repository": { "type": "git", "url": "https://github.com/SSlinky/VBA-LanguageServer"