Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion promptshell/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from .ai_terminal_assistant import AITerminalAssistant
from .readline_setup import setup_readline
from .readline_setup import setup_readline, clear_screen
import platform
import os
import sys
Expand All @@ -26,6 +26,7 @@ def main():

enable_ansi_support()
setup_readline()
custom_input = setup_readline()
model_name = get_active_model()

assistant = AITerminalAssistant(config=config, model_name=model_name)
Expand All @@ -46,6 +47,22 @@ def main():
if user_input.lower() in ('quit', 'exit'):
print(format_text('red', bold=True) + "\nTerminating..." + reset_format())
break

# Use custom input if available (from prompt_toolkit), otherwise use standard input
if custom_input:
user_input = custom_input(prompt).strip()
else:
user_input = input(prompt).strip()

# Handle Ctrl+L clear screen command
if user_input == "clear_screen":
clear_screen()
continue

# Handle clear/cls commands
if user_input.lower() in ('clear', 'cls'):
clear_screen()
continue

if user_input.lower() == "--config":
setup_wizard()
Expand Down
140 changes: 117 additions & 23 deletions promptshell/readline_setup.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,131 @@
import sys
import glob
import os
import atexit
import glob
import platform

# Define internal commands for tab completion
INTERNAL_COMMANDS = [
'--help', '--config', '--tutorial',
'alias', 'exit', 'quit', 'clear', 'cls'
]

def clear_screen():
"""Clear the screen using ANSI escape sequences."""
sys.stdout.write("\033[2J\033[H")
sys.stdout.flush()

def setup_readline():
"""Configures tab completion and history support."""
"""Configures tab completion, history support, and keyboard shortcuts."""
histfile = os.path.join(os.path.expanduser("~"), ".promptshell_history")
custom_prompt = None

try:
import readline # Works on Unix-like systems
# Unix-like systems
import readline

# Load existing history
try:
readline.read_history_file(histfile)
except FileNotFoundError:
open(histfile, 'a').close()

# Set history length and save on exit
readline.set_history_length(1000)
atexit.register(readline.write_history_file, histfile)

# Configure tab completion
readline.set_completer(completer)
readline.set_completer_delims(" \t\n;")
readline.parse_and_bind("tab: complete")

# Bind Ctrl+L to clear screen
readline.parse_and_bind("Control-l: clear_screen")
print("Using readline for enhanced input features.")

except ImportError:
if sys.platform == "win32":
try:
import pyreadline3 as readline # Use pyreadline3 on Windows
# Windows with pyreadline
import pyreadline3 as readline

# Load existing history
try:
readline.read_history_file(histfile)
except FileNotFoundError:
open(histfile, 'a').close()

# Set history length and save on exit
readline.set_history_length(1000)
atexit.register(readline.write_history_file, histfile)

# Configure tab completion
readline.set_completer(completer)
readline.parse_and_bind("tab: complete")

# Bind Ctrl+L to clear screen
readline.parse_and_bind("Control-l: clear_screen")
print("Using pyreadline for enhanced input features.")

except ImportError:
# Fallback to prompt_toolkit
try:
import prompt_toolkit # Alternative for better Windows support
from prompt_toolkit.completion import PathCompleter
from prompt_toolkit.shortcuts import prompt

def complete_path():
return prompt(">>> ", completer=PathCompleter())

print("Using prompt_toolkit for tab completion.")
return complete_path # Return prompt-based tab completion
import prompt_toolkit
from prompt_toolkit.completion import Completer, Completion
from prompt_toolkit.shortcuts import prompt as pt_prompt
from prompt_toolkit.keys import Keys
from prompt_toolkit.key_binding import KeyBindings
from prompt_toolkit.history import FileHistory

print("Using prompt_toolkit for enhanced input features.")

# Set up history
history = FileHistory(histfile)

# Custom completer class
class InternalCompleter(Completer):
def get_completions(self, document, complete_event):
text = document.text_before_cursor
# Internal commands
for cmd in INTERNAL_COMMANDS:
if cmd.startswith(text):
yield Completion(cmd, start_position=-len(text))
# File paths
for path in glob.glob(os.path.expanduser(text) + "*"):
yield Completion(path, start_position=-len(text))

# Key bindings for clear screen (Ctrl+L)
bindings = KeyBindings()

@bindings.add(Keys.ControlL)
def clear_screen(event):
event.app.renderer.clear()

def custom_prompt(prompt_str):
return pt_prompt(
prompt_str,
history=history,
completer=InternalCompleter(),
key_bindings=bindings
)

return custom_prompt

except ImportError:
print("Warning: No readline or pyreadline3 found. Tab completion will not work.")
return

# Configure readline for tab completion
readline.parse_and_bind("tab: complete")

def complete(text, state):
matches = glob.glob(os.path.expanduser(text) + "*") + [None]
return matches[state]
else:
print("Warning: readline not available. Tab completion will not work.")

return custom_prompt

readline.set_completer(complete)
readline.set_completer_delims(" \t\n;")
def completer(text, state):
"""Tab completion function that completes both internal commands and file paths."""
# First check internal commands
command_matches = [cmd for cmd in INTERNAL_COMMANDS if cmd.startswith(text)]

# Then check file paths
file_matches = glob.glob(os.path.expanduser(text) + "*")

# Combine both types of matches
matches = command_matches + file_matches
return matches[state] if state < len(matches) else None