diff --git a/src/serena/cli.py b/src/serena/cli.py index 457b3acb..9927390c 100644 --- a/src/serena/cli.py +++ b/src/serena/cli.py @@ -31,6 +31,7 @@ from serena.project import Project from serena.tools import ToolRegistry from serena.util.logging import MemoryLogHandler from solidlsp.ls_config import Language +from solidlsp.util.subprocess_util import subprocess_kwargs log = logging.getLogger(__name__) @@ -40,18 +41,19 @@ log = logging.getLogger(__name__) def _open_in_editor(path: str) -> None: """Open the given file in the system's default editor or viewer.""" editor = os.environ.get("EDITOR") + run_kwargs = subprocess_kwargs() try: if editor: - subprocess.run([editor, path], check=False) + subprocess.run([editor, path], check=False, **run_kwargs) elif sys.platform.startswith("win"): try: os.startfile(path) except OSError: - subprocess.run(["notepad.exe", path], check=False) + subprocess.run(["notepad.exe", path], check=False, **run_kwargs) elif sys.platform == "darwin": - subprocess.run(["open", path], check=False) + subprocess.run(["open", path], check=False, **run_kwargs) else: - subprocess.run(["xdg-open", path], check=False) + subprocess.run(["xdg-open", path], check=False, **run_kwargs) except Exception as e: print(f"Failed to open {path}: {e}") diff --git a/src/serena/util/shell.py b/src/serena/util/shell.py index c899b212..59bc006f 100644 --- a/src/serena/util/shell.py +++ b/src/serena/util/shell.py @@ -4,6 +4,8 @@ import subprocess from pydantic import BaseModel +from solidlsp.util.subprocess_util import subprocess_kwargs + class ShellCommandResult(BaseModel): stdout: str @@ -36,6 +38,7 @@ def execute_shell_command(command: str, cwd: str | None = None, capture_stderr: encoding="utf-8", errors="replace", cwd=cwd, + **subprocess_kwargs(), ) stdout, stderr = process.communicate() @@ -43,15 +46,7 @@ def execute_shell_command(command: str, cwd: str | None = None, capture_stderr: def subprocess_check_output(args: list[str], encoding: str = "utf-8", strip: bool = True, timeout: float | None = None) -> str: - kwargs = { - "stdin": subprocess.DEVNULL, - "stderr": subprocess.PIPE, - "timeout": timeout, - "env": os.environ.copy(), - } - if platform.system() == "Windows": - kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW # type: ignore - output = subprocess.check_output(args, **kwargs).decode(encoding) # type: ignore + output = subprocess.check_output(args, stdin=subprocess.DEVNULL, stderr=subprocess.PIPE, timeout=timeout, env=os.environ.copy(), **subprocess_kwargs()).decode(encoding) # type: ignore if strip: output = output.strip() return output diff --git a/src/solidlsp/language_servers/common.py b/src/solidlsp/language_servers/common.py index 1587d0a9..4a1fa865 100644 --- a/src/solidlsp/language_servers/common.py +++ b/src/solidlsp/language_servers/common.py @@ -9,6 +9,7 @@ from dataclasses import dataclass from solidlsp.ls_logger import LanguageServerLogger from solidlsp.ls_utils import FileUtils, PlatformUtils +from solidlsp.util.subprocess_util import subprocess_kwargs log = logging.getLogger(__name__) @@ -73,10 +74,8 @@ class RuntimeDependencyCollection: @staticmethod def _run_command(command: str | list[str], cwd: str) -> None: - kwargs = {} - if PlatformUtils.get_platform_id().is_windows(): - kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW # type: ignore - else: + kwargs = subprocess_kwargs() + if not PlatformUtils.get_platform_id().is_windows(): import pwd kwargs["user"] = pwd.getpwuid(os.getuid()).pw_name diff --git a/src/solidlsp/ls_handler.py b/src/solidlsp/ls_handler.py index 6a994ed3..f81dde53 100644 --- a/src/solidlsp/ls_handler.py +++ b/src/solidlsp/ls_handler.py @@ -32,6 +32,7 @@ from solidlsp.lsp_protocol_handler.server import ( make_request, make_response, ) +from solidlsp.util.subprocess_util import subprocess_kwargs log = logging.getLogger(__name__) @@ -181,6 +182,8 @@ class SolidLanguageServerHandler: # on Linux/macOS cmd = " ".join(cmd) log.info("Starting language server process via command: %s", self.process_launch_info.cmd) + kwargs = subprocess_kwargs() + kwargs["start_new_session"] = self.start_independent_lsp_process self.process = subprocess.Popen( cmd, stdout=subprocess.PIPE, @@ -188,8 +191,8 @@ class SolidLanguageServerHandler: stderr=subprocess.PIPE, env=child_proc_env, cwd=self.process_launch_info.cwd, - start_new_session=self.start_independent_lsp_process, shell=True, + **kwargs, ) # Check if process terminated immediately diff --git a/src/solidlsp/util/subprocess_util.py b/src/solidlsp/util/subprocess_util.py new file mode 100644 index 00000000..ac6a4e2b --- /dev/null +++ b/src/solidlsp/util/subprocess_util.py @@ -0,0 +1,13 @@ +import platform +import subprocess + + +def subprocess_kwargs(): + """ + Returns a dictionary of keyword arguments for subprocess calls, adding platform-specific + flags that we want to use consistently. + """ + kwargs = {} + if platform.system() == "Windows": + kwargs["creationflags"] = subprocess.CREATE_NO_WINDOW # type: ignore + return kwargs