kollabor 0.4.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- core/__init__.py +18 -0
- core/application.py +578 -0
- core/cli.py +193 -0
- core/commands/__init__.py +43 -0
- core/commands/executor.py +277 -0
- core/commands/menu_renderer.py +319 -0
- core/commands/parser.py +186 -0
- core/commands/registry.py +331 -0
- core/commands/system_commands.py +479 -0
- core/config/__init__.py +7 -0
- core/config/llm_task_config.py +110 -0
- core/config/loader.py +501 -0
- core/config/manager.py +112 -0
- core/config/plugin_config_manager.py +346 -0
- core/config/plugin_schema.py +424 -0
- core/config/service.py +399 -0
- core/effects/__init__.py +1 -0
- core/events/__init__.py +12 -0
- core/events/bus.py +129 -0
- core/events/executor.py +154 -0
- core/events/models.py +258 -0
- core/events/processor.py +176 -0
- core/events/registry.py +289 -0
- core/fullscreen/__init__.py +19 -0
- core/fullscreen/command_integration.py +290 -0
- core/fullscreen/components/__init__.py +12 -0
- core/fullscreen/components/animation.py +258 -0
- core/fullscreen/components/drawing.py +160 -0
- core/fullscreen/components/matrix_components.py +177 -0
- core/fullscreen/manager.py +302 -0
- core/fullscreen/plugin.py +204 -0
- core/fullscreen/renderer.py +282 -0
- core/fullscreen/session.py +324 -0
- core/io/__init__.py +52 -0
- core/io/buffer_manager.py +362 -0
- core/io/config_status_view.py +272 -0
- core/io/core_status_views.py +410 -0
- core/io/input_errors.py +313 -0
- core/io/input_handler.py +2655 -0
- core/io/input_mode_manager.py +402 -0
- core/io/key_parser.py +344 -0
- core/io/layout.py +587 -0
- core/io/message_coordinator.py +204 -0
- core/io/message_renderer.py +601 -0
- core/io/modal_interaction_handler.py +315 -0
- core/io/raw_input_processor.py +946 -0
- core/io/status_renderer.py +845 -0
- core/io/terminal_renderer.py +586 -0
- core/io/terminal_state.py +551 -0
- core/io/visual_effects.py +734 -0
- core/llm/__init__.py +26 -0
- core/llm/api_communication_service.py +863 -0
- core/llm/conversation_logger.py +473 -0
- core/llm/conversation_manager.py +414 -0
- core/llm/file_operations_executor.py +1401 -0
- core/llm/hook_system.py +402 -0
- core/llm/llm_service.py +1629 -0
- core/llm/mcp_integration.py +386 -0
- core/llm/message_display_service.py +450 -0
- core/llm/model_router.py +214 -0
- core/llm/plugin_sdk.py +396 -0
- core/llm/response_parser.py +848 -0
- core/llm/response_processor.py +364 -0
- core/llm/tool_executor.py +520 -0
- core/logging/__init__.py +19 -0
- core/logging/setup.py +208 -0
- core/models/__init__.py +5 -0
- core/models/base.py +23 -0
- core/plugins/__init__.py +13 -0
- core/plugins/collector.py +212 -0
- core/plugins/discovery.py +386 -0
- core/plugins/factory.py +263 -0
- core/plugins/registry.py +152 -0
- core/storage/__init__.py +5 -0
- core/storage/state_manager.py +84 -0
- core/ui/__init__.py +6 -0
- core/ui/config_merger.py +176 -0
- core/ui/config_widgets.py +369 -0
- core/ui/live_modal_renderer.py +276 -0
- core/ui/modal_actions.py +162 -0
- core/ui/modal_overlay_renderer.py +373 -0
- core/ui/modal_renderer.py +591 -0
- core/ui/modal_state_manager.py +443 -0
- core/ui/widget_integration.py +222 -0
- core/ui/widgets/__init__.py +27 -0
- core/ui/widgets/base_widget.py +136 -0
- core/ui/widgets/checkbox.py +85 -0
- core/ui/widgets/dropdown.py +140 -0
- core/ui/widgets/label.py +78 -0
- core/ui/widgets/slider.py +185 -0
- core/ui/widgets/text_input.py +224 -0
- core/utils/__init__.py +11 -0
- core/utils/config_utils.py +656 -0
- core/utils/dict_utils.py +212 -0
- core/utils/error_utils.py +275 -0
- core/utils/key_reader.py +171 -0
- core/utils/plugin_utils.py +267 -0
- core/utils/prompt_renderer.py +151 -0
- kollabor-0.4.9.dist-info/METADATA +298 -0
- kollabor-0.4.9.dist-info/RECORD +128 -0
- kollabor-0.4.9.dist-info/WHEEL +5 -0
- kollabor-0.4.9.dist-info/entry_points.txt +2 -0
- kollabor-0.4.9.dist-info/licenses/LICENSE +21 -0
- kollabor-0.4.9.dist-info/top_level.txt +4 -0
- kollabor_cli_main.py +20 -0
- plugins/__init__.py +1 -0
- plugins/enhanced_input/__init__.py +18 -0
- plugins/enhanced_input/box_renderer.py +103 -0
- plugins/enhanced_input/box_styles.py +142 -0
- plugins/enhanced_input/color_engine.py +165 -0
- plugins/enhanced_input/config.py +150 -0
- plugins/enhanced_input/cursor_manager.py +72 -0
- plugins/enhanced_input/geometry.py +81 -0
- plugins/enhanced_input/state.py +130 -0
- plugins/enhanced_input/text_processor.py +115 -0
- plugins/enhanced_input_plugin.py +385 -0
- plugins/fullscreen/__init__.py +9 -0
- plugins/fullscreen/example_plugin.py +327 -0
- plugins/fullscreen/matrix_plugin.py +132 -0
- plugins/hook_monitoring_plugin.py +1299 -0
- plugins/query_enhancer_plugin.py +350 -0
- plugins/save_conversation_plugin.py +502 -0
- plugins/system_commands_plugin.py +93 -0
- plugins/tmux_plugin.py +795 -0
- plugins/workflow_enforcement_plugin.py +629 -0
- system_prompt/default.md +1286 -0
- system_prompt/default_win.md +265 -0
- system_prompt/example_with_trender.md +47 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""Example full-screen plugin demonstrating framework capabilities."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import math
|
|
5
|
+
from core.fullscreen import FullScreenPlugin
|
|
6
|
+
from core.fullscreen.plugin import PluginMetadata
|
|
7
|
+
from core.fullscreen.components.drawing import DrawingPrimitives
|
|
8
|
+
from core.fullscreen.components.animation import AnimationFramework, EasingFunctions
|
|
9
|
+
from core.io.visual_effects import ColorPalette
|
|
10
|
+
from core.io.key_parser import KeyPress
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ExamplePlugin(FullScreenPlugin):
|
|
14
|
+
"""Example plugin showcasing full-screen framework features.
|
|
15
|
+
|
|
16
|
+
This plugin demonstrates:
|
|
17
|
+
- Drawing primitives (text, borders, shapes)
|
|
18
|
+
- Animation framework (fade, slide, bounce)
|
|
19
|
+
- Input handling
|
|
20
|
+
- Multi-page layouts
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self):
|
|
24
|
+
"""Initialize the example plugin."""
|
|
25
|
+
metadata = PluginMetadata(
|
|
26
|
+
name="example",
|
|
27
|
+
description="Example plugin showcasing framework features",
|
|
28
|
+
version="1.0.0",
|
|
29
|
+
author="Framework",
|
|
30
|
+
category="demo",
|
|
31
|
+
icon="🎯",
|
|
32
|
+
aliases=[]
|
|
33
|
+
)
|
|
34
|
+
super().__init__(metadata)
|
|
35
|
+
|
|
36
|
+
# Plugin state
|
|
37
|
+
self.current_page = 0
|
|
38
|
+
self.total_pages = 4
|
|
39
|
+
self.animation_framework = AnimationFramework()
|
|
40
|
+
self.page_transition_id = None
|
|
41
|
+
self.demo_animations = {}
|
|
42
|
+
self.frame_count = 0
|
|
43
|
+
|
|
44
|
+
async def initialize(self, renderer) -> bool:
|
|
45
|
+
"""Initialize the example plugin."""
|
|
46
|
+
print("🔍 CRITICAL: ExamplePlugin.initialize() called")
|
|
47
|
+
try:
|
|
48
|
+
if not await super().initialize(renderer):
|
|
49
|
+
print("❌ CRITICAL: super().initialize() failed")
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
# Setup initial animations
|
|
53
|
+
current_time = asyncio.get_event_loop().time()
|
|
54
|
+
self.demo_animations['title_fade'] = self.animation_framework.fade_in(2.0, current_time)
|
|
55
|
+
self.demo_animations['bounce'] = self.animation_framework.bounce_in(1.5, current_time + 0.5)
|
|
56
|
+
|
|
57
|
+
print("✅ CRITICAL: ExamplePlugin.initialize() completed successfully")
|
|
58
|
+
return True
|
|
59
|
+
except Exception as e:
|
|
60
|
+
print(f"❌ CRITICAL: Exception in initialize(): {e}")
|
|
61
|
+
import traceback
|
|
62
|
+
traceback.print_exc()
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
async def on_start(self):
|
|
66
|
+
"""Called when Example plugin starts."""
|
|
67
|
+
await super().on_start()
|
|
68
|
+
|
|
69
|
+
async def render_frame(self, delta_time: float) -> bool:
|
|
70
|
+
"""Render the example plugin frame."""
|
|
71
|
+
if not self.renderer:
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
# Increment frame counter for animations
|
|
75
|
+
self.frame_count += 1
|
|
76
|
+
|
|
77
|
+
# Clear screen and show content
|
|
78
|
+
self.renderer.clear_screen()
|
|
79
|
+
width, height = self.renderer.get_terminal_size()
|
|
80
|
+
|
|
81
|
+
# Render current page
|
|
82
|
+
if self.current_page == 0:
|
|
83
|
+
self._render_welcome_page(width, height)
|
|
84
|
+
elif self.current_page == 1:
|
|
85
|
+
self._render_drawing_demo(width, height)
|
|
86
|
+
elif self.current_page == 2:
|
|
87
|
+
self._render_animation_demo(width, height)
|
|
88
|
+
elif self.current_page == 3:
|
|
89
|
+
self._render_final_page(width, height)
|
|
90
|
+
|
|
91
|
+
# Show navigation instructions
|
|
92
|
+
nav_text = f"Page {self.current_page + 1}/{self.total_pages} • ←→ or h/l navigate • 1-4 direct • q/ESC exit"
|
|
93
|
+
nav_x = (width - len(nav_text)) // 2
|
|
94
|
+
self.renderer.write_at(nav_x, height - 1, nav_text, "\033[37m")
|
|
95
|
+
|
|
96
|
+
# Flush output
|
|
97
|
+
self.renderer.flush()
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
def _render_welcome_page(self, width: int, height: int):
|
|
101
|
+
"""Render the welcome page."""
|
|
102
|
+
# Animated title
|
|
103
|
+
title_alpha = self.animation_framework.get_value(self.demo_animations.get('title_fade', 0))
|
|
104
|
+
if title_alpha > 0.5: # Show when fade is mostly complete
|
|
105
|
+
DrawingPrimitives.draw_text_centered(
|
|
106
|
+
self.renderer, height // 4,
|
|
107
|
+
"🎯 Full-Screen Framework Demo",
|
|
108
|
+
ColorPalette.BRIGHT_CYAN
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
# Bouncing subtitle
|
|
112
|
+
bounce_offset = int(self.animation_framework.get_value(self.demo_animations.get('bounce', 0)) * 3)
|
|
113
|
+
DrawingPrimitives.draw_text_centered(
|
|
114
|
+
self.renderer, height // 2 - bounce_offset,
|
|
115
|
+
"Welcome to the Plugin Framework!",
|
|
116
|
+
ColorPalette.BRIGHT_GREEN
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Static content
|
|
120
|
+
DrawingPrimitives.draw_text_centered(
|
|
121
|
+
self.renderer, height // 2 + 2,
|
|
122
|
+
"This framework provides:",
|
|
123
|
+
ColorPalette.WHITE
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
features = [
|
|
127
|
+
"• Complete terminal takeover",
|
|
128
|
+
"• Modal system integration",
|
|
129
|
+
"• Drawing primitives & animations",
|
|
130
|
+
"• Plugin lifecycle management",
|
|
131
|
+
"• Input handling & routing"
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
for i, feature in enumerate(features):
|
|
135
|
+
DrawingPrimitives.draw_text_centered(
|
|
136
|
+
self.renderer, height // 2 + 4 + i,
|
|
137
|
+
feature,
|
|
138
|
+
ColorPalette.YELLOW
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
def _render_drawing_demo(self, width: int, height: int):
|
|
142
|
+
"""Render drawing primitives demonstration."""
|
|
143
|
+
DrawingPrimitives.draw_text_centered(
|
|
144
|
+
self.renderer, 2,
|
|
145
|
+
"Drawing Primitives Demo",
|
|
146
|
+
ColorPalette.BRIGHT_MAGENTA
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# Draw various shapes and elements
|
|
150
|
+
center_x, center_y = width // 2, height // 2
|
|
151
|
+
|
|
152
|
+
# Border around demo area
|
|
153
|
+
DrawingPrimitives.draw_border(
|
|
154
|
+
self.renderer, center_x - 20, center_y - 8, 40, 16,
|
|
155
|
+
color=ColorPalette.CYAN
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Progress bar
|
|
159
|
+
progress = (self.frame_count % 100) / 100.0
|
|
160
|
+
DrawingPrimitives.draw_progress_bar(
|
|
161
|
+
self.renderer, center_x - 15, center_y - 5, 30, progress,
|
|
162
|
+
color=ColorPalette.GREEN
|
|
163
|
+
)
|
|
164
|
+
DrawingPrimitives.draw_text_centered(
|
|
165
|
+
self.renderer, center_y - 6,
|
|
166
|
+
f"Progress: {progress:.0%}",
|
|
167
|
+
ColorPalette.WHITE
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
# Spinner
|
|
171
|
+
DrawingPrimitives.draw_spinner(
|
|
172
|
+
self.renderer, center_x - 2, center_y - 2, self.frame_count // 5,
|
|
173
|
+
color=ColorPalette.BRIGHT_BLUE
|
|
174
|
+
)
|
|
175
|
+
self.renderer.write_at(center_x + 2, center_y - 2, "Loading...", ColorPalette.WHITE)
|
|
176
|
+
|
|
177
|
+
# Circle points
|
|
178
|
+
radius = 8
|
|
179
|
+
DrawingPrimitives.draw_circle_points(
|
|
180
|
+
self.renderer, center_x, center_y + 3, radius,
|
|
181
|
+
char="●", color=ColorPalette.RED
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Wave
|
|
185
|
+
wave_phase = self.frame_count * 0.1
|
|
186
|
+
DrawingPrimitives.draw_wave(
|
|
187
|
+
self.renderer, height - 5, 2, 0.3, wave_phase,
|
|
188
|
+
char="~", color=ColorPalette.BLUE
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def _render_animation_demo(self, width: int, height: int):
|
|
192
|
+
"""Render animation framework demonstration."""
|
|
193
|
+
DrawingPrimitives.draw_text_centered(
|
|
194
|
+
self.renderer, 2,
|
|
195
|
+
"Animation Framework Demo",
|
|
196
|
+
ColorPalette.BRIGHT_YELLOW
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
center_x, center_y = width // 2, height // 2
|
|
200
|
+
|
|
201
|
+
# Create cycling animations
|
|
202
|
+
current_time = asyncio.get_event_loop().time()
|
|
203
|
+
|
|
204
|
+
# Pulsing circle
|
|
205
|
+
pulse_size = 5 + int(3 * math.sin(current_time * 2))
|
|
206
|
+
for r in range(1, pulse_size):
|
|
207
|
+
DrawingPrimitives.draw_circle_points(
|
|
208
|
+
self.renderer, center_x, center_y, r,
|
|
209
|
+
char="○", color=ColorPalette.GREEN
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Sliding text
|
|
213
|
+
slide_x = int(20 * math.sin(current_time))
|
|
214
|
+
self.renderer.write_at(center_x + slide_x, center_y - 5, "← Sliding Text →", ColorPalette.CYAN)
|
|
215
|
+
|
|
216
|
+
# Fading elements
|
|
217
|
+
fade_alpha = (math.sin(current_time * 1.5) + 1) / 2
|
|
218
|
+
if fade_alpha > 0.3: # Only show when bright enough
|
|
219
|
+
intensity = "▓" if fade_alpha > 0.7 else "░"
|
|
220
|
+
fade_text = f"Fading {intensity}"
|
|
221
|
+
DrawingPrimitives.draw_text_centered(
|
|
222
|
+
self.renderer, center_y + 3,
|
|
223
|
+
fade_text,
|
|
224
|
+
ColorPalette.MAGENTA
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
# Bouncing ball
|
|
228
|
+
bounce_y = center_y + 6 + int(3 * abs(math.sin(current_time * 3)))
|
|
229
|
+
self.renderer.write_at(center_x, bounce_y, "●", ColorPalette.RED)
|
|
230
|
+
|
|
231
|
+
def _render_final_page(self, width: int, height: int):
|
|
232
|
+
"""Render the final page with improved layout."""
|
|
233
|
+
# Title at top
|
|
234
|
+
DrawingPrimitives.draw_text_centered(
|
|
235
|
+
self.renderer, 3,
|
|
236
|
+
"🚀 Ready to Build Plugins!",
|
|
237
|
+
ColorPalette.BRIGHT_GREEN
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
# Plugin template example - more compact positioning
|
|
241
|
+
code_lines = [
|
|
242
|
+
"class MyPlugin(FullScreenPlugin):",
|
|
243
|
+
" async def render_frame(self, delta_time):",
|
|
244
|
+
" self.renderer.clear_screen()",
|
|
245
|
+
" # Your awesome content here!",
|
|
246
|
+
" return True",
|
|
247
|
+
"",
|
|
248
|
+
" async def handle_input(self, key_press):",
|
|
249
|
+
" return key_press.char == 'q'"
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
# Position code in upper middle area
|
|
253
|
+
start_y = 6
|
|
254
|
+
for i, line in enumerate(code_lines):
|
|
255
|
+
x = max(0, (width - len(line)) // 2)
|
|
256
|
+
self.renderer.write_at(x, start_y + i, line, ColorPalette.YELLOW)
|
|
257
|
+
|
|
258
|
+
# Features section positioned below code
|
|
259
|
+
features_start_y = start_y + len(code_lines) + 2
|
|
260
|
+
DrawingPrimitives.draw_text_centered(
|
|
261
|
+
self.renderer, features_start_y,
|
|
262
|
+
"Framework Features Available:",
|
|
263
|
+
ColorPalette.WHITE
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
features = [
|
|
267
|
+
"✓ Modal system integration",
|
|
268
|
+
"✓ Terminal state management",
|
|
269
|
+
"✓ Drawing primitives library",
|
|
270
|
+
"✓ Animation framework",
|
|
271
|
+
"✓ Input handling system"
|
|
272
|
+
]
|
|
273
|
+
|
|
274
|
+
for i, feature in enumerate(features):
|
|
275
|
+
DrawingPrimitives.draw_text_centered(
|
|
276
|
+
self.renderer, features_start_y + 2 + i,
|
|
277
|
+
feature,
|
|
278
|
+
ColorPalette.BRIGHT_CYAN
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
def _render_navigation(self, width: int, height: int):
|
|
282
|
+
"""Render navigation controls."""
|
|
283
|
+
nav_text = f"Page {self.current_page + 1}/{self.total_pages} • ←→ Navigate • Q/ESC Exit"
|
|
284
|
+
DrawingPrimitives.draw_text_centered(
|
|
285
|
+
self.renderer, height - 2,
|
|
286
|
+
nav_text,
|
|
287
|
+
ColorPalette.DIM_WHITE
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
async def handle_input(self, key_press: KeyPress) -> bool:
|
|
291
|
+
"""Handle input for the example plugin."""
|
|
292
|
+
# Exit on 'q' or ESC
|
|
293
|
+
if key_press.char in ['q', '\x1b'] or key_press.name == "Escape":
|
|
294
|
+
return True
|
|
295
|
+
|
|
296
|
+
# Navigation with multiple options
|
|
297
|
+
if key_press.char == 'h' or key_press.char == 'a' or key_press.name == "ArrowLeft":
|
|
298
|
+
if self.current_page > 0:
|
|
299
|
+
self.current_page -= 1
|
|
300
|
+
await self._start_page_transition()
|
|
301
|
+
elif key_press.char == 'l' or key_press.char == 'd' or key_press.name == "ArrowRight":
|
|
302
|
+
if self.current_page < self.total_pages - 1:
|
|
303
|
+
self.current_page += 1
|
|
304
|
+
await self._start_page_transition()
|
|
305
|
+
elif key_press.char in ['1', '2', '3', '4']: # Direct page navigation
|
|
306
|
+
new_page = int(key_press.char) - 1
|
|
307
|
+
if 0 <= new_page < self.total_pages:
|
|
308
|
+
self.current_page = new_page
|
|
309
|
+
await self._start_page_transition()
|
|
310
|
+
|
|
311
|
+
return False
|
|
312
|
+
|
|
313
|
+
async def _start_page_transition(self):
|
|
314
|
+
"""Start page transition animation."""
|
|
315
|
+
current_time = asyncio.get_event_loop().time()
|
|
316
|
+
# Could add page transition animations here
|
|
317
|
+
# For now, just reset some demo animations
|
|
318
|
+
self.demo_animations['bounce'] = self.animation_framework.bounce_in(0.5, current_time)
|
|
319
|
+
|
|
320
|
+
async def on_stop(self):
|
|
321
|
+
"""Called when Example plugin stops."""
|
|
322
|
+
await super().on_stop()
|
|
323
|
+
|
|
324
|
+
async def cleanup(self):
|
|
325
|
+
"""Clean up example plugin resources."""
|
|
326
|
+
self.animation_framework.clear_all()
|
|
327
|
+
await super().cleanup()
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Matrix rain plugin using the full-screen framework."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
from core.fullscreen import FullScreenPlugin
|
|
6
|
+
from core.fullscreen.plugin import PluginMetadata
|
|
7
|
+
from core.fullscreen.components.matrix_components import MatrixRenderer
|
|
8
|
+
from core.io.key_parser import KeyPress
|
|
9
|
+
|
|
10
|
+
logger = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MatrixRainPlugin(FullScreenPlugin):
|
|
14
|
+
"""Matrix rain effect implemented as a full-screen plugin.
|
|
15
|
+
|
|
16
|
+
This plugin creates the iconic Matrix digital rain effect with falling
|
|
17
|
+
green characters, providing an immersive full-screen experience.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self):
|
|
21
|
+
"""Initialize the Matrix rain plugin."""
|
|
22
|
+
metadata = PluginMetadata(
|
|
23
|
+
name="matrix",
|
|
24
|
+
description="Enter the Matrix with falling code rain",
|
|
25
|
+
version="1.0.0",
|
|
26
|
+
author="Framework",
|
|
27
|
+
category="effects",
|
|
28
|
+
icon="🔋",
|
|
29
|
+
aliases=[]
|
|
30
|
+
)
|
|
31
|
+
super().__init__(metadata)
|
|
32
|
+
|
|
33
|
+
# Matrix-specific state
|
|
34
|
+
self.matrix_renderer = None
|
|
35
|
+
self.start_time = 0
|
|
36
|
+
|
|
37
|
+
async def initialize(self, renderer) -> bool:
|
|
38
|
+
"""Initialize the Matrix plugin.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
renderer: FullScreenRenderer instance
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
True if initialization successful
|
|
45
|
+
"""
|
|
46
|
+
if not await super().initialize(renderer):
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
# Get terminal dimensions for Matrix renderer
|
|
51
|
+
width, height = renderer.get_terminal_size()
|
|
52
|
+
|
|
53
|
+
# Create Matrix renderer with current terminal size
|
|
54
|
+
self.matrix_renderer = MatrixRenderer(width, height)
|
|
55
|
+
|
|
56
|
+
return True
|
|
57
|
+
|
|
58
|
+
except Exception as e:
|
|
59
|
+
logger.error(f"Failed to initialize Matrix renderer: {e}")
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
async def on_start(self):
|
|
63
|
+
"""Called when Matrix plugin starts."""
|
|
64
|
+
await super().on_start()
|
|
65
|
+
self.start_time = asyncio.get_event_loop().time()
|
|
66
|
+
|
|
67
|
+
# DISTINCTIVE LOG TO PROVE NEW FRAMEWORK IS USED
|
|
68
|
+
logger.info("🎯 NEW FRAMEWORK: MatrixRainPlugin.on_start() called - using full-screen plugin framework!")
|
|
69
|
+
print("🎯 NEW FRAMEWORK: Matrix plugin starting via full-screen framework!")
|
|
70
|
+
|
|
71
|
+
# Reset Matrix renderer for fresh start
|
|
72
|
+
if self.matrix_renderer:
|
|
73
|
+
self.matrix_renderer.reset()
|
|
74
|
+
|
|
75
|
+
async def render_frame(self, delta_time: float) -> bool:
|
|
76
|
+
"""Render a Matrix rain frame.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
delta_time: Time elapsed since last frame
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
True to continue, False to exit
|
|
83
|
+
"""
|
|
84
|
+
if not self.renderer or not self.matrix_renderer:
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
try:
|
|
88
|
+
# Calculate current time for Matrix animation
|
|
89
|
+
current_time = asyncio.get_event_loop().time() - self.start_time
|
|
90
|
+
|
|
91
|
+
# Update Matrix animation
|
|
92
|
+
self.matrix_renderer.update(current_time)
|
|
93
|
+
|
|
94
|
+
# Render Matrix to screen
|
|
95
|
+
self.matrix_renderer.render(self.renderer)
|
|
96
|
+
|
|
97
|
+
# Update frame statistics
|
|
98
|
+
self.update_frame_stats()
|
|
99
|
+
|
|
100
|
+
return True
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.error(f"Error rendering Matrix frame: {e}")
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
async def handle_input(self, key_press: KeyPress) -> bool:
|
|
107
|
+
"""Handle input for Matrix plugin.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
key_press: Key that was pressed
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
True to exit Matrix, False to continue
|
|
114
|
+
"""
|
|
115
|
+
# Exit on 'q', ESC, or Escape key
|
|
116
|
+
if key_press.char in ['q', '\x1b'] or key_press.name == "Escape":
|
|
117
|
+
return True
|
|
118
|
+
|
|
119
|
+
# Continue running for all other keys
|
|
120
|
+
return False
|
|
121
|
+
|
|
122
|
+
async def on_stop(self):
|
|
123
|
+
"""Called when Matrix plugin stops."""
|
|
124
|
+
await super().on_stop()
|
|
125
|
+
|
|
126
|
+
# Optional: Could add fade-out effect here
|
|
127
|
+
# or save statistics about the session
|
|
128
|
+
|
|
129
|
+
async def cleanup(self):
|
|
130
|
+
"""Clean up Matrix plugin resources."""
|
|
131
|
+
self.matrix_renderer = None
|
|
132
|
+
await super().cleanup()
|