From 25de4a6673eb4a7bc184905bc6f28808832b78bf Mon Sep 17 00:00:00 2001 From: k Date: Tue, 2 Jul 2024 09:26:36 +0200 Subject: [PATCH 01/10] Remove populateCacheFromDisplay config --- src/haxeLanguageServer/Configuration.hx | 2 -- src/haxeLanguageServer/server/HaxeServer.hx | 1 - 2 files changed, 3 deletions(-) diff --git a/src/haxeLanguageServer/Configuration.hx b/src/haxeLanguageServer/Configuration.hx index e00013c2..ce9b0fad 100644 --- a/src/haxeLanguageServer/Configuration.hx +++ b/src/haxeLanguageServer/Configuration.hx @@ -94,7 +94,6 @@ typedef UserConfig = { var buildCompletionCache:Bool; var enableCompletionCacheWarning:Bool; var useLegacyCompletion:Bool; - var populateCacheFromDisplay:Bool; var codeGeneration:CodeGenerationConfig; var exclude:Array; var postfixCompletion:PostfixCompletionConfig; @@ -162,7 +161,6 @@ class Configuration { displayPort: null, buildCompletionCache: true, enableCompletionCacheWarning: true, - populateCacheFromDisplay: true, useLegacyCompletion: false, codeGeneration: { functions: { diff --git a/src/haxeLanguageServer/server/HaxeServer.hx b/src/haxeLanguageServer/server/HaxeServer.hx index f37776f3..ca78f20c 100644 --- a/src/haxeLanguageServer/server/HaxeServer.hx +++ b/src/haxeLanguageServer/server/HaxeServer.hx @@ -205,7 +205,6 @@ class HaxeServer { context.callHaxeMethod(ServerMethods.Configure, { noModuleChecks: true, print: context.config.displayServer.print, - populateCacheFromDisplay: context.config.user.populateCacheFromDisplay, legacyCompletion: context.config.user.useLegacyCompletion }, null, _ -> null, function(error) { trace("Error during " + ServerMethods.Configure + " " + error); From 99d048fca56674a65e1e011a3633c64b4ac67ac1 Mon Sep 17 00:00:00 2001 From: k Date: Tue, 2 Jul 2024 09:30:01 +0200 Subject: [PATCH 02/10] [POC] Switch to json rpc diagnostics TODO: only when this method is available --- .../features/haxe/DiagnosticsFeature.hx | 123 +++++------------- .../DiagnosticsCodeActionFeature.hx | 13 +- .../diagnostics/CompilerErrorActions.hx | 2 +- .../diagnostics/MissingFieldsActions.hx | 1 + .../diagnostics/OrganizeImportActions.hx | 4 +- .../diagnostics/ParserErrorActions.hx | 2 +- .../diagnostics/ReplaceableCodeActions.hx | 2 +- .../UnresolvedIdentifierActions.hx | 8 +- .../diagnostics/UpdateSyntaxActions.hx | 2 +- 9 files changed, 47 insertions(+), 110 deletions(-) diff --git a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx index 1d5cc1c2..a7e29a00 100644 --- a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx @@ -1,5 +1,7 @@ package haxeLanguageServer.features.haxe; +import haxe.display.Diagnostic; +import haxe.display.Display.DisplayMethods; import haxe.Json; import haxe.display.JsonModuleTypes; import haxe.ds.BalancedTree; @@ -13,10 +15,10 @@ import js.Node.setImmediate; import js.node.ChildProcess; import jsonrpc.CancellationToken; import languageServerProtocol.Types.Diagnostic; -import languageServerProtocol.Types.DiagnosticSeverity; import languageServerProtocol.Types.Location; using Lambda; +using haxeLanguageServer.features.haxe.DiagnosticsFeature; class DiagnosticsFeature { public static inline final SortImportsUsingsTitle = "Sort imports/usings"; @@ -45,12 +47,13 @@ class DiagnosticsFeature { function onRunGlobalDiagnostics(_) { final stopProgress = context.startProgress("Collecting Diagnostics"); - final onResolve = context.startTimer("@diagnostics"); + final onResolve = context.startTimer("display/diagnostics"); - context.callDisplay("global diagnostics", ["diagnostics"], null, null, function(result) { + context.callHaxeMethod(DisplayMethods.Diagnostics, {}, null, result -> { processDiagnosticsReply(null, onResolve, result); context.languageServerProtocol.sendNotification(LanguageServerMethods.DidRunRunGlobalDiagnostics); stopProgress(); + return null; }, function(error) { processErrorReply(null, error); stopProgress(); @@ -108,7 +111,7 @@ class DiagnosticsFeature { final diag = { range: {start: position, end: endPosition}, - severity: DiagnosticSeverity.Error, + severity: languageServerProtocol.Types.DiagnosticSeverity.Error, message: problemMatcher.matched(7) }; publishDiagnostic(targetUri, diag, error); @@ -122,7 +125,7 @@ class DiagnosticsFeature { } final diag = { range: {start: {line: 0, character: 0}, end: {line: 0, character: 0}}, - severity: DiagnosticSeverity.Error, + severity: languageServerProtocol.Types.DiagnosticSeverity.Error, message: problemMatcher.matched(2) }; publishDiagnostic(errorUri, diag, error); @@ -132,22 +135,11 @@ class DiagnosticsFeature { function publishDiagnostic(uri:DocumentUri, diag:Diagnostic, error:String) { context.languageServerProtocol.sendNotification(PublishDiagnosticsNotification.type, {uri: uri, diagnostics: [diag]}); final argumentsMap = diagnosticsArguments[uri] = new DiagnosticsMap(); - argumentsMap.set({code: CompilerError, range: diag.range}, error); + argumentsMap.set({code: DKCompilerError, range: diag.range}, error); } - function processDiagnosticsReply(uri:Null, onResolve:(result:Dynamic, ?debugInfo:String) -> Void, result:DisplayResult) { + function processDiagnosticsReply(uri:Null, onResolve:(result:Dynamic, ?debugInfo:String) -> Void, data:ReadOnlyArray<{ file : haxe.display.FsPath, diagnostics : ReadOnlyArray> }>) { clearDiagnosticsOnClient(errorUri); - final data:Array> = switch result { - case DResult(s): - try { - Json.parse(s); - } catch (e) { - trace("Error parsing diagnostics response: " + e); - return; - } - case DCancelled: - return; - } var count = 0; final sent = new Map(); for (data in data) { @@ -181,7 +173,7 @@ class DiagnosticsFeature { final diag:Diagnostic = { range: range, code: hxDiag.code, - severity: hxDiag.severity, + severity: cast hxDiag.severity, message: hxDiag.kind.getMessage(doc, hxDiag.args, range), data: {kind: hxDiag.kind}, relatedInformation: hxDiag.relatedInformation?.map(rel -> { @@ -192,7 +184,7 @@ class DiagnosticsFeature { message: convertIndentation(rel.message, rel.depth) }) } - if (kind == ReplaceableCode || kind == UnusedImport || diag.message.contains("has no effect") || kind == InactiveBlock) { + if (kind == ReplacableCode || kind == DKUnusedImport || diag.message.contains("has no effect") || kind == InactiveBlock) { diag.severity = Hint; diag.tags = [Unnecessary]; } @@ -229,23 +221,23 @@ class DiagnosticsFeature { return !PathHelper.matches(path, pathFilter); } - function filterRelevantDiagnostics(diagnostics:Array>):Array> { + function filterRelevantDiagnostics(diagnostics:ReadOnlyArray>):ReadOnlyArray> { // hide regular compiler errors while there's parser errors, they can be misleading final hasProblematicParserErrors = diagnostics.find(d -> switch (d.kind : Int) { - case ParserError: d.args != "Missing ;"; // don't be too strict + case DKParserError: d.args != "Missing ;"; // don't be too strict case _: false; }) != null; if (hasProblematicParserErrors) { diagnostics = diagnostics.filter(d -> switch (d.kind : Int) { - case CompilerError, UnresolvedIdentifier: false; + case DKCompilerError, DKUnresolvedIdentifier: false; case _: true; }); } // hide unused import warnings while there's compiler errors (to avoid false positives) - final hasCompilerErrors = diagnostics.find(d -> d.kind == cast CompilerError) != null; + final hasCompilerErrors = diagnostics.find(d -> d.kind == cast DKCompilerError) != null; if (hasCompilerErrors) { - diagnostics = diagnostics.filter(d -> d.kind != cast UnusedImport); + diagnostics = diagnostics.filter(d -> d.kind != cast DKUnusedImport); } // hide inactive blocks that are contained within other inactive blocks @@ -301,10 +293,11 @@ class DiagnosticsFeature { function invokePendingRequest(uri:DocumentUri, token:CancellationToken) { final doc:Null = context.documents.getHaxe(uri); if (doc != null) { - final onResolve = context.startTimer("@diagnostics"); - context.callDisplay("@diagnostics", [doc.uri.toFsPath() + "@0@diagnostics"], null, token, result -> { + final onResolve = context.startTimer("display/diagnostics"); + context.callHaxeMethod(DisplayMethods.Diagnostics, {file: doc.uri.toFsPath()}, token, result -> { pendingRequests.remove(uri); processDiagnosticsReply(uri, onResolve, result); + return null; }, error -> { pendingRequests.remove(uri); processErrorReply(uri, error); @@ -333,79 +326,21 @@ class DiagnosticsFeature { } } -enum abstract UnresolvedIdentifierSuggestion(Int) { - final Import; - final Typo; -} - -enum abstract MissingFieldCauseKind(String) { - final AbstractParent:MissingFieldCauseKind<{parent:JsonTypePathWithParams}>; - final ImplementedInterface:MissingFieldCauseKind<{parent:JsonTypePathWithParams}>; - final PropertyAccessor:MissingFieldCauseKind<{property:JsonClassField, isGetter:Bool}>; - final FieldAccess:MissingFieldCauseKind<{}>; - final FinalFields:MissingFieldCauseKind<{fields:Array}>; -} - -typedef MissingFieldCause = { - var kind:MissingFieldCauseKind; - var args:T; -} - -typedef MissingField = { - var field:JsonClassField; - var type:JsonType; - - /** - When implementing multiple interfaces, there can be field duplicates among them. This flag is only - true for the first such occurrence of a field, so that the "Implement all" code action doesn't end - up implementing the same field multiple times. - **/ - var unique:Bool; -} - -typedef MissingFieldDiagnostic = { - var fields:Array; - var cause:MissingFieldCause; -} - -typedef MissingFieldDiagnostics = { - var moduleType:JsonModuleType; - var moduleFile:String; - var entries:Array; -} - -typedef ReplaceableCode = { - var description:String; - var range:Range; - var ?newCode:String; -} - -enum abstract DiagnosticKind(Int) from Int to Int { - final UnusedImport:DiagnosticKind; - final UnresolvedIdentifier:DiagnosticKind>; - final CompilerError:DiagnosticKind; - final ReplaceableCode:DiagnosticKind; - final ParserError:DiagnosticKind; - final DeprecationWarning:DiagnosticKind; - final InactiveBlock:DiagnosticKind; - final MissingFields:DiagnosticKind; - - public inline function new(i:Int) { - this = i; - } +class DiagnosticKindHelper { + public static function make(code:Int) return (code:DiagnosticKind); - public function getMessage(doc:Null, args:T, range:Range) { - return switch (this : DiagnosticKind) { - case UnusedImport: "Unused import/using"; - case UnresolvedIdentifier: + public static function getMessage(dk:DiagnosticKind, doc:Null, args:T, range:Range) { + return switch dk { + case DKUnusedImport: "Unused import/using"; + case DKUnresolvedIdentifier: var message = 'Unknown identifier'; if (doc != null) { message += ' : ${doc.getText(range)}'; } message; - case CompilerError: args.trim(); - case ReplaceableCode: args.description; - case ParserError: args; + case DKCompilerError: args.trim(); + case ReplacableCode: args.description; + case DKParserError: args; case DeprecationWarning: args; case InactiveBlock: "Inactive conditional compilation block"; case MissingFields: diff --git a/src/haxeLanguageServer/features/haxe/codeAction/DiagnosticsCodeActionFeature.hx b/src/haxeLanguageServer/features/haxe/codeAction/DiagnosticsCodeActionFeature.hx index cb72f51d..6217562e 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/DiagnosticsCodeActionFeature.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/DiagnosticsCodeActionFeature.hx @@ -1,5 +1,6 @@ package haxeLanguageServer.features.haxe.codeAction; +import haxe.display.Diagnostic.DiagnosticKind; import haxeLanguageServer.features.haxe.DiagnosticsFeature; import haxeLanguageServer.features.haxe.codeAction.CodeActionFeature; import haxeLanguageServer.features.haxe.codeAction.diagnostics.AddTypeHintActions; @@ -39,13 +40,13 @@ class DiagnosticsCodeActionFeature implements CodeActionContributor { if (kind == null || !(kind is Int)) { // our codes are int, so we don't handle other stuff continue; } - final code = new DiagnosticKind(kind); + final code:DiagnosticKind = DiagnosticKindHelper.make(kind); actions = actions.concat(switch code { - case UnusedImport: UnusedImportActions.createUnusedImportActions(context, params, diagnostic); - case UnresolvedIdentifier: UnresolvedIdentifierActions.createUnresolvedIdentifierActions(context, params, diagnostic); - case CompilerError: CompilerErrorActions.createCompilerErrorActions(context, params, diagnostic); - case ReplaceableCode: ReplaceableCodeActions.createReplaceableCodeActions(context, params, diagnostic); - case ParserError: ParserErrorActions.createParserErrorActions(context, params, diagnostic); + case DKUnusedImport: UnusedImportActions.createUnusedImportActions(context, params, diagnostic); + case DKUnresolvedIdentifier: UnresolvedIdentifierActions.createUnresolvedIdentifierActions(context, params, diagnostic); + case DKCompilerError: CompilerErrorActions.createCompilerErrorActions(context, params, diagnostic); + case ReplacableCode: ReplaceableCodeActions.createReplaceableCodeActions(context, params, diagnostic); + case DKParserError: ParserErrorActions.createParserErrorActions(context, params, diagnostic); case MissingFields: MissingFieldsActions.createMissingFieldsActions(context, params, diagnostic); case _: []; }); diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/CompilerErrorActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/CompilerErrorActions.hx index d4dd340f..9bdd2105 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/CompilerErrorActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/CompilerErrorActions.hx @@ -8,7 +8,7 @@ class CompilerErrorActions { return []; } final actions:Array = []; - final arg = context.diagnostics.getArguments(params.textDocument.uri, CompilerError, diagnostic.range); + final arg = context.diagnostics.getArguments(params.textDocument.uri, DKCompilerError, diagnostic.range); if (arg == null) { return actions; } diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingFieldsActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingFieldsActions.hx index f6a6f2b1..4caf8d51 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingFieldsActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/MissingFieldsActions.hx @@ -1,5 +1,6 @@ package haxeLanguageServer.features.haxe.codeAction.diagnostics; +import haxe.display.Diagnostic.MissingFieldCause; import haxe.display.JsonModuleTypes; import haxe.ds.Option; import haxe.io.Path; diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/OrganizeImportActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/OrganizeImportActions.hx index 2226eaab..2749af25 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/OrganizeImportActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/OrganizeImportActions.hx @@ -1,6 +1,6 @@ package haxeLanguageServer.features.haxe.codeAction.diagnostics; -import haxeLanguageServer.features.haxe.DiagnosticsFeature.DiagnosticKind; +import haxe.display.Diagnostic.DiagnosticKind; import haxeLanguageServer.features.haxe.codeAction.CodeActionFeature; import haxeLanguageServer.features.haxe.codeAction.OrganizeImportsFeature; import haxeLanguageServer.helper.DocHelper; @@ -29,7 +29,7 @@ class OrganizeImportActions { final map = context.diagnostics.getArgumentsMap(uri); final removeUnusedFixes = if (map == null) [] else [ for (key in map.keys()) { - if (key.code == DiagnosticKind.UnusedImport) { + if (key.code == DiagnosticKind.DKUnusedImport) { WorkspaceEditHelper.removeText(DocHelper.untrimRange(doc, key.range)); } } diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ParserErrorActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ParserErrorActions.hx index 089d89bd..3e158c30 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ParserErrorActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ParserErrorActions.hx @@ -9,7 +9,7 @@ class ParserErrorActions { return []; } final actions:Array = []; - final arg = context.diagnostics.getArguments(params.textDocument.uri, ParserError, diagnostic.range); + final arg = context.diagnostics.getArguments(params.textDocument.uri, DKParserError, diagnostic.range); if (arg == null) { return actions; } diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ReplaceableCodeActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ReplaceableCodeActions.hx index fc6ebadc..266f6ec7 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ReplaceableCodeActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ReplaceableCodeActions.hx @@ -5,7 +5,7 @@ class ReplaceableCodeActions { if ((params.context.only != null) && (!params.context.only.contains(QuickFix))) { return []; } - final args = context.diagnostics.getArguments(params.textDocument.uri, ReplaceableCode, diagnostic.range); + final args = context.diagnostics.getArguments(params.textDocument.uri, ReplacableCode, diagnostic.range); final range = args!.range; final newText = args!.newCode; if (range == null) { diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnresolvedIdentifierActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnresolvedIdentifierActions.hx index a5bf4b8c..4f75801b 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnresolvedIdentifierActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UnresolvedIdentifierActions.hx @@ -9,16 +9,16 @@ class UnresolvedIdentifierActions { if ((params.context.only != null) && (!params.context.only.contains(QuickFix))) { return []; } - final args = context.diagnostics.getArguments(params.textDocument.uri, UnresolvedIdentifier, diagnostic.range); + final args = context.diagnostics.getArguments(params.textDocument.uri, DKUnresolvedIdentifier, diagnostic.range); if (args == null) { return []; } var actions:Array = []; - final importCount = args.count(a -> a.kind == Import); + final importCount = args.count(a -> a.kind == UISImport); for (arg in args) { actions = actions.concat(switch arg.kind { - case Import: createUnresolvedImportActions(context, params, diagnostic, arg, importCount); - case Typo: createTypoActions(context, params, diagnostic, arg); + case UISImport: createUnresolvedImportActions(context, params, diagnostic, arg, importCount); + case UISTypo: createTypoActions(context, params, diagnostic, arg); }); } return actions; diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UpdateSyntaxActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UpdateSyntaxActions.hx index c8a162db..f6cd5a8d 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UpdateSyntaxActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/UpdateSyntaxActions.hx @@ -1,6 +1,6 @@ package haxeLanguageServer.features.haxe.codeAction.diagnostics; -import haxeLanguageServer.features.haxe.DiagnosticsFeature.DiagnosticKind; +import haxe.display.Diagnostic.DiagnosticKind; import haxeLanguageServer.features.haxe.codeAction.CodeActionFeature; import haxeLanguageServer.helper.DocHelper; import haxeLanguageServer.helper.FormatterHelper; From a46f11032a0735af01418fc030b98fe452958c36 Mon Sep 17 00:00:00 2001 From: k Date: Tue, 2 Jul 2024 10:49:58 +0200 Subject: [PATCH 03/10] Only use json rpc if available --- .../features/haxe/DiagnosticsFeature.hx | 84 ++++++++++++++----- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx index a7e29a00..97c688ce 100644 --- a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx @@ -32,6 +32,9 @@ class DiagnosticsFeature { final pendingRequests:Map; final errorUri:DocumentUri; + final useJsonRpc:Bool; + final timerName:String; + var haxelibPath:Null; public function new(context:Context) { @@ -40,6 +43,9 @@ class DiagnosticsFeature { pendingRequests = new Map(); errorUri = new FsPath(Path.join([context.workspacePath.toString(), "Error"])).toUri(); + useJsonRpc = context.haxeServer.supports(DisplayMethods.Diagnostics); + timerName = useJsonRpc ? DisplayMethods.Diagnostics : "@diagnostics"; + ChildProcess.exec(context.config.haxelib.executable + " config", (error, stdout, stderr) -> haxelibPath = new FsPath(stdout.trim())); context.languageServerProtocol.onNotification(LanguageServerMethods.RunGlobalDiagnostics, onRunGlobalDiagnostics); @@ -47,17 +53,43 @@ class DiagnosticsFeature { function onRunGlobalDiagnostics(_) { final stopProgress = context.startProgress("Collecting Diagnostics"); - final onResolve = context.startTimer("display/diagnostics"); - - context.callHaxeMethod(DisplayMethods.Diagnostics, {}, null, result -> { - processDiagnosticsReply(null, onResolve, result); - context.languageServerProtocol.sendNotification(LanguageServerMethods.DidRunRunGlobalDiagnostics); - stopProgress(); - return null; - }, function(error) { - processErrorReply(null, error); - stopProgress(); - }); + final onResolve = context.startTimer(timerName); + + if (useJsonRpc) { + context.callHaxeMethod(DisplayMethods.Diagnostics, {}, null, result -> { + processDiagnosticsReply(null, onResolve, result); + context.languageServerProtocol.sendNotification(LanguageServerMethods.DidRunRunGlobalDiagnostics); + stopProgress(); + return null; + }, function(error) { + processErrorReply(null, error); + stopProgress(); + }); + } else { + context.callDisplay("global diagnostics", ["diagnostics"], null, null, function(result) { + final data = parseLegacyDiagnostics(result); + if (data == null) clearDiagnosticsOnClient(errorUri); + else processDiagnosticsReply(null, onResolve, data); + context.languageServerProtocol.sendNotification(LanguageServerMethods.DidRunRunGlobalDiagnostics); + stopProgress(); + }, function(error) { + processErrorReply(null, error); + stopProgress(); + }); + } + } + + function parseLegacyDiagnostics(result:DisplayResult):Null> }>> { + return switch result { + case DResult(s): + try { + Json.parse(s); + } catch (e) { + trace("Error parsing diagnostics response: " + e); + null; + } + case DCancelled: null; + }; } function processErrorReply(uri:Null, error:String) { @@ -293,15 +325,27 @@ class DiagnosticsFeature { function invokePendingRequest(uri:DocumentUri, token:CancellationToken) { final doc:Null = context.documents.getHaxe(uri); if (doc != null) { - final onResolve = context.startTimer("display/diagnostics"); - context.callHaxeMethod(DisplayMethods.Diagnostics, {file: doc.uri.toFsPath()}, token, result -> { - pendingRequests.remove(uri); - processDiagnosticsReply(uri, onResolve, result); - return null; - }, error -> { - pendingRequests.remove(uri); - processErrorReply(uri, error); - }); + final onResolve = context.startTimer(timerName); + if (useJsonRpc) { + context.callHaxeMethod(DisplayMethods.Diagnostics, {file: doc.uri.toFsPath()}, token, result -> { + pendingRequests.remove(uri); + processDiagnosticsReply(uri, onResolve, result); + return null; + }, error -> { + pendingRequests.remove(uri); + processErrorReply(uri, error); + }); + } else { + context.callDisplay("@diagnostics", [doc.uri.toFsPath() + "@0@diagnostics"], null, token, result -> { + pendingRequests.remove(uri); + final data = parseLegacyDiagnostics(result); + if (data == null) clearDiagnosticsOnClient(errorUri); + else processDiagnosticsReply(null, onResolve, data); + }, error -> { + pendingRequests.remove(uri); + processErrorReply(uri, error); + }); + } } else { pendingRequests.remove(uri); } From f833ead6dd13d1d00964dbe9fd0492e5948fbd3a Mon Sep 17 00:00:00 2001 From: k Date: Tue, 2 Jul 2024 11:02:13 +0200 Subject: [PATCH 04/10] Run formatter --- .../features/haxe/DiagnosticsFeature.hx | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx index 97c688ce..964fda8b 100644 --- a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx @@ -68,8 +68,10 @@ class DiagnosticsFeature { } else { context.callDisplay("global diagnostics", ["diagnostics"], null, null, function(result) { final data = parseLegacyDiagnostics(result); - if (data == null) clearDiagnosticsOnClient(errorUri); - else processDiagnosticsReply(null, onResolve, data); + if (data == null) + clearDiagnosticsOnClient(errorUri); + else + processDiagnosticsReply(null, onResolve, data); context.languageServerProtocol.sendNotification(LanguageServerMethods.DidRunRunGlobalDiagnostics); stopProgress(); }, function(error) { @@ -79,7 +81,7 @@ class DiagnosticsFeature { } } - function parseLegacyDiagnostics(result:DisplayResult):Null> }>> { + function parseLegacyDiagnostics(result:DisplayResult):Null>}>> { return switch result { case DResult(s): try { @@ -170,7 +172,8 @@ class DiagnosticsFeature { argumentsMap.set({code: DKCompilerError, range: diag.range}, error); } - function processDiagnosticsReply(uri:Null, onResolve:(result:Dynamic, ?debugInfo:String) -> Void, data:ReadOnlyArray<{ file : haxe.display.FsPath, diagnostics : ReadOnlyArray> }>) { + function processDiagnosticsReply(uri:Null, onResolve:(result:Dynamic, ?debugInfo:String) -> Void, + data:ReadOnlyArray<{file:haxe.display.FsPath, diagnostics:ReadOnlyArray>}>) { clearDiagnosticsOnClient(errorUri); var count = 0; final sent = new Map(); @@ -339,8 +342,10 @@ class DiagnosticsFeature { context.callDisplay("@diagnostics", [doc.uri.toFsPath() + "@0@diagnostics"], null, token, result -> { pendingRequests.remove(uri); final data = parseLegacyDiagnostics(result); - if (data == null) clearDiagnosticsOnClient(errorUri); - else processDiagnosticsReply(null, onResolve, data); + if (data == null) + clearDiagnosticsOnClient(errorUri); + else + processDiagnosticsReply(null, onResolve, data); }, error -> { pendingRequests.remove(uri); processErrorReply(uri, error); @@ -371,7 +376,8 @@ class DiagnosticsFeature { } class DiagnosticKindHelper { - public static function make(code:Int) return (code:DiagnosticKind); + public static function make(code:Int) + return (code : DiagnosticKind); public static function getMessage(dk:DiagnosticKind, doc:Null, args:T, range:Range) { return switch dk { From ec0646078759bbddbf731e9a532aff70f64dcb41 Mon Sep 17 00:00:00 2001 From: k Date: Tue, 2 Jul 2024 11:02:24 +0200 Subject: [PATCH 05/10] Update Haxe version --- .haxerc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.haxerc b/.haxerc index b6edbfab..0ea2bfb4 100644 --- a/.haxerc +++ b/.haxerc @@ -1,4 +1,4 @@ { - "version": "569e52e", + "version": "15abdcc", "resolveLibs": "scoped" -} \ No newline at end of file +} From 1dd581f531a4c94753d9fb6cade3c43fe10e7bf6 Mon Sep 17 00:00:00 2001 From: k Date: Tue, 2 Jul 2024 11:35:53 +0200 Subject: [PATCH 06/10] Cleanup ReplaceableCode --- src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx | 4 ++-- .../features/haxe/codeAction/DiagnosticsCodeActionFeature.hx | 2 +- .../haxe/codeAction/diagnostics/ReplaceableCodeActions.hx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx index 964fda8b..f2ddab78 100644 --- a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx @@ -219,7 +219,7 @@ class DiagnosticsFeature { message: convertIndentation(rel.message, rel.depth) }) } - if (kind == ReplacableCode || kind == DKUnusedImport || diag.message.contains("has no effect") || kind == InactiveBlock) { + if (kind == ReplaceableCode || kind == DKUnusedImport || diag.message.contains("has no effect") || kind == InactiveBlock) { diag.severity = Hint; diag.tags = [Unnecessary]; } @@ -389,7 +389,7 @@ class DiagnosticKindHelper { } message; case DKCompilerError: args.trim(); - case ReplacableCode: args.description; + case ReplaceableCode: args.description; case DKParserError: args; case DeprecationWarning: args; case InactiveBlock: "Inactive conditional compilation block"; diff --git a/src/haxeLanguageServer/features/haxe/codeAction/DiagnosticsCodeActionFeature.hx b/src/haxeLanguageServer/features/haxe/codeAction/DiagnosticsCodeActionFeature.hx index 6217562e..e39dcb2f 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/DiagnosticsCodeActionFeature.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/DiagnosticsCodeActionFeature.hx @@ -45,7 +45,7 @@ class DiagnosticsCodeActionFeature implements CodeActionContributor { case DKUnusedImport: UnusedImportActions.createUnusedImportActions(context, params, diagnostic); case DKUnresolvedIdentifier: UnresolvedIdentifierActions.createUnresolvedIdentifierActions(context, params, diagnostic); case DKCompilerError: CompilerErrorActions.createCompilerErrorActions(context, params, diagnostic); - case ReplacableCode: ReplaceableCodeActions.createReplaceableCodeActions(context, params, diagnostic); + case ReplaceableCode: ReplaceableCodeActions.createReplaceableCodeActions(context, params, diagnostic); case DKParserError: ParserErrorActions.createParserErrorActions(context, params, diagnostic); case MissingFields: MissingFieldsActions.createMissingFieldsActions(context, params, diagnostic); case _: []; diff --git a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ReplaceableCodeActions.hx b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ReplaceableCodeActions.hx index 266f6ec7..fc6ebadc 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ReplaceableCodeActions.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/diagnostics/ReplaceableCodeActions.hx @@ -5,7 +5,7 @@ class ReplaceableCodeActions { if ((params.context.only != null) && (!params.context.only.contains(QuickFix))) { return []; } - final args = context.diagnostics.getArguments(params.textDocument.uri, ReplacableCode, diagnostic.range); + final args = context.diagnostics.getArguments(params.textDocument.uri, ReplaceableCode, diagnostic.range); final range = args!.range; final newText = args!.newCode; if (range == null) { From 88832c540e8cad5fd132c8458b3e11b8a7620a0c Mon Sep 17 00:00:00 2001 From: k Date: Tue, 2 Jul 2024 12:43:13 +0200 Subject: [PATCH 07/10] [tests] Map order is unreliable --- .../features/haxe/codeAction/OrganizeImportsFeature.hx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx b/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx index 615a5278..bc2da86f 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx @@ -187,9 +187,14 @@ class OrganizeImportsFeature { static function organizeImportGroups(doc:HxTextDocument, context:Context, importGroups:Map):Array { var edits:Array = []; + var last = importGroups.get(-1); + importGroups.remove(-1); + for (group in importGroups) { edits = edits.concat(organizeImportGroup(doc, context, group)); } + + if (last != null) edits = edits.concat(organizeImportGroup(doc, context, last)); return edits; } From d703b943d19ceeff248bde4b1148494403483b9c Mon Sep 17 00:00:00 2001 From: k Date: Tue, 2 Jul 2024 12:43:45 +0200 Subject: [PATCH 08/10] Run formatter --- .../features/haxe/codeAction/OrganizeImportsFeature.hx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx b/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx index bc2da86f..6ee31d17 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx @@ -194,7 +194,8 @@ class OrganizeImportsFeature { edits = edits.concat(organizeImportGroup(doc, context, group)); } - if (last != null) edits = edits.concat(organizeImportGroup(doc, context, last)); + if (last != null) + edits = edits.concat(organizeImportGroup(doc, context, last)); return edits; } From fa33a1deb11329288cee9084b377543054d0a924 Mon Sep 17 00:00:00 2001 From: k Date: Tue, 2 Jul 2024 15:38:00 +0200 Subject: [PATCH 09/10] [Diagnostics] Run json rpc diagnostics for all (Haxe) open files Unless disabled by config --- src/haxeLanguageServer/Configuration.hx | 2 ++ .../features/haxe/DiagnosticsFeature.hx | 32 +++++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/haxeLanguageServer/Configuration.hx b/src/haxeLanguageServer/Configuration.hx index ce9b0fad..f28026c9 100644 --- a/src/haxeLanguageServer/Configuration.hx +++ b/src/haxeLanguageServer/Configuration.hx @@ -88,6 +88,7 @@ typedef UserConfig = { var enableDiagnostics:Bool; var enableServerView:Bool; var enableSignatureHelpDocumentation:Bool; + var diagnosticsForAllOpenFiles:Bool; var diagnosticsPathFilter:String; var displayHost:String; var displayPort:EitherType; @@ -156,6 +157,7 @@ class Configuration { enableDiagnostics: true, enableServerView: false, enableSignatureHelpDocumentation: true, + diagnosticsForAllOpenFiles: true, diagnosticsPathFilter: "${workspaceRoot}", displayHost: null, displayPort: null, diff --git a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx index f2ddab78..a8c83226 100644 --- a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx @@ -1,8 +1,9 @@ package haxeLanguageServer.features.haxe; +import haxe.Json; import haxe.display.Diagnostic; +import haxe.display.Display.DiagnosticsParams; import haxe.display.Display.DisplayMethods; -import haxe.Json; import haxe.display.JsonModuleTypes; import haxe.ds.BalancedTree; import haxe.io.Path; @@ -327,10 +328,23 @@ class DiagnosticsFeature { function invokePendingRequest(uri:DocumentUri, token:CancellationToken) { final doc:Null = context.documents.getHaxe(uri); + if (doc != null) { final onResolve = context.startTimer(timerName); if (useJsonRpc) { - context.callHaxeMethod(DisplayMethods.Diagnostics, {file: doc.uri.toFsPath()}, token, result -> { + var params:DiagnosticsParams = {fileContents: []}; + + if (context.config.user.diagnosticsForAllOpenFiles) { + context.documents.iter(function(doc) { + final path = doc.uri.toFsPath(); + if (doc.languageId == "haxe" && !isPathFiltered(path)) + params.fileContents.sure().push({file: path, contents: null}); + }); + } else { + params.file = doc.uri.toFsPath(); + } + + context.callHaxeMethod(DisplayMethods.Diagnostics, params, token, result -> { pendingRequests.remove(uri); processDiagnosticsReply(uri, onResolve, result); return null; @@ -357,10 +371,16 @@ class DiagnosticsFeature { } function cancelPendingRequest(uri:DocumentUri) { - var tokenSource = pendingRequests[uri]; - if (tokenSource != null) { - pendingRequests.remove(uri); - tokenSource.cancel(); + if (useJsonRpc && context.config.user.diagnosticsForAllOpenFiles) { + for (tokenSource in pendingRequests) + tokenSource.cancel(); + pendingRequests.clear(); + } else { + var tokenSource = pendingRequests[uri]; + if (tokenSource != null) { + pendingRequests.remove(uri); + tokenSource.cancel(); + } } } From 7ad2553fcec0d5f2cbd807de81772ee5df209a17 Mon Sep 17 00:00:00 2001 From: k Date: Wed, 3 Jul 2024 06:57:25 +0200 Subject: [PATCH 10/10] Curlies --- .../features/haxe/DiagnosticsFeature.hx | 16 ++++++++++------ .../haxe/codeAction/OrganizeImportsFeature.hx | 4 +++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx index a8c83226..71430b6b 100644 --- a/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/DiagnosticsFeature.hx @@ -69,10 +69,11 @@ class DiagnosticsFeature { } else { context.callDisplay("global diagnostics", ["diagnostics"], null, null, function(result) { final data = parseLegacyDiagnostics(result); - if (data == null) + if (data == null) { clearDiagnosticsOnClient(errorUri); - else + } else { processDiagnosticsReply(null, onResolve, data); + } context.languageServerProtocol.sendNotification(LanguageServerMethods.DidRunRunGlobalDiagnostics); stopProgress(); }, function(error) { @@ -337,8 +338,9 @@ class DiagnosticsFeature { if (context.config.user.diagnosticsForAllOpenFiles) { context.documents.iter(function(doc) { final path = doc.uri.toFsPath(); - if (doc.languageId == "haxe" && !isPathFiltered(path)) + if (doc.languageId == "haxe" && !isPathFiltered(path)) { params.fileContents.sure().push({file: path, contents: null}); + } }); } else { params.file = doc.uri.toFsPath(); @@ -356,10 +358,11 @@ class DiagnosticsFeature { context.callDisplay("@diagnostics", [doc.uri.toFsPath() + "@0@diagnostics"], null, token, result -> { pendingRequests.remove(uri); final data = parseLegacyDiagnostics(result); - if (data == null) + if (data == null) { clearDiagnosticsOnClient(errorUri); - else + } else { processDiagnosticsReply(null, onResolve, data); + } }, error -> { pendingRequests.remove(uri); processErrorReply(uri, error); @@ -372,8 +375,9 @@ class DiagnosticsFeature { function cancelPendingRequest(uri:DocumentUri) { if (useJsonRpc && context.config.user.diagnosticsForAllOpenFiles) { - for (tokenSource in pendingRequests) + for (tokenSource in pendingRequests) { tokenSource.cancel(); + } pendingRequests.clear(); } else { var tokenSource = pendingRequests[uri]; diff --git a/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx b/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx index 6ee31d17..dc96d974 100644 --- a/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx +++ b/src/haxeLanguageServer/features/haxe/codeAction/OrganizeImportsFeature.hx @@ -194,8 +194,10 @@ class OrganizeImportsFeature { edits = edits.concat(organizeImportGroup(doc, context, group)); } - if (last != null) + if (last != null) { edits = edits.concat(organizeImportGroup(doc, context, last)); + } + return edits; }