diff --git a/OsShell.py b/OsShell.py index 741f103..f7c424b 100644 --- a/OsShell.py +++ b/OsShell.py @@ -9,7 +9,7 @@ from . import SublimeHelper as SH -def process(commands, callback=None, stdin=None, settings=None, working_dir=None, wait_for_completion=None, **kwargs): +def process(commands, callback=None, stdin=None, settings=None, working_dir=None, wait_for_completion=None, shell=None, **kwargs): # If there's no callback method then just return the output as # a string: @@ -26,12 +26,13 @@ def process(commands, callback=None, stdin=None, settings=None, working_dir=None 'stdin': stdin, 'settings': settings, 'working_dir': working_dir, - 'wait_for_completion': wait_for_completion + 'wait_for_completion': wait_for_completion, + 'shell': shell }) thread.start() -def _process(commands, callback=None, stdin=None, settings=None, working_dir=None, wait_for_completion=None, **kwargs): +def _process(commands, callback=None, stdin=None, settings=None, working_dir=None, wait_for_completion=None, shell=None, **kwargs): '''Process one or more OS commands.''' if wait_for_completion is None: @@ -57,6 +58,23 @@ def _process(commands, callback=None, stdin=None, settings=None, working_dir=Non startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + # If 'shell' is not set, get it from setrtings + if shell is None: + shell = settings.get('shell') + + is_shell = isinstance(shell, str) + + # Replace $input var + if not is_shell and '$input' in shell: + shell = list(filter(lambda sharg: sharg is not None, [stdin if sh == '$input' else sh for sh in shell])) + stdin = None + + def decorate_shell_command(cmd): + if is_shell: + return shell.replace('$cmd', cmd) + else: + return [arg.replace('$cmd', cmd) for arg in shell] + # Now we can execute each command: # for command in commands: @@ -73,12 +91,11 @@ def _process(commands, callback=None, stdin=None, settings=None, working_dir=Non command = '. {} && {}'.format(bash_env, command) try: - - proc = subprocess.Popen(command, + proc = subprocess.Popen(decorate_shell_command(command), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - shell=True, + shell=is_shell, cwd=working_dir, startupinfo=startupinfo) diff --git a/ShellCommand.py b/ShellCommand.py index d975196..e1d79de 100644 --- a/ShellCommand.py +++ b/ShellCommand.py @@ -1,4 +1,7 @@ import sublime +import os.path +import shlex +import re from . import SublimeHelper as SH from . import OsShell @@ -16,7 +19,7 @@ def __init__(self, plugin, default_prompt=None, **kwargs): self.data_key = 'ShellCommand' self.output_written = False - def run(self, edit, command=None, command_prefix=None, prompt=None, region=None, arg_required=None, stdin=None, panel=None, title=None, syntax=None, refresh=None, wait_for_completion=None, root_dir=False): + def run(self, edit, command=None, command_prefix=None, prompt=None, region=None, arg_required=None, stdin=None, panel=None, title=None, syntax=None, refresh=None, wait_for_completion=None, root_dir=False, shell=None): # Map previous use of 'region' parameter: # @@ -61,7 +64,7 @@ def _C(command): if arg is not None: command = command + ' ' + arg - self.run_shell_command(command, stdin=stdin, panel=panel, title=title, syntax=syntax, refresh=refresh, wait_for_completion=wait_for_completion, root_dir=root_dir) + self.run_shell_command(command, stdin=stdin, panel=panel, title=title, syntax=syntax, refresh=refresh, wait_for_completion=wait_for_completion, root_dir=root_dir, shell=shell) # If no command is specified then we prompt for one, otherwise # we can just execute the command: @@ -73,7 +76,7 @@ def _C(command): else: _C(command) - def run_shell_command(self, command=None, stdin=None, panel=False, title=None, syntax=None, refresh=False, console=None, working_dir=None, wait_for_completion=None, root_dir=False): + def run_shell_command(self, command=None, stdin=None, panel=False, title=None, syntax=None, refresh=False, console=None, working_dir=None, wait_for_completion=None, root_dir=False, shell=None): view = self.view window = view.window() @@ -83,9 +86,22 @@ def run_shell_command(self, command=None, stdin=None, panel=False, title=None, s sublime.message_dialog('No command provided.') return + # replace '$path' with view file path, '$file' with view file name and '$dir' with view file dir + file_path = view.file_name() + if file_path: + (file_dir, file_name) = os.path.split(file_path) + command = command.replace('$path', shlex.quote(file_path)).replace('$file', shlex.quote(file_name)).replace('$dir', shlex.quote(file_dir)) + if working_dir is None: working_dir = self.get_working_dir(root_dir=root_dir) + # Match syntax by settings regexes + if syntax is None: + syntax_match = settings.get('syntax_match') + for syntax_re, syntax_sy in syntax_match.items(): + if re.match(syntax_re, command): + syntax = syntax_sy + # Run the command and write any output to the buffer: # message = self.default_prompt + ': (' + ''.join(command)[:20] + ')' @@ -143,7 +159,8 @@ def _C(output): title=title, syntax=syntax, panel=panel, - console=console) + console=console, + shell=shell) # Switch our progress bar to the new window: # @@ -159,7 +176,7 @@ def _C(output): self.output_target.append_text(output) self.output_written = True - OsShell.process(command, _C, stdin=stdin, settings=settings, working_dir=working_dir, wait_for_completion=wait_for_completion) + OsShell.process(command, _C, stdin=stdin, settings=settings, working_dir=working_dir, wait_for_completion=wait_for_completion, shell=shell) class ShellCommandOnRegionCommand(ShellCommandCommand): @@ -186,5 +203,5 @@ def run(self, edit, callback=None): console.run_command('sublime_helper_clear_buffer') console.set_read_only(True) - self.run_shell_command(command=data['command'], console=console, working_dir=data['working_dir']) + self.run_shell_command(command=data['command'], console=console, working_dir=data['working_dir'], shell=data['shell']) diff --git a/ShellCommand.sublime-settings b/ShellCommand.sublime-settings index d596c32..5828d41 100644 --- a/ShellCommand.sublime-settings +++ b/ShellCommand.sublime-settings @@ -17,4 +17,22 @@ */ , "progress_display_heartbeat": 500 + + /** + * Command to invoke + * String stays for shell command, so default '$cmd' means just 'run command with shell' + * List stays for process name with args, for example + * ['powershell', '-Command', '& { $cmd }'] will run powershell with specified arguments + * There are also $input metavar which is used when there are some input + * if '$input' present, input will be passed as argument instead of writing it to stdin + */ + +, "shell": "$cmd" + /** + * Set syntax if command matches specified regex + * Example: + * { "^svn.*\bdiff\b": "Diff" } + * Will set 'Diff' syntax for commands like 'svn diff ...' or 'svn log -l 10 --diff' + */ +, "syntax_match": {} } diff --git a/SublimeHelper.py b/SublimeHelper.py index 28f47e2..f45bd6a 100644 --- a/SublimeHelper.py +++ b/SublimeHelper.py @@ -152,7 +152,7 @@ def run(self, edit): class OutputTarget(): - def __init__(self, window, data_key, command, working_dir, title=None, syntax=None, panel=False, console=None): + def __init__(self, window, data_key, command, working_dir, title=None, syntax=None, panel=False, console=None, shell=None): # If a panel has been requested then create one and show it, # otherwise create a new buffer, and set its caption: @@ -189,7 +189,8 @@ def __init__(self, window, data_key, command, working_dir, title=None, syntax=No # data = { 'command': command, - 'working_dir': working_dir + 'working_dir': working_dir, + 'shell': shell } settings.set(data_key + '_data', data)