From 8847f4101613b4cf9adea99617edb0703663b6e5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Oct 2025 19:47:35 +0000 Subject: [PATCH 01/15] Initial plan From 265075590a5d8d16340386d21259d7d034d89f06 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 26 Oct 2025 20:04:04 +0000 Subject: [PATCH 02/15] Add support for textDocument/diagnostic (LSP 3.17) - Implement standard diagnostic() method in BSLTextDocumentService - Configure DiagnosticRegistrationOptions in server capabilities - Add tests for the new diagnostic endpoint - All existing tests pass Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../bsl/languageserver/BSLLanguageServer.java | 10 +++++++ .../BSLTextDocumentService.java | 22 ++++++++++++++ .../BSLTextDocumentServiceTest.java | 30 +++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java index 8764d3f1df1..43f64bd0782 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java @@ -38,6 +38,7 @@ import org.eclipse.lsp4j.CodeLensOptions; import org.eclipse.lsp4j.ColorProviderOptions; import org.eclipse.lsp4j.DefinitionOptions; +import org.eclipse.lsp4j.DiagnosticRegistrationOptions; import org.eclipse.lsp4j.DocumentFormattingOptions; import org.eclipse.lsp4j.DocumentLinkOptions; import org.eclipse.lsp4j.DocumentRangeFormattingOptions; @@ -130,6 +131,7 @@ public CompletableFuture initialize(InitializeParams params) { capabilities.setRenameProvider(getRenameProvider(params)); capabilities.setInlayHintProvider(getInlayHintProvider()); capabilities.setExecuteCommandProvider(getExecuteCommandProvider()); + capabilities.setDiagnosticProvider(getDiagnosticProvider()); var result = new InitializeResult(capabilities, serverInfo); @@ -337,6 +339,14 @@ private static InlayHintRegistrationOptions getInlayHintProvider() { return inlayHintOptions; } + private static DiagnosticRegistrationOptions getDiagnosticProvider() { + var diagnosticOptions = new DiagnosticRegistrationOptions(); + diagnosticOptions.setWorkDoneProgress(Boolean.FALSE); + diagnosticOptions.setInterFileDependencies(Boolean.FALSE); + diagnosticOptions.setWorkspaceDiagnostics(Boolean.FALSE); + return diagnosticOptions; + } + private ExecuteCommandOptions getExecuteCommandProvider() { var executeCommandOptions = new ExecuteCommandOptions(); executeCommandOptions.setCommands(commandProvider.getCommandIds()); diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 223d3b4a6bb..6efe75a1b6d 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -66,6 +66,8 @@ import org.eclipse.lsp4j.DidOpenTextDocumentParams; import org.eclipse.lsp4j.DidSaveTextDocumentParams; import org.eclipse.lsp4j.DocumentColorParams; +import org.eclipse.lsp4j.DocumentDiagnosticParams; +import org.eclipse.lsp4j.DocumentDiagnosticReport; import org.eclipse.lsp4j.DocumentFormattingParams; import org.eclipse.lsp4j.DocumentLink; import org.eclipse.lsp4j.DocumentLinkParams; @@ -85,6 +87,7 @@ import org.eclipse.lsp4j.PrepareRenameResult; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.RelatedFullDocumentDiagnosticReport; import org.eclipse.lsp4j.RenameParams; import org.eclipse.lsp4j.SelectionRange; import org.eclipse.lsp4j.SelectionRangeParams; @@ -466,6 +469,25 @@ public CompletableFuture diagnostics(DiagnosticParams params) { }); } + @Override + public CompletableFuture diagnostic(DocumentDiagnosticParams params) { + var documentContext = context.getDocument(params.getTextDocument().getUri()); + if (documentContext == null) { + return CompletableFuture.completedFuture( + new DocumentDiagnosticReport(new RelatedFullDocumentDiagnosticReport(Collections.emptyList())) + ); + } + + return CompletableFuture.supplyAsync( + () -> { + var diagnostics = documentContext.getDiagnostics(); + var report = new RelatedFullDocumentDiagnosticReport(diagnostics); + return new DocumentDiagnosticReport(report); + }, + executorService + ); + } + @Override public CompletableFuture> prepareRename(PrepareRenameParams params) { var documentContext = context.getDocument(params.getTextDocument().getUri()); diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java index 17d3381bca7..649251629a5 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentServiceTest.java @@ -29,6 +29,7 @@ import org.eclipse.lsp4j.DidCloseTextDocumentParams; import org.eclipse.lsp4j.DidOpenTextDocumentParams; import org.eclipse.lsp4j.DidSaveTextDocumentParams; +import org.eclipse.lsp4j.DocumentDiagnosticParams; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.PrepareRenameParams; import org.eclipse.lsp4j.RenameParams; @@ -140,6 +141,35 @@ void testDiagnosticsKnownFileFilteredRange() throws ExecutionException, Interrup assertThat(diagnostics.getDiagnostics()).hasSize(2); } + @Test + void testStandardDiagnosticUnknownFile() throws ExecutionException, InterruptedException { + // when + var params = new DocumentDiagnosticParams(getTextDocumentIdentifier()); + var diagnosticReport = textDocumentService.diagnostic(params).get(); + + // then + assertThat(diagnosticReport).isNotNull(); + assertThat(diagnosticReport.getLeft()).isNotNull(); + assertThat(diagnosticReport.getLeft().getItems()).isEmpty(); + } + + @Test + void testStandardDiagnosticKnownFile() throws ExecutionException, InterruptedException, IOException { + // given + var textDocumentItem = getTextDocumentItem(); + var didOpenParams = new DidOpenTextDocumentParams(textDocumentItem); + textDocumentService.didOpen(didOpenParams); + + // when + var params = new DocumentDiagnosticParams(getTextDocumentIdentifier()); + var diagnosticReport = textDocumentService.diagnostic(params).get(); + + // then + assertThat(diagnosticReport).isNotNull(); + assertThat(diagnosticReport.getLeft()).isNotNull(); + assertThat(diagnosticReport.getLeft().getItems()).isNotEmpty(); + } + @Test void testRename() throws ExecutionException, InterruptedException, IOException { var params = new RenameParams(); From 8bce6b26866e4638dd57837590d9eb9e91cbe005 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 02:50:50 +0000 Subject: [PATCH 03/15] Refactor diagnostic implementation based on feedback - Move diagnostic() logic to DiagnosticProvider - Add client capabilities check to avoid publishDiagnostics when client supports pull model - Add getDiagnosticReport() method in DiagnosticProvider - Simplify BSLTextDocumentService to delegate to DiagnosticProvider Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../BSLTextDocumentService.java | 14 +---- .../providers/DiagnosticProvider.java | 53 ++++++++++++++++++- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 6efe75a1b6d..361f9a2279b 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -87,7 +87,6 @@ import org.eclipse.lsp4j.PrepareRenameResult; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.ReferenceParams; -import org.eclipse.lsp4j.RelatedFullDocumentDiagnosticReport; import org.eclipse.lsp4j.RenameParams; import org.eclipse.lsp4j.SelectionRange; import org.eclipse.lsp4j.SelectionRangeParams; @@ -472,18 +471,9 @@ public CompletableFuture diagnostics(DiagnosticParams params) { @Override public CompletableFuture diagnostic(DocumentDiagnosticParams params) { var documentContext = context.getDocument(params.getTextDocument().getUri()); - if (documentContext == null) { - return CompletableFuture.completedFuture( - new DocumentDiagnosticReport(new RelatedFullDocumentDiagnosticReport(Collections.emptyList())) - ); - } - + return CompletableFuture.supplyAsync( - () -> { - var diagnostics = documentContext.getDiagnostics(); - var report = new RelatedFullDocumentDiagnosticReport(diagnostics); - return new DocumentDiagnosticReport(report); - }, + () -> diagnosticProvider.getDiagnosticReport(documentContext), executorService ); } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java index cd46d1529d0..3a8322cb7e7 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java @@ -21,11 +21,14 @@ */ package com.github._1c_syntax.bsl.languageserver.providers; +import com.github._1c_syntax.bsl.languageserver.ClientCapabilitiesHolder; import com.github._1c_syntax.bsl.languageserver.LanguageClientHolder; import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; import lombok.RequiredArgsConstructor; import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DocumentDiagnosticReport; import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.RelatedFullDocumentDiagnosticReport; import org.springframework.stereotype.Component; import java.util.Collections; @@ -33,11 +36,13 @@ import java.util.function.Supplier; /** - * Провайдер для публикации диагностических сообщений. + * Провайдер для диагностических сообщений. *

- * Отвечает за публикацию диагностик с использованием {@code textDocument/publishDiagnostics}. + * Отвечает за публикацию диагностик с использованием {@code textDocument/publishDiagnostics} + * и предоставление диагностик по запросу {@code textDocument/diagnostic}. * * @see PublishDiagnostics Notification specification + * @see Diagnostic Pull Request specification */ @Component @RequiredArgsConstructor @@ -46,16 +51,48 @@ public final class DiagnosticProvider { public static final String SOURCE = "bsl-language-server"; private final LanguageClientHolder clientHolder; + private final ClientCapabilitiesHolder clientCapabilitiesHolder; /** * Вычислить и опубликовать диагностики для документа. + *

+ * Если клиент поддерживает pull-модель диагностик, публикация не выполняется. * * @param documentContext Контекст документа */ public void computeAndPublishDiagnostics(DocumentContext documentContext) { + computeAndPublishDiagnostics(documentContext, false); + } + + /** + * Вычислить и опубликовать диагностики для документа. + * + * @param documentContext Контекст документа + * @param force Принудительная публикация диагностик (игнорирует поддержку pull-модели клиентом) + */ + public void computeAndPublishDiagnostics(DocumentContext documentContext, boolean force) { + if (!force && clientSupportsPullDiagnostics()) { + return; + } publishDiagnostics(documentContext, documentContext::getDiagnostics); } + /** + * Получить диагностики для документа (pull-модель). + * + * @param documentContext Контекст документа + * @return Отчет с диагностиками + */ + public DocumentDiagnosticReport getDiagnosticReport(DocumentContext documentContext) { + if (documentContext == null) { + return new DocumentDiagnosticReport(new RelatedFullDocumentDiagnosticReport(Collections.emptyList())); + } + + var diagnostics = documentContext.getDiagnostics(); + var report = new RelatedFullDocumentDiagnosticReport(diagnostics); + return new DocumentDiagnosticReport(report); + } + /** * Опубликовать пустой список диагностик для документа. * @@ -65,6 +102,18 @@ public void publishEmptyDiagnosticList(DocumentContext documentContext) { publishDiagnostics(documentContext, Collections::emptyList); } + /** + * Проверить, поддерживает ли клиент pull-модель диагностик. + * + * @return true, если клиент поддерживает pull-модель диагностик + */ + private boolean clientSupportsPullDiagnostics() { + return clientCapabilitiesHolder.getCapabilities() + .map(capabilities -> capabilities.getTextDocument()) + .map(textDocument -> textDocument.getDiagnostic()) + .isPresent(); + } + private void publishDiagnostics(DocumentContext documentContext, Supplier> diagnostics) { clientHolder.execIfConnected(languageClient -> languageClient.publishDiagnostics( From 712373ba22dcb6313f6297d5dba84eeafe186603 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 03:03:56 +0000 Subject: [PATCH 04/15] Set interFileDependencies to true for diagnostic provider BSL code has inter-file dependencies where changes in one module can affect diagnostics in other modules. Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java index 43f64bd0782..39d90226e67 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLLanguageServer.java @@ -342,7 +342,7 @@ private static InlayHintRegistrationOptions getInlayHintProvider() { private static DiagnosticRegistrationOptions getDiagnosticProvider() { var diagnosticOptions = new DiagnosticRegistrationOptions(); diagnosticOptions.setWorkDoneProgress(Boolean.FALSE); - diagnosticOptions.setInterFileDependencies(Boolean.FALSE); + diagnosticOptions.setInterFileDependencies(Boolean.TRUE); diagnosticOptions.setWorkspaceDiagnostics(Boolean.FALSE); return diagnosticOptions; } From 9ae7be999f166b32f5b80bbeaf00c829ffb7dd68 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 06:03:31 +0000 Subject: [PATCH 05/15] Move pull diagnostics check to BSLTextDocumentService Moved client capability check from DiagnosticProvider to BSLTextDocumentService's validate() method to maintain clear separation of responsibilities. DiagnosticProvider now focuses solely on publishing and providing diagnostics, while BSLTextDocumentService handles client capability checks. Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../BSLTextDocumentService.java | 11 +++++++ .../providers/DiagnosticProvider.java | 29 ------------------- 2 files changed, 11 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 361f9a2279b..ed9a09b280c 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -134,6 +134,7 @@ public class BSLTextDocumentService implements TextDocumentService, ProtocolExte private final ColorProvider colorProvider; private final RenameProvider renameProvider; private final InlayHintProvider inlayHintProvider; + private final ClientCapabilitiesHolder clientCapabilitiesHolder; private final ExecutorService executorService = Executors.newCachedThreadPool(new CustomizableThreadFactory("text-document-service-")); @@ -509,7 +510,17 @@ public void reset() { } private void validate(DocumentContext documentContext) { + if (clientSupportsPullDiagnostics()) { + return; + } diagnosticProvider.computeAndPublishDiagnostics(documentContext); } + private boolean clientSupportsPullDiagnostics() { + return clientCapabilitiesHolder.getCapabilities() + .map(capabilities -> capabilities.getTextDocument()) + .map(textDocument -> textDocument.getDiagnostic()) + .isPresent(); + } + } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java index 3a8322cb7e7..f8df450b716 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java @@ -21,7 +21,6 @@ */ package com.github._1c_syntax.bsl.languageserver.providers; -import com.github._1c_syntax.bsl.languageserver.ClientCapabilitiesHolder; import com.github._1c_syntax.bsl.languageserver.LanguageClientHolder; import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; import lombok.RequiredArgsConstructor; @@ -51,29 +50,13 @@ public final class DiagnosticProvider { public static final String SOURCE = "bsl-language-server"; private final LanguageClientHolder clientHolder; - private final ClientCapabilitiesHolder clientCapabilitiesHolder; /** * Вычислить и опубликовать диагностики для документа. - *

- * Если клиент поддерживает pull-модель диагностик, публикация не выполняется. * * @param documentContext Контекст документа */ public void computeAndPublishDiagnostics(DocumentContext documentContext) { - computeAndPublishDiagnostics(documentContext, false); - } - - /** - * Вычислить и опубликовать диагностики для документа. - * - * @param documentContext Контекст документа - * @param force Принудительная публикация диагностик (игнорирует поддержку pull-модели клиентом) - */ - public void computeAndPublishDiagnostics(DocumentContext documentContext, boolean force) { - if (!force && clientSupportsPullDiagnostics()) { - return; - } publishDiagnostics(documentContext, documentContext::getDiagnostics); } @@ -102,18 +85,6 @@ public void publishEmptyDiagnosticList(DocumentContext documentContext) { publishDiagnostics(documentContext, Collections::emptyList); } - /** - * Проверить, поддерживает ли клиент pull-модель диагностик. - * - * @return true, если клиент поддерживает pull-модель диагностик - */ - private boolean clientSupportsPullDiagnostics() { - return clientCapabilitiesHolder.getCapabilities() - .map(capabilities -> capabilities.getTextDocument()) - .map(textDocument -> textDocument.getDiagnostic()) - .isPresent(); - } - private void publishDiagnostics(DocumentContext documentContext, Supplier> diagnostics) { clientHolder.execIfConnected(languageClient -> languageClient.publishDiagnostics( From 5d80665a3a1852d27de3f7d21867c28897c170ed Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 06:10:27 +0000 Subject: [PATCH 06/15] Rename getDiagnosticReport to getDiagnostic Renamed method for better naming consistency with LSP protocol. Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../_1c_syntax/bsl/languageserver/BSLTextDocumentService.java | 2 +- .../bsl/languageserver/providers/DiagnosticProvider.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index ed9a09b280c..96625a84cab 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -474,7 +474,7 @@ public CompletableFuture diagnostic(DocumentDiagnostic var documentContext = context.getDocument(params.getTextDocument().getUri()); return CompletableFuture.supplyAsync( - () -> diagnosticProvider.getDiagnosticReport(documentContext), + () -> diagnosticProvider.getDiagnostic(documentContext), executorService ); } diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java index f8df450b716..a1dcbc57dda 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java @@ -66,7 +66,7 @@ public void computeAndPublishDiagnostics(DocumentContext documentContext) { * @param documentContext Контекст документа * @return Отчет с диагностиками */ - public DocumentDiagnosticReport getDiagnosticReport(DocumentContext documentContext) { + public DocumentDiagnosticReport getDiagnostic(DocumentContext documentContext) { if (documentContext == null) { return new DocumentDiagnosticReport(new RelatedFullDocumentDiagnosticReport(Collections.emptyList())); } From 63c03f2e1385852bf94c206dba9f079795087339 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 06:19:42 +0000 Subject: [PATCH 07/15] Move null check to BSLTextDocumentService Moved null check for documentContext from DiagnosticProvider to BSLTextDocumentService.diagnostic() method, following the same pattern as other methods in the service. DiagnosticProvider now expects a valid DocumentContext. Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../bsl/languageserver/BSLTextDocumentService.java | 6 ++++++ .../bsl/languageserver/providers/DiagnosticProvider.java | 4 ---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 96625a84cab..8dae1c6f9ca 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -87,6 +87,7 @@ import org.eclipse.lsp4j.PrepareRenameResult; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.RelatedFullDocumentDiagnosticReport; import org.eclipse.lsp4j.RenameParams; import org.eclipse.lsp4j.SelectionRange; import org.eclipse.lsp4j.SelectionRangeParams; @@ -472,6 +473,11 @@ public CompletableFuture diagnostics(DiagnosticParams params) { @Override public CompletableFuture diagnostic(DocumentDiagnosticParams params) { var documentContext = context.getDocument(params.getTextDocument().getUri()); + if (documentContext == null) { + return CompletableFuture.completedFuture( + new DocumentDiagnosticReport(new RelatedFullDocumentDiagnosticReport(Collections.emptyList())) + ); + } return CompletableFuture.supplyAsync( () -> diagnosticProvider.getDiagnostic(documentContext), diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java index a1dcbc57dda..c19a3a10666 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java @@ -67,10 +67,6 @@ public void computeAndPublishDiagnostics(DocumentContext documentContext) { * @return Отчет с диагностиками */ public DocumentDiagnosticReport getDiagnostic(DocumentContext documentContext) { - if (documentContext == null) { - return new DocumentDiagnosticReport(new RelatedFullDocumentDiagnosticReport(Collections.emptyList())); - } - var diagnostics = documentContext.getDiagnostics(); var report = new RelatedFullDocumentDiagnosticReport(diagnostics); return new DocumentDiagnosticReport(report); From a236b9e0d372d010699bc0fddc70c1f8e11c72a4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 06:27:33 +0000 Subject: [PATCH 08/15] Cache pull diagnostics support flag Added caching for clientSupportsPullDiagnostics flag to avoid repeated capability checks on every document validation. Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../bsl/languageserver/BSLTextDocumentService.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 8dae1c6f9ca..9157ecbbfe4 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -138,6 +138,8 @@ public class BSLTextDocumentService implements TextDocumentService, ProtocolExte private final ClientCapabilitiesHolder clientCapabilitiesHolder; private final ExecutorService executorService = Executors.newCachedThreadPool(new CustomizableThreadFactory("text-document-service-")); + + private Boolean clientSupportsPullDiagnostics; @PreDestroy private void onDestroy() { @@ -523,10 +525,13 @@ private void validate(DocumentContext documentContext) { } private boolean clientSupportsPullDiagnostics() { - return clientCapabilitiesHolder.getCapabilities() - .map(capabilities -> capabilities.getTextDocument()) - .map(textDocument -> textDocument.getDiagnostic()) - .isPresent(); + if (clientSupportsPullDiagnostics == null) { + clientSupportsPullDiagnostics = clientCapabilitiesHolder.getCapabilities() + .map(capabilities -> capabilities.getTextDocument()) + .map(textDocument -> textDocument.getDiagnostic()) + .isPresent(); + } + return clientSupportsPullDiagnostics; } } From 8c5606bf2ebc28ecb3ff7ed3bbc2bb2688ca9912 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 06:37:55 +0000 Subject: [PATCH 09/15] Subscribe to initialize event and add comprehensive tests - Changed to event-based initialization for pull diagnostics flag - Added @EventListener for LanguageServerInitializeRequestReceivedEvent - Created comprehensive tests for DiagnosticProvider covering all public methods Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../BSLTextDocumentService.java | 24 ++++-- .../providers/DiagnosticProviderTest.java | 83 +++++++++++++++++-- 2 files changed, 95 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 9157ecbbfe4..4040887bd01 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -25,6 +25,7 @@ import com.github._1c_syntax.bsl.languageserver.configuration.diagnostics.ComputeTrigger; import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; import com.github._1c_syntax.bsl.languageserver.context.ServerContext; +import com.github._1c_syntax.bsl.languageserver.events.LanguageServerInitializeRequestReceivedEvent; import com.github._1c_syntax.bsl.languageserver.jsonrpc.DiagnosticParams; import com.github._1c_syntax.bsl.languageserver.jsonrpc.Diagnostics; import com.github._1c_syntax.bsl.languageserver.jsonrpc.ProtocolExtension; @@ -97,6 +98,7 @@ import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.jsonrpc.messages.Either3; import org.eclipse.lsp4j.services.TextDocumentService; +import org.springframework.context.event.EventListener; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; import org.springframework.stereotype.Component; @@ -517,6 +519,20 @@ public void reset() { context.clear(); } + /** + * Обработчик события {@link LanguageServerInitializeRequestReceivedEvent}. + *

+ * Проверяет поддержку клиентом pull-модели диагностик. + * + * @param event Событие + */ + @EventListener + public void handleInitializeEvent(LanguageServerInitializeRequestReceivedEvent event) { + clientSupportsPullDiagnostics = event.getParams().getCapabilities() + .getTextDocument() + .getDiagnostic() != null; + } + private void validate(DocumentContext documentContext) { if (clientSupportsPullDiagnostics()) { return; @@ -525,13 +541,7 @@ private void validate(DocumentContext documentContext) { } private boolean clientSupportsPullDiagnostics() { - if (clientSupportsPullDiagnostics == null) { - clientSupportsPullDiagnostics = clientCapabilitiesHolder.getCapabilities() - .map(capabilities -> capabilities.getTextDocument()) - .map(textDocument -> textDocument.getDiagnostic()) - .isPresent(); - } - return clientSupportsPullDiagnostics; + return clientSupportsPullDiagnostics != null && clientSupportsPullDiagnostics; } } diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProviderTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProviderTest.java index 2e17100eb9f..7e08280222e 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProviderTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProviderTest.java @@ -21,16 +21,20 @@ */ package com.github._1c_syntax.bsl.languageserver.providers; +import com.github._1c_syntax.bsl.languageserver.LanguageClientHolder; import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; import com.github._1c_syntax.bsl.languageserver.util.TestUtils; import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DocumentDiagnosticReport; +import org.eclipse.lsp4j.RelatedFullDocumentDiagnosticReport; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import java.util.List; -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; @SpringBootTest class DiagnosticProviderTest { @@ -38,18 +42,87 @@ class DiagnosticProviderTest { @Autowired private DiagnosticProvider diagnosticProvider; + @Autowired + private LanguageClientHolder languageClientHolder; + + @Test + void testComputeAndPublishDiagnostics() { + // given + final DocumentContext documentContext + = TestUtils.getDocumentContextFromFile("./src/test/resources/providers/diagnosticProvider.bsl"); + + // when-then + assertThatCode(() -> diagnosticProvider.computeAndPublishDiagnostics(documentContext)) + .doesNotThrowAnyException(); + } + + @Test + void testPublishEmptyDiagnosticList() { + // given + final DocumentContext documentContext + = TestUtils.getDocumentContextFromFile("./src/test/resources/providers/diagnosticProvider.bsl"); + + // when-then + assertThatCode(() -> diagnosticProvider.publishEmptyDiagnosticList(documentContext)) + .doesNotThrowAnyException(); + } + + @Test + void testGetDiagnostic() { + // given + final DocumentContext documentContext + = TestUtils.getDocumentContextFromFile("./src/test/resources/providers/diagnosticProvider.bsl"); + + // when + final DocumentDiagnosticReport report = diagnosticProvider.getDiagnostic(documentContext); + + // then + assertThat(report).isNotNull(); + assertThat(report.getLeft()).isNotNull(); + assertThat(report.getLeft()).isInstanceOf(RelatedFullDocumentDiagnosticReport.class); + + RelatedFullDocumentDiagnosticReport fullReport = report.getLeft(); + assertThat(fullReport.getItems()).isNotNull(); + assertThat(fullReport.getItems()).isNotEmpty(); + } + @Test - void testComputeDiagnostics() { + void testGetDiagnosticWithNoDiagnostics() { // given - // TODO: это тест на новый getDiagnostics, а не на DiagnosticProvider + final DocumentContext documentContext + = TestUtils.getDocumentContext(""); + + // when + final DocumentDiagnosticReport report = diagnosticProvider.getDiagnostic(documentContext); + + // then + assertThat(report).isNotNull(); + assertThat(report.getLeft()).isNotNull(); + assertThat(report.getLeft()).isInstanceOf(RelatedFullDocumentDiagnosticReport.class); + + RelatedFullDocumentDiagnosticReport fullReport = report.getLeft(); + assertThat(fullReport.getItems()).isNotNull(); + assertThat(fullReport.getItems()).isEmpty(); + } + @Test + void testGetDiagnosticReportStructure() { + // given final DocumentContext documentContext = TestUtils.getDocumentContextFromFile("./src/test/resources/providers/diagnosticProvider.bsl"); // when - final List diagnostics = documentContext.getDiagnostics(); + final DocumentDiagnosticReport report = diagnosticProvider.getDiagnostic(documentContext); // then - assertThat(diagnostics.size()).isPositive(); + RelatedFullDocumentDiagnosticReport fullReport = report.getLeft(); + assertThat(fullReport.getKind()).isEqualTo("full"); + assertThat(fullReport.getItems()).hasSizeGreaterThan(0); + + // Verify diagnostics have required fields + Diagnostic firstDiagnostic = fullReport.getItems().get(0); + assertThat(firstDiagnostic.getRange()).isNotNull(); + assertThat(firstDiagnostic.getMessage()).isNotNull(); + assertThat(firstDiagnostic.getSource()).isEqualTo(DiagnosticProvider.SOURCE); } } From e5cbb95cf5eeb39baebd139615b15311b30aaf0f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 07:58:49 +0000 Subject: [PATCH 10/15] Change clientSupportsPullDiagnostics to primitive boolean Changed from Boolean to boolean with default value of false, simplifying the accessor method. Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../bsl/languageserver/BSLTextDocumentService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 4040887bd01..81f14c47324 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -141,7 +141,7 @@ public class BSLTextDocumentService implements TextDocumentService, ProtocolExte private final ExecutorService executorService = Executors.newCachedThreadPool(new CustomizableThreadFactory("text-document-service-")); - private Boolean clientSupportsPullDiagnostics; + private boolean clientSupportsPullDiagnostics; @PreDestroy private void onDestroy() { @@ -534,14 +534,14 @@ public void handleInitializeEvent(LanguageServerInitializeRequestReceivedEvent e } private void validate(DocumentContext documentContext) { - if (clientSupportsPullDiagnostics()) { + if (clientSupportsPullDiagnostics) { return; } diagnosticProvider.computeAndPublishDiagnostics(documentContext); } private boolean clientSupportsPullDiagnostics() { - return clientSupportsPullDiagnostics != null && clientSupportsPullDiagnostics; + return clientSupportsPullDiagnostics; } } From 5352e03c96b958a5158f864ad77edc1e5bf4ff37 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 08:06:36 +0000 Subject: [PATCH 11/15] Remove unnecessary clientSupportsPullDiagnostics() accessor Since the field is now a primitive boolean and accessed directly, the accessor method is no longer needed. Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../_1c_syntax/bsl/languageserver/BSLTextDocumentService.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 81f14c47324..581a144806c 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -540,8 +540,4 @@ private void validate(DocumentContext documentContext) { diagnosticProvider.computeAndPublishDiagnostics(documentContext); } - private boolean clientSupportsPullDiagnostics() { - return clientSupportsPullDiagnostics; - } - } From a48c1c80c38b870b131ac1d0648a81e820ba2bf2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 08:16:52 +0000 Subject: [PATCH 12/15] Add workspace/diagnostic/refresh support - Added event listener for LanguageServerInitializeRequestReceivedEvent to check if client supports workspace/diagnostic/refresh - Added event listener for LanguageServerConfigurationChangedEvent to send refresh notification when configuration changes - Client receives refreshDiagnostics() request when configuration changes and refresh is supported Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../providers/DiagnosticProvider.java | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java index c19a3a10666..0d91f5c5af2 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java @@ -21,13 +21,18 @@ */ package com.github._1c_syntax.bsl.languageserver.providers; +import com.github._1c_syntax.bsl.languageserver.ClientCapabilitiesHolder; import com.github._1c_syntax.bsl.languageserver.LanguageClientHolder; +import com.github._1c_syntax.bsl.languageserver.configuration.events.LanguageServerConfigurationChangedEvent; import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; +import com.github._1c_syntax.bsl.languageserver.events.LanguageServerInitializeRequestReceivedEvent; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DocumentDiagnosticReport; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.RelatedFullDocumentDiagnosticReport; +import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; import java.util.Collections; @@ -37,12 +42,15 @@ /** * Провайдер для диагностических сообщений. *

- * Отвечает за публикацию диагностик с использованием {@code textDocument/publishDiagnostics} - * и предоставление диагностик по запросу {@code textDocument/diagnostic}. + * Отвечает за публикацию диагностик с использованием {@code textDocument/publishDiagnostics}, + * предоставление диагностик по запросу {@code textDocument/diagnostic} + * и уведомление об обновлении диагностик через {@code workspace/diagnostic/refresh}. * * @see PublishDiagnostics Notification specification * @see Diagnostic Pull Request specification + * @see Diagnostic Refresh Request specification */ +@Slf4j @Component @RequiredArgsConstructor public final class DiagnosticProvider { @@ -50,6 +58,9 @@ public final class DiagnosticProvider { public static final String SOURCE = "bsl-language-server"; private final LanguageClientHolder clientHolder; + private final ClientCapabilitiesHolder clientCapabilitiesHolder; + + private boolean clientSupportsRefresh; /** * Вычислить и опубликовать диагностики для документа. @@ -81,6 +92,39 @@ public void publishEmptyDiagnosticList(DocumentContext documentContext) { publishDiagnostics(documentContext, Collections::emptyList); } + /** + * Обработчик события {@link LanguageServerInitializeRequestReceivedEvent}. + *

+ * Проверяет поддержку клиентом workspace/diagnostic/refresh. + * + * @param event Событие + */ + @EventListener + public void handleInitializeEvent(LanguageServerInitializeRequestReceivedEvent event) { + clientSupportsRefresh = clientCapabilitiesHolder.getCapabilities() + .map(capabilities -> capabilities.getWorkspace()) + .map(workspace -> workspace.getDiagnostics()) + .map(diagnostics -> diagnostics.getRefreshSupport()) + .orElse(false); + } + + /** + * Обработчик события {@link LanguageServerConfigurationChangedEvent}. + *

+ * Отправляет клиенту запрос на обновление диагностик при изменении конфигурации. + * + * @param event Событие + */ + @EventListener + public void handleConfigurationChangedEvent(LanguageServerConfigurationChangedEvent event) { + if (clientSupportsRefresh) { + clientHolder.execIfConnected(languageClient -> { + LOGGER.debug("Requesting diagnostic refresh from client"); + languageClient.refreshDiagnostics(); + }); + } + } + private void publishDiagnostics(DocumentContext documentContext, Supplier> diagnostics) { clientHolder.execIfConnected(languageClient -> languageClient.publishDiagnostics( From 5506fd3db419f9f5593902bec6cff1d03f840893 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 08:38:05 +0000 Subject: [PATCH 13/15] Add tests for workspace/diagnostic/refresh functionality - Added testHandleInitializeEvent to verify initialization event handling - Added testHandleInitializeEventWithoutDiagnosticsCapabilities for edge case - Added testHandleConfigurationChangedEvent to verify refresh is triggered - All tests verify that event handlers don't throw exceptions Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../providers/DiagnosticProviderTest.java | 59 ++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProviderTest.java b/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProviderTest.java index 7e08280222e..9d153f7309b 100644 --- a/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProviderTest.java +++ b/src/test/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProviderTest.java @@ -22,19 +22,26 @@ package com.github._1c_syntax.bsl.languageserver.providers; import com.github._1c_syntax.bsl.languageserver.LanguageClientHolder; +import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration; +import com.github._1c_syntax.bsl.languageserver.configuration.events.LanguageServerConfigurationChangedEvent; import com.github._1c_syntax.bsl.languageserver.context.DocumentContext; +import com.github._1c_syntax.bsl.languageserver.events.LanguageServerInitializeRequestReceivedEvent; import com.github._1c_syntax.bsl.languageserver.util.TestUtils; +import org.eclipse.lsp4j.ClientCapabilities; import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticWorkspaceCapabilities; import org.eclipse.lsp4j.DocumentDiagnosticReport; +import org.eclipse.lsp4j.InitializeParams; import org.eclipse.lsp4j.RelatedFullDocumentDiagnosticReport; +import org.eclipse.lsp4j.WorkspaceClientCapabilities; +import org.eclipse.lsp4j.services.LanguageServer; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import java.util.List; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.AssertionsForClassTypes.assertThatCode; +import static org.mockito.Mockito.mock; @SpringBootTest class DiagnosticProviderTest { @@ -125,4 +132,52 @@ void testGetDiagnosticReportStructure() { assertThat(firstDiagnostic.getMessage()).isNotNull(); assertThat(firstDiagnostic.getSource()).isEqualTo(DiagnosticProvider.SOURCE); } + + @Test + void testHandleInitializeEvent() { + // given + var languageServer = mock(LanguageServer.class); + var params = new InitializeParams(); + var capabilities = new ClientCapabilities(); + var workspace = new WorkspaceClientCapabilities(); + var diagnostics = new DiagnosticWorkspaceCapabilities(); + diagnostics.setRefreshSupport(true); + workspace.setDiagnostics(diagnostics); + capabilities.setWorkspace(workspace); + params.setCapabilities(capabilities); + + var event = new LanguageServerInitializeRequestReceivedEvent(languageServer, params); + + // when-then + assertThatCode(() -> diagnosticProvider.handleInitializeEvent(event)) + .doesNotThrowAnyException(); + } + + @Test + void testHandleInitializeEventWithoutDiagnosticsCapabilities() { + // given + var languageServer = mock(LanguageServer.class); + var params = new InitializeParams(); + var capabilities = new ClientCapabilities(); + var workspace = new WorkspaceClientCapabilities(); + capabilities.setWorkspace(workspace); + params.setCapabilities(capabilities); + + var event = new LanguageServerInitializeRequestReceivedEvent(languageServer, params); + + // when-then + assertThatCode(() -> diagnosticProvider.handleInitializeEvent(event)) + .doesNotThrowAnyException(); + } + + @Test + void testHandleConfigurationChangedEvent() { + // given + var configuration = mock(LanguageServerConfiguration.class); + var event = new LanguageServerConfigurationChangedEvent(configuration); + + // when-then + assertThatCode(() -> diagnosticProvider.handleConfigurationChangedEvent(event)) + .doesNotThrowAnyException(); + } } From 3bfdeab46bd9aa8461b3ddd6ba0d7c0ad55b18d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:13:20 +0000 Subject: [PATCH 14/15] Fix null safety in event handlers - Added null checks in DiagnosticProvider.handleInitializeEvent for workspace and diagnostics capabilities - Added null checks in BSLTextDocumentService.handleInitializeEvent for capabilities and text document - All tests now pass Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../bsl/languageserver/BSLTextDocumentService.java | 7 ++++--- .../bsl/languageserver/providers/DiagnosticProvider.java | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 581a144806c..2eeb7e7bb54 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -528,9 +528,10 @@ public void reset() { */ @EventListener public void handleInitializeEvent(LanguageServerInitializeRequestReceivedEvent event) { - clientSupportsPullDiagnostics = event.getParams().getCapabilities() - .getTextDocument() - .getDiagnostic() != null; + var capabilities = event.getParams().getCapabilities(); + if (capabilities != null && capabilities.getTextDocument() != null) { + clientSupportsPullDiagnostics = capabilities.getTextDocument().getDiagnostic() != null; + } } private void validate(DocumentContext documentContext) { diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java index 0d91f5c5af2..52938cfa1ba 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java @@ -103,8 +103,11 @@ public void publishEmptyDiagnosticList(DocumentContext documentContext) { public void handleInitializeEvent(LanguageServerInitializeRequestReceivedEvent event) { clientSupportsRefresh = clientCapabilitiesHolder.getCapabilities() .map(capabilities -> capabilities.getWorkspace()) + .filter(workspace -> workspace != null) .map(workspace -> workspace.getDiagnostics()) + .filter(diagnostics -> diagnostics != null) .map(diagnostics -> diagnostics.getRefreshSupport()) + .filter(refreshSupport -> refreshSupport != null) .orElse(false); } From ea9dc69789f69a761cd1eb0efc0ceb90db5fc854 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Oct 2025 09:25:21 +0000 Subject: [PATCH 15/15] Improve event handlers to use clientCapabilitiesHolder - BSLTextDocumentService: Use clientCapabilitiesHolder with map chain instead of event params - DiagnosticProvider: Remove redundant null filters in Optional chain (map handles nulls) - Both use method references for cleaner code - Follows established patterns in codebase (e.g., WorkDoneProgressHelper) Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com> --- .../bsl/languageserver/BSLTextDocumentService.java | 10 ++++++---- .../languageserver/providers/DiagnosticProvider.java | 12 ++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java index 2eeb7e7bb54..f361f1aa21e 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java @@ -53,6 +53,7 @@ import org.eclipse.lsp4j.CallHierarchyOutgoingCall; import org.eclipse.lsp4j.CallHierarchyOutgoingCallsParams; import org.eclipse.lsp4j.CallHierarchyPrepareParams; +import org.eclipse.lsp4j.ClientCapabilities; import org.eclipse.lsp4j.CodeAction; import org.eclipse.lsp4j.CodeActionParams; import org.eclipse.lsp4j.CodeLens; @@ -93,6 +94,7 @@ import org.eclipse.lsp4j.SelectionRange; import org.eclipse.lsp4j.SelectionRangeParams; import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.TextDocumentClientCapabilities; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.WorkspaceEdit; import org.eclipse.lsp4j.jsonrpc.messages.Either; @@ -528,10 +530,10 @@ public void reset() { */ @EventListener public void handleInitializeEvent(LanguageServerInitializeRequestReceivedEvent event) { - var capabilities = event.getParams().getCapabilities(); - if (capabilities != null && capabilities.getTextDocument() != null) { - clientSupportsPullDiagnostics = capabilities.getTextDocument().getDiagnostic() != null; - } + clientSupportsPullDiagnostics = clientCapabilitiesHolder.getCapabilities() + .map(ClientCapabilities::getTextDocument) + .map(TextDocumentClientCapabilities::getDiagnostic) + .isPresent(); } private void validate(DocumentContext documentContext) { diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java index 52938cfa1ba..23f72a60dd0 100644 --- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java +++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/providers/DiagnosticProvider.java @@ -28,10 +28,13 @@ import com.github._1c_syntax.bsl.languageserver.events.LanguageServerInitializeRequestReceivedEvent; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.eclipse.lsp4j.ClientCapabilities; import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticWorkspaceCapabilities; import org.eclipse.lsp4j.DocumentDiagnosticReport; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.RelatedFullDocumentDiagnosticReport; +import org.eclipse.lsp4j.WorkspaceClientCapabilities; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @@ -102,12 +105,9 @@ public void publishEmptyDiagnosticList(DocumentContext documentContext) { @EventListener public void handleInitializeEvent(LanguageServerInitializeRequestReceivedEvent event) { clientSupportsRefresh = clientCapabilitiesHolder.getCapabilities() - .map(capabilities -> capabilities.getWorkspace()) - .filter(workspace -> workspace != null) - .map(workspace -> workspace.getDiagnostics()) - .filter(diagnostics -> diagnostics != null) - .map(diagnostics -> diagnostics.getRefreshSupport()) - .filter(refreshSupport -> refreshSupport != null) + .map(ClientCapabilities::getWorkspace) + .map(WorkspaceClientCapabilities::getDiagnostics) + .map(DiagnosticWorkspaceCapabilities::getRefreshSupport) .orElse(false); }