Improve multiline input handling - support paste, bracket detection, empty line finish

parent 3e4b1ca6
...@@ -1092,14 +1092,59 @@ def run_interactive_shell(client: CoderClient, session_manager: SessionManager) ...@@ -1092,14 +1092,59 @@ def run_interactive_shell(client: CoderClient, session_manager: SessionManager)
lines = [] lines = []
while True: while True:
line = input(prompt) try:
# Check if line ends with backslash for continuation line = input(prompt)
except EOFError:
# Handle Ctrl+D as end of multiline input
if lines:
break
raise
lines.append(line)
# Check for explicit continuation with backslash
if line.rstrip().endswith('\\'): if line.rstrip().endswith('\\'):
lines.append(line.rstrip()[:-1]) # Remove backslash lines[-1] = line.rstrip()[:-1] # Remove backslash
prompt = f"{Colors.BLUE} ...>{Colors.RESET} " # Continuation prompt prompt = f"{Colors.BLUE} ...>{Colors.RESET} " # Continuation prompt
else: continue
lines.append(line)
# Check for incomplete brackets (multiline paste detection)
joined = '\n'.join(lines)
open_brackets = joined.count('(') - joined.count(')')
open_brackets += joined.count('[') - joined.count(']')
open_brackets += joined.count('{') - joined.count('}')
# Check for incomplete code blocks or sentences
stripped = line.strip()
ends_with_colon = stripped.endswith(':')
ends_with_open = stripped.endswith(('(', '[', '{'))
if open_brackets > 0 or ends_with_colon or ends_with_open:
prompt = f"{Colors.BLUE} ...>{Colors.RESET} " # Continuation prompt
continue
# Empty line after content - finish input (for paste mode)
if not stripped and len(lines) > 1:
lines.pop() # Remove the empty line
break break
# Single line input - we're done
if len(lines) == 1 and not open_brackets and not ends_with_colon and not ends_with_open:
break
# Multiple lines with balanced brackets - finish on empty line or new prompt
if open_brackets == 0 and not ends_with_colon and not ends_with_open:
# For pasted multiline content, finish immediately
# For manual entry, require empty line
if '\n'.join(lines).count('\n') >= 1 and not stripped:
lines.pop() # Remove the empty line
break
elif '\n'.join(lines).count('\n') >= 1 and stripped:
# Pasted content with balanced brackets - likely done
break
else:
prompt = f"{Colors.BLUE} ...>{Colors.RESET} "
continue
user_input = '\n'.join(lines).strip() user_input = '\n'.join(lines).strip()
...@@ -1237,7 +1282,10 @@ def print_help(): ...@@ -1237,7 +1282,10 @@ def print_help():
{Colors.YELLOW}/confirm <tool> <y/n>{Colors.RESET} Enable/disable tool confirmation {Colors.YELLOW}/confirm <tool> <y/n>{Colors.RESET} Enable/disable tool confirmation
{Colors.BOLD}{Colors.CYAN}Multiline Input:{Colors.RESET} {Colors.BOLD}{Colors.CYAN}Multiline Input:{Colors.RESET}
End a line with {Colors.YELLOW}\\{Colors.RESET} to continue on next line - End a line with {Colors.YELLOW}\\{Colors.RESET} to continue
- Or paste multiline content directly
- Or press Enter twice to finish
- Unclosed brackets ( ) [ ] {{ }} or : continue automatically
Example: Example:
CoderCLI> This is a \\ CoderCLI> This is a \\
...> multiline message ...> multiline message
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment