From d232116e00b52432eb949cf600330742bdf8ea2a Mon Sep 17 00:00:00 2001 From: ttimo <ttimo@ttimo.net> Date: Thu, 31 Aug 2023 14:17:50 -0500 Subject: [PATCH] Add support for custom windows terminals, pass --with-conemu=<path to conemu> or --with-cmder=<path to cmder>. Setting is persistent, set to empty string to reset. --- client/devkit_client/__init__.py | 6 +++ client/devkit_client/custom_terminal.py | 65 +++++++++++++++++++++++++ client/devkit_client/gui2/gui2.py | 11 +++++ 3 files changed, 82 insertions(+) create mode 100644 client/devkit_client/custom_terminal.py diff --git a/client/devkit_client/__init__.py b/client/devkit_client/__init__.py index 6a12cf0..e531d0f 100644 --- a/client/devkit_client/__init__.py +++ b/client/devkit_client/__init__.py @@ -61,6 +61,7 @@ import appdirs import paramiko import devkit_client.zeroconf as zeroconf import devkit_client.captured_popen as captured_popen +import devkit_client.custom_terminal as custom_terminal try: import devkit_client.version @@ -122,6 +123,7 @@ g_external_tools = None g_lock = threading.Lock() g_captured_popen_factory = captured_popen.CapturedPopenFactory() +g_custom_terminal = custom_terminal.CustomTerminal() # This burned me twice now .. https://twitter.com/TTimo/status/1582509449838989313 from os import getenv as os_getenv @@ -1286,6 +1288,10 @@ def run_in_terminal(commands): cwd = os.getcwd() creationflags=0 if platform.system() == 'Windows': + p = g_custom_terminal.Popen(commands) + if p is not None: + return p + # After a bunch of iteration, writing a ps1 script and running it from the ssh.exe directory seems the most reliable # trying to pass all command line parameters with a direct powershell.exe invocation runs into a nightmare of path escaping business # this also enables us to provide better error handling and diagnostics diff --git a/client/devkit_client/custom_terminal.py b/client/devkit_client/custom_terminal.py new file mode 100644 index 0000000..9d4891e --- /dev/null +++ b/client/devkit_client/custom_terminal.py @@ -0,0 +1,65 @@ +import logging +import shutil +import subprocess + +logger = logging.getLogger(__name__) + +# Support the use of conemu or cmder on Windows +# glue between config settings and the low level run_in_terminal logic +class CustomTerminal: + TERM_KEY = 'CustomTerminal.Term' + STYLE_KEY = 'CustomTerminal.Style' # 0: disabled, 1: conemu, 2: cmder + + def __init__(self): + self.conf = None + self.settings = None + + def setup(self, conf, settings): + self.conf = conf + self.settings = settings + + matched = False + for (term_attr, style) in (('with_conemu', 1), ('with_cmder', 2)): + term = vars(self.conf).get(term_attr) + if term is None: + continue + matched = True + if term == "": + # Explicit disable + style = 0 + break + if len(term) > 0: + # Can pass a full path, or we will lookup here + term = shutil.which(term) + if term is not None: + break + + if not matched: + # settings are unchanged, the command line options were not used + return + + if style == 0 or term is None: + logger.info(f'Custom windows terminal is disabled') + self.settings[self.STYLE_KEY] = 0 + return + + logger.info(f'Using custom windows terminal: {term}') + self.settings[self.STYLE_KEY] = style + self.settings[self.TERM_KEY] = term + + def Popen(self, commands): + if self.settings[self.STYLE_KEY] == 0: + return + + if self.settings[self.STYLE_KEY] == 1: + commands = [self.settings[self.TERM_KEY], '-run'] + commands + elif self.settings[self.STYLE_KEY] == 2: + commands = [self.settings[self.TERM_KEY], '/x', '-run ' + ' '.join(commands)] + else: + raise Exception(f'Unexpected STYLE_KEY {self.settings[self.STYLE_KEY]} value in CustomTerminal') + + logging.info(f'Run in terminal - custom terminal: {commands!r}') + p = subprocess.Popen( + commands, + ) + return p diff --git a/client/devkit_client/gui2/gui2.py b/client/devkit_client/gui2/gui2.py index 5bb89f9..b92ccb6 100644 --- a/client/devkit_client/gui2/gui2.py +++ b/client/devkit_client/gui2/gui2.py @@ -3315,6 +3315,15 @@ def main(): '--disable-popen-capture', required=False, action='store_true', help='Disable capturing of launched external processes output to the status window.' ) + if platform.system() == 'Windows': + parser.add_argument( + '--with-conemu', required=False, action='store', + help='Configure run in terminal to use given exe with conemu syntax. Set to blank to clear.' + ) + parser.add_argument( + '--with-cmder', required=False, action='store', + help='Configure run in terminal to use given exe with cmder syntax. Set to blank to clear.' + ) conf = parser.parse_args() @@ -3349,6 +3358,8 @@ def main(): shutdown_signal.connect(settings.on_shutdown_signal) atexit.register(settings.shutdown) # saves settings on abnormal termination + devkit_client.g_custom_terminal.setup(conf, settings) + devkit_commands = DevkitCommands(conf, shutdown_signal) devkit_commands.setup() -- GitLab