mirror of
https://github.com/tiennm99/serena.git
synced 2026-10-03 09:13:49 +00:00
feat: add BSL (1C:Enterprise) language server support (#1430)
Required bumping of java to 21 in CI
This commit is contained in:
1 parent
737ef76723
commit
fb9c822178
24 files changed
+930
-4
No files matched your search
@@ -138,7 +138,7 @@ jobs:
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
java-version: '21'
|
||||
- name: Setup .NET SDK (for F# and C# languages)
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
|
||||
@@ -29,6 +29,7 @@ Status of the `main` branch. Changes prior to the next official version change w
|
||||
- Add **Angular** (experimental) via a dual-server architecture: `@angular/language-server` (ngserver) handles standalone `.html` template files, while a companion `typescript-language-server` with `@angular/language-service` loaded as a tsserver plugin handles all `.ts` operations including inline templates. Provides type-aware navigation between templates and component classes. Requires Node.js, npm, and `@angular/core` installed in the project (`npm install` in the project root). Subsumes `typescript`+`html` for `.ts`/`.html` files when active; SCSS is not subsumed.
|
||||
- Add **HTML** (experimental) using `vscode-html-language-server` from the `vscode-langservers-extracted` npm package. Provides in-file element/id symbols via documentSymbol; cross-file references are not meaningful for HTML. Also used as a companion server by the Angular LS for plain HTML documentSymbol support.
|
||||
- Add **SCSS / Sass / CSS** (experimental) using [some-sass-language-server](https://github.com/wkillerud/some-sass). Handles `.scss`, `.sass`, and `.css` through one server, with full `@use`/`@forward` workspace-wide go-to-definition and find-references for variables, mixins, and functions across Sass files. The `.css` path uses the same `vscode-css-languageservice` engine that powers the standalone CSS LS; CSS feature toggles default off upstream and are flipped on at startup so symbols, hover, completion, and syntax-level diagnostics work for plain CSS as well.
|
||||
- Add **1C / OneScript** support using [BSL Language Server](https://github.com/1c-syntax/bsl-language-server/).
|
||||
- Add support for more filenames to be considered by ccls and clangd.
|
||||
- Clojure (`clojure-lsp`): Fix incomplete `find_referencing_symbols` results in multi-module monorepos. clojure-lsp only discovers source paths from the descriptor at the workspace root and does not recurse for sub-module `deps.edn` / `project.clj` / `shadow-cljs.edn` / `bb.edn` files, so references in sibling modules were silently missed until those files happened to be opened by `find_symbol` / `get_symbols_overview`. Serena now scans the repo for project descriptors at startup and passes the union of their declared source paths to clojure-lsp via `initializationOptions`. Project-local `.lsp/config.edn` files are honoured as-is (no override). New `ls_specific_settings.clojure` keys: `source_paths` (explicit override) and `config_edn_path` (parse `:source-paths` from a user-supplied config file).
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ Serena incorporates a powerful abstraction layer for the integration of language
|
||||
The underlying language servers are typically open-source projects or at least freely available for use.
|
||||
|
||||
When using Serena's language server backend, we provide **support for over 40 programming languages**, including
|
||||
Ada / SPARK, AL, Angular, Ansible, Bash, C#, C/C++, Clojure, Crystal, Dart, Elixir, Elm, Erlang, Fortran, F#, GLSL, Go, Groovy, Haskell, Haxe, HLSL, HTML, Java, JavaScript, JSON, Julia, Kotlin, Lean 4, Lua, Luau, Markdown, MATLAB, mSL, Nix, OCaml, Perl, PHP, PowerShell, Python, R, Ruby, Rust, Scala, SCSS / Sass / CSS, Solidity, Swift, TOML, TypeScript, WGSL, YAML, and Zig.
|
||||
Ada / SPARK, AL, Angular, Ansible, Bash, BSL, C#, C/C++, Clojure, Crystal, Dart, Elixir, Elm, Erlang, Fortran, F#, GLSL, Go, Groovy, Haskell, Haxe, HLSL, HTML, Java, JavaScript, JSON, Julia, Kotlin, Lean 4, Lua, Luau, Markdown, MATLAB, mSL, Nix, OCaml, Perl, PHP, PowerShell, Python, R, Ruby, Rust, Scala, SCSS / Sass / CSS, Solidity, Swift, TOML, TypeScript, WGSL, YAML, and Zig.
|
||||
|
||||
### The Serena JetBrains Plugin
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ Some languages require additional installations or setup steps, as noted.
|
||||
semantic tokens, and validation; document symbols, workspace symbols, references, and rename
|
||||
are not supported by this version)
|
||||
* **Bash**
|
||||
* **BSL** (1C:Enterprise / OneScript)
|
||||
(requires Java 21+ on PATH; uses [bsl-language-server](https://github.com/1c-syntax/bsl-language-server) by 1c-syntax; the JAR is auto-downloaded and SHA-256-verified for the bundled default version; supports `.bsl` and `.os` files; configure optional `ls_path` or `bsl_ls_version` under `ls_specific_settings.bsl`)
|
||||
* **C#**
|
||||
(by default, uses the Roslyn language server (language `csharp`), requiring [.NET v10+](https://dotnet.microsoft.com/en-us/download/dotnet) and, on Windows, `pwsh` ([PowerShell 7+](https://learn.microsoft.com/en-us/powershell/scripting/install/install-powershell-on-windows?view=powershell-7.5));
|
||||
set language to `csharp_omnisharp` to use OmiSharp instead)
|
||||
|
||||
@@ -227,7 +227,7 @@ ls_specific_settings:
|
||||
|
||||
This is supported by all language servers deriving their dependency provider from `LanguageServerDependencyProviderSinglePath`,
|
||||
and by some additional wrappers that explicitly expose `ls_path`.
|
||||
Common examples include: `ansible`, `bash`, `clojure`, `cpp`, `cpp_ccls`, `hlsl`, `html`, `kotlin`, `lean4`, `luau`, `markdown`, `php`,
|
||||
Common examples include: `ansible`, `bash`, `bsl`, `clojure`, `cpp`, `cpp_ccls`, `hlsl`, `html`, `kotlin`, `lean4`, `luau`, `markdown`, `php`,
|
||||
`php_phpactor`, `python`, `rust`, `scss`, `solidity`, `systemverilog`, `toml`, `typescript`, and `yaml`.
|
||||
|
||||
Note: `angular` does **not** support `ls_path` — the Angular language server is part of a multi-process orchestration
|
||||
@@ -308,6 +308,29 @@ Supported settings:
|
||||
| `bash_language_server_version` | `5.6.0` | Override the npm package version Serena installs when `ls_path` is not set. |
|
||||
| `npm_registry` | `null` | Override the npm registry Serena uses for the managed install. |
|
||||
|
||||
#### BSL (1C:Enterprise / OneScript)
|
||||
|
||||
Serena uses [bsl-language-server](https://github.com/1c-syntax/bsl-language-server) by 1c-syntax
|
||||
for BSL support. The JAR is downloaded automatically on first use and SHA-256-verified for the
|
||||
bundled default version. **Requires Java 21+ on `PATH`** — bsl-language-server v0.29.0 is built
|
||||
with `targetCompatibility = JavaVersion.VERSION_21` and fails to launch under older JDKs.
|
||||
|
||||
Supported settings:
|
||||
|
||||
| Setting | Default | Description |
|
||||
|---|---|---|
|
||||
| `ls_path` | managed download | Override the path to an existing `bsl-language-server-*-exec.jar`. When set, Serena does not download anything; the JAR is launched directly via `java -jar`. |
|
||||
| `bsl_ls_version` | `0.29.0` | Override the bsl-language-server release version Serena downloads when `ls_path` is not set. SHA-256 verification is performed only for the default version; user-overridden versions install without SHA verification. |
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
ls_specific_settings:
|
||||
bsl:
|
||||
bsl_ls_version: "0.29.0"
|
||||
# ls_path: "/opt/bsl/bsl-language-server-0.29.0-exec.jar" # optional
|
||||
```
|
||||
|
||||
#### Clojure
|
||||
|
||||
Serena uses `clojure-lsp` for Clojure support.
|
||||
|
||||
@@ -294,6 +294,9 @@ max-complexity = 20
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/**" = ["D103"]
|
||||
"scripts/**" = ["D103"]
|
||||
# BSL integration tests deliberately contain Cyrillic identifiers (1C:Enterprise metadata
|
||||
# object names and procedure names). ruff's ambiguous-unicode rules flag every such char.
|
||||
"test/solidlsp/bsl/**" = ["RUF001", "RUF002", "RUF003"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
addopts = "--snapshot-patch-pycharm-diff"
|
||||
@@ -349,6 +352,7 @@ markers = [
|
||||
"solidity: language server running for Solidity (uses @nomicfoundation/solidity-language-server)",
|
||||
"ansible: language server running for Ansible (uses @ansible/ansible-language-server)",
|
||||
"msl: language server running for mSL (mIRC Scripting Language)",
|
||||
"bsl: language server running for BSL (1C:Enterprise / OneScript)",
|
||||
"html: language server running for HTML (vscode-html-language-server, used as companion by Angular)",
|
||||
"scss: language server running for SCSS / Sass / CSS (some-sass-language-server)",
|
||||
"angular: language server running for Angular (uses @angular/language-server + @angular/language-service tsserver plugin)",
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
"""
|
||||
Provides BSL (1C:Enterprise) specific instantiation of the LanguageServer class
|
||||
using bsl-language-server by 1c-syntax. Supports .bsl and .os files.
|
||||
Requires Java 21+ on PATH (bsl-language-server v0.29.0 is built with
|
||||
``targetCompatibility = JavaVersion.VERSION_21``).
|
||||
|
||||
You can configure the following options in ls_specific_settings (in serena_config.yml):
|
||||
|
||||
ls_specific_settings:
|
||||
bsl:
|
||||
ls_path: '/path/to/bsl-language-server.jar' # Custom path to BSL Language Server JAR
|
||||
bsl_ls_version: '0.29.0' # BSL Language Server version (default: current bundled version)
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import threading
|
||||
|
||||
from solidlsp.language_servers.common import RuntimeDependency, RuntimeDependencyCollection
|
||||
from solidlsp.ls import (
|
||||
LanguageServerDependencyProvider,
|
||||
LanguageServerDependencyProviderSinglePath,
|
||||
SolidLanguageServer,
|
||||
)
|
||||
from solidlsp.ls_config import LanguageServerConfig
|
||||
from solidlsp.lsp_protocol_handler.lsp_types import InitializeParams
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_BSL_LS_VERSION = "0.29.0"
|
||||
BSL_LS_JAR_SHA256_BY_VERSION = {
|
||||
"0.29.0": "d6fa9ad638ba51855e260b88ad1f8ce4e602385845a4ee43600d148f779bcf0b",
|
||||
}
|
||||
BSL_LS_MIN_JAVA_VERSION = 21
|
||||
"""Minimum Java major version required to run the bundled bsl-language-server JAR.
|
||||
|
||||
bsl-language-server v0.29.0 is compiled with ``targetCompatibility = VERSION_21`` and
|
||||
therefore fails at class-load time on older JDKs (``UnsupportedClassVersionError``),
|
||||
which manifests as ``LanguageServerTerminatedException`` in Serena. We enforce the
|
||||
check up front so the user gets an actionable error instead of a dead LSP process.
|
||||
"""
|
||||
|
||||
|
||||
def _get_java_major_version(java_exe: str) -> int | None:
|
||||
"""Returns the detected Java major version (e.g. 21) or ``None`` if detection fails.
|
||||
|
||||
:param java_exe: path to the ``java`` executable.
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[java_exe, "-version"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=15,
|
||||
check=False,
|
||||
)
|
||||
except (OSError, subprocess.TimeoutExpired) as exc:
|
||||
log.warning("Failed to invoke '%s -version': %s", java_exe, exc)
|
||||
return None
|
||||
|
||||
output = (result.stderr or "") + "\n" + (result.stdout or "")
|
||||
# modern JDKs print: openjdk version "21.0.2" 2024-01-16
|
||||
# legacy JDKs print: java version "1.8.0_402" (major = 8)
|
||||
m = re.search(r'version "(\d+)(?:\.(\d+))?', output)
|
||||
if not m:
|
||||
log.warning("Could not parse Java version from output of '%s -version': %s", java_exe, output.strip()[:200])
|
||||
return None
|
||||
|
||||
first = int(m.group(1))
|
||||
if first == 1 and m.group(2):
|
||||
return int(m.group(2)) # 1.8 -> 8
|
||||
return first
|
||||
|
||||
|
||||
def _verify_java_available() -> None:
|
||||
"""Ensures a suitable ``java`` (>= :data:`BSL_LS_MIN_JAVA_VERSION`) is on ``PATH``.
|
||||
|
||||
:raises RuntimeError: if ``java`` is missing or its major version is too low.
|
||||
"""
|
||||
java_exe = shutil.which("java")
|
||||
if java_exe is None:
|
||||
raise RuntimeError(f"Java {BSL_LS_MIN_JAVA_VERSION}+ is required for BSL Language Server but 'java' was not found on PATH.")
|
||||
|
||||
major = _get_java_major_version(java_exe)
|
||||
if major is None:
|
||||
# detection failed; log a warning but let the LSP attempt to start
|
||||
log.warning("Could not determine Java version for '%s'; BSL LSP requires Java %d+.", java_exe, BSL_LS_MIN_JAVA_VERSION)
|
||||
return
|
||||
|
||||
if major < BSL_LS_MIN_JAVA_VERSION:
|
||||
raise RuntimeError(
|
||||
f"Java {BSL_LS_MIN_JAVA_VERSION}+ is required for BSL Language Server, but '{java_exe}' is Java {major}. "
|
||||
f"Install a newer JDK (e.g. Temurin {BSL_LS_MIN_JAVA_VERSION}) and ensure it appears first on PATH "
|
||||
f"or point JAVA_HOME to it."
|
||||
)
|
||||
|
||||
|
||||
class BSLLanguageServer(SolidLanguageServer):
|
||||
"""
|
||||
BSL (1C:Enterprise / OneScript) language server integration for Serena.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
config: LanguageServerConfig,
|
||||
repository_root_path: str,
|
||||
solidlsp_settings: SolidLSPSettings,
|
||||
):
|
||||
super().__init__(
|
||||
config,
|
||||
repository_root_path,
|
||||
None,
|
||||
"bsl",
|
||||
solidlsp_settings,
|
||||
)
|
||||
self.server_ready = threading.Event()
|
||||
|
||||
def _create_dependency_provider(self) -> LanguageServerDependencyProvider:
|
||||
return self.DependencyProvider(self._custom_settings, self._ls_resources_dir)
|
||||
|
||||
class DependencyProvider(LanguageServerDependencyProviderSinglePath):
|
||||
def _get_or_install_core_dependency(self) -> str:
|
||||
# resolve target version; custom versions intentionally skip SHA verification below
|
||||
bsl_version = self._custom_settings.get("bsl_ls_version", DEFAULT_BSL_LS_VERSION)
|
||||
user_overrode_version = bsl_version != DEFAULT_BSL_LS_VERSION
|
||||
|
||||
jar_dir = os.path.join(self._ls_resources_dir, f"bsl-ls-{bsl_version}")
|
||||
jar_path = os.path.join(jar_dir, f"bsl-language-server-{bsl_version}-exec.jar")
|
||||
|
||||
# download only when the versioned JAR is missing
|
||||
if not os.path.exists(jar_path):
|
||||
jar_url = (
|
||||
f"https://github.com/1c-syntax/bsl-language-server/releases/download/"
|
||||
f"v{bsl_version}/bsl-language-server-{bsl_version}-exec.jar"
|
||||
)
|
||||
expected_sha256 = None if user_overrode_version else BSL_LS_JAR_SHA256_BY_VERSION.get(bsl_version)
|
||||
|
||||
deps = RuntimeDependencyCollection(
|
||||
[
|
||||
RuntimeDependency(
|
||||
id="bsl-language-server",
|
||||
description="BSL Language Server JAR by 1c-syntax",
|
||||
url=jar_url,
|
||||
sha256=expected_sha256,
|
||||
archive_type="binary",
|
||||
binary_name=f"bsl-language-server-{bsl_version}-exec.jar",
|
||||
platform_id="any",
|
||||
),
|
||||
]
|
||||
)
|
||||
deps.install(jar_dir)
|
||||
|
||||
if not os.path.exists(jar_path):
|
||||
raise FileNotFoundError(f"BSL Language Server JAR not found at {jar_path} after installation.")
|
||||
|
||||
log.info(f"Using BSL Language Server v{bsl_version} at {jar_path}")
|
||||
return jar_path
|
||||
|
||||
def _create_launch_command(self, core_path: str) -> list[str]:
|
||||
# Java availability+version is required for both managed installs and user-provided jars (ls_path)
|
||||
_verify_java_available()
|
||||
return ["java", "-jar", core_path]
|
||||
|
||||
@staticmethod
|
||||
def _get_initialize_params(repository_absolute_path: str) -> InitializeParams:
|
||||
root_uri = pathlib.Path(repository_absolute_path).as_uri()
|
||||
return { # type: ignore[return-value]
|
||||
"locale": "en",
|
||||
"capabilities": {
|
||||
"textDocument": {
|
||||
"synchronization": {"didSave": True, "dynamicRegistration": True},
|
||||
"definition": {"dynamicRegistration": True},
|
||||
"references": {"dynamicRegistration": True},
|
||||
"documentSymbol": {
|
||||
"dynamicRegistration": True,
|
||||
"hierarchicalDocumentSymbolSupport": True,
|
||||
"symbolKind": {"valueSet": list(range(1, 27))}, # type: ignore
|
||||
},
|
||||
"hover": {"dynamicRegistration": True, "contentFormat": ["markdown", "plaintext"]}, # type: ignore
|
||||
"rename": {"dynamicRegistration": True, "prepareSupport": True},
|
||||
},
|
||||
"workspace": {
|
||||
"workspaceFolders": True,
|
||||
"didChangeConfiguration": {"dynamicRegistration": True},
|
||||
"symbol": {"dynamicRegistration": True},
|
||||
},
|
||||
},
|
||||
"processId": os.getpid(),
|
||||
"rootPath": repository_absolute_path,
|
||||
"rootUri": root_uri,
|
||||
"workspaceFolders": [
|
||||
{"uri": root_uri, "name": os.path.basename(repository_absolute_path)},
|
||||
],
|
||||
}
|
||||
|
||||
def _start_server(self) -> None:
|
||||
def window_log_message(msg: dict) -> None:
|
||||
log.info("BSL LSP: %s", msg.get("message", ""))
|
||||
|
||||
def do_nothing(_: dict) -> None:
|
||||
return
|
||||
|
||||
self.server.on_notification("window/logMessage", window_log_message)
|
||||
self.server.on_notification("$/progress", do_nothing)
|
||||
self.server.on_notification("textDocument/publishDiagnostics", do_nothing)
|
||||
self.server.on_request(
|
||||
"client/registerCapability",
|
||||
lambda params: None,
|
||||
)
|
||||
|
||||
log.info("Starting BSL language server process")
|
||||
self.server.start()
|
||||
|
||||
init_params = self._get_initialize_params(self.repository_root_path)
|
||||
init_response = self.server.send.initialize(init_params)
|
||||
log.debug("BSL LSP initialize response: %s", init_response)
|
||||
|
||||
assert "capabilities" in init_response, "BSL LSP did not return capabilities"
|
||||
|
||||
self.server.notify.initialized({})
|
||||
self.server_ready.set()
|
||||
@@ -110,6 +110,11 @@ class Language(str, Enum):
|
||||
Uses a custom LSP server based on pygls. Automatically sets up
|
||||
a virtual environment with pygls dependencies on first use.
|
||||
"""
|
||||
BSL = "bsl"
|
||||
"""BSL Language Server for 1C:Enterprise and OneScript languages.
|
||||
Uses bsl-language-server by 1c-syntax. Automatically downloads the JAR.
|
||||
Supports .bsl and .os files. Requires Java 21+ on PATH.
|
||||
"""
|
||||
ADA = "ada"
|
||||
"""Ada / SPARK language server using AdaCore's Ada Language Server (ALS).
|
||||
Supports .ads (specs), .adb (bodies), and .ada files. Auto-downloads the
|
||||
@@ -463,6 +468,8 @@ class Language(str, Enum):
|
||||
return FilenameMatcher(".yaml", ".yml")
|
||||
case self.MSL:
|
||||
return FilenameMatcher(".mrc")
|
||||
case self.BSL:
|
||||
return FilenameMatcher(".bsl", ".os")
|
||||
case self.ADA:
|
||||
return FilenameMatcher(".ads", ".adb", ".ada", case_sensitive=False)
|
||||
case self.HTML:
|
||||
@@ -515,7 +522,7 @@ class Language(str, Enum):
|
||||
|
||||
return CSharpLanguageServer
|
||||
case self.CSHARP_OMNISHARP:
|
||||
from solidlsp.language_servers.omnisharp import OmniSharp
|
||||
from solidlsp.language_servers.omnisharp import OmniSharp # type: ignore[attr-defined]
|
||||
|
||||
return OmniSharp
|
||||
case self.TYPESCRIPT:
|
||||
@@ -712,6 +719,10 @@ class Language(str, Enum):
|
||||
from solidlsp.language_servers.msl_language_server import MslLanguageServer
|
||||
|
||||
return MslLanguageServer
|
||||
case self.BSL:
|
||||
from solidlsp.language_servers.bsl_language_server import BSLLanguageServer
|
||||
|
||||
return BSLLanguageServer
|
||||
case self.ADA:
|
||||
from solidlsp.language_servers.ada_language_server import AdaLanguageServer
|
||||
|
||||
|
||||
@@ -278,6 +278,10 @@ _LANGUAGE_PYTEST_MARKERS: dict[Language, list[MarkDecorator | Mark]] = {
|
||||
Language.PYTHON_TY: [pytest.mark.python],
|
||||
Language.RUST: [pytest.mark.rust],
|
||||
Language.TYPESCRIPT: [pytest.mark.typescript],
|
||||
Language.BSL: [
|
||||
pytest.mark.bsl,
|
||||
pytest.mark.skipif(_sh.which("java") is None, reason="Java is not installed"),
|
||||
],
|
||||
Language.ANGULAR: [pytest.mark.angular],
|
||||
Language.HTML: [pytest.mark.html],
|
||||
Language.SCSS: [pytest.mark.scss],
|
||||
@@ -331,6 +335,10 @@ def _determine_disabled_languages() -> list[Language]:
|
||||
if not al_tests_enabled:
|
||||
result.append(Language.AL)
|
||||
|
||||
# Disable BSL tests only when Java is not available (Java IS present in CI via actions/setup-java)
|
||||
if _sh.which("java") is None:
|
||||
result.append(Language.BSL)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"language": "ru",
|
||||
"diagnosticLanguage": "ru",
|
||||
"computeDiagnostics": "onSave"
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1,14 @@
|
||||
// CommonModule.bsl - common module with reusable procedures
|
||||
|
||||
Процедура ВывестиСообщение(Текст) Экспорт
|
||||
Сообщить(Текст);
|
||||
КонецПроцедуры
|
||||
|
||||
Функция ПолучитьПриветствие(Имя) Экспорт
|
||||
Возврат "Привет, " + Имя + "!";
|
||||
КонецФункции
|
||||
|
||||
Процедура ВызватьПриветствие() Экспорт
|
||||
Сообщение = ПолучитьПриветствие("Мир");
|
||||
ВывестиСообщение(Сообщение);
|
||||
КонецПроцедуры
|
||||
@@ -0,0 +1,12 @@
|
||||
// ObjectModule.bsl - object module example
|
||||
|
||||
Перем ВнутреннееСостояние;
|
||||
|
||||
Процедура Инициализировать() Экспорт
|
||||
ВнутреннееСостояние = "ready";
|
||||
ВывестиСообщение("Объект инициализирован");
|
||||
КонецПроцедуры
|
||||
|
||||
Функция ПолучитьСостояние() Экспорт
|
||||
Возврат ВнутреннееСостояние;
|
||||
КонецФункции
|
||||
@@ -0,0 +1,6 @@
|
||||
// diagnostics_sample.bsl — намеренно сломанный файл для проверки диагностик BSL LS.
|
||||
// Содержит синтаксическую ошибку (незакрытая строка), которую bsl-language-server гарантированно флагнет.
|
||||
|
||||
Процедура СломаннаяПроцедура() Экспорт
|
||||
Текст = "незакрытая строка;
|
||||
КонецПроцедуры
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.20">
|
||||
<CommonModule uuid="e63ad502-3c78-4345-97f7-b72ac549ddf2">
|
||||
<Properties>
|
||||
<Name>ОбщийМодуль1</Name>
|
||||
<Synonym/>
|
||||
<Comment/>
|
||||
<Global>false</Global>
|
||||
<ClientManagedApplication>false</ClientManagedApplication>
|
||||
<Server>true</Server>
|
||||
<ExternalConnection>true</ExternalConnection>
|
||||
<ClientOrdinaryApplication>false</ClientOrdinaryApplication>
|
||||
<ServerCall>true</ServerCall>
|
||||
<Privileged>false</Privileged>
|
||||
<ReturnValuesReuse>DontUse</ReturnValuesReuse>
|
||||
</Properties>
|
||||
</CommonModule>
|
||||
</MetaDataObject>
|
||||
@@ -0,0 +1,5 @@
|
||||
// CommonModule1 — shared helpers called from other modules.
|
||||
|
||||
Процедура ВывестиСообщение(Текст) Экспорт
|
||||
Сообщить(Текст);
|
||||
КонецПроцедуры
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.20">
|
||||
<CommonModule uuid="814448ec-aec2-49d6-8d8a-79f49628493c">
|
||||
<Properties>
|
||||
<Name>ОбщийМодуль2</Name>
|
||||
<Synonym/>
|
||||
<Comment/>
|
||||
<Global>false</Global>
|
||||
<ClientManagedApplication>false</ClientManagedApplication>
|
||||
<Server>true</Server>
|
||||
<ExternalConnection>true</ExternalConnection>
|
||||
<ClientOrdinaryApplication>false</ClientOrdinaryApplication>
|
||||
<ServerCall>true</ServerCall>
|
||||
<Privileged>false</Privileged>
|
||||
<ReturnValuesReuse>DontUse</ReturnValuesReuse>
|
||||
</Properties>
|
||||
</CommonModule>
|
||||
</MetaDataObject>
|
||||
@@ -0,0 +1,5 @@
|
||||
// CommonModule2 — exercises a cross-module call into CommonModule1.
|
||||
|
||||
Процедура ПозватьМодуль1() Экспорт
|
||||
ОбщийМодуль1.ВывестиСообщение("Hello from CommonModule2");
|
||||
КонецПроцедуры
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ConfigDumpInfo xmlns="http://v8.1c.ru/8.3/xcf/dumpinfo" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" format="Hierarchical" version="2.20">
|
||||
<ConfigVersions>
|
||||
<Metadata name="CommonModule.ОбщийМодуль1" id="e63ad502-3c78-4345-97f7-b72ac549ddf2" configVersion="c6c95de4be61d045b57c6f7286f1d04d00000000"/>
|
||||
<Metadata name="CommonModule.ОбщийМодуль2" id="814448ec-aec2-49d6-8d8a-79f49628493c" configVersion="30bb706dbfabfa4b940bb6064997d47c00000000"/>
|
||||
<Metadata name="CommonModule.ОбщийМодуль2.Module" id="814448ec-aec2-49d6-8d8a-79f49628493c.0" configVersion="3d251b408205a64daf243988c6afcd4c00000000"/>
|
||||
<Metadata name="Configuration.Конфигурация" id="77dbe7df-5681-44a5-bb9e-bb8cb297021a" configVersion="8caf1d64045c77468d007c890e712a8100000000"/>
|
||||
<Metadata name="Language.Русский" id="e707122a-91c0-40f4-ae5a-46cbcd3ff534" configVersion="358e84df1ac94b4ba768fc864e827eb400000000"/>
|
||||
</ConfigVersions>
|
||||
</ConfigDumpInfo>
|
||||
@@ -0,0 +1,252 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.20">
|
||||
<Configuration uuid="77dbe7df-5681-44a5-bb9e-bb8cb297021a">
|
||||
<InternalInfo>
|
||||
<xr:ContainedObject>
|
||||
<xr:ClassId>9cd510cd-abfc-11d4-9434-004095e12fc7</xr:ClassId>
|
||||
<xr:ObjectId>f2bbb9be-74c9-40ac-a945-4b03d2624a80</xr:ObjectId>
|
||||
</xr:ContainedObject>
|
||||
<xr:ContainedObject>
|
||||
<xr:ClassId>9fcd25a0-4822-11d4-9414-008048da11f9</xr:ClassId>
|
||||
<xr:ObjectId>74c2c4b9-ca2e-4c29-9ac1-c9a686dffd48</xr:ObjectId>
|
||||
</xr:ContainedObject>
|
||||
<xr:ContainedObject>
|
||||
<xr:ClassId>e3687481-0a87-462c-a166-9f34594f9bba</xr:ClassId>
|
||||
<xr:ObjectId>e6d84959-ef42-417d-b585-89b178e2ebe4</xr:ObjectId>
|
||||
</xr:ContainedObject>
|
||||
<xr:ContainedObject>
|
||||
<xr:ClassId>9de14907-ec23-4a07-96f0-85521cb6b53b</xr:ClassId>
|
||||
<xr:ObjectId>bb344884-c3a2-4197-ad5d-7e6c391de24f</xr:ObjectId>
|
||||
</xr:ContainedObject>
|
||||
<xr:ContainedObject>
|
||||
<xr:ClassId>51f2d5d8-ea4d-4064-8892-82951750031e</xr:ClassId>
|
||||
<xr:ObjectId>4c2a3610-e746-47e5-a127-f6ef59fba16d</xr:ObjectId>
|
||||
</xr:ContainedObject>
|
||||
<xr:ContainedObject>
|
||||
<xr:ClassId>e68182ea-4237-4383-967f-90c1e3370bc7</xr:ClassId>
|
||||
<xr:ObjectId>f94ef4a2-9b6b-4ef7-8fc1-b69a351798cd</xr:ObjectId>
|
||||
</xr:ContainedObject>
|
||||
<xr:ContainedObject>
|
||||
<xr:ClassId>fb282519-d103-4dd3-bc12-cb271d631dfc</xr:ClassId>
|
||||
<xr:ObjectId>d1f9e184-8cf0-47a9-a487-22516bb66c8c</xr:ObjectId>
|
||||
</xr:ContainedObject>
|
||||
</InternalInfo>
|
||||
<Properties>
|
||||
<Name>Конфигурация</Name>
|
||||
<Synonym/>
|
||||
<Comment/>
|
||||
<NamePrefix/>
|
||||
<ConfigurationExtensionCompatibilityMode>Version8_3_27</ConfigurationExtensionCompatibilityMode>
|
||||
<DefaultRunMode>ManagedApplication</DefaultRunMode>
|
||||
<UsePurposes>
|
||||
<v8:Value xsi:type="app:ApplicationUsePurpose">PlatformApplication</v8:Value>
|
||||
</UsePurposes>
|
||||
<ScriptVariant>Russian</ScriptVariant>
|
||||
<DefaultRoles/>
|
||||
<Vendor/>
|
||||
<Version/>
|
||||
<UpdateCatalogAddress/>
|
||||
<IncludeHelpInContents>false</IncludeHelpInContents>
|
||||
<UseManagedFormInOrdinaryApplication>false</UseManagedFormInOrdinaryApplication>
|
||||
<UseOrdinaryFormInManagedApplication>false</UseOrdinaryFormInManagedApplication>
|
||||
<AdditionalFullTextSearchDictionaries/>
|
||||
<CommonSettingsStorage/>
|
||||
<ReportsUserSettingsStorage/>
|
||||
<ReportsVariantsStorage/>
|
||||
<FormDataSettingsStorage/>
|
||||
<DynamicListsUserSettingsStorage/>
|
||||
<URLExternalDataStorage/>
|
||||
<Content/>
|
||||
<DefaultReportForm/>
|
||||
<DefaultReportVariantForm/>
|
||||
<DefaultReportSettingsForm/>
|
||||
<DefaultReportAppearanceTemplate/>
|
||||
<DefaultDynamicListSettingsForm/>
|
||||
<DefaultSearchForm/>
|
||||
<DefaultDataHistoryChangeHistoryForm/>
|
||||
<DefaultDataHistoryVersionDataForm/>
|
||||
<DefaultDataHistoryVersionDifferencesForm/>
|
||||
<DefaultCollaborationSystemUsersChoiceForm/>
|
||||
<RequiredMobileApplicationPermissions/>
|
||||
<UsedMobileApplicationFunctionalities>
|
||||
<app:functionality>
|
||||
<app:functionality>Biometrics</app:functionality>
|
||||
<app:use>true</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>Location</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>BackgroundLocation</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>BluetoothPrinters</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>WiFiPrinters</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>Contacts</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>Calendars</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>PushNotifications</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>LocalNotifications</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>InAppPurchases</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>PersonalComputerFileExchange</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>Ads</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>NumberDialing</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>CallProcessing</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>CallLog</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>AutoSendSMS</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>ReceiveSMS</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>SMSLog</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>Camera</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>Microphone</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>MusicLibrary</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>PictureAndVideoLibraries</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>AudioPlaybackAndVibration</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>BackgroundAudioPlaybackAndVibration</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>InstallPackages</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>OSBackup</app:functionality>
|
||||
<app:use>true</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>ApplicationUsageStatistics</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>BarcodeScanning</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>BackgroundAudioRecording</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>AllFilesAccess</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>Videoconferences</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>NFC</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>DocumentScanning</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>SpeechToText</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>Geofences</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>IncomingShareRequests</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>AllIncomingShareRequestsTypesProcessing</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
<app:functionality>
|
||||
<app:functionality>TextToSpeech</app:functionality>
|
||||
<app:use>false</app:use>
|
||||
</app:functionality>
|
||||
</UsedMobileApplicationFunctionalities>
|
||||
<StandaloneConfigurationRestrictionRoles/>
|
||||
<MobileApplicationURLs/>
|
||||
<AllowedIncomingShareRequestTypes/>
|
||||
<MainClientApplicationWindowMode>Normal</MainClientApplicationWindowMode>
|
||||
<DefaultInterface/>
|
||||
<DefaultStyle/>
|
||||
<DefaultLanguage>Language.Русский</DefaultLanguage>
|
||||
<BriefInformation/>
|
||||
<DetailedInformation/>
|
||||
<Copyright/>
|
||||
<VendorInformationAddress/>
|
||||
<ConfigurationInformationAddress/>
|
||||
<DataLockControlMode>Managed</DataLockControlMode>
|
||||
<ObjectAutonumerationMode>NotAutoFree</ObjectAutonumerationMode>
|
||||
<ModalityUseMode>DontUse</ModalityUseMode>
|
||||
<SynchronousPlatformExtensionAndAddInCallUseMode>DontUse</SynchronousPlatformExtensionAndAddInCallUseMode>
|
||||
<InterfaceCompatibilityMode>Taxi</InterfaceCompatibilityMode>
|
||||
<DatabaseTablespacesUseMode>DontUse</DatabaseTablespacesUseMode>
|
||||
<CompatibilityMode>Version8_3_27</CompatibilityMode>
|
||||
<DefaultConstantsForm/>
|
||||
</Properties>
|
||||
<ChildObjects>
|
||||
<Language>Русский</Language>
|
||||
<CommonModule>ОбщийМодуль1</CommonModule>
|
||||
<CommonModule>ОбщийМодуль2</CommonModule>
|
||||
</ChildObjects>
|
||||
</Configuration>
|
||||
</MetaDataObject>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MetaDataObject xmlns="http://v8.1c.ru/8.3/MDClasses" xmlns:app="http://v8.1c.ru/8.2/managed-application/core" xmlns:cfg="http://v8.1c.ru/8.1/data/enterprise/current-config" xmlns:cmi="http://v8.1c.ru/8.2/managed-application/cmi" xmlns:ent="http://v8.1c.ru/8.1/data/enterprise" xmlns:lf="http://v8.1c.ru/8.2/managed-application/logform" xmlns:style="http://v8.1c.ru/8.1/data/ui/style" xmlns:sys="http://v8.1c.ru/8.1/data/ui/fonts/system" xmlns:v8="http://v8.1c.ru/8.1/data/core" xmlns:v8ui="http://v8.1c.ru/8.1/data/ui" xmlns:web="http://v8.1c.ru/8.1/data/ui/colors/web" xmlns:win="http://v8.1c.ru/8.1/data/ui/colors/windows" xmlns:xen="http://v8.1c.ru/8.3/xcf/enums" xmlns:xpr="http://v8.1c.ru/8.3/xcf/predef" xmlns:xr="http://v8.1c.ru/8.3/xcf/readable" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.20">
|
||||
<Language uuid="e707122a-91c0-40f4-ae5a-46cbcd3ff534">
|
||||
<Properties>
|
||||
<Name>Русский</Name>
|
||||
<Synonym>
|
||||
<v8:item>
|
||||
<v8:lang>ru</v8:lang>
|
||||
<v8:content>Русский</v8:content>
|
||||
</v8:item>
|
||||
</Synonym>
|
||||
<Comment/>
|
||||
<LanguageCode>ru</LanguageCode>
|
||||
</Properties>
|
||||
</Language>
|
||||
</MetaDataObject>
|
||||
Whitespace-only changes.
@@ -0,0 +1,269 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from solidlsp.ls_utils import SymbolUtils
|
||||
from solidlsp.settings import SolidLSPSettings
|
||||
from test.solidlsp.conftest import format_symbol_for_assert, has_malformed_name, request_all_symbols
|
||||
|
||||
|
||||
@pytest.mark.bsl
|
||||
class TestBSLLanguageServer:
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
@pytest.mark.parametrize("repo_path", [Language.BSL], indirect=True)
|
||||
def test_ls_is_running(self, language_server: SolidLanguageServer, repo_path: Path) -> None:
|
||||
"""Language server starts and attaches to the test repository."""
|
||||
assert language_server.is_running()
|
||||
assert Path(language_server.language_server.repository_root_path).resolve() == repo_path.resolve()
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
def test_find_symbol(self, language_server: SolidLanguageServer) -> None:
|
||||
symbols = language_server.request_full_symbol_tree()
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "ВывестиСообщение"), "ВывестиСообщение not found in symbol tree"
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "ПолучитьПриветствие"), "ПолучитьПриветствие not found in symbol tree"
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "Инициализировать"), "Инициализировать not found in symbol tree"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
def test_document_symbols(self, language_server: SolidLanguageServer) -> None:
|
||||
doc_symbols = language_server.request_document_symbols("CommonModule.bsl")
|
||||
all_symbols, _ = doc_symbols.get_all_symbols_and_roots()
|
||||
names = [s.get("name") for s in all_symbols if s.get("name")]
|
||||
assert "ВывестиСообщение" in names, f"ВывестиСообщение not found in CommonModule.bsl symbols. Found: {names}"
|
||||
assert "ПолучитьПриветствие" in names, f"ПолучитьПриветствие not found in CommonModule.bsl symbols. Found: {names}"
|
||||
assert "ВызватьПриветствие" in names, f"ВызватьПриветствие not found in CommonModule.bsl symbols. Found: {names}"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
def test_full_symbol_tree_within_file(self, language_server: SolidLanguageServer) -> None:
|
||||
"""Scoping the full-tree request to a single file returns that file's symbols."""
|
||||
symbols = language_server.request_full_symbol_tree(within_relative_path="ObjectModule.bsl")
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "Инициализировать"), (
|
||||
"Инициализировать not found in ObjectModule.bsl symbol tree"
|
||||
)
|
||||
assert SymbolUtils.symbol_tree_contains_name(symbols, "ПолучитьСостояние"), (
|
||||
"ПолучитьСостояние not found in ObjectModule.bsl symbol tree"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
def test_find_references_within_file(self, language_server: SolidLanguageServer) -> None:
|
||||
# CommonModule.bsl (0-indexed):
|
||||
# line 2: Процедура ВывестиСообщение(Текст) Экспорт <- declaration (name starts at col 10)
|
||||
# line 13: ВывестиСообщение(Сообщение); <- internal call
|
||||
# This test asserts within-file resolution on a bare ``.bsl`` file (no surrounding
|
||||
# 1C project metadata). Cross-module resolution is exercised separately via the
|
||||
# dedicated ``src/`` fixture in ``test_find_references_across_files`` below.
|
||||
refs = language_server.request_references("CommonModule.bsl", line=2, column=10)
|
||||
assert refs, "Expected at least one reference to ВывестиСообщение"
|
||||
file_names = [ref.get("relativePath", "") for ref in refs]
|
||||
assert any("CommonModule.bsl" in f for f in file_names), f"Expected self-reference in CommonModule.bsl, got: {file_names}"
|
||||
# the internal call is on line 13
|
||||
matching_lines = [ref["range"]["start"]["line"] for ref in refs if "CommonModule.bsl" in ref.get("relativePath", "")]
|
||||
assert 12 in matching_lines, f"Expected a reference on line 12 (0-indexed), got lines: {matching_lines}"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
def test_find_references_to_function_within_file(self, language_server: SolidLanguageServer) -> None:
|
||||
# CommonModule.bsl (0-indexed):
|
||||
# line 6: Функция ПолучитьПриветствие(Имя) Экспорт <- declaration (name starts at col 8)
|
||||
# line 12: Сообщение = ПолучитьПриветствие("Мир"); <- internal call at col 16
|
||||
refs = language_server.request_references("CommonModule.bsl", line=6, column=8)
|
||||
assert refs, "Expected at least one reference to ПолучитьПриветствие"
|
||||
matching_lines = [ref["range"]["start"]["line"] for ref in refs if "CommonModule.bsl" in ref.get("relativePath", "")]
|
||||
assert 11 in matching_lines, f"Expected a reference on line 11 (0-indexed), got lines: {matching_lines}"
|
||||
|
||||
# --- Cross-file reference resolution ---
|
||||
#
|
||||
# bsl-language-server links common modules across files only when the fixture ships
|
||||
# proper 1C Configuration metadata (``Configuration.xml`` + per-module ``.mdo`` /
|
||||
# ``Ext/Module.bsl`` layout). The ``src/`` subtree under the BSL test repo provides
|
||||
# a minimal-but-complete Designer-format dump for exactly this purpose. The two
|
||||
# tests below request references and the go-to-definition from the cross-module
|
||||
# call site ``ОбщийМодуль1.ВывестиСообщение(...)`` in ``ОбщийМодуль2``.
|
||||
|
||||
_CROSS_REF_MODULE1 = os.path.join("src", "CommonModules", "ОбщийМодуль1", "Ext", "Module.bsl")
|
||||
_CROSS_REF_MODULE2 = os.path.join("src", "CommonModules", "ОбщийМодуль2", "Ext", "Module.bsl")
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
def test_find_references_across_files(self, language_server: SolidLanguageServer) -> None:
|
||||
"""``request_references`` from the declaration must include the cross-module call-site."""
|
||||
# ОбщийМодуль1 / Ext / Module.bsl (0-indexed):
|
||||
# line 2: Процедура ВывестиСообщение(Текст) Экспорт <- declaration (name at col 10)
|
||||
# ОбщийМодуль2 / Ext / Module.bsl (0-indexed):
|
||||
# line 3: ОбщийМодуль1.ВывестиСообщение("Hello from CommonModule2"); <- cross-module call (col 17)
|
||||
refs = language_server.request_references(self._CROSS_REF_MODULE1, line=2, column=10)
|
||||
assert refs, "Expected at least one reference to ВывестиСообщение across modules"
|
||||
call_site_paths = [ref.get("relativePath", "") for ref in refs if "ОбщийМодуль2" in ref.get("relativePath", "")]
|
||||
assert call_site_paths, (
|
||||
f"Expected a cross-module reference from ОбщийМодуль2, got relativePaths: {[ref.get('relativePath', '') for ref in refs]}"
|
||||
)
|
||||
call_site_lines = [ref["range"]["start"]["line"] for ref in refs if "ОбщийМодуль2" in ref.get("relativePath", "")]
|
||||
assert 3 in call_site_lines, f"Expected a reference at ОбщийМодуль2/Module.bsl line 3, got lines: {call_site_lines}"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
def test_find_definition_across_files(self, language_server: SolidLanguageServer) -> None:
|
||||
"""``request_definition`` from a cross-module call-site must resolve to the other module."""
|
||||
# cursor on "ВывестиСообщение" inside
|
||||
# ОбщийМодуль1.ВывестиСообщение("Hello from CommonModule2"); (line 3, col 17 — 0-indexed)
|
||||
definitions = language_server.request_definition(self._CROSS_REF_MODULE2, line=3, column=17)
|
||||
assert definitions, "Expected a cross-module definition for ВывестиСообщение"
|
||||
target_paths = [d.get("relativePath", "") for d in definitions]
|
||||
assert any("ОбщийМодуль1" in p for p in target_paths), f"Expected definition to resolve to ОбщийМодуль1, got: {target_paths}"
|
||||
target_lines = [d["range"]["start"]["line"] for d in definitions if "ОбщийМодуль1" in d.get("relativePath", "")]
|
||||
assert 2 in target_lines, f"Expected the definition to point at ОбщийМодуль1/Module.bsl line 2, got: {target_lines}"
|
||||
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
def test_bare_symbol_names(self, language_server: SolidLanguageServer) -> None:
|
||||
all_symbols = request_all_symbols(language_server)
|
||||
malformed = [s for s in all_symbols if has_malformed_name(s)]
|
||||
if malformed:
|
||||
pytest.fail(
|
||||
f"Found malformed symbols: {[format_symbol_for_assert(s) for s in malformed]}",
|
||||
pytrace=False,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Unit tests — no language server needed, always run regardless of Java
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_bsl_filename_matcher() -> None:
|
||||
matcher = Language.BSL.get_source_fn_matcher()
|
||||
assert matcher.is_relevant_filename("module.bsl")
|
||||
assert matcher.is_relevant_filename("script.os")
|
||||
assert not matcher.is_relevant_filename("module.py")
|
||||
|
||||
|
||||
def test_bsl_enum_registration() -> None:
|
||||
assert Language.BSL.value == "bsl"
|
||||
assert Language.BSL.get_ls_class().__name__ == "BSLLanguageServer"
|
||||
|
||||
|
||||
def test_bsl_dependency_provider_default_version() -> None:
|
||||
"""DependencyProvider resolves the default version to the expected versioned JAR path."""
|
||||
from solidlsp.language_servers.bsl_language_server import (
|
||||
DEFAULT_BSL_LS_VERSION,
|
||||
BSLLanguageServer,
|
||||
)
|
||||
|
||||
settings = SolidLSPSettings()
|
||||
provider = BSLLanguageServer.DependencyProvider(
|
||||
settings.get_ls_specific_settings(Language.BSL),
|
||||
"/tmp/ls_resources",
|
||||
)
|
||||
|
||||
expected_version = DEFAULT_BSL_LS_VERSION
|
||||
expected_jar_dir = os.path.join("/tmp/ls_resources", f"bsl-ls-{expected_version}")
|
||||
expected_jar_path = os.path.join(expected_jar_dir, f"bsl-language-server-{expected_version}-exec.jar")
|
||||
|
||||
# pretend JAR is already on disk so no download is attempted
|
||||
with mock.patch("os.path.exists", return_value=True):
|
||||
jar_path = provider._get_or_install_core_dependency()
|
||||
|
||||
assert jar_path == expected_jar_path
|
||||
|
||||
|
||||
def test_bsl_dependency_provider_custom_version_no_sha() -> None:
|
||||
"""User-overridden versions must install without SHA256 verification."""
|
||||
from solidlsp.language_servers.bsl_language_server import BSLLanguageServer
|
||||
from solidlsp.language_servers.common import RuntimeDependencyCollection
|
||||
|
||||
settings = SolidLSPSettings()
|
||||
settings.ls_specific_settings[Language.BSL] = {"bsl_ls_version": "0.28.0"}
|
||||
provider = BSLLanguageServer.DependencyProvider(
|
||||
settings.get_ls_specific_settings(Language.BSL),
|
||||
"/tmp/ls_resources",
|
||||
)
|
||||
|
||||
custom_version = "0.28.0"
|
||||
expected_jar_dir = os.path.join("/tmp/ls_resources", f"bsl-ls-{custom_version}")
|
||||
expected_jar_path = os.path.join(expected_jar_dir, f"bsl-language-server-{custom_version}-exec.jar")
|
||||
|
||||
installed_deps = []
|
||||
|
||||
def fake_install(self_inner, install_dir):
|
||||
installed_deps.extend(self_inner.get_dependencies_for_current_platform())
|
||||
os.makedirs(install_dir, exist_ok=True)
|
||||
open(expected_jar_path, "w").close()
|
||||
|
||||
with mock.patch.object(RuntimeDependencyCollection, "install", fake_install):
|
||||
jar_path = provider._get_or_install_core_dependency()
|
||||
|
||||
assert jar_path == expected_jar_path
|
||||
assert len(installed_deps) == 1
|
||||
assert installed_deps[0].sha256 is None, "SHA256 must be None for user-overridden version"
|
||||
|
||||
if os.path.exists(expected_jar_path):
|
||||
os.remove(expected_jar_path)
|
||||
if os.path.exists(expected_jar_dir):
|
||||
os.rmdir(expected_jar_dir)
|
||||
|
||||
|
||||
def test_bsl_launch_command_uses_ls_path_without_download() -> None:
|
||||
"""
|
||||
When ``ls_path`` is set, the public launch-command flow must return the user's JAR
|
||||
unchanged and must NOT invoke the download / install path. This covers the real
|
||||
code path used at runtime (``create_launch_command``), not just private helpers.
|
||||
"""
|
||||
from solidlsp.language_servers import bsl_language_server
|
||||
from solidlsp.language_servers.bsl_language_server import BSLLanguageServer
|
||||
|
||||
settings = SolidLSPSettings()
|
||||
settings.ls_specific_settings[Language.BSL] = {"ls_path": "/custom/path/bsl-language-server.jar"}
|
||||
provider = BSLLanguageServer.DependencyProvider(
|
||||
settings.get_ls_specific_settings(Language.BSL),
|
||||
"/tmp/ls_resources",
|
||||
)
|
||||
|
||||
with (
|
||||
mock.patch.object(bsl_language_server.shutil, "which", return_value="/usr/bin/java"),
|
||||
mock.patch.object(bsl_language_server, "_get_java_major_version", return_value=21),
|
||||
mock.patch.object(
|
||||
BSLLanguageServer.DependencyProvider,
|
||||
"_get_or_install_core_dependency",
|
||||
side_effect=AssertionError("must not be called when ls_path is provided"),
|
||||
) as install_mock,
|
||||
):
|
||||
cmd = provider.create_launch_command()
|
||||
|
||||
assert cmd == ["java", "-jar", "/custom/path/bsl-language-server.jar"]
|
||||
install_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_bsl_launch_command_requires_java() -> None:
|
||||
"""Launch command construction must fail fast when Java is missing."""
|
||||
from solidlsp.language_servers import bsl_language_server
|
||||
from solidlsp.language_servers.bsl_language_server import BSLLanguageServer
|
||||
|
||||
settings = SolidLSPSettings()
|
||||
settings.ls_specific_settings[Language.BSL] = {"ls_path": "/custom/path/bsl-language-server.jar"}
|
||||
provider = BSLLanguageServer.DependencyProvider(
|
||||
settings.get_ls_specific_settings(Language.BSL),
|
||||
"/tmp/ls_resources",
|
||||
)
|
||||
|
||||
with mock.patch.object(bsl_language_server.shutil, "which", return_value=None):
|
||||
with pytest.raises(RuntimeError, match="not found on PATH"):
|
||||
provider.create_launch_command()
|
||||
|
||||
|
||||
def test_bsl_launch_command_rejects_old_java() -> None:
|
||||
"""Java older than the minimum supported major version must be rejected up front."""
|
||||
from solidlsp.language_servers import bsl_language_server
|
||||
from solidlsp.language_servers.bsl_language_server import BSL_LS_MIN_JAVA_VERSION, BSLLanguageServer
|
||||
|
||||
settings = SolidLSPSettings()
|
||||
settings.ls_specific_settings[Language.BSL] = {"ls_path": "/custom/path/bsl-language-server.jar"}
|
||||
provider = BSLLanguageServer.DependencyProvider(
|
||||
settings.get_ls_specific_settings(Language.BSL),
|
||||
"/tmp/ls_resources",
|
||||
)
|
||||
|
||||
with (
|
||||
mock.patch.object(bsl_language_server.shutil, "which", return_value="/usr/bin/java"),
|
||||
mock.patch.object(bsl_language_server, "_get_java_major_version", return_value=BSL_LS_MIN_JAVA_VERSION - 1),
|
||||
):
|
||||
with pytest.raises(RuntimeError, match=f"Java {BSL_LS_MIN_JAVA_VERSION}\\+"):
|
||||
provider.create_launch_command()
|
||||
@@ -0,0 +1,21 @@
|
||||
import shutil
|
||||
|
||||
import pytest
|
||||
|
||||
from solidlsp import SolidLanguageServer
|
||||
from solidlsp.ls_config import Language
|
||||
from test.solidlsp.util.diagnostics import assert_file_diagnostics
|
||||
|
||||
|
||||
@pytest.mark.bsl
|
||||
@pytest.mark.skipif(shutil.which("java") is None, reason="Java 21+ is required for BSL LSP")
|
||||
class TestBSLDiagnostics:
|
||||
@pytest.mark.parametrize("language_server", [Language.BSL], indirect=True)
|
||||
def test_file_diagnostics(self, language_server: SolidLanguageServer) -> None:
|
||||
"""bsl-language-server must flag the unterminated string literal in the fixture."""
|
||||
assert_file_diagnostics(
|
||||
language_server,
|
||||
"diagnostics_sample.bsl",
|
||||
(),
|
||||
min_count=1,
|
||||
)
|
||||
Reference in new issue
Block a user