forked from genewildish/Mainline
Implement a Read-Eval-Print Loop (REPL) effect that provides a HUD-style overlay for interactive pipeline control. ## New Files - engine/effects/plugins/repl.py - REPL effect plugin with command processor - engine/display/backends/terminal.py - Added raw mode and input handling - examples/repl_simple.py - Simple demonstration script - tests/test_repl_effect.py - 18 comprehensive tests ## Features ### REPL Interface - HUD-style overlay showing FPS, command history, output buffer size - Command history navigation (Up/Down arrows) - Command execution (Enter) - Character input and backspace support - Output buffer with scrolling ### Commands - help - Show available commands - status - Show pipeline status and metrics - effects - List all effects in pipeline - effect <name> <on|off> - Toggle effect - param <effect> <param> <value> - Set parameter - pipeline - Show current pipeline order - clear - Clear output buffer - quit - Show exit message ### Terminal Input Support - Added set_raw_mode() to TerminalDisplay for capturing keystrokes - Added get_input_keys() to read keyboard input - Proper terminal state restoration on cleanup ## Usage Add 'repl' to effects in your configuration: ## Testing All 18 REPL tests pass, covering: - Effect registration - Command processing - Navigation (history, editing) - Configuration - Rendering ## Integration The REPL effect integrates with the existing pipeline system: - Uses EffectPlugin interface - Supports partial updates - Reads metrics from EffectContext - Can be controlled via keyboard when terminal display is in raw mode Next steps: - Integrate REPL input handling into pipeline_runner.py - Add keyboard event processing loop - Create full demo with interactive features
146 lines
4.3 KiB
Python
146 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
REPL Demo - Interactive command-line interface for pipeline control
|
|
|
|
This demo shows how to use the REPL effect plugin to interact with
|
|
the Mainline pipeline in real-time.
|
|
|
|
Features:
|
|
- HUD-style overlay showing FPS, frame time, command history
|
|
- Command history navigation (Up/Down arrows)
|
|
- Pipeline inspection and control commands
|
|
- Parameter adjustment in real-time
|
|
|
|
Usage:
|
|
python examples/repl_demo.py
|
|
|
|
Keyboard Controls:
|
|
Enter - Execute command
|
|
Up/Down - Navigate command history
|
|
Backspace - Delete character
|
|
Ctrl+C - Exit
|
|
"""
|
|
|
|
import sys
|
|
import time
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from engine.effects.plugins import discover_plugins
|
|
from engine.pipeline.hybrid_config import PipelineConfig
|
|
|
|
|
|
def main():
|
|
"""Run the REPL demo."""
|
|
print("REPL Demo - Interactive Pipeline Control")
|
|
print("=" * 50)
|
|
print()
|
|
print("This demo will:")
|
|
print("1. Create a pipeline with REPL effect")
|
|
print("2. Enable raw terminal mode for input")
|
|
print("3. Show REPL interface with HUD overlay")
|
|
print()
|
|
print("Keyboard controls:")
|
|
print(" Enter - Execute command")
|
|
print(" Up/Down - Navigate command history")
|
|
print(" Backspace - Delete character")
|
|
print(" Ctrl+C - Exit")
|
|
print()
|
|
print("Commands to try:")
|
|
print(" help - Show available commands")
|
|
print(" status - Show pipeline status")
|
|
print(" effects - List effects")
|
|
print(" pipeline - Show pipeline order")
|
|
print()
|
|
input("Press Enter to start...")
|
|
|
|
# Discover plugins
|
|
discover_plugins()
|
|
|
|
# Create pipeline with REPL effect
|
|
config = PipelineConfig(
|
|
source="headlines",
|
|
camera={"mode": "scroll", "speed": 1.0},
|
|
effects=[
|
|
{"name": "noise", "intensity": 0.3},
|
|
{"name": "fade", "intensity": 0.5},
|
|
{"name": "repl", "intensity": 1.0}, # Add REPL effect
|
|
],
|
|
display={"backend": "terminal", "positioning": "mixed"},
|
|
)
|
|
|
|
pipeline = config.to_pipeline(viewport_width=80, viewport_height=24)
|
|
|
|
# Initialize pipeline
|
|
if not pipeline.initialize():
|
|
print("Failed to initialize pipeline")
|
|
return
|
|
|
|
# Get the REPL effect instance
|
|
repl_effect = None
|
|
for stage in pipeline._stages.values():
|
|
if hasattr(stage, "_effect") and stage._effect.name == "repl":
|
|
repl_effect = stage._effect
|
|
break
|
|
|
|
if not repl_effect:
|
|
print("REPL effect not found in pipeline")
|
|
return
|
|
|
|
# Enable raw mode for input
|
|
display = pipeline.context.get("display")
|
|
if display and hasattr(display, "set_raw_mode"):
|
|
display.set_raw_mode(True)
|
|
|
|
# Main loop
|
|
try:
|
|
frame_count = 0
|
|
while True:
|
|
# Get keyboard input
|
|
if display and hasattr(display, "get_input_keys"):
|
|
keys = display.get_input_keys(timeout=0.01)
|
|
for key in keys:
|
|
if key == "return":
|
|
repl_effect.process_command(
|
|
repl_effect.state.current_command, pipeline.context
|
|
)
|
|
elif key == "up":
|
|
repl_effect.navigate_history(-1)
|
|
elif key == "down":
|
|
repl_effect.navigate_history(1)
|
|
elif key == "backspace":
|
|
repl_effect.backspace()
|
|
elif key == "ctrl_c":
|
|
raise KeyboardInterrupt
|
|
elif len(key) == 1:
|
|
repl_effect.append_to_command(key)
|
|
|
|
# Execute pipeline
|
|
result = pipeline.execute([])
|
|
|
|
if not result.success:
|
|
print(f"Pipeline error: {result.error}")
|
|
break
|
|
|
|
# Check for pending commands
|
|
pending = repl_effect.get_pending_command()
|
|
if pending:
|
|
print(f"\nPending command: {pending}\n")
|
|
|
|
frame_count += 1
|
|
time.sleep(0.033) # ~30 FPS
|
|
|
|
except KeyboardInterrupt:
|
|
print("\n\nExiting REPL demo...")
|
|
finally:
|
|
# Restore terminal mode
|
|
if display and hasattr(display, "set_raw_mode"):
|
|
display.set_raw_mode(False)
|
|
# Cleanup pipeline
|
|
pipeline.cleanup()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|