diff --git a/client/src/syntaxes/vba.tmLanguage.yaml b/client/src/syntaxes/vba.tmLanguage.yaml index 961ab17..99e6e9b 100644 --- a/client/src/syntaxes/vba.tmLanguage.yaml +++ b/client/src/syntaxes/vba.tmLanguage.yaml @@ -17,6 +17,7 @@ repository: - include: "#methodSignature" - include: "#continuations" # Consume continuations so they "continue" other matches. - include: "#enum" + - include: "#struct" - include: "#syntaxLines" # Split document lines into syntax lines. continuations: @@ -40,16 +41,18 @@ repository: syntaxLines: name: meta.syntax-lines.vba - match: ((?:[^\n":]|"(?:\\.|[^\n"\\])*")+|"(?:\\.|[^\n"\\])*") + match: ((?:[^\n"':]|"(?:\\.|[^\n"\\])*")+|"(?:\\.|[^\n"\\])*")(?:('.*)*)? captures: 1: # Split line patterns: - include: "#main" + 2: # Comments + patterns: + - include: "#comments" main: patterns: - include: "#moduleHeader" - - include: "#struct" - include: "#declareFunctionSignature" - include: "#methodSignature" - include: "#variableDeclarations" @@ -148,12 +151,11 @@ 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|each|in|to|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 @@ -170,7 +172,7 @@ repository: inlineIfElse: name: meta.flow.inline-if-else.vba - match: (?i)\b(if)\s+(.*?)\s+(then)\s+(.*)\s+(else)\s+(.*) + match: (?i)\s*((?:else)?if)\s+(.*?)\s+(then)\s+(.*)\s+(else)\s+([^'\n]*) captures: 1: name: keyword.control.flow.decision.vba @@ -193,7 +195,7 @@ repository: inlineIf: name: meta.flow.inline-if.vba - match: (?i)\b(if)\s+(.*?)\s+(then) + match: (?i)\s*((?:else)?if)\s+(.*?)\s+(then) captures: 1: name: keyword.control.flow.decision.vba @@ -417,13 +419,13 @@ 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: (?i)'.*\s_\s* + begin: (?i)\s*'.*\s_\s* end: \n patterns: - include: "#lineContinuation" apostropheComments: - name: comment.line.apostrophe.vba - match: (?i)'.* + name: comment.line.apostropheXX.vba + match: (?i)\s*'.* remarkComments: name: comment.line.remark.vba match: (?i)(?<=^|:)\s*Rem\b.* @@ -459,7 +461,7 @@ repository: enum: name: meta.enum.declaration.vba - begin: (?i)^\s*((?:(?:Public|Private)\s+)?\s*Enum)\s+([a-z][a-z0-9_]+)(\s+(?:'|Rem).*) + begin: (?i)^\s*((?:(?:Public|Private)\s+)?\s*Enum)\s+([a-z][a-z0-9_]+)(\s+(?:'|Rem).*)? beginCaptures: 1: name: storage.type.enum.vba @@ -471,13 +473,17 @@ repository: patterns: - include: "#comment" - include: "#enumMember" - end: (?i)^\s*End\s+Enum\b + - include: "#language" + end: (?i)^\s*(End\s+Enum)(\s+'.*)? endCaptures: - 0: + 1: name: storage.type.enum.vba + 2: + patterns: + - include: "#comments" enumMember: - match: (?i)^\s*([a-z][a-z0-9_]*)(?:\s+(=)\s+([^\n']*)\s+)?('.*)?$ + match: (?i)^\s*([a-z][a-z0-9_]*)(?:\s+(=)\s+([^\n']*))?(\s+(?:'|Rem).*)? captures: 1: name: constant.numeric.enum.vba @@ -493,34 +499,42 @@ repository: struct: name: meta.struct.declaration.vba - begin: "(?i)^\\s*((?:(?:Public|Private) )?\\s*Type)\\s+([a-z][a-z0-9_]*)" + begin: (?i)^\s*((?:(?:Public|Private)\s+)?Type)\s+([a-z][a-z0-9_]*)?(\s+(?:'|Rem).*)? beginCaptures: - 1: + 1: # Type declaration name: storage.type.struct.vba - 2: + 2: # Type name name: entity.name.type.struct.vba + 3: # Comments? + patterns: + - include: "#comments" patterns: + - include: "#comment" - include: "#structProperty" + - include: "#language" - end: "(?i)^\\s*End\\s+Type\\b" + end: (?i)^\s*(End\s+Type)(\s+'.*)? endCaptures: - 0: + 1: name: storage.type.struct.vba + 2: + patterns: + - include: "#comments" structProperty: - match: "(?i)^\\s*([a-z][a-z0-9_]*)(\\(.*\\))?(\\s+As\\s+[a-z][a-z0-9_]*)?" + match: (?i)^\s*([a-z][a-z0-9_]*)(\(.*\))?(\s+As\s+[a-z][a-z0-9_]*)?(\s+(?:'|Rem).*)? captures: - 1: - # Property + 1: # Property name: variable.other.readwrite.vba - 2: - # Array bounds? + 2: # Array bounds? patterns: - include: "#language" - 3: - # As Type + 3: # As Type? patterns: - include: "#types" + 4: # Comments? + patterns: + - include: "#comments" declareFunctionSignature: name: source.declare.signature.vba diff --git a/package-lock.json b/package-lock.json index 19cac30..89e76b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vba-lsp", - "version": "1.3.0", + "version": "1.3.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vba-lsp", - "version": "1.3.0", + "version": "1.3.2", "hasInstallScript": true, "license": "MIT", "devDependencies": { diff --git a/package.json b/package.json index 26e3403..9d114bf 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "icon": "images/vba-lsp-icon.png", "author": "SSlinky", "license": "MIT", - "version": "1.3.0", + "version": "1.3.2", "repository": { "type": "git", "url": "https://github.com/SSlinky/VBA-LanguageServer" diff --git a/server/src/antlr/vba.g4 b/server/src/antlr/vba.g4 index 1f3ec80..3b59580 100644 --- a/server/src/antlr/vba.g4 +++ b/server/src/antlr/vba.g4 @@ -52,8 +52,7 @@ moduleDeclarationsElement: comment | declareStmt | implementsStmt - | moduleOption - | unknownLine; + | moduleOption; macroStmt: macroConstStmt | macroIfThenElseStmt; @@ -461,7 +460,19 @@ stopStmt: STOP; timeStmt: TIME WS? EQ WS? valueStmt; typeStmt: - (visibility WS)? TYPE WS ambiguousIdentifier endOfStatement typeStmt_Element* END_TYPE; + (visibility WS)? TYPE WS ambiguousIdentifier endOfStatement (typeStmt_Element|macroTypeIfThenElseStmt)* END_TYPE; + +macroTypeIfThenElseStmt: + macroTypeIfBlockStmt macroTypeElseIfBlockStmt* macroTypeElseBlockStmt? MACRO_END_IF endOfStatement; + +macroTypeIfBlockStmt: + MACRO_IF WS? ifConditionStmt WS THEN endOfStatement typeStmt_Element*; + +macroTypeElseIfBlockStmt: + MACRO_ELSEIF WS? ifConditionStmt WS THEN endOfStatement typeStmt_Element*; + +macroTypeElseBlockStmt: + MACRO_ELSE endOfStatement typeStmt_Element*; typeStmt_Element: ambiguousIdentifier (WS? LPAREN (WS? subscripts)? WS? RPAREN)? ( @@ -489,21 +500,10 @@ valueStmt: | implicitCallStmt_InStmt WS? ASSIGN WS? valueStmt # vsAssign | valueStmt WS? IS WS? valueStmt # vsIs | valueStmt WS? LIKE WS? valueStmt # vsLike - | valueStmt WS? GEQ WS? valueStmt # vsGeq - | valueStmt WS? LEQ WS? valueStmt # vsLeq - | valueStmt WS? GT WS? valueStmt # vsGt - | valueStmt WS? LT WS? valueStmt # vsLt - | valueStmt WS? NEQ WS? valueStmt # vsNeq - | valueStmt WS? EQ WS? valueStmt # vsEq - | valueStmt WS? POW WS? valueStmt # vsPow + | valueStmt WS? operatorsStmt WS? valueStmt # vsOperator | MINUS WS? valueStmt # vsNegation | PLUS WS? valueStmt # vsPlus - | valueStmt WS? DIV WS? valueStmt # vsDiv - | valueStmt WS? MULT WS? valueStmt # vsMult | valueStmt WS? MOD WS? valueStmt # vsMod - | valueStmt WS? PLUS WS? valueStmt # vsAdd - | valueStmt WS? MINUS WS? valueStmt # vsMinus - | valueStmt WS? AMPERSAND WS? valueStmt # vsAmp | valueStmt WS? IMP WS? valueStmt # vsImp | valueStmt WS? EQV WS? valueStmt # vsEqv | valueStmt WS? XOR WS? valueStmt # vsXor @@ -511,6 +511,21 @@ valueStmt: | valueStmt WS? AND WS? valueStmt # vsAnd | NOT WS? valueStmt # vsNot; +operatorsStmt: + (GEQ + | LEQ + | LT + | NEQ + | EQ + | POW + | DIV + | MULT + | MOD + | PLUS + | MINUS + | AMPERSAND + )+; + variableStmt: (DIM | STATIC | visibility) WS (WITHEVENTS WS)? variableListStmt; variableListStmt: @@ -1086,7 +1101,7 @@ R_SQUARE_BRACKET: ']'; STRINGLITERAL: '"' (~["\r\n] | '""')* '"'; OCTLITERAL: '&O' [0-7]+ '&'?; HEXLITERAL: '&H' [0-9A-F]+ '&'?; -SHORTLITERAL: (PLUS | MINUS)? DIGIT+ ('#' | '&' | '@')?; +SHORTLITERAL: (PLUS | MINUS)? DIGIT+ ('#' | '&' | '@' | '^')?; INTEGERLITERAL: SHORTLITERAL (E SHORTLITERAL)?; DOUBLELITERAL: (PLUS | MINUS)? DIGIT* '.' DIGIT+ (E SHORTLITERAL)?; DATELITERAL: '#' DATEORTIME '#'; diff --git a/server/src/capabilities/diagnostics.ts b/server/src/capabilities/diagnostics.ts index 1b552c5..0f2c86f 100644 --- a/server/src/capabilities/diagnostics.ts +++ b/server/src/capabilities/diagnostics.ts @@ -1,6 +1,30 @@ -import { TextDocumentClientCapabilities } from 'vscode-languageserver'; +import { CodeDescription, Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, DiagnosticTag, Range, TextDocumentClientCapabilities } from 'vscode-languageserver'; function hasDiagnosticRelatedInformationCapability(x: TextDocumentClientCapabilities) { return !!(x && x.publishDiagnostics && x.publishDiagnostics.relatedInformation); +} + +abstract class BaseDiagnostic implements Diagnostic { + range: Range; + severity?: DiagnosticSeverity | undefined; + code?: string | number | undefined; + codeDescription?: CodeDescription | undefined; + source?: string | undefined; + abstract message: string; + tags?: DiagnosticTag[] | undefined; + relatedInformation?: DiagnosticRelatedInformation[] | undefined; + data?: unknown; + + constructor(range: Range) { + this.range = range; + } +} + + +export class MultipleOperatorsDiagnostic extends BaseDiagnostic { + message = "Unexpected duplicate operator"; + constructor(range: Range) { + super(range); + } } \ No newline at end of file diff --git a/server/src/project/document.ts b/server/src/project/document.ts index 75eadd0..b692297 100644 --- a/server/src/project/document.ts +++ b/server/src/project/document.ts @@ -1,7 +1,7 @@ -import { CancellationToken, Diagnostic, LSPErrorCodes, ResponseError, SemanticTokens, SymbolInformation, SymbolKind } from 'vscode-languageserver'; +import { CancellationToken, Diagnostic, LSPErrorCodes, PublishDiagnosticsParams, ResponseError, SemanticTokens, SymbolInformation, SymbolKind } from 'vscode-languageserver'; import { Workspace } from './workspace'; import { FoldableElement } from './elements/special'; -import { BaseSyntaxElement, HasAttribute, HasSemanticToken, HasSymbolInformation } from './elements/base'; +import { BaseSyntaxElement, HasAttribute, HasDiagnosticCapability, HasSemanticToken, HasSymbolInformation } from './elements/base'; import { Range, TextDocument } from 'vscode-languageserver-textdocument'; import { SyntaxParser } from './parser/vbaSyntaxParser'; import { FoldingRange } from '../capabilities/folding'; @@ -17,6 +17,7 @@ export abstract class BaseProjectDocument { protected _unhandledNamedElements: [] = []; protected _publicScopeDeclarations: Map = new Map(); protected _documentScopeDeclarations: Map> = new Map(); + protected _hasDiagnosticElements: HasDiagnosticCapability[] = []; protected _diagnostics: Diagnostic[] = []; protected _elementParents: BaseSyntaxElement[] = []; @@ -77,6 +78,10 @@ export abstract class BaseProjectDocument { if (await (new SyntaxParser()).parseAsync(this, token)) { this.isBusy = false; } + this._hasDiagnosticElements.forEach(element => { + element.evaluateDiagnostics; + this._diagnostics.concat(element.diagnostics); + }); }; registerNamedElementDeclaration(element: any) { @@ -88,6 +93,11 @@ export abstract class BaseProjectDocument { throw new Error("Not implemented"); } + registerDiagnosticElement(element: HasDiagnosticCapability) { + console.log("Registering diagnostic element"); + this._hasDiagnosticElements.push(element); + } + /** * Pushes an element to the attribute elements stack. * Be careful to pair a register action with an appropriate deregister. @@ -171,6 +181,16 @@ export abstract class BaseProjectDocument { this.workspace.connection.console.info('Processing request for Folding Range'); return this._foldableElements; } + + getDiagnostics(): PublishDiagnosticsParams { + this._hasDiagnosticElements.forEach(e => + e.evaluateDiagnostics() + ); + return { + uri: this.textDocument.uri, + diagnostics: this._hasDiagnosticElements + .map((e) => e.diagnostics).flat(1) }; + } } diff --git a/server/src/project/elements/base.ts b/server/src/project/elements/base.ts index 3a3cdd3..8f46396 100644 --- a/server/src/project/elements/base.ts +++ b/server/src/project/elements/base.ts @@ -1,5 +1,5 @@ import { ParserRuleContext } from 'antlr4ts'; -import { Range, SemanticTokenModifiers, SemanticTokenTypes, SymbolInformation, SymbolKind } from 'vscode-languageserver'; +import { Diagnostic, Range, SemanticTokenModifiers, SemanticTokenTypes, SymbolInformation, SymbolKind } from 'vscode-languageserver'; import { Position, TextDocument } from 'vscode-languageserver-textdocument'; import { FoldingRangeKind } from '../../capabilities/folding'; import { IdentifierElement } from './memory'; @@ -21,6 +21,11 @@ interface SyntaxElement extends ContextOptionalSyntaxElement { context: ParserRuleContext; } +export interface HasDiagnosticCapability { + diagnostics: Diagnostic[]; + evaluateDiagnostics(): void; +} + export interface HasAttribute { processAttribute(context: AttributeStmtContext): void; } @@ -90,7 +95,7 @@ export abstract class BaseSyntaxElement implements ContextOptionalSyntaxElement const stopIndex = this.context.stop?.stopIndex ?? startIndex; return Range.create( this.document.positionAt(startIndex), - this.document.positionAt(stopIndex) + this.document.positionAt(stopIndex + 1) ); } } diff --git a/server/src/project/elements/operator.ts b/server/src/project/elements/operator.ts new file mode 100644 index 0000000..b8180b8 --- /dev/null +++ b/server/src/project/elements/operator.ts @@ -0,0 +1,20 @@ +import { BaseContextSyntaxElement, HasDiagnosticCapability } from './base'; +import { OperatorsStmtContext } from '../../antlr/out/vbaParser'; +import { TextDocument } from 'vscode-languageserver-textdocument'; +import { Diagnostic } from 'vscode-languageserver'; +import { MultipleOperatorsDiagnostic } from '../../capabilities/diagnostics'; + + +export class OperatorElement extends BaseContextSyntaxElement implements HasDiagnosticCapability { + diagnostics: Diagnostic[] = []; + + constructor(context: OperatorsStmtContext, document: TextDocument) { + super(context, document); + } + + evaluateDiagnostics(): void { + if (this.context.childCount > 1) { + this.diagnostics.push(new MultipleOperatorsDiagnostic(this.range)); + } + } +} diff --git a/server/src/project/parser/vbaSyntaxParser.ts b/server/src/project/parser/vbaSyntaxParser.ts index bcb11da..c31c750 100644 --- a/server/src/project/parser/vbaSyntaxParser.ts +++ b/server/src/project/parser/vbaSyntaxParser.ts @@ -6,7 +6,7 @@ import { ErrorNode } from 'antlr4ts/tree/ErrorNode'; import { ParseTreeWalker } from 'antlr4ts/tree/ParseTreeWalker'; import { vbaLexer as VbaLexer } from '../../antlr/out/vbaLexer'; -import { AttributeStmtContext, ConstStmtContext, EnumerationStmtContext, EnumerationStmt_ConstantContext, FoldingBlockStmtContext, MethodStmtContext, ModuleContext, ModuleHeaderContext, VariableStmtContext, vbaParser as VbaParser } from '../../antlr/out/vbaParser'; +import { AttributeStmtContext, ConstStmtContext, EnumerationStmtContext, EnumerationStmt_ConstantContext, FoldingBlockStmtContext, MethodStmtContext, ModuleContext, ModuleHeaderContext, OperatorsStmtContext, VariableStmtContext, vbaParser as VbaParser } from '../../antlr/out/vbaParser'; import { vbaListener } from '../../antlr/out/vbaListener'; import { VbaClassDocument, VbaModuleDocument } from '../document'; @@ -15,6 +15,7 @@ import { ConstDeclarationsElement, EnumBlockDeclarationElement, EnumMemberDeclar import { ModuleElement } from '../elements/module'; import { sleep } from '../../utils/helpers'; import { CancellationToken } from 'vscode-languageserver'; +import { OperatorElement } from '../elements/operator'; export class SyntaxParser { private static _lockIdentifier = 0; @@ -38,7 +39,7 @@ export class SyntaxParser { // }); // Refuse to do anything that seems like too much work. - if (document.textDocument.lineCount > 1000) { + if (document.textDocument.lineCount > 1500) { // 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.`); @@ -110,6 +111,7 @@ class VbaTreeWalkListener implements vbaListener { }; exitEnumerationStmt = (_: EnumerationStmtContext) => { + console.warn("Entered enum statement."); this.document.deregisterScopedElement(); }; @@ -155,9 +157,15 @@ class VbaTreeWalkListener implements vbaListener { }; enterVariableStmt = (ctx: VariableStmtContext) => { + console.warn("Entered value statement. " + ctx.text); const element = new VariableDeclarationsElement(ctx, this.document.textDocument); element.declarations.forEach((e) => this.document.registerSymbolInformation(e)); }; + + enterOperatorsStmt = (ctx: OperatorsStmtContext) => { + const element = new OperatorElement(ctx, this.document.textDocument); + this.document.registerDiagnosticElement(element); + }; } class VbaErrorListener extends ConsoleErrorListener { diff --git a/server/src/project/workspace.ts b/server/src/project/workspace.ts index 6c7fc4b..493fe51 100644 --- a/server/src/project/workspace.ts +++ b/server/src/project/workspace.ts @@ -1,4 +1,4 @@ -import { CancellationToken, CancellationTokenSource, CompletionItem, CompletionParams, DidChangeConfigurationNotification, DidChangeConfigurationParams, DidChangeWatchedFilesParams, DocumentSymbolParams, FoldingRange, FoldingRangeParams, Hover, HoverParams, SemanticTokensParams, SemanticTokensRangeParams, SymbolInformation, TextDocuments, WorkspaceFoldersChangeEvent, _Connection } from 'vscode-languageserver'; +import { CancellationToken, CancellationTokenSource, CompletionItem, CompletionParams, DidChangeConfigurationNotification, DidChangeConfigurationParams, DidChangeWatchedFilesParams, DocumentSymbolParams, FoldingRange, FoldingRangeParams, Hover, HoverParams, PublishDiagnosticsParams, SemanticTokensParams, SemanticTokensRangeParams, SymbolInformation, TextDocuments, WorkspaceFoldersChangeEvent, _Connection } from 'vscode-languageserver'; import { BaseProjectDocument } from './document'; import { LanguageServerConfiguration } from '../server'; import { hasConfigurationCapability } from '../capabilities/workspaceFolder'; @@ -56,6 +56,7 @@ export class Workspace { } class WorkspaceEvents { + private readonly _connection: _Connection; private readonly _workspace: Workspace; private readonly _documents: TextDocuments; private readonly _configuration: LanguageServerConfiguration; @@ -64,25 +65,26 @@ class WorkspaceEvents { activeDocument?: BaseProjectDocument; constructor(params: {connection: _Connection, workspace: Workspace, configuration: LanguageServerConfiguration}) { + this._connection = params.connection; this._workspace = params.workspace; this._configuration = params.configuration; this._documents = new TextDocuments(TextDocument); this.initialiseConnectionEvents(params.connection); - this.initialiseDocumentsEvents(); + this._initialiseDocumentsEvents(); this._documents.listen(params.connection); } private initialiseConnectionEvents(connection: _Connection) { - 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, token) => await this.onDocumentSymbolAsync(params, token)); - connection.onHover(params => this.onHover(params)); + 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, token) => await this._onDocumentSymbolAsync(params, token)); + connection.onHover(params => this._onHover(params)); if (hasConfigurationCapability(this._configuration)) { - connection.onFoldingRanges(async (params, token) => this.onFoldingRanges(params, token)); + connection.onFoldingRanges(async (params, token) => this._onFoldingRanges(params, token)); } connection.onRequest((method: string, params: object | object[] | any) => { @@ -100,46 +102,50 @@ class WorkspaceEvents { }); } - private initialiseDocumentsEvents() { + private _sendDiagnostics() { + this._connection.sendDiagnostics(this.activeDocument?.getDiagnostics() ?? {uri: "", diagnostics: []}); + } + + private _initialiseDocumentsEvents() { this._documents.onDidChangeContent(async (e) => await this.onDidChangeContentAsync(e.document)); } /** Connection event handlers */ - private onCompletion(params: CompletionParams): never[] { + private _onCompletion(params: CompletionParams): never[] { return []; } - private onCompletionResolve(item: CompletionItem): CompletionItem { + private _onCompletionResolve(item: CompletionItem): CompletionItem { return item; } - private onDidChangeConfiguration(params: DidChangeConfigurationParams): void { + private _onDidChangeConfiguration(params: DidChangeConfigurationParams): void { console.log(`onDidChangeConfiguration: ${params}`); } - private onDidChangeWatchedFiles(params: DidChangeWatchedFilesParams) { + private _onDidChangeWatchedFiles(params: DidChangeWatchedFilesParams) { console.log(`onDidChangeWatchedFiles: ${params}`); } // TODO: Should trigger a full workspace refresh. - private onDidChangeWorkspaceFolders(e: WorkspaceFoldersChangeEvent) { + private _onDidChangeWorkspaceFolders(e: WorkspaceFoldersChangeEvent) { this._workspace.connection.console.log(`Workspace folder change event received.\n${e}`); } - private async onDocumentSymbolAsync(params: DocumentSymbolParams, token: CancellationToken): Promise { + private async _onDocumentSymbolAsync(params: DocumentSymbolParams, token: CancellationToken): Promise { return await this.activeDocument?.languageServerSymbolInformationAsync(token) ?? []; } - private async onFoldingRanges(params: FoldingRangeParams, token: CancellationToken): Promise { + private async _onFoldingRanges(params: FoldingRangeParams, token: CancellationToken): Promise { return await this._workspace.activeDocument?.getFoldingRanges(token) ?? []; } - private onHover(params: HoverParams): Hover { + private _onHover(params: HoverParams): Hover { return { contents: '' }; } - private onInitialized(): void { + private _onInitialized(): void { const connection = this._workspace.connection; // Register for client configuration notification changes. connection.client.register(DidChangeConfigurationNotification.type, undefined); @@ -147,7 +153,7 @@ class WorkspaceEvents { // This is how we can listen for changes to workspace folders. if (hasConfigurationCapability(this._configuration)) { connection.workspace.onDidChangeWorkspaceFolders(e => - this.onDidChangeWorkspaceFolders(e) + this._onDidChangeWorkspaceFolders(e) ); } } @@ -165,6 +171,7 @@ class WorkspaceEvents { this.activeDocument = BaseProjectDocument.create(this._workspace, doc); this._parseCancellationToken = new CancellationTokenSource(); await this.activeDocument.parseAsync(this._parseCancellationToken.token); + this._sendDiagnostics(); this._parseCancellationToken = undefined; this._workspace.activateDocument(this.activeDocument); } diff --git a/server/src/server.ts b/server/src/server.ts index 38a1a65..623678a 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -53,11 +53,39 @@ class LanguageServer { export class LanguageServerConfiguration { params: InitializeParams; capabilities: ServerCapabilities = { - hoverProvider: false, - textDocumentSync: TextDocumentSyncKind.Incremental, - completionProvider: { resolveProvider: false }, - foldingRangeProvider: true, + // Implemented documentSymbolProvider: true, + foldingRangeProvider: true, + textDocumentSync: TextDocumentSyncKind.Incremental, + + // Implement soon. + codeActionProvider: false, + completionProvider: undefined, + hoverProvider: false, + + // Not implemented. + signatureHelpProvider: undefined, + declarationProvider: false, + definitionProvider: false, + typeDefinitionProvider: false, + implementationProvider: false, + referencesProvider: false, + documentHighlightProvider: false, + codeLensProvider: undefined, + documentLinkProvider: undefined, + colorProvider: false, + workspaceSymbolProvider: false, + documentFormattingProvider: false, + documentRangeFormattingProvider: false, + documentOnTypeFormattingProvider: undefined, + renameProvider: false, + selectionRangeProvider: false, + executeCommandProvider: undefined, + callHierarchyProvider: false, + linkedEditingRangeProvider: false, + workspace: undefined, + monikerProvider: false, + experimental: undefined, }; constructor(params: InitializeParams) {