2026-01-18 00:52:54 -06:00
|
|
|
# Python imports
|
|
|
|
|
import inspect
|
|
|
|
|
from typing import Dict, Type
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
# Lib imports
|
|
|
|
|
|
|
|
|
|
# Application imports
|
|
|
|
|
from .singleton import Singleton
|
|
|
|
|
|
|
|
|
|
from .dto.base_event import BaseEvent
|
2026-03-08 00:46:21 -06:00
|
|
|
from .dto.code import events as code
|
2026-01-18 00:52:54 -06:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class EventFactory(Singleton):
|
|
|
|
|
def __init__(self):
|
2026-03-08 00:46:21 -06:00
|
|
|
|
2026-01-18 00:52:54 -06:00
|
|
|
self._event_classes: Dict[str, Type[BaseEvent]] = {}
|
|
|
|
|
|
|
|
|
|
self._auto_register_events( code.__dict__.items() )
|
|
|
|
|
|
|
|
|
|
def register_event(self, event_type: str, event_class: Type[BaseEvent]):
|
|
|
|
|
self._event_classes[event_type] = event_class
|
|
|
|
|
|
2026-03-15 20:45:58 -05:00
|
|
|
def register_events(self, events: dict):
|
2026-03-15 23:40:40 -05:00
|
|
|
i = 0
|
2026-03-15 20:45:58 -05:00
|
|
|
for name, obj in events:
|
|
|
|
|
if not self._is_valid_event_class(obj): continue
|
|
|
|
|
|
|
|
|
|
event_type = self._class_name_to_event_type(name)
|
|
|
|
|
|
2026-03-15 23:40:40 -05:00
|
|
|
self._event_classes[event_type] = obj
|
|
|
|
|
Code_Event_Types.add_event_class(name, obj)
|
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
logger.debug(f"Registered {i} event types:")
|
2026-03-15 20:45:58 -05:00
|
|
|
|
feat: Complete plugin lifecycle management with lazy loading and runtime reload
Major changes:
- Add unload() method to all plugins for proper cleanup (unregister commands/providers/LSP clients, destroy widgets, clear state)
- Implement lazy widget loading via "show" signal across all containers
- Add autoload: false manifest option for manual/conditional plugin loading
- Add Plugins UI with runtime load/unload toggle via Ctrl+Shift+p
- Implement controller unregistration system with proper signal disconnection
- Add new events: UnregisterCommandEvent, GetFilesEvent, GetSourceViewsEvent, TogglePluginsUiEvent
- Fix signal leaks by tracking and disconnecting handlers in widgets (search/replace, LSP manager, tabs, telescope, markdown preview)
- Add Save/Save As to tabs context menu
- Improve search/replace behavior (selection handling, focus management)
- Add telescope file initialization from existing loaded files
- Refactor plugin reload watcher to dynamically add/remove plugins on filesystem changes
- Add new plugins: file_history, extend_source_view_menu, godot_lsp_client
- Fix bug in prettify_json (undefined variable reference
2026-03-21 13:26:12 -05:00
|
|
|
def unregister_events(self, events: dict):
|
|
|
|
|
i = 0
|
|
|
|
|
for name, obj in events:
|
|
|
|
|
if not self._is_valid_event_class(obj): continue
|
|
|
|
|
|
|
|
|
|
event_type = self._class_name_to_event_type(name)
|
|
|
|
|
|
|
|
|
|
del self._event_classes[event_type]
|
|
|
|
|
Code_Event_Types.remove_event_class(name)
|
|
|
|
|
i += 1
|
|
|
|
|
|
|
|
|
|
logger.debug(f"Unregistered {i} event types:")
|
|
|
|
|
|
2026-01-18 00:52:54 -06:00
|
|
|
def create_event(self, event_type: str, **kwargs) -> BaseEvent:
|
|
|
|
|
if event_type not in self._event_classes:
|
|
|
|
|
raise ValueError(f"Unknown event type: {event_type}")
|
|
|
|
|
|
|
|
|
|
event_class = self._event_classes[event_type]
|
|
|
|
|
event = event_class()
|
|
|
|
|
|
|
|
|
|
for key, value in kwargs.items():
|
|
|
|
|
if not hasattr(event, key):
|
|
|
|
|
raise ValueError(f"Event class {event_class.__name__} has no attribute '{key}'")
|
|
|
|
|
|
|
|
|
|
setattr(event, key, value)
|
|
|
|
|
|
|
|
|
|
return event
|
|
|
|
|
|
|
|
|
|
|
2026-03-15 20:45:58 -05:00
|
|
|
def _auto_register_events(self, events: dict):
|
|
|
|
|
self.register_events(events)
|
2026-01-18 00:52:54 -06:00
|
|
|
|
|
|
|
|
def _is_valid_event_class(self, obj) -> bool:
|
|
|
|
|
return (
|
|
|
|
|
inspect.isclass(obj) and
|
|
|
|
|
issubclass(obj, BaseEvent) and
|
|
|
|
|
obj != BaseEvent
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def _class_name_to_event_type(self, class_name: str) -> str:
|
|
|
|
|
base_name = class_name[:-5] if class_name.endswith('Event') else class_name
|
|
|
|
|
return re.sub(r'(?<!^)(?=[A-Z])', '_', base_name).lower()
|
|
|
|
|
|
|
|
|
|
|
2026-03-15 23:40:40 -05:00
|
|
|
class EventNamespace:
|
|
|
|
|
"""Dynamic namespace for event types."""
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _is_valid_event_class(self, obj) -> bool:
|
|
|
|
|
return (inspect.isclass(obj) and issubclass(obj, BaseEvent) and obj != BaseEvent)
|
|
|
|
|
|
|
|
|
|
def add_event_class(self, name: str, event_class: Type[BaseEvent]):
|
|
|
|
|
setattr(self, name, event_class)
|
|
|
|
|
|
feat: Complete plugin lifecycle management with lazy loading and runtime reload
Major changes:
- Add unload() method to all plugins for proper cleanup (unregister commands/providers/LSP clients, destroy widgets, clear state)
- Implement lazy widget loading via "show" signal across all containers
- Add autoload: false manifest option for manual/conditional plugin loading
- Add Plugins UI with runtime load/unload toggle via Ctrl+Shift+p
- Implement controller unregistration system with proper signal disconnection
- Add new events: UnregisterCommandEvent, GetFilesEvent, GetSourceViewsEvent, TogglePluginsUiEvent
- Fix signal leaks by tracking and disconnecting handlers in widgets (search/replace, LSP manager, tabs, telescope, markdown preview)
- Add Save/Save As to tabs context menu
- Improve search/replace behavior (selection handling, focus management)
- Add telescope file initialization from existing loaded files
- Refactor plugin reload watcher to dynamically add/remove plugins on filesystem changes
- Add new plugins: file_history, extend_source_view_menu, godot_lsp_client
- Fix bug in prettify_json (undefined variable reference
2026-03-21 13:26:12 -05:00
|
|
|
def remove_event_class(self, name: str):
|
|
|
|
|
delattr(self, name)
|
|
|
|
|
|
2026-03-15 23:40:40 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
Code_Event_Types = EventNamespace()
|
2026-01-18 00:52:54 -06:00
|
|
|
Event_Factory = EventFactory()
|
2026-03-15 23:40:40 -05:00
|
|
|
|