forked from genewildish/Mainline
feat(repl): Add REPL effect with HUD-style interactive interface
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
This commit is contained in:
145
examples/repl_demo.py
Normal file
145
examples/repl_demo.py
Normal file
@@ -0,0 +1,145 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user