From 648a3e062e55612d6fbf708528cd8003797743e2 Mon Sep 17 00:00:00 2001 From: f4r3n Date: Wed, 6 Mar 2024 21:08:15 +0100 Subject: [PATCH 1/3] WIP --- editor/package.json | 8 +- editor/src/commands.ts | 32 ++++---- editor/src/ctx.ts | 161 ++++++++++++++++++++++++----------------- editor/src/lsp_ext.ts | 2 +- 4 files changed, 119 insertions(+), 84 deletions(-) diff --git a/editor/package.json b/editor/package.json index 0e3c3ce..601cf63 100644 --- a/editor/package.json +++ b/editor/package.json @@ -99,7 +99,13 @@ "markdownDescription": "Precise the scope of the diagnostics. If 'workspace' is selected, every methods will be checked. If 'Document' is selected, only the current document will be checked" } } - } + }, + "commands": [ + { + "command": "4d-analyzer.checkWorkspaceSyntax", + "title": "4D Analyzer: Check workspace syntax" + } + ] }, "scripts": { "vscode:prepublish": "npm run esbuild-base -- --minify", diff --git a/editor/src/commands.ts b/editor/src/commands.ts index 1089365..bfd2e98 100644 --- a/editor/src/commands.ts +++ b/editor/src/commands.ts @@ -43,36 +43,38 @@ export function filesStatus(ctx: Ctx): Cmd { })); }; } -let id = 0; -export function checkSyntax(ctx: Ctx): Cmd { + +export function checkWorkspaceSyntax(ctx: Ctx): Cmd { return async()=> { - id++; + const client = ctx.client; const params = client.code2ProtocolConverter.asTextDocumentIdentifier( vscode.window.activeTextEditor.document ); - const response = await client.sendRequest(ext.checkSyntax, params); - let currentItem : WorkspaceFullDocumentDiagnosticReport; - const diagnosticName : string = client.diagnostics.name; - console.log("NAME" + diagnosticName); - //. - const diagnosticCollection = client.diagnostics; - diagnosticCollection.clear(); - const diagnostics : vscode.Diagnostic[] = []; + const response = await client.sendRequest(ext.checkWorkspaceSyntax, params); + + + let diagnosticCollection = client.diagnostics; + for(const diagWorkspace of response.items) { - currentItem = diagWorkspace as WorkspaceFullDocumentDiagnosticReport; + const diagnostics : vscode.Diagnostic[] = []; + let currentItem = diagWorkspace as WorkspaceFullDocumentDiagnosticReport; for(const diag of currentItem.items) { const range : vscode.Range = new vscode.Range(diag.range.start.line, diag.range.start.character, diag.range.end.line, diag.range.end.character); const diagnostic = new vscode.Diagnostic(range, diag.message, diag.severity - 1); diagnostics.push(diagnostic); } + diagnosticCollection.set(vscode.Uri.parse(currentItem.uri), diagnostics); } - - ctx.extensionContext.subscriptions.push(diagnosticCollection); - + /* + ctx.extensionContext.subscriptions.push(vscode.languages.onDidChangeDiagnostics((event)=>{ + event.uris.forEach((uri)=> { + console.log(uri, client.diagnostics.get(uri)) + }) + }));*/ }; } diff --git a/editor/src/ctx.ts b/editor/src/ctx.ts index 60875b5..9fe3797 100644 --- a/editor/src/ctx.ts +++ b/editor/src/ctx.ts @@ -1,10 +1,10 @@ import * as vscode from 'vscode'; import * as Commands from "./commands"; -import {Config} from "./config"; +import { Config } from "./config"; import { - LanguageClient, - LanguageClientOptions, - StreamInfo + LanguageClient, + LanguageClientOptions, + StreamInfo } from 'vscode-languageclient/node'; import { workspace } from 'vscode'; @@ -12,84 +12,78 @@ import * as child_process from 'child_process'; import * as net from 'net'; +import { ProvideDiagnosticSignature, DocumentDiagnosticRequest, DocumentDiagnosticReportKind, DocumentDiagnosticParams } from 'vscode-languageclient' export type CommandCallback = { call: (ctx: Ctx) => Commands.Cmd; }; -export class Ctx -{ - private _client : LanguageClient; - private _extensionContext : vscode.ExtensionContext; - private _commands : Record; - private _config : Config; +export class Ctx { + private _client: LanguageClient; + private _extensionContext: vscode.ExtensionContext; + private _commands: Record; + private _config: Config; - constructor(ctx : vscode.ExtensionContext) { + constructor(ctx: vscode.ExtensionContext) { this._client = null; this._extensionContext = ctx; this._commands = {}; this._config = null; } - public get extensionContext() : vscode.ExtensionContext - { + public get extensionContext(): vscode.ExtensionContext { return this._extensionContext; } - public get client() : LanguageClient - { + public get client(): LanguageClient { return this._client; } - public set client(inClient : LanguageClient) { + public set client(inClient: LanguageClient) { this._client = inClient; } - private _getServerPath(isDebug : boolean) : string { - let serverPath : string = this._config.serverPath; + private _getServerPath(isDebug: boolean): string { + let serverPath: string = this._config.serverPath; - if(process.env.ANALYZER_4D_PATH) - { + if (process.env.ANALYZER_4D_PATH) { serverPath = process.env.ANALYZER_4D_PATH; } - - if(isDebug) { + + if (isDebug) { serverPath = '';//debug } return serverPath; } - private _getPort(isDebug : boolean) : number { + private _getPort(isDebug: boolean): number { let port = 0; - if(process.env.ANALYZER_4D_PORT) - { + if (process.env.ANALYZER_4D_PORT) { port = parseInt(process.env.ANALYZER_4D_PORT); } - if(isDebug) { + if (isDebug) { port = 1800; } return port; } - public start() - { + public start() { this._config = new Config(this._extensionContext); this._config.setContext(this); this._config.checkSettings(); - let isDebug : boolean; + let isDebug: boolean; isDebug = false; - if(process.env.ANALYZER_4D_DEBUG) - { + if (process.env.ANALYZER_4D_DEBUG) { isDebug = true; } - - const serverPath : string = this._getServerPath(isDebug); - const port : number= this._getPort(isDebug); + + const serverPath: string = this._getServerPath(isDebug); + const port: number = this._getPort(isDebug); console.log("SERVER PATH", serverPath); - + // If the extension is launched in debug mode then the debug server options are used // Otherwise the run options are used const serverOptions = () => @@ -111,24 +105,24 @@ export class Ctx server.close(); }); //server.close() - resolve({ reader: socket, writer: socket, detached : false }); + resolve({ reader: socket, writer: socket, detached: false }); }); - + // Listen on random port server.listen(port, '127.0.0.1', () => { console.log(`Listens on port: ${(server.address() as net.AddressInfo).port}`); - - if(serverPath != '') { + + if (serverPath != '') { const childProcess = child_process.spawn(serverPath, [ '--lsp=' + (server.address() as net.AddressInfo).port, ]); - + childProcess.stderr.on('data', (chunk: Buffer) => { const str = chunk.toString(); console.log('4D Language Server:', str); this._client.outputChannel.appendLine(str); }); - + childProcess.on('exit', (code, signal) => { this._client.outputChannel.appendLine( `Language server exited ` + (signal ? `from signal ${signal}` : `with exit code ${code}`) @@ -137,30 +131,65 @@ export class Ctx this._client.outputChannel.show(); } }); - - - server.on('close', function() { + + + server.on('close', function () { console.log("KILL"); childProcess.kill(); }); - + return childProcess; } - + }); }); - - // Options to control the language client - const clientOptions: LanguageClientOptions = { - // Register the server for plain text documents - documentSelector: [{ scheme: 'file', language: '4d' }], - synchronize: { - // Notify the server about file changes to '.clientrc files contained in the workspace - fileEvents: workspace.createFileSystemWatcher('**/.4DSettings') + + // Options to control the language client + const clientOptions: LanguageClientOptions = { + // Register the server for plain text documents + documentSelector: [{ scheme: 'file', language: '4d' }], + synchronize: { + // Notify the server about file changes to '.clientrc files contained in the workspace + fileEvents: workspace.createFileSystemWatcher('**/.4DSettings') + }, + initializationOptions: this._config.cfg, + diagnosticCollectionName: "4d", + middleware: { + handleDiagnostics: (uri: vscode.Uri, diagnostics: vscode.Diagnostic[], next: any) => { + console.log("handleDiagnostics", diagnostics) + next(uri, diagnostics); + }, + + provideDiagnostics: (document, previousResultId, token, next) => { + + const next2: ProvideDiagnosticSignature = (document, previousResultId, token) => { + const params: DocumentDiagnosticParams = { + identifier: "4d", + textDocument: { uri: this.client.code2ProtocolConverter.asUri(document instanceof vscode.Uri ? document : document.uri) }, + previousResultId: previousResultId + }; + if (/*this.isDisposed === true ||*/ !this.client.isRunning()) { + return { kind: DocumentDiagnosticReportKind.Full, items: [] }; + } + return this.client.sendRequest(DocumentDiagnosticRequest.type, params, token).then(async (result) => { + if (result === undefined || result === null /*|| this.isDisposed*/ || token.isCancellationRequested) { + return { kind: DocumentDiagnosticReportKind.Full, items: [] }; + } + if (result.kind === DocumentDiagnosticReportKind.Full) { + return { kind: DocumentDiagnosticReportKind.Full, resultId: result.resultId, items: await this.client.protocol2CodeConverter.asDiagnostics(result.items, token) }; + } else { + return { kind: DocumentDiagnosticReportKind.Unchanged, resultId: result.resultId }; + } + }, (error) => { + return this.client.handleFailedRequest(DocumentDiagnosticRequest.type, token, error, { kind: DocumentDiagnosticReportKind.Full, items: [] }); + }); + }; + + return next2(document, previousResultId, token) + }, - initializationOptions: this._config.cfg, - diagnosticCollectionName:"4d" - }; + } + }; // Create the language client and start the client. this._client = new LanguageClient( '4D-Analyzer', @@ -172,17 +201,16 @@ export class Ctx this._client.start(); } - public registerCommands() - { + public registerCommands() { this._commands = { - filesStatus:{call:Commands.filesStatus}, - checkSyntax:{call:Commands.checkSyntax} - }; + filesStatus: { call: Commands.filesStatus }, + checkWorkspaceSyntax: { call: Commands.checkWorkspaceSyntax } + }; - for (const [name, command] of Object.entries(this._commands)) { + for (const [name, command] of Object.entries(this._commands)) { const fullName = `4d-analyzer.${name}`; const callback = command.call(this); - + this._extensionContext.subscriptions.push(vscode.commands.registerCommand(fullName, callback)); } } @@ -191,12 +219,11 @@ export class Ctx this._extensionContext.subscriptions.push(d); } - stop() : undefined | Promise - { + stop(): undefined | Promise { if (!this._client) { return undefined; } - + return this._client.stop(); } } diff --git a/editor/src/lsp_ext.ts b/editor/src/lsp_ext.ts index e99e631..2091dfb 100644 --- a/editor/src/lsp_ext.ts +++ b/editor/src/lsp_ext.ts @@ -5,6 +5,6 @@ export const filesStatus = new lc.RequestType0( "experimental/filesStatus" ); -export const checkSyntax = new lc.RequestType( +export const checkWorkspaceSyntax = new lc.RequestType( "experimental/checkSyntax" ); From 9dea73b45c1ef94be04837db5664fd590fd842de Mon Sep 17 00:00:00 2001 From: f4r3n Date: Wed, 6 Mar 2024 22:26:50 +0100 Subject: [PATCH 2/3] wip --- editor/src/commands.ts | 10 ++++++++-- editor/src/ctx.ts | 24 ++++++++++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/editor/src/commands.ts b/editor/src/commands.ts index bfd2e98..a0e65f7 100644 --- a/editor/src/commands.ts +++ b/editor/src/commands.ts @@ -52,14 +52,20 @@ export function checkWorkspaceSyntax(ctx: Ctx): Cmd { vscode.window.activeTextEditor.document ); const response = await client.sendRequest(ext.checkWorkspaceSyntax, params); + for(const diagWorkspace of response.items) + { + let currentItem = diagWorkspace as WorkspaceFullDocumentDiagnosticReport; + //client.diagnostics.set(vscode.Uri.parse(currentItem.uri), undefined); + let diagnostics = vscode.languages.getDiagnostics(vscode.Uri.parse(currentItem.uri)) + } - - let diagnosticCollection = client.diagnostics; + let diagnosticCollection = ctx.workspaceDiagnostic; for(const diagWorkspace of response.items) { const diagnostics : vscode.Diagnostic[] = []; let currentItem = diagWorkspace as WorkspaceFullDocumentDiagnosticReport; + for(const diag of currentItem.items) { const range : vscode.Range = new vscode.Range(diag.range.start.line, diag.range.start.character, diag.range.end.line, diag.range.end.character); diff --git a/editor/src/ctx.ts b/editor/src/ctx.ts index 9fe3797..6b03fe7 100644 --- a/editor/src/ctx.ts +++ b/editor/src/ctx.ts @@ -12,7 +12,7 @@ import * as child_process from 'child_process'; import * as net from 'net'; -import { ProvideDiagnosticSignature, DocumentDiagnosticRequest, DocumentDiagnosticReportKind, DocumentDiagnosticParams } from 'vscode-languageclient' +import { ProvideDiagnosticSignature, DocumentDiagnosticRequest, DocumentDiagnosticReportKind, DocumentDiagnosticParams, FullDocumentDiagnosticReport } from 'vscode-languageclient' export type CommandCallback = { call: (ctx: Ctx) => Commands.Cmd; }; @@ -22,12 +22,18 @@ export class Ctx { private _extensionContext: vscode.ExtensionContext; private _commands: Record; private _config: Config; + private _workspaceDiagnostic : vscode.DiagnosticCollection; constructor(ctx: vscode.ExtensionContext) { this._client = null; this._extensionContext = ctx; this._commands = {}; this._config = null; + this._workspaceDiagnostic = vscode.languages.createDiagnosticCollection("4d_workspace"); + } + + public get workspaceDiagnostic(): vscode.DiagnosticCollection { + return this._workspaceDiagnostic; } public get extensionContext(): vscode.ExtensionContext { @@ -159,22 +165,25 @@ export class Ctx { console.log("handleDiagnostics", diagnostics) next(uri, diagnostics); }, - provideDiagnostics: (document, previousResultId, token, next) => { - - const next2: ProvideDiagnosticSignature = (document, previousResultId, token) => { + this._workspaceDiagnostic.set(document instanceof vscode.Uri ? document : document.uri, undefined) + return next(document, previousResultId, token); + const p: any = async (document, previousResultId, token) => { const params: DocumentDiagnosticParams = { identifier: "4d", textDocument: { uri: this.client.code2ProtocolConverter.asUri(document instanceof vscode.Uri ? document : document.uri) }, previousResultId: previousResultId }; - if (/*this.isDisposed === true ||*/ !this.client.isRunning()) { + if (!this.client.isRunning()) { return { kind: DocumentDiagnosticReportKind.Full, items: [] }; } return this.client.sendRequest(DocumentDiagnosticRequest.type, params, token).then(async (result) => { - if (result === undefined || result === null /*|| this.isDisposed*/ || token.isCancellationRequested) { + if (result === undefined || result === null || token.isCancellationRequested) { return { kind: DocumentDiagnosticReportKind.Full, items: [] }; } + + + if (result.kind === DocumentDiagnosticReportKind.Full) { return { kind: DocumentDiagnosticReportKind.Full, resultId: result.resultId, items: await this.client.protocol2CodeConverter.asDiagnostics(result.items, token) }; } else { @@ -185,8 +194,7 @@ export class Ctx { }); }; - return next2(document, previousResultId, token) - + return p(document, previousResultId, token) }, } }; From 0f3409d279a09c16bbcf46e0ae2f74a28d1ae784 Mon Sep 17 00:00:00 2001 From: Guillaume Kotulski Date: Thu, 7 Mar 2024 11:14:26 +0100 Subject: [PATCH 3/3] clean up duplicates --- editor/src/commands.ts | 42 +++++++++++++++++++++++------------------ editor/src/config.ts | 10 +++++++++- editor/src/ctx.ts | 43 ++++++++---------------------------------- 3 files changed, 41 insertions(+), 54 deletions(-) diff --git a/editor/src/commands.ts b/editor/src/commands.ts index a0e65f7..7651517 100644 --- a/editor/src/commands.ts +++ b/editor/src/commands.ts @@ -45,42 +45,48 @@ export function filesStatus(ctx: Ctx): Cmd { } export function checkWorkspaceSyntax(ctx: Ctx): Cmd { - return async()=> { - + if(ctx.config.diagnosticEnabled && ctx.config.diagnosticScope === "Workspace") + { + return async()=>{ + const userResponse = await vscode.window.showErrorMessage( + `Workspace syntax checking is already running` + ); + } + } + + return async()=> {vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: "Workspace syntax check running", + cancellable: false + }, async (progress, token) => { const client = ctx.client; const params = client.code2ProtocolConverter.asTextDocumentIdentifier( vscode.window.activeTextEditor.document ); const response = await client.sendRequest(ext.checkWorkspaceSyntax, params); - for(const diagWorkspace of response.items) - { - let currentItem = diagWorkspace as WorkspaceFullDocumentDiagnosticReport; - //client.diagnostics.set(vscode.Uri.parse(currentItem.uri), undefined); - let diagnostics = vscode.languages.getDiagnostics(vscode.Uri.parse(currentItem.uri)) - } let diagnosticCollection = ctx.workspaceDiagnostic; - + diagnosticCollection.clear() for(const diagWorkspace of response.items) { const diagnostics : vscode.Diagnostic[] = []; let currentItem = diagWorkspace as WorkspaceFullDocumentDiagnosticReport; - + let currentDiagnostics = vscode.languages.getDiagnostics(vscode.Uri.parse(currentItem.uri)) for(const diag of currentItem.items) { const range : vscode.Range = new vscode.Range(diag.range.start.line, diag.range.start.character, diag.range.end.line, diag.range.end.character); const diagnostic = new vscode.Diagnostic(range, diag.message, diag.severity - 1); - diagnostics.push(diagnostic); + if(!currentDiagnostics.find((cdiagnostic =>{ + return cdiagnostic.range.isEqual(diagnostic.range) && cdiagnostic.message === diagnostic.message + }))) + { + diagnostics.push(diagnostic); + } + } diagnosticCollection.set(vscode.Uri.parse(currentItem.uri), diagnostics); } - /* - ctx.extensionContext.subscriptions.push(vscode.languages.onDidChangeDiagnostics((event)=>{ - event.uris.forEach((uri)=> { - console.log(uri, client.diagnostics.get(uri)) - }) - }));*/ - }; + });} } diff --git a/editor/src/config.ts b/editor/src/config.ts index f1be633..5826a29 100644 --- a/editor/src/config.ts +++ b/editor/src/config.ts @@ -9,7 +9,7 @@ export class Config { readonly rootSection = "4D-Analyzer"; - _ctx : Ctx; + private _ctx : Ctx; private readonly requiresReloadOpts = [ "server.path", "diagnostics.enable", @@ -29,6 +29,14 @@ export class Config { return vscode.workspace.getConfiguration(this.rootSection); } + public get diagnosticScope() : string{ + return this.get("diagnostics.scope"); + } + + public get diagnosticEnabled() : string{ + return this.get("diagnostics.enable"); + } + private get(path: string): T { return this.cfg.get(path)!; } diff --git a/editor/src/ctx.ts b/editor/src/ctx.ts index 6b03fe7..e06fba3 100644 --- a/editor/src/ctx.ts +++ b/editor/src/ctx.ts @@ -11,8 +11,6 @@ import { workspace } from 'vscode'; import * as child_process from 'child_process'; import * as net from 'net'; - -import { ProvideDiagnosticSignature, DocumentDiagnosticRequest, DocumentDiagnosticReportKind, DocumentDiagnosticParams, FullDocumentDiagnosticReport } from 'vscode-languageclient' export type CommandCallback = { call: (ctx: Ctx) => Commands.Cmd; }; @@ -32,6 +30,10 @@ export class Ctx { this._workspaceDiagnostic = vscode.languages.createDiagnosticCollection("4d_workspace"); } + public get config(): Config { + return this._config; + } + public get workspaceDiagnostic(): vscode.DiagnosticCollection { return this._workspaceDiagnostic; } @@ -161,41 +163,12 @@ export class Ctx { initializationOptions: this._config.cfg, diagnosticCollectionName: "4d", middleware: { - handleDiagnostics: (uri: vscode.Uri, diagnostics: vscode.Diagnostic[], next: any) => { - console.log("handleDiagnostics", diagnostics) - next(uri, diagnostics); - }, provideDiagnostics: (document, previousResultId, token, next) => { - this._workspaceDiagnostic.set(document instanceof vscode.Uri ? document : document.uri, undefined) + console.log(document instanceof vscode.Uri ? document : document.uri) + if(this._config.diagnosticEnabled) + this._workspaceDiagnostic.set(document instanceof vscode.Uri ? document : document.uri, undefined) return next(document, previousResultId, token); - const p: any = async (document, previousResultId, token) => { - const params: DocumentDiagnosticParams = { - identifier: "4d", - textDocument: { uri: this.client.code2ProtocolConverter.asUri(document instanceof vscode.Uri ? document : document.uri) }, - previousResultId: previousResultId - }; - if (!this.client.isRunning()) { - return { kind: DocumentDiagnosticReportKind.Full, items: [] }; - } - return this.client.sendRequest(DocumentDiagnosticRequest.type, params, token).then(async (result) => { - if (result === undefined || result === null || token.isCancellationRequested) { - return { kind: DocumentDiagnosticReportKind.Full, items: [] }; - } - - - - if (result.kind === DocumentDiagnosticReportKind.Full) { - return { kind: DocumentDiagnosticReportKind.Full, resultId: result.resultId, items: await this.client.protocol2CodeConverter.asDiagnostics(result.items, token) }; - } else { - return { kind: DocumentDiagnosticReportKind.Unchanged, resultId: result.resultId }; - } - }, (error) => { - return this.client.handleFailedRequest(DocumentDiagnosticRequest.type, token, error, { kind: DocumentDiagnosticReportKind.Full, items: [] }); - }); - }; - - return p(document, previousResultId, token) - }, + } } }; // Create the language client and start the client.