diff --git a/src/core/widgets/code/command_system.py b/src/core/widgets/code/command_system.py index 4421d9f..c168e83 100644 --- a/src/core/widgets/code/command_system.py +++ b/src/core/widgets/code/command_system.py @@ -3,14 +3,8 @@ # Lib imports # Application imports -from libs.dto.code import ( - CodeEvent, - RequestCompletionEvent, - GetFileEvent, - GetSwapFileEvent, - AddNewFileEvent, - RemoveFileEvent, -) +from libs.dto.code import CodeEvent +from .event_factory import Event_Factory, Event_Factory_Types from . import commands @@ -55,43 +49,47 @@ class CommandSystem: def get_file(self, view: SourceView): - event = GetFileEvent() - event.view = view - event.buffer = view.get_buffer() + event = Event_Factory.create_get_file( + view = view, + buffer = view.get_buffer() + ) self.emit_to("files", event) return event.response def get_swap_file(self, view: SourceView): - event = GetSwapFileEvent() - event.view = self - event.buffer = view.get_buffer() + event = Event_Factory.create_get_swap_file( + view = view, + buffer = view.get_buffer() + ) self.emit_to("files", event) return event.response def new_file(self, view: SourceView): - event = AddNewFileEvent() - event.view = view + event = Event_Factory.create_event("add_new_file", view = view) self.emit_to("files", event) return event.response def remove_file(self, view: SourceView): - event = RemoveFileEvent() - event.view = view - event.buffer = view.get_buffer() + event = Event_Factory.create_remove_file( + view = view, + buffer = view.get_buffer() + ) self.emit_to("files", event) return event.response def request_completion(self, view: SourceView): - event = RequestCompletionEvent() - event.view = view - event.buffer = view.get_buffer() + event = Event_Factory.create_event( + "request_completion", + view = view, + buffer = view.get_buffer() + ) self.emit_to("completion", event) diff --git a/src/core/widgets/code/controllers/files_controller.py b/src/core/widgets/code/controllers/files_controller.py index 078eef1..12ece61 100644 --- a/src/core/widgets/code/controllers/files_controller.py +++ b/src/core/widgets/code/controllers/files_controller.py @@ -3,20 +3,8 @@ # Lib imports # Application imports -from libs.dto.code import ( - CodeEvent, - FilePathSetEvent, - GetSwapFileEvent, - GetFileEvent, - AddNewFileEvent, - PopFileEvent, - SwapFileEvent, - RemoveFileEvent, - AddedNewFileEvent, - SwappedFileEvent, - PoppedFileEvent, - RemovedFileEvent -) +from libs.dto.code import CodeEvent +from ..event_factory import Event_Factory, Event_Factory_Types from ..source_file import SourceFile from ..source_buffer import SourceBuffer @@ -31,20 +19,20 @@ class FilesController(ControllerBase, list): def _controller_message(self, event: CodeEvent): - if isinstance(event, AddNewFileEvent): + if isinstance(event, Event_Factory_Types.AddNewFileEvent): self.new_file(event) - elif isinstance(event, SwapFileEvent): + elif isinstance(event, Event_Factory_Types.SwapFileEvent): self.swap_file(event) - elif isinstance(event, PopFileEvent): + elif isinstance(event, Event_Factory_Types.PopFileEvent): self.pop_file(event) - elif isinstance(event, RemoveFileEvent): + elif isinstance(event, Event_Factory_Types.RemoveFileEvent): self.remove_file(event) - elif isinstance(event, GetFileEvent): + elif isinstance(event, Event_Factory_Types.GetFileEvent): self.get_file(event) - elif isinstance(event, GetSwapFileEvent): + elif isinstance(event, Event_Factory_Types.GetSwapFileEvent): self.get_swap_file(event) - def get_file(self, event: GetFileEvent): + def get_file(self, event: Event_Factory_Types.GetFileEvent): if not event.buffer: return for file in self: @@ -54,7 +42,7 @@ class FilesController(ControllerBase, list): return file - def get_swap_file(self, event: GetSwapFileEvent): + def get_swap_file(self, event: Event_Factory_Types.GetSwapFileEvent): if not event.buffer: return for i, file in enumerate(self): @@ -68,23 +56,25 @@ class FilesController(ControllerBase, list): return swapped_file, next_file - def new_file(self, event: AddNewFileEvent): + def new_file(self, event: Event_Factory_Types.AddNewFileEvent): file = SourceFile() file.emit = self.emit file.emit_to = self.emit_to event.response = file - eve = AddedNewFileEvent() - eve.view = event.view - eve.file = file + eve = Event_Factory.create_event( + "added_new_file", + view = event.view, + file = file + ) self.message_all(eve) self.append(file) return file - def swap_file(self, event: GetSwapFileEvent): + def swap_file(self, event: Event_Factory_Types.GetSwapFileEvent): if not event.buffer: return for i, file in enumerate(self): @@ -98,7 +88,7 @@ class FilesController(ControllerBase, list): return swapped_file, next_file - def pop_file(self, event: PopFileEvent): + def pop_file(self, event: Event_Factory_Types.PopFileEvent): if not event.buffer: return for i, file in enumerate(self): @@ -110,15 +100,17 @@ class FilesController(ControllerBase, list): event.response = [popped_file, next_file] - eve = PoppedFileEvent() - eve.view = view - eve.file = popped_file - eve.next_file = next_file - self.message_all(eve) + eve = Event_Factory.create_event( + "popped_file", + view = view, + file = popped_file, + next_file = next_file + ) + self.message_all(eve) - return popped_file, next_file + return popped_file, next_file - def remove_file(self, event: RemoveFileEvent): + def remove_file(self, event: Event_Factory_Types.RemoveFileEvent): if not event.buffer: return for i, file in enumerate(self): @@ -129,11 +121,13 @@ class FilesController(ControllerBase, list): event.response = next_file - eve = RemovedFileEvent() - eve.view = event.view - eve.ignore_focus = True - eve.file = file - eve.next_file = next_file + eve = Event_Factory.create_event( + "removed_file", + view = event.view, + ignore_focus = True, + file = file, + next_file = next_file + ) self.message_all(eve) self.remove(file) diff --git a/src/core/widgets/code/controllers/source_views_controller.py b/src/core/widgets/code/controllers/source_views_controller.py index 3fd9209..7782187 100644 --- a/src/core/widgets/code/controllers/source_views_controller.py +++ b/src/core/widgets/code/controllers/source_views_controller.py @@ -3,16 +3,7 @@ # Lib imports # Application imports -from libs.dto.code import ( - CodeEvent, - GetCommandSystemEvent, - CursorMovedEvent, - TextChangedEvent, - FocusedViewEvent, - SetActiveFileEvent, - RemoveFileEvent, - RemovedFileEvent -) +from ..event_factory import Event_Factory, Event_Factory_Types from ..command_system import CommandSystem from ..key_mapper import KeyMapper @@ -32,7 +23,7 @@ class SourceViewsController(ControllerBase, list): def get_command_system(self): - event = GetCommandSystemEvent() + event = Event_Factory.create_event("get_command_system") self.message_to("commands", event) command = event.response @@ -49,10 +40,10 @@ class SourceViewsController(ControllerBase, list): self.append(source_view) return source_view - def _controller_message(self, event: CodeEvent): - if isinstance(event, RemovedFileEvent): + def _controller_message(self, event: Event_Factory_Types.CodeEvent): + if isinstance(event, Event_Factory_Types.RemovedFileEvent): self._remove_file(event) - if isinstance(event, TextChangedEvent): + elif isinstance(event, Event_Factory_Types.TextChangedEvent): self.active_view.command.exec("update_info_bar") def _map_signals(self, source_view: SourceView): @@ -70,21 +61,21 @@ class SourceViewsController(ControllerBase, list): view.command.exec("set_focus_border") view.command.exec("update_info_bar") - event = FocusedViewEvent() - event.view = view + event = Event_Factory.create_focused_view(view = view) self.emit(event) def _move_cursor(self, view, step, count, extend_selection): - event = CursorMovedEvent() buffer = view.get_buffer() iter = buffer.get_iter_at_mark( buffer.get_insert() ) line = iter.get_line() char = iter.get_line_offset() - event.view = view - event.buffer = buffer - event.line = line - event.char = char + event = Event_Factory.create_cursor_moved( + view = view, + buffer = buffer, + line = line, + char = char + ) self.emit(event) @@ -102,7 +93,7 @@ class SourceViewsController(ControllerBase, list): view.command.exec(command) - return False + return True def _key_release_event(self, view, eve): command = self.key_mapper._key_release_event(eve) @@ -110,9 +101,9 @@ class SourceViewsController(ControllerBase, list): view.command.exec(command) - return False + return True - def _remove_file(self, event: RemovedFileEvent): + def _remove_file(self, event: Event_Factory_Types.RemovedFileEvent): for view in self: if not event.file.buffer == view.get_buffer(): continue if not event.next_file: diff --git a/src/core/widgets/code/controllers/tabs_controller.py b/src/core/widgets/code/controllers/tabs_controller.py index cd5abf8..ab74c40 100644 --- a/src/core/widgets/code/controllers/tabs_controller.py +++ b/src/core/widgets/code/controllers/tabs_controller.py @@ -3,16 +3,8 @@ # Lib imports # Application imports -from libs.dto.code import ( - CodeEvent, - FocusedViewEvent, - FilePathSetEvent, - RemoveFileEvent, - SetActiveFileEvent, - AddedNewFileEvent, - PoppedFileEvent, - RemovedFileEvent -) +from libs.dto.code import CodeEvent +from ..event_factory import Event_Factory, Event_Factory_Types from ..tabs_widget import TabsWidget from ..tab_widget import TabWidget @@ -32,30 +24,32 @@ class TabsController(ControllerBase): def _controller_message(self, event: CodeEvent): - if isinstance(event, FocusedViewEvent): + if isinstance(event, Event_Factory_Types.FocusedViewEvent): self.active_view = event.view - elif isinstance(event, FilePathSetEvent): + elif isinstance(event, Event_Factory_Types.FilePathSetEvent): self.update_tab_label(event) - elif isinstance(event, AddedNewFileEvent): + elif isinstance(event, Event_Factory_Types.AddedNewFileEvent): self.add_tab(event) - elif isinstance(event, PoppedFileEvent): + elif isinstance(event, Event_Factory_Types.PoppedFileEvent): ... - elif isinstance(event, RemovedFileEvent): + elif isinstance(event, Event_Factory_Types.RemovedFileEvent): self.remove_tab(event) def get_tabs_widget(self): return self.tabs_widget - def update_tab_label(self, event: FilePathSetEvent): + def update_tab_label(self, event: Event_Factory_Types.FilePathSetEvent): for tab in self.tabs_widget.get_children(): if not event.file == tab.file: continue tab.label.set_label(event.file.fname) break - def add_tab(self, event: AddedNewFileEvent): + def add_tab(self, event: Event_Factory_Types.AddedNewFileEvent): def set_active_tab(tab, eve, file): - event = SetActiveFileEvent() - event.buffer = tab.get_parent().file.buffer + event = Event_Factory.create_event( + "set_active_file", + buffer = tab.get_parent().file.buffer + ) self.active_view.set_buffer( tab.get_parent().file.buffer @@ -64,8 +58,10 @@ class TabsController(ControllerBase): self.message_all(event) def close_tab(tab, eve, file): - event = RemoveFileEvent() - event.buffer = tab.get_parent().file.buffer + event = Event_Factory.create_event( + "remove_file", + buffer = tab.get_parent().file.buffer + ) self.message_all(event) @@ -78,7 +74,7 @@ class TabsController(ControllerBase): self.tabs_widget.add(tab) tab.show() - def remove_tab(self, event: RemovedFileEvent): + def remove_tab(self, event: Event_Factory_Types.RemovedFileEvent): for tab in self.tabs_widget.get_children(): if not event.file == tab.file: continue diff --git a/src/core/widgets/code/event_factory.py b/src/core/widgets/code/event_factory.py new file mode 100644 index 0000000..7e34aae --- /dev/null +++ b/src/core/widgets/code/event_factory.py @@ -0,0 +1,101 @@ +# Python imports +import inspect +from typing import Dict, Type +import re + +# Lib imports + +# Application imports +from libs.singleton import Singleton +from libs.dto.code import CodeEvent +from libs.dto import code + + + +class EventFactory(Singleton): + def __init__(self): + self._event_classes: Dict[str, Type[CodeEvent]] = {} + + self._auto_register_events() + + def register_event(self, event_type: str, event_class: Type[CodeEvent]): + self._event_classes[event_type] = event_class + + def create_event(self, event_type: str, **kwargs) -> CodeEvent: + 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 hasattr(event, key): + setattr(event, key, value) + else: + raise ValueError(f"Event class {event_class.__name__} has no attribute '{key}'") + + return event + + def _auto_register_events(self): + for name, obj in code.__dict__.items(): + if not self._is_valid_event_class(obj): continue + + event_type = self._class_name_to_event_type(name) + self.register_event(event_type, obj) + + logger.debug(f"Auto-registered {len(self._event_classes)} event types") + + def _is_valid_event_class(self, obj) -> bool: + return (inspect.isclass(obj) and + issubclass(obj, CodeEvent) and + obj != CodeEvent) + + 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'(?