{
+
+ protected final LanguageServerConfiguration configuration;
+
+ private boolean clientIsSupported;
+
+ /**
+ * Обработчик события {@link LanguageServerInitializeRequestReceivedEvent}.
+ *
+ * Анализирует тип подключенного клиента и управляет применимостью линзы.
+ *
+ * @param event Событие
+ */
+ @EventListener
+ @CacheEvict(allEntries = true)
+ public void handleEvent(LanguageServerInitializeRequestReceivedEvent event) {
+ var clientName = Optional.of(event)
+ .map(LanguageServerInitializeRequestReceivedEvent::getParams)
+ .map(InitializeParams::getClientInfo)
+ .map(ClientInfo::getName)
+ .orElse("");
+ clientIsSupported = "Visual Studio Code".equals(clientName);
+ }
+
+ /**
+ * Обработчик события {@link LanguageServerConfigurationChangedEvent}.
+ *
+ * Сбрасывает кеш при изменении конфигурации.
+ *
+ * @param event Событие
+ */
+ @EventListener
+ @CacheEvict(allEntries = true)
+ public void handleLanguageServerConfigurationChange(LanguageServerConfigurationChangedEvent event) {
+ // No-op. Служит для сброса кеша при изменении конфигурации
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isApplicable(DocumentContext documentContext) {
+ var uri = documentContext.getUri();
+ var testSources = getSelf().getTestSources(documentContext.getServerContext().getConfigurationRoot());
+
+ return clientIsSupported
+ && documentContext.getFileType() == FileType.OS
+ && testSources.stream().anyMatch(testSource -> isInside(uri, testSource));
+ }
+
+ /**
+ * Получить self-injected экземпляр себя для работы механизмов кэширования.
+ *
+ * @return Управляемый Spring'ом экземпляр себя
+ */
+ protected abstract AbstractRunTestsCodeLensSupplier getSelf();
+
+ /**
+ * Получить список каталогов с тестами с учетом корня рабочей области.
+ *
+ * public для работы @Cachable.
+ *
+ * @param configurationRoot Корень конфигурации
+ * @return Список исходных файлов тестов
+ */
+ @Cacheable
+ public Set getTestSources(@Nullable Path configurationRoot) {
+ var configurationRootString = Optional.ofNullable(configurationRoot)
+ .map(Path::toString)
+ .orElse("");
+
+ return configuration.getCodeLensOptions().getTestRunnerAdapterOptions().getTestSources()
+ .stream()
+ .map(testDir -> Path.of(configurationRootString, testDir))
+ .map(path -> Absolute.path(path).toUri())
+ .collect(Collectors.toSet());
+ }
+
+ private static boolean isInside(URI childURI, URI parentURI) {
+ return !parentURI.relativize(childURI).isAbsolute();
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensData.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensData.java
index 9baab40a82f..f32f001ee72 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensData.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensData.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensSupplier.java
index d249f68cc0c..44842fa3bef 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensSupplier.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CodeLensSupplier.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
@@ -46,6 +46,8 @@
*/
public interface CodeLensSupplier {
+ String CODE_LENS_SUPPLIER_SUFFIX = "CodeLensSupplier";
+
/**
* Идентификатор сапплаера. Если линза содержит поле {@link CodeLens#getData()},
* идентификатор в данных линзы должен совпадать с данным идентификатором.
@@ -54,8 +56,8 @@ public interface CodeLensSupplier {
*/
default String getId() {
String simpleName = getClass().getSimpleName();
- if (simpleName.endsWith("CodeLensSupplier")) {
- simpleName = simpleName.substring(0, simpleName.length() - "CodeLensSupplier".length());
+ if (simpleName.endsWith(CODE_LENS_SUPPLIER_SUFFIX)) {
+ simpleName = simpleName.substring(0, simpleName.length() - CODE_LENS_SUPPLIER_SUFFIX.length());
simpleName = Introspector.decapitalize(simpleName);
}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CognitiveComplexityCodeLensSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CognitiveComplexityCodeLensSupplier.java
index 851525faa7b..bbe60e7bb47 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CognitiveComplexityCodeLensSupplier.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CognitiveComplexityCodeLensSupplier.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.codelenses;
+import com.github._1c_syntax.bsl.languageserver.commands.ToggleCognitiveComplexityInlayHintsCommandSupplier;
import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
@@ -34,8 +35,11 @@
@Component
public class CognitiveComplexityCodeLensSupplier extends AbstractMethodComplexityCodeLensSupplier {
- public CognitiveComplexityCodeLensSupplier(LanguageServerConfiguration configuration) {
- super(configuration);
+ public CognitiveComplexityCodeLensSupplier(
+ LanguageServerConfiguration configuration,
+ ToggleCognitiveComplexityInlayHintsCommandSupplier commandSupplier
+ ) {
+ super(configuration, commandSupplier);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CyclomaticComplexityCodeLensSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CyclomaticComplexityCodeLensSupplier.java
index 0356d9aa740..7c28e0911fc 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CyclomaticComplexityCodeLensSupplier.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/CyclomaticComplexityCodeLensSupplier.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
@@ -21,6 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.codelenses;
+import com.github._1c_syntax.bsl.languageserver.commands.ToggleCyclomaticComplexityInlayHintsCommandSupplier;
import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
@@ -34,8 +35,11 @@
@Component
public class CyclomaticComplexityCodeLensSupplier extends AbstractMethodComplexityCodeLensSupplier {
- public CyclomaticComplexityCodeLensSupplier(LanguageServerConfiguration configuration) {
- super(configuration);
+ public CyclomaticComplexityCodeLensSupplier(
+ LanguageServerConfiguration configuration,
+ ToggleCyclomaticComplexityInlayHintsCommandSupplier commandSupplier
+ ) {
+ super(configuration, commandSupplier);
}
@Override
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/DefaultCodeLensData.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/DefaultCodeLensData.java
index 1976dc1d253..6a4a2fd1126 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/DefaultCodeLensData.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/DefaultCodeLensData.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
@@ -21,7 +21,7 @@
*/
package com.github._1c_syntax.bsl.languageserver.codelenses;
-import com.github._1c_syntax.bsl.languageserver.codelenses.databind.URITypeAdapter;
+import com.github._1c_syntax.bsl.languageserver.databind.URITypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import lombok.Value;
import lombok.experimental.NonFinal;
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/RunAllTestsCodeLensSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/RunAllTestsCodeLensSupplier.java
new file mode 100644
index 00000000000..48d4c5d1434
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/RunAllTestsCodeLensSupplier.java
@@ -0,0 +1,133 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright (c) 2018-2025
+ * Alexey Sosnoviy , Nikita Fedkin and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3.0 of the License, or (at your option) any later version.
+ *
+ * BSL Language Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.codelenses;
+
+import com.github._1c_syntax.bsl.languageserver.codelenses.testrunner.TestRunnerAdapter;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
+import com.github._1c_syntax.bsl.languageserver.utils.Resources;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.lsp4j.CodeLens;
+import org.eclipse.lsp4j.Command;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Поставщик линзы для запуска всех тестов в текущем файле.
+ */
+@Component
+@Slf4j
+public class RunAllTestsCodeLensSupplier
+ extends AbstractRunTestsCodeLensSupplier {
+
+ private static final String COMMAND_ID = "language-1c-bsl.languageServer.runAllTests";
+
+ private final TestRunnerAdapter testRunnerAdapter;
+ private final Resources resources;
+
+ // Self-injection для работы кэша в базовом классе.
+ @Autowired
+ @Lazy
+ @Getter
+ private RunAllTestsCodeLensSupplier self;
+
+ public RunAllTestsCodeLensSupplier(
+ LanguageServerConfiguration configuration,
+ TestRunnerAdapter testRunnerAdapter,
+ Resources resources
+ ) {
+ super(configuration);
+ this.testRunnerAdapter = testRunnerAdapter;
+ this.resources = resources;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List getCodeLenses(DocumentContext documentContext) {
+
+ var testIds = testRunnerAdapter.getTestIds(documentContext);
+
+ if (testIds.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ var methods = documentContext.getSymbolTree().getMethods();
+ if (methods.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ var firstMethod = methods.get(0);
+
+ return List.of(toCodeLens(firstMethod, documentContext));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CodeLens resolve(DocumentContext documentContext, CodeLens unresolved, DefaultCodeLensData data) {
+ var path = Paths.get(documentContext.getUri());
+
+ var options = configuration.getCodeLensOptions().getTestRunnerAdapterOptions();
+ var executable = options.getExecutableForCurrentOS();
+ String runText = executable + " " + options.getRunAllTestsArguments();
+ runText = String.format(runText, path);
+
+ var command = new Command();
+ command.setTitle(resources.getResourceString(getClass(), "runAllTests"));
+ command.setCommand(COMMAND_ID);
+ command.setArguments(List.of(Map.of("text", runText)));
+
+ unresolved.setCommand(command);
+
+ return unresolved;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Class getCodeLensDataClass() {
+ return DefaultCodeLensData.class;
+ }
+
+ private CodeLens toCodeLens(MethodSymbol method, DocumentContext documentContext) {
+
+ var codeLensData = new DefaultCodeLensData(documentContext.getUri(), getId());
+
+ var codeLens = new CodeLens(method.getSubNameRange());
+ codeLens.setData(codeLensData);
+
+ return codeLens;
+ }
+
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/RunTestCodeLensSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/RunTestCodeLensSupplier.java
new file mode 100644
index 00000000000..e084375c203
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/RunTestCodeLensSupplier.java
@@ -0,0 +1,163 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright (c) 2018-2025
+ * Alexey Sosnoviy , Nikita Fedkin and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3.0 of the License, or (at your option) any later version.
+ *
+ * BSL Language Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.codelenses;
+
+import com.github._1c_syntax.bsl.languageserver.codelenses.testrunner.TestRunnerAdapter;
+import com.github._1c_syntax.bsl.languageserver.configuration.LanguageServerConfiguration;
+import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
+import com.github._1c_syntax.bsl.languageserver.context.FileType;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.MethodSymbol;
+import com.github._1c_syntax.bsl.languageserver.utils.Resources;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+import lombok.Value;
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.lsp4j.CodeLens;
+import org.eclipse.lsp4j.Command;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+
+import java.beans.ConstructorProperties;
+import java.net.URI;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Поставщик линз для запуска теста по конкретному тестовому методу.
+ */
+@Component
+@Slf4j
+public class RunTestCodeLensSupplier
+ extends AbstractRunTestsCodeLensSupplier {
+
+ private static final String COMMAND_ID = "language-1c-bsl.languageServer.runTest";
+
+ private final TestRunnerAdapter testRunnerAdapter;
+ private final Resources resources;
+
+ // Self-injection для работы кэша в базовом классе.
+ @Autowired
+ @Lazy
+ @Getter
+ private RunTestCodeLensSupplier self;
+
+ public RunTestCodeLensSupplier(
+ LanguageServerConfiguration configuration,
+ TestRunnerAdapter testRunnerAdapter,
+ Resources resources
+ ) {
+ super(configuration);
+ this.testRunnerAdapter = testRunnerAdapter;
+ this.resources = resources;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List getCodeLenses(DocumentContext documentContext) {
+
+ if (documentContext.getFileType() == FileType.BSL) {
+ return Collections.emptyList();
+ }
+
+ var testIds = testRunnerAdapter.getTestIds(documentContext);
+ var symbolTree = documentContext.getSymbolTree();
+
+ return testIds.stream()
+ .map(symbolTree::getMethodSymbol)
+ .flatMap(Optional::stream)
+ .map(methodSymbol -> toCodeLens(methodSymbol, documentContext))
+ .toList();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Class getCodeLensDataClass() {
+ return RunTestCodeLensData.class;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CodeLens resolve(DocumentContext documentContext, CodeLens unresolved, RunTestCodeLensData data) {
+
+ var path = Paths.get(documentContext.getUri());
+ var testId = data.getTestId();
+
+ var options = configuration.getCodeLensOptions().getTestRunnerAdapterOptions();
+ var executable = options.getExecutableForCurrentOS();
+ String runText = executable + " " + options.getRunTestArguments();
+ runText = String.format(runText, path, testId);
+
+ var command = new Command();
+ command.setTitle(resources.getResourceString(getClass(), "runTest"));
+ command.setCommand(COMMAND_ID);
+ command.setArguments(List.of(Map.of("text", runText)));
+
+ unresolved.setCommand(command);
+
+ return unresolved;
+ }
+
+ private CodeLens toCodeLens(MethodSymbol method, DocumentContext documentContext) {
+ var testId = method.getName();
+ var codeLensData = new RunTestCodeLensData(documentContext.getUri(), getId(), testId);
+
+ var codeLens = new CodeLens(method.getSubNameRange());
+ codeLens.setData(codeLensData);
+
+ return codeLens;
+ }
+
+ /**
+ * DTO для хранения данных линз о сложности методов в документе.
+ */
+ @Value
+ @EqualsAndHashCode(callSuper = true)
+ @ToString(callSuper = true)
+ public static class RunTestCodeLensData extends DefaultCodeLensData {
+ /**
+ * Имя метода.
+ */
+ String testId;
+
+ /**
+ * @param uri URI документа.
+ * @param id Идентификатор линзы.
+ * @param testId Идентификатор теста.
+ */
+ @ConstructorProperties({"uri", "id", "testId"})
+ public RunTestCodeLensData(URI uri, String id, String testId) {
+ super(uri, id);
+ this.testId = testId;
+ }
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/databind/CodeLensDataObjectMapper.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/databind/CodeLensDataObjectMapper.java
deleted file mode 100644
index 7f1ecd561db..00000000000
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/databind/CodeLensDataObjectMapper.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * This file is a part of BSL Language Server.
- *
- * Copyright (c) 2018-2022
- * Alexey Sosnoviy , Nikita Fedkin and contributors
- *
- * SPDX-License-Identifier: LGPL-3.0-or-later
- *
- * BSL Language Server is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3.0 of the License, or (at your option) any later version.
- *
- * BSL Language Server is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with BSL Language Server.
- */
-package com.github._1c_syntax.bsl.languageserver.codelenses.databind;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.jsontype.NamedType;
-import com.github._1c_syntax.bsl.languageserver.codelenses.CodeLensData;
-import com.github._1c_syntax.bsl.languageserver.codelenses.CodeLensSupplier;
-import org.springframework.stereotype.Component;
-
-import java.util.List;
-
-/**
- * Преднастроенный экземпляр {@link ObjectMapper} для десериализации {@link CodeLensData}.
- */
-@Component
-public class CodeLensDataObjectMapper extends ObjectMapper {
-
- private static final long serialVersionUID = 8904131809077953315L;
-
- public CodeLensDataObjectMapper(List> codeLensResolvers) {
- super();
-
- codeLensResolvers.stream()
- .map(CodeLensDataObjectMapper::toNamedType)
- .forEach(this::registerSubtypes);
- }
-
- private static NamedType toNamedType(CodeLensSupplier extends CodeLensData> codeLensSupplier) {
- return new NamedType(codeLensSupplier.getCodeLensDataClass(), codeLensSupplier.getId());
- }
-}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/infrastructure/CodeLensesConfiguration.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/infrastructure/CodeLensesConfiguration.java
index ba1c22f0579..abdbe59a0d5 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/infrastructure/CodeLensesConfiguration.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/infrastructure/CodeLensesConfiguration.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/infrastructure/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/infrastructure/package-info.java
index ef3110f6ce2..c5b8c6fb6d5 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/infrastructure/package-info.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/infrastructure/package-info.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
@@ -23,7 +23,8 @@
* Spring-специфичные классы для настройки внутренней инфраструктуры
* пакета {@link com.github._1c_syntax.bsl.languageserver.codelenses}.
*/
-@ParametersAreNonnullByDefault
+@DefaultAnnotation(NonNull.class)
package com.github._1c_syntax.bsl.languageserver.codelenses.infrastructure;
-import javax.annotation.ParametersAreNonnullByDefault;
+import edu.umd.cs.findbugs.annotations.DefaultAnnotation;
+import edu.umd.cs.findbugs.annotations.NonNull;
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/package-info.java
index 7c51585d1a6..6236a336560 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/package-info.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/package-info.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
@@ -23,7 +23,8 @@
* Пакет предназначен для реализации различных видов линз ("code lenses"),
* используемых {@link com.github._1c_syntax.bsl.languageserver.providers.CodeLensProvider}.
*/
-@ParametersAreNonnullByDefault
+@DefaultAnnotation(NonNull.class)
package com.github._1c_syntax.bsl.languageserver.codelenses;
-import javax.annotation.ParametersAreNonnullByDefault;
+import edu.umd.cs.findbugs.annotations.DefaultAnnotation;
+import edu.umd.cs.findbugs.annotations.NonNull;
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/testrunner/TestRunnerAdapter.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/testrunner/TestRunnerAdapter.java
new file mode 100644
index 00000000000..1e5d2b6c592
--- /dev/null
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/testrunner/TestRunnerAdapter.java
@@ -0,0 +1,161 @@
+/*
+ * This file is a part of BSL Language Server.
+ *
+ * Copyright (c) 2018-2025
+ * Alexey Sosnoviy , Nikita Fedkin and contributors
+ *
+ * SPDX-License-Identifier: LGPL-3.0-or-later
+ *
+ * BSL Language Server is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3.0 of the License, or (at your option) any later version.
+ *
+ * BSL Language Server is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with BSL Language Server.
+ */
+package com.github._1c_syntax.bsl.languageserver.codelenses.testrunner;
+
+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.context.symbol.MethodSymbol;
+import com.github._1c_syntax.bsl.languageserver.context.symbol.annotations.Annotation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.exec.CommandLine;
+import org.apache.commons.exec.DefaultExecuteResultHandler;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.ExecuteWatchdog;
+import org.apache.commons.exec.PumpStreamHandler;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.lang3.SystemUtils;
+import org.springframework.cache.annotation.CacheConfig;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Paths;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Расчетчик списка тестов в документе.
+ * Физически выполняет команды по получению идентификаторов тестов на основании конфигурации.
+ */
+@Component
+@RequiredArgsConstructor
+@Slf4j
+@CacheConfig(cacheNames = "testIds")
+public class TestRunnerAdapter {
+
+ private static final Pattern NEW_LINE_PATTERN = Pattern.compile("\r?\n");
+
+ private final LanguageServerConfiguration configuration;
+
+ /**
+ * Обработчик события {@link LanguageServerConfigurationChangedEvent}.
+ *
+ * Очищает кэш при изменении конфигурации.
+ *
+ * @param event Событие
+ */
+ @EventListener
+ @CacheEvict(allEntries = true)
+ public void handleEvent(LanguageServerConfigurationChangedEvent event) {
+ // No-op. Служит для сброса кеша при изменении конфигурации
+ }
+
+ /**
+ * Получить идентификаторы тестов, содержащихся в файле.
+ *
+ * @param documentContext Контекст документа с тестами.
+ * @return Список идентификаторов тестов.
+ */
+ @Cacheable
+ public List getTestIds(DocumentContext documentContext) {
+ var options = configuration.getCodeLensOptions().getTestRunnerAdapterOptions();
+
+ if (options.isGetTestsByTestRunner()) {
+ return computeTestIdsByTestRunner(documentContext);
+ }
+
+ return computeTestIdsByLanguageServer(documentContext);
+ }
+
+ private List computeTestIdsByTestRunner(DocumentContext documentContext) {
+ var options = configuration.getCodeLensOptions().getTestRunnerAdapterOptions();
+
+ var executable = SystemUtils.IS_OS_WINDOWS ? options.getExecutableWin() : options.getExecutable();
+ var path = Paths.get(documentContext.getUri()).toString();
+ var arguments = String.format(options.getGetTestsArguments(), path);
+
+ var getTestsCommand = new CommandLine(executable).addArguments(arguments, false);
+
+ var timeout = 10_000L;
+ var watchdog = ExecuteWatchdog.builder().setTimeout(Duration.ofMillis(timeout)).get();
+
+ var outputStream = new ByteArrayOutputStream();
+ var streamHandler = new PumpStreamHandler(outputStream);
+
+ var resultHandler = new DefaultExecuteResultHandler();
+
+ var executor = DefaultExecutor.builder().get();
+ executor.setWatchdog(watchdog);
+ executor.setStreamHandler(streamHandler);
+
+ try {
+ executor.execute(getTestsCommand, resultHandler);
+ } catch (IOException e) {
+ LOGGER.error("Can't execute testrunner getTests command", e);
+ return Collections.emptyList();
+ }
+ try {
+ resultHandler.waitFor();
+ } catch (InterruptedException e) {
+ LOGGER.error("Can't wait for testrunner getTests command", e);
+ Thread.currentThread().interrupt();
+ return Collections.emptyList();
+ }
+
+ var getTestsRegex = Pattern.compile(options.getGetTestsResultPattern());
+
+ Charset charset;
+ if (SystemUtils.IS_OS_WINDOWS) {
+ charset = Charset.forName("cp866");
+ } else {
+ charset = Charset.defaultCharset();
+ }
+ var output = outputStream.toString(charset);
+
+ return Arrays.stream(NEW_LINE_PATTERN.split(output))
+ .map(getTestsRegex::matcher)
+ .filter(Matcher::matches)
+ .map(matcher -> matcher.group(1))
+ .toList();
+ }
+
+ private List computeTestIdsByLanguageServer(DocumentContext documentContext) {
+ var annotations = configuration.getCodeLensOptions().getTestRunnerAdapterOptions().getAnnotations();
+ return documentContext.getSymbolTree()
+ .getMethods()
+ .stream()
+ .filter(methodSymbol -> methodSymbol.getAnnotations().stream()
+ .map(Annotation::getName)
+ .anyMatch(annotations::contains))
+ .map(MethodSymbol::getName)
+ .toList();
+ }
+}
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/databind/package-info.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/testrunner/package-info.java
similarity index 71%
rename from src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/databind/package-info.java
rename to src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/testrunner/package-info.java
index d1478cbc737..75fa5e6d12f 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/databind/package-info.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/codelenses/testrunner/package-info.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
@@ -20,10 +20,10 @@
* License along with BSL Language Server.
*/
/**
- * Сериализация и десериализация классов пакета
- * {@link com.github._1c_syntax.bsl.languageserver.codelenses}.
+ * Запуск инструментов тестирования.
*/
-@ParametersAreNonnullByDefault
-package com.github._1c_syntax.bsl.languageserver.codelenses.databind;
+@DefaultAnnotation(NonNull.class)
+package com.github._1c_syntax.bsl.languageserver.codelenses.testrunner;
-import javax.annotation.ParametersAreNonnullByDefault;
+import edu.umd.cs.findbugs.annotations.DefaultAnnotation;
+import edu.umd.cs.findbugs.annotations.NonNull;
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/BSLColor.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/BSLColor.java
index 6043d6b6b9c..139356c565a 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/BSLColor.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/BSLColor.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ColorInformationSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ColorInformationSupplier.java
index b6fd5dd1068..8f5526a4a04 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ColorInformationSupplier.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ColorInformationSupplier.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ColorPresentationSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ColorPresentationSupplier.java
index a906bb5a747..cd7c376c2dd 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ColorPresentationSupplier.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ColorPresentationSupplier.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ConstructorColorInformationSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ConstructorColorInformationSupplier.java
index 5f1df21f905..4afd6e6db8c 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ConstructorColorInformationSupplier.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ConstructorColorInformationSupplier.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
@@ -24,6 +24,7 @@
import com.github._1c_syntax.bsl.languageserver.context.DocumentContext;
import com.github._1c_syntax.bsl.languageserver.utils.Ranges;
import com.github._1c_syntax.bsl.languageserver.utils.Trees;
+import com.github._1c_syntax.bsl.languageserver.utils.bsl.Constructors;
import com.github._1c_syntax.bsl.parser.BSLParser;
import com.github._1c_syntax.utils.CaseInsensitivePattern;
import org.antlr.v4.runtime.Token;
@@ -46,7 +47,6 @@
@Component
public class ConstructorColorInformationSupplier implements ColorInformationSupplier {
- private static final Pattern QUOTE_PATTERN = Pattern.compile("\"");
private static final Pattern COLOR_PATTERN = CaseInsensitivePattern.compile("^(?:Цвет|Color)$");
@Override
@@ -58,23 +58,11 @@ public List getColorInformation(DocumentContext documentContex
return newExpressions.stream()
.map(BSLParser.NewExpressionContext.class::cast)
- .filter(newExpression -> COLOR_PATTERN.matcher(typeName(newExpression)).matches())
+ .filter(newExpression -> Constructors.typeName(newExpression).filter(name -> COLOR_PATTERN.matcher(name).matches()).isPresent())
.map(ConstructorColorInformationSupplier::toColorInformation)
.collect(Collectors.toList());
}
- private static String typeName(BSLParser.NewExpressionContext ctx) {
- if (ctx.typeName() != null) {
- return ctx.typeName().getText();
- }
-
- if (ctx.doCall() == null || ctx.doCall().callParamList().isEmpty()) {
- return "";
- }
-
- return QUOTE_PATTERN.matcher(ctx.doCall().callParamList().callParam(0).getText()).replaceAll("");
- }
-
private static ColorInformation toColorInformation(BSLParser.NewExpressionContext ctx) {
byte redPosition;
byte greenPosition;
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ConstructorColorPresentationSupplier.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ConstructorColorPresentationSupplier.java
index cd00ab01206..5810f53018f 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ConstructorColorPresentationSupplier.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/ConstructorColorPresentationSupplier.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin and contributors
*
* SPDX-License-Identifier: LGPL-3.0-or-later
diff --git a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/WebColor.java b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/WebColor.java
index 83e77b94b1b..7d0177dbb29 100644
--- a/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/WebColor.java
+++ b/src/main/java/com/github/_1c_syntax/bsl/languageserver/color/WebColor.java
@@ -1,7 +1,7 @@
/*
* This file is a part of BSL Language Server.
*
- * Copyright (c) 2018-2022
+ * Copyright (c) 2018-2025
* Alexey Sosnoviy , Nikita Fedkin