Spaces:
Sleeping
Sleeping
| import os | |
| import platform | |
| import re | |
| from ..subprocess_code_interpreter import SubprocessCodeInterpreter | |
| class Shell(SubprocessCodeInterpreter): | |
| file_extension = 'sh' | |
| proper_name = 'Shell' | |
| def __init__(self): | |
| super().__init__() | |
| # Determine the start command based on the platform | |
| if platform.system() == 'Windows': | |
| self.start_cmd = 'cmd.exe' | |
| else: | |
| self.start_cmd = os.environ.get('SHELL', 'bash') | |
| def preprocess_code(self, code): | |
| return preprocess_shell(code) | |
| def line_postprocessor(self, line): | |
| return line | |
| def detect_active_line(self, line): | |
| if '##active_line' in line: | |
| return int(line.split('##active_line')[1].split('##')[0]) | |
| return None | |
| def detect_end_of_execution(self, line): | |
| return '##end_of_execution##' in line | |
| def preprocess_shell(code): | |
| """ | |
| Add active line markers | |
| Wrap in a try except (trap in shell) | |
| Add end of execution marker | |
| """ | |
| # Add commands that tell us what the active line is | |
| # if it's multiline, just skip this. soon we should make it work with multiline | |
| if not has_multiline_commands(code): | |
| code = add_active_line_prints(code) | |
| # Add end command (we'll be listening for this so we know when it ends) | |
| code += '\necho "##end_of_execution##"' | |
| return code | |
| def add_active_line_prints(code): | |
| """ | |
| Add echo statements indicating line numbers to a shell string. | |
| """ | |
| lines = code.split('\n') | |
| for index, line in enumerate(lines): | |
| # Insert the echo command before the actual line | |
| lines[index] = f'echo "##active_line{index + 1}##"\n{line}' | |
| return '\n'.join(lines) | |
| def has_multiline_commands(script_text): | |
| # Patterns that indicate a line continues | |
| continuation_patterns = [ | |
| r'\\$', # Line continuation character at the end of the line | |
| r'\|$', # Pipe character at the end of the line indicating a pipeline continuation | |
| r'&&\s*$', # Logical AND at the end of the line | |
| r'\|\|\s*$', # Logical OR at the end of the line | |
| r'<\($', # Start of process substitution | |
| r'\($', # Start of subshell | |
| r'{\s*$', # Start of a block | |
| r'\bif\b', # Start of an if statement | |
| r'\bwhile\b', # Start of a while loop | |
| r'\bfor\b', # Start of a for loop | |
| r'do\s*$', # 'do' keyword for loops | |
| r'then\s*$', # 'then' keyword for if statements | |
| ] | |
| # Check each line for multiline patterns | |
| for line in script_text.splitlines(): | |
| if any( | |
| re.search(pattern, line.rstrip()) | |
| for pattern in continuation_patterns): | |
| return True | |
| return False | |