diff --git a/plugin/commands/console_loggings.py b/plugin/commands/console_loggings.py index c636d54..de0efc6 100644 --- a/plugin/commands/console_loggings.py +++ b/plugin/commands/console_loggings.py @@ -2,45 +2,51 @@ from abc import ABC from collections.abc import Callable +from functools import cached_property import sublime import sublime_plugin class AbstractToggleConsoleLoggingCommand(sublime_plugin.ApplicationCommand, ABC): - @property - def logging_method_name(self) -> str: - # strips the leading "toggle_" from the command name - return self.name()[7:] + @cached_property + def logger_func_name(self) -> str: + """The logger function name in the `sublime` module. E.g., `"log_commands"`.""" + return self.name()[7:] # strips the leading "toggle_" from the command name - @property - def logging_method(self) -> Callable[..., None] | None: - return getattr(sublime, self.logging_method_name, None) + @cached_property + def logger_status_getter(self) -> Callable[[], bool] | None: + """The getter function to check the status of the logger. E.g., `sublime.get_log_commands`.""" + return getattr(sublime, f"get_{self.logger_func_name}", None) + + @cached_property + def logger_status_setter(self) -> Callable[..., None] | None: + """The setter function to set/toggle the logger status. E.g., `sublime.log_commands`.""" + return getattr(sublime, self.logger_func_name, None) @property - def logging_status_method(self) -> Callable[[], bool] | None: - return getattr(sublime, f"get_{self.logging_method_name}", None) + def logger_status(self) -> bool | None: + """The current status of the logger. `None` if there is no such logger.""" + return self.logger_status_getter() if self.logger_status_getter else None def description(self) -> str: - # "toogle_log_fps" => "Toggle log fps" - return self.name().replace("_", " ").capitalize() + # "toogle_log_fps" => "Toggle Log FPS" + return self.name().replace("_", " ").title().replace("Fps", "FPS") def is_checked(self) -> bool: - return (self.logging_status_method)() if self.logging_status_method else False + return bool(self.logger_status) def is_enabled(self) -> bool: - try: - return bool(self.logging_method and self.logging_status_method) - except AttributeError: - return False + return bool(self.logger_status_getter and self.logger_status_setter) is_visible = is_enabled def run(self, enable: bool | None = None) -> None: - if not self.logging_method: - return - args = tuple() if enable is None else (enable,) - self.logging_method(*args) + if self.logger_status_setter: + if enable is None: + self.logger_status_setter() + else: + self.logger_status_setter(enable) class ToggleLogBuildSystemsCommand(AbstractToggleConsoleLoggingCommand): diff --git a/plugin/commands/open_sublime_text_dir.py b/plugin/commands/open_sublime_text_dir.py index 3c4a069..39a2032 100644 --- a/plugin/commands/open_sublime_text_dir.py +++ b/plugin/commands/open_sublime_text_dir.py @@ -1,7 +1,8 @@ from __future__ import annotations +import os import tempfile -from functools import lru_cache +from functools import cached_property from pathlib import Path import sublime @@ -12,48 +13,49 @@ PACKAGE_NAME = __package__.partition(".")[0] -@lru_cache -def _get_folder_map() -> dict[str, str]: - def may_resolve_path(path: Path) -> Path: - try: - return path.resolve() # will fail on a Direct-IO disk - except OSError: - return path - - cache_path = Path(sublime.cache_path()) - packages_path = Path(sublime.packages_path()) +class OpenSublimeTextDirCommand(sublime_plugin.ApplicationCommand): + @cached_property + def folder_map(self) -> dict[str, str]: + def _may_resolve_path(path: Path) -> Path: + try: + return path.resolve() # will fail on a Direct-IO disk + except OSError: + return path - return { - name: str(may_resolve_path(path)) - for name, path in ( - # from OS - ("home", Path.home()), - ("temp_dir", Path(tempfile.gettempdir())), - # from ST itself - ("bin", Path(sublime.executable_path()).parent), - ("cache", cache_path), - ("data", packages_path / ".."), - ("index", cache_path / "../Index"), - ("installed_packages", Path(sublime.installed_packages_path())), - ("lib", packages_path / "../Lib"), - ("local", packages_path / "../Local"), - ("log", packages_path / "../Log"), - ("packages", packages_path), - # from LSP - ("package_storage", cache_path / "../Package Storage"), - ) - } + cache_path = Path(sublime.cache_path()) + packages_path = Path(sublime.packages_path()) + installed_packages = Path(sublime.installed_packages_path()) + return { + name: str(_may_resolve_path(path)) + for name, path in ( + # from OS + ("home", Path.home()), + ("temp_dir", Path(tempfile.gettempdir())), + # from ST itself + ("bin", Path(sublime.executable_path()).parent), + ("cache", cache_path), + ("data", packages_path / ".."), + ("index", cache_path / "../Index"), + ("installed_packages", installed_packages), + ("lib", packages_path / "../Lib"), + ("local", packages_path / "../Local"), + ("log", packages_path / "../Log"), + ("packages", packages_path), + # from LSP + ("package_storage", cache_path / "../Package Storage"), + ) + } -class OpenSublimeTextDirCommand(sublime_plugin.ApplicationCommand): def run(self, folder: str, error_on_not_found: bool = True) -> None: window = sublime.active_window() path = Path( sublime.expand_variables( folder, { + **os.environ, **window.extract_variables(), # type: ignore - **_get_folder_map(), + **self.folder_map, }, ) ) diff --git a/plugin/commands/restart_in_safe_mode.py b/plugin/commands/restart_in_safe_mode.py index 96c21a8..8fa332a 100644 --- a/plugin/commands/restart_in_safe_mode.py +++ b/plugin/commands/restart_in_safe_mode.py @@ -1,43 +1,28 @@ from __future__ import annotations -import os import subprocess -from collections.abc import Iterable -from pathlib import Path -from typing import Any import sublime import sublime_plugin -def _close_application(pid: int, post_close_cmd: Iterable[str | Path] | None = None, **kwargs: Any) -> None: - if sublime.platform() == "windows": - cmd = ["taskkill", "/f", "/pid", str(pid)] - # do not create a window for the process - startupinfo = subprocess.STARTUPINFO() # type: ignore - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW # type: ignore - else: - cmd = ["kill", "-9", str(pid)] - startupinfo = None # type: ignore - - if post_close_cmd: - cmd.append("&&") - cmd.extend(map(str, post_close_cmd)) - - subprocess.call(cmd, shell=True, startupinfo=startupinfo, **kwargs) - - class RestartInSafeModeCommand(sublime_plugin.ApplicationCommand): - def run(self) -> None: + def run(self, *, restart: bool = True) -> None: if sublime.ok_cancel_dialog( "In order to restart in safe mode, the current Sublime Text has to be closed." + " Be careful, unsaved changes may lose. Are you sure to continue?" ): - self.go_safe_mode() + self.open_safe_mode(close_self=restart) @staticmethod - def go_safe_mode() -> None: - _close_application( - os.getppid(), # plugin_host's parent is the Sublime Text process - post_close_cmd=(sublime.executable_path(), "--safe-mode"), - ) + def open_safe_mode(*, close_self: bool = True) -> None: + if sublime.platform() == "windows": + startupinfo = subprocess.STARTUPINFO() # type: ignore + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW # type: ignore + else: + startupinfo = None # type: ignore + + subprocess.Popen([sublime.executable_path(), "--safe-mode"], shell=True, startupinfo=startupinfo) + + if close_self: + sublime.run_command("exit")