diff --git a/CHANGELOG.md b/CHANGELOG.md index df802ac9..5ba7a287 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Status of the `main` branch. Changes prior to the next official version change w - Allow `query_project` tool to access read-only tools that are not enabled in the current configuration - Fix: JetBrains mode prompt was not provided to agents; The mode is now treated as a (background) base mode in `ActiveModes` which reduces the surface for issues pertaining to custom handling of modes. + - Improve quoting/escaping of arguments in shell executions on Windows (via `oslex` dependency) * Language Servers: - `typescript_vts`: Add `initialization_options` setting in `ls_specific_settings.typescript_vts`. @@ -43,6 +44,9 @@ Status of the `main` branch. Changes prior to the next official version change w - Tray manager: Add NixOS-support for AppIndicator-based trays (e.g., most Wayland-trays) to the package in flake.nix. - Fix: Wait for the subprocess that opens the browser window, preventing zombie processes #1488 +Dependencies: + - Add dependency `oslex` + # v1.5.3 (2026-05-26) Add meta-data for the GitHub MCP registry diff --git a/pyproject.toml b/pyproject.toml index 9a03e553..ca221c0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,6 +51,7 @@ dependencies = [ "cryptography==46.0.7", "regex==2026.2.28", "pythonnet==3.1.0 ; sys_platform == 'win32'", + "oslex==2.0.0", ] diff --git a/src/solidlsp/util/subprocess_util.py b/src/solidlsp/util/subprocess_util.py index 9d13773a..579b856e 100644 --- a/src/solidlsp/util/subprocess_util.py +++ b/src/solidlsp/util/subprocess_util.py @@ -1,8 +1,8 @@ import logging import platform -import shlex import subprocess +import oslex import psutil log = logging.getLogger(__name__) @@ -19,17 +19,16 @@ def subprocess_kwargs() -> dict: return kwargs -def convert_shell_cmd(cmd: str | list[str]) -> str | list[str]: +def convert_shell_cmd(cmd: str | list[str]) -> str: """ - Converts a command (specified as a list or string) to a format supported by subprocess calls with shell=True on the current platform. - List format must be converted to string format on POSIX systems, quoting arguments appropriately, - while it can be used as-is on Windows. + Converts a command (specified as a list or string) to a format supported by subprocess calls with shell=True on the current platform, + applying necessary escaping and quoting if the command is specified as a list of arguments. :param cmd: the command to convert, specified as a list of arguments :return: a suitable representation of the command for subprocess calls on the current platform """ - if isinstance(cmd, list) and platform.system() != "Windows": - return " ".join(shlex.quote(arg) for arg in cmd) + if isinstance(cmd, list): + return oslex.join(cmd) else: return cmd diff --git a/uv.lock b/uv.lock index 0f97a31d..bcaa24da 100644 --- a/uv.lock +++ b/uv.lock @@ -1466,6 +1466,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/f2/08ace4142eb281c12701fc3b93a10795e4d4dc7f753911d836675050f886/msgpack-1.1.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d99ef64f349d5ec3293688e91486c5fdb925ed03807f64d98d205d2713c60b46", size = 70868, upload-time = "2025-10-08T09:15:44.959Z" }, ] +[[package]] +name = "mslex" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/97/7022667073c99a0fe028f2e34b9bf76b49a611afd21b02527fbfd92d4cd5/mslex-1.3.0.tar.gz", hash = "sha256:641c887d1d3db610eee2af37a8e5abda3f70b3006cdfd2d0d29dc0d1ae28a85d", size = 11583, upload-time = "2024-10-16T13:16:18.523Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/f2/66bd65ca0139675a0d7b18f0bada6e12b51a984e41a76dbe44761bf1b3ee/mslex-1.3.0-py3-none-any.whl", hash = "sha256:c7074b347201b3466fc077c5692fbce9b5f62a63a51f537a53fbbd02eff2eea4", size = 7820, upload-time = "2024-10-16T13:16:17.566Z" }, +] + [[package]] name = "mypy" version = "1.17.0" @@ -1594,6 +1603,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, ] +[[package]] +name = "oslex" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mslex" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/24/19/b74ea9590378a35014acf72f221e84c5980aa7531d1852ef961764e7d3a6/oslex-2.0.0.tar.gz", hash = "sha256:30d9f4a7201bdce3ab7d9cfc0f9ee9e18c423b2b1d1668141b0dd3594b368ffe", size = 23942, upload-time = "2026-05-10T21:22:36.627Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b1/d1/3c0bad919598c4216944934db565ed9834ad5b792e1b5e67e911bb2976d2/oslex-2.0.0-py3-none-any.whl", hash = "sha256:f1c2944072aafcb06b6ee8a6c018d9ebb8a7f43d7cf0b6630b4f5d7be45f6ae4", size = 5905, upload-time = "2026-05-10T21:22:37.514Z" }, +] + [[package]] name = "overrides" version = "7.7.0" @@ -2827,6 +2848,7 @@ dependencies = [ { name = "joblib" }, { name = "lsprotocol" }, { name = "mcp" }, + { name = "oslex" }, { name = "overrides" }, { name = "pathspec" }, { name = "psutil" }, @@ -2900,6 +2922,7 @@ requires-dist = [ { name = "lsprotocol", specifier = "==2025.0.0" }, { name = "mcp", specifier = "==1.27.0" }, { name = "mypy", marker = "extra == 'dev'", specifier = "==1.17.0" }, + { name = "oslex", specifier = "==2.0.0" }, { name = "overrides", specifier = "==7.7.0" }, { name = "pathspec", specifier = "==0.12.1" }, { name = "poethepoet", marker = "extra == 'dev'", specifier = "==0.36.0" },