Code Widget refactor; observable refactor

This commit is contained in:
2025-12-28 19:53:05 -06:00
parent 12ada8568e
commit e18be655e8
37 changed files with 853 additions and 173 deletions

View File

@@ -0,0 +1,38 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from ...widgets.code.tabs_widget import TabsWidget
from .editors_container import EditorsContainer
class CodeContainer(Gtk.Box):
def __init__(self):
super(CodeContainer, self).__init__()
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show_all()
def _setup_styling(self):
self.set_orientation(Gtk.Orientation.VERTICAL)
def _setup_signals(self):
...
def _subscribe_to_events(self):
...
def _load_widgets(self):
self.add( TabsWidget() )
self.add( EditorsContainer() )

View File

@@ -21,8 +21,6 @@ class EditorsContainer(Gtk.Box):
self._subscribe_to_events()
self._load_widgets()
self.show_all()
def _setup_styling(self):
...

View File

@@ -6,7 +6,7 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from .code.editors_container import EditorsContainer
from .code.code_container import CodeContainer
@@ -36,4 +36,4 @@ class FooterContainer(Gtk.Box):
...
def _load_widgets(self):
self.add( EditorsContainer() )
self.add( CodeContainer() )

View File

@@ -12,12 +12,15 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Close File Command")
buffer = editor.get_buffer()
buffer = view.get_buffer()
editor.command.exec("new_file")
sibling_file = view.files_manager.remove_file(buffer)
if not sibling_file:
view.command.exec("new_file")
else:
view.set_buffer(sibling_file.buffer)
editor.files.remove_file(buffer)
editor.command.exec("update_info_bar")
view.command.exec("update_info_bar")

View File

@@ -13,26 +13,23 @@ from gi.repository import Gio
def execute(
editor: GtkSource.View,
view: GtkSource.View,
uri: str
):
logger.debug("DnD Load File To Buffer Command")
if not uri: return
buffer = editor.get_buffer()
file = editor.files.get_file(buffer)
buffer = view.get_buffer()
file = view.files_manager.get_file(buffer)
if not file.ftype == "buffer": return
if not file.ftype == "buffer":
file = view.command.exec("new_file")
gfile = Gio.File.new_for_uri(uri)
editor.command.exec_with_args(
view.command.exec_with_args(
"load_file",
(editor, gfile, file)
(view, gfile, file)
)
ctx = editor.get_parent().get_style_context()
is_focused = ctx.has_class("source-view-focused")
if is_focused:
editor.command.exec("update_info_bar")
return uri
has_focus = view.command.exec("has_focus")
if has_focus:
view.command.exec("update_info_bar")

View File

@@ -14,7 +14,7 @@ from ..source_file import SourceFile
def execute(
editor: GtkSource.View,
view: GtkSource.View,
uris: list = []
):
logger.debug("DnD Load Files Command")
@@ -24,4 +24,4 @@ def execute(
except Exception as e:
gfile = Gio.File.new_for_path(uri)
editor.command.exec_with_args("load_file", (editor, gfile))
view.command.exec_with_args("load_file", (view, gfile))

View File

@@ -12,9 +12,9 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Focus Left Sibling Command")
if not editor.sibling_left: return
editor.sibling_left.grab_focus()
editor.sibling_left.command.exec("set_miniview")
if not view.sibling_left: return
view.sibling_left.grab_focus()
view.sibling_left.command.exec("set_miniview")

View File

@@ -12,9 +12,9 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Focus Right Sibling Command")
if not editor.sibling_right: return
editor.sibling_right.grab_focus()
editor.sibling_right.command.exec("set_miniview")
if not view.sibling_right: return
view.sibling_right.grab_focus()
view.sibling_right.command.exec("set_miniview")

View File

@@ -12,8 +12,8 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Has Focus Command")
ctx = editor.get_parent().get_style_context()
ctx = view.get_parent().get_style_context()
return ctx.has_class("source-view-focused")

View File

@@ -12,7 +12,7 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Line Up Command")
editor.emit("move-lines", True)
view.emit("move-lines", True)

View File

@@ -12,7 +12,7 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Line Up Command")
editor.emit("move-lines", False)
view.emit("move-lines", False)

View File

@@ -14,19 +14,19 @@ from ..source_file import SourceFile
def execute(
editor: GtkSource.View,
view: GtkSource.View,
gfile: Gio.File,
file: SourceFile = None,
):
logger.debug("Load File Command")
if not file:
file = editor.files.new()
file = view.files_manager.new()
file.load_path(gfile)
language = editor.language_manager \
language = view.language_manager \
.guess_language(file.fname, None)
file.ftype = language
file.buffer.set_language(language)
file.buffer.set_style_scheme(editor.syntax_theme)
file.buffer.set_style_scheme(view.syntax_theme)

View File

@@ -14,7 +14,7 @@ from ..source_file import SourceFile
def execute(
editor: GtkSource.View,
view: GtkSource.View,
):
logger.debug("Load Start File(s) Command")
@@ -25,12 +25,12 @@ def execute(
file = starting_files.pop()
file = file.replace("FILE|", "")
gfile = Gio.File.new_for_path(file)
buffer = editor.get_buffer()
file = editor.files.get_file(buffer)
buffer = view.get_buffer()
file = view.files_manager.get_file(buffer)
editor.command.exec_with_args(
view.command.exec_with_args(
"load_file",
(editor, gfile, file)
(view, gfile, file)
)
if len(starting_files) == 0: return
@@ -39,4 +39,4 @@ def execute(
file = file.replace("FILE|", "")
gfile = Gio.File.new_for_path(file)
editor.command.exec_with_args("load_file", (editor, gfile))
view.command.exec_with_args("load_file", (view, gfile))

View File

@@ -12,23 +12,22 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Move To Left Sibling Command")
if not editor.sibling_left: return
if not view.sibling_left: return
buffer = editor.get_buffer()
popped_file, sibling_file = editor.files.pop_file(buffer)
buffer = view.get_buffer()
popped_file, sibling_file = view.files_manager.swap_file(buffer)
if sibling_file:
sibling_file.subscribe(editor)
editor.set_buffer(sibling_file.buffer)
sibling_file.add_observer(view)
view.set_buffer(sibling_file.buffer)
else:
sibling_file = editor.command.exec("new_file")
sibling_file = view.command.exec("new_file")
popped_file.unsubscribe(editor)
popped_file.subscribe(editor.sibling_left)
popped_file.remove_observer(view)
popped_file.add_observer(view.sibling_left)
editor.sibling_left.set_buffer(buffer)
editor.sibling_left.files.append(popped_file)
editor.sibling_left.grab_focus()
view.sibling_left.set_buffer(buffer)
view.sibling_left.grab_focus()

View File

@@ -12,24 +12,23 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Move To Right Sibling Command")
if not editor.sibling_right: return
if not view.sibling_right: return
buffer = editor.get_buffer()
popped_file, sibling_file = editor.files.pop_file(buffer)
buffer = view.get_buffer()
popped_file, sibling_file = view.files_manager.swap_file(buffer)
if sibling_file:
sibling_file.subscribe(editor)
editor.set_buffer(sibling_file.buffer)
sibling_file.add_observer(view)
view.set_buffer(sibling_file.buffer)
else:
sibling_file = editor.command.exec("new_file")
sibling_file = view.command.exec("new_file")
popped_file.unsubscribe(editor)
popped_file.subscribe(editor.sibling_right)
popped_file.remove_observer(view)
popped_file.add_observer(view.sibling_right)
editor.sibling_right.set_buffer(buffer)
editor.sibling_right.files.append(popped_file)
editor.sibling_right.grab_focus()
view.sibling_right.set_buffer(buffer)
view.sibling_right.grab_focus()

View File

@@ -1,5 +1,6 @@
# Python imports
# Lib imports
import gi
@@ -12,21 +13,21 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("New File Command")
file = editor.files.new()
language = editor.language_manager \
file = view.files_manager.new()
language = view.language_manager \
.guess_language("file.txt", None)
file.buffer.set_language(language)
file.buffer.set_style_scheme(editor.syntax_theme)
file.buffer.set_style_scheme(view.syntax_theme)
editor.set_buffer(file.buffer)
file.subscribe(editor)
view.set_buffer(file.buffer)
file.add_observer(view)
has_focus = editor.command.exec("has_focus")
has_focus = view.command.exec("has_focus")
if not has_focus: return file
editor.command.exec("update_info_bar")
view.command.exec("update_info_bar")
return file

View File

@@ -12,7 +12,7 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Open File(s) Command")
gfiles = event_system.emit_and_await("open-files")
@@ -20,14 +20,14 @@ def execute(
size = len(gfiles)
for i, gfile in enumerate(gfiles):
file = editor.files.new()
editor.command.exec_with_args("load_file", (editor, gfile, file))
file = view.files_manager.new()
view.command.exec_with_args("load_file", (view, gfile, file))
if i == (size - 1):
buffer = editor.get_buffer()
_file = editor.files.get_file(buffer)
_file.unsubscribe(editor)
buffer = view.get_buffer()
_file = view.files_manager.get_file(buffer)
_file.remove_observer(view)
editor.set_buffer(file.buffer)
file.subscribe(editor)
editor.command.exec("update_info_bar")
view.set_buffer(file.buffer)
file.add_observer(view)
view.command.exec("update_info_bar")

View File

@@ -12,16 +12,16 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Save File Command")
buffer = editor.get_buffer()
file = editor.files.get_file(buffer)
buffer = view.get_buffer()
file = view.files_manager.get_file(buffer)
if file.ftype == "buffer":
file.save_as()
language = editor.language_manager \
.guess_language(file.fname, None)
language = view.language_manager \
.guess_language(file.fname, None)
file.ftype = language
file.buffer.set_language(language)
return

View File

@@ -12,17 +12,17 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.info("Save File As Command")
buffer = editor.get_buffer()
file = editor.files.get_file(buffer)
buffer = view.get_buffer()
file = view.files_manager.get_file(buffer)
file.save_as()
language = editor.language_manager \
language = view.language_manager \
.guess_language(file.fname, None)
file.ftype = language
file.buffer.set_language(language)
file.subscribe(editor)
editor.exec_command("update_info_bar")
file.add_observer(view)
view.exec_command("update_info_bar")

View File

@@ -12,15 +12,15 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Set Focus Border Command")
ctx = editor.get_parent().get_style_context()
ctx = view.get_parent().get_style_context()
ctx.add_class("source-view-focused")
if editor.sibling_right:
ctx = editor.sibling_right.get_parent().get_style_context()
elif editor.sibling_left:
ctx = editor.sibling_left.get_parent().get_style_context()
if view.sibling_right:
ctx = view.sibling_right.get_parent().get_style_context()
elif view.sibling_left:
ctx = view.sibling_left.get_parent().get_style_context()
ctx.remove_class("source-view-focused")

View File

@@ -9,13 +9,19 @@ from gi.repository import GtkSource
from gi.repository import Gio
# Application imports
from libs.dto.code_event import CodeEvent
from ..source_file import SourceFile
def execute(
editor: GtkSource.View,
view: GtkSource.View,
):
logger.debug("Set MiniView Command")
event_system.emit("set-mini-view", (editor,))
event_system.emit("set-mini-view", (view,))
event = CodeEvent()
event.etype = "focused_view_change"
event.view = view
view.notify_observers(event)

View File

@@ -12,7 +12,7 @@ from gi.repository import GtkSource
def execute(
editor: GtkSource.View = None
view: GtkSource.View = None
):
logger.debug("Show Completion Command")
editor.completion.request_completion()
view.completion.request_completion()

View File

@@ -14,11 +14,11 @@ from ..source_file import SourceFile
def execute(
editor: GtkSource.View,
view: GtkSource.View,
):
logger.debug("Update Info Bar Command")
buffer = editor.get_buffer()
file = editor.files.get_file(buffer)
buffer = view.get_buffer()
file = view.files_manager.get_file(buffer)
if not file: return

View File

@@ -26,10 +26,8 @@ class GeneralInfoWidget(Gtk.Box):
def _setup_styling(self):
self.set_margin_top(20)
self.set_margin_bottom(20)
self.set_margin_left(25)
self.set_margin_right(25)
self.set_margin_start(25)
self.set_margin_end(25)
def _setup_signals(self):
...

View File

@@ -29,8 +29,12 @@ class SourceViewDnDMixin:
if len(uris) == 0:
uris = data.get_text().split("\n")
pop_file = self.command.exec_with_args("dnd_load_file_to_buffer", (self, uris[0]))
if pop_file:
uris.pop(0)
self._on_uri_data_received(uris)
def _on_uri_data_received(self, uris: []):
uri = uris.pop(0)
self.command.exec_with_args("dnd_load_file_to_buffer", (self, uri))
if len(uris) == 0: return
self.command.exec_with_args("dnd_load_files", (self, uris))

View File

@@ -3,6 +3,7 @@
# Lib imports
# Application imports
from libs.dto.code_event import CodeEvent
@@ -35,12 +36,12 @@ class SourceViewEventsMixin:
self.command.exec(command)
return True
def notify(self, file, buffer, etype: str):
def notification(self, event: CodeEvent):
has_focus = self.command.exec("has_focus")
if not has_focus: return
self.command.exec("update_info_bar")
match etype:
match event.etype:
case "changed":
logger.debug("SourceFile._changed")
case "modified_changed":

View File

@@ -12,11 +12,14 @@ from gi.repository import GtkSource
from gi.repository import Gio
# Application imports
from libs.mixins.observable_mixin import ObservableMixin
from libs.dto.code_event import CodeEvent
from .source_buffer import SourceBuffer
class SourceFile(GtkSource.File):
class SourceFile(GtkSource.File, ObservableMixin):
def __init__(self):
super(SourceFile, self).__init__()
@@ -44,19 +47,39 @@ class SourceFile(GtkSource.File):
def _insert_text(self, buffer: SourceBuffer, location: Gtk.TextIter,
text: str, length: int
):
self.notify((self, buffer, "insert_text"))
event = CodeEvent()
event.etype = "insert_text"
event.file = self
event.buffer = buffer
self.notify_observers(event)
def _changed(self, buffer: SourceBuffer):
self.notify((self, buffer, "changed"))
event = CodeEvent()
event.etype = "changed"
event.file = self
event.buffer = buffer
self.notify_observers(event)
def _mark_set(self, buffer: SourceBuffer, location: Gtk.TextIter,
mark: Gtk.TextMark
):
# self.notify((self, buffer, "mark_set"))
# event = CodeEvent()
# event.etype = "mark_set"
# event.file = self
# event.buffer = buffer
# self.notify_observers(event)
...
def _modified_changed(self, buffer: SourceBuffer):
self.notify((self, buffer, "modified_changed"))
event = CodeEvent()
event.etype = "modified_changed"
event.file = self
event.buffer = buffer
self.notify_observers(event)
def _write_file(self, gfile: Gio.File):
@@ -87,16 +110,11 @@ class SourceFile(GtkSource.File):
self.fpath = gfile.get_path()
self.fname = gfile.get_basename()
event = CodeEvent()
event.etype = "set_path"
event.file = self
def subscribe(self, editor):
self.observers.append(editor)
def unsubscribe(self, editor):
self.observers.remove(editor)
def notify(self, data):
for editor in self.observers:
editor.notify(*data)
self.notify_observers(event)
def save(self):
self._write_file( self.get_location() )
@@ -113,5 +131,5 @@ class SourceFile(GtkSource.File):
def close(self):
self.observers.clear()
del observers
del self.observers
del self.buffer

View File

@@ -3,15 +3,21 @@
# Lib imports
# Application imports
from libs.mixins.observable_mixin import ObservableMixin
from libs.singleton import Singleton
from libs.dto.code_event import CodeEvent
from .source_file import SourceFile
from .source_buffer import SourceBuffer
class SourceFilesManager(list):
class SourceFilesManager(Singleton, list, ObservableMixin):
def __init__(self):
super(SourceFilesManager, self).__init__()
self.observers = []
def new(self):
file = SourceFile()
@@ -22,10 +28,16 @@ class SourceFilesManager(list):
if not file: return
super().append(file)
event = CodeEvent()
event.file = file
event.etype = "appended_file"
self.notify_observers(event)
def get_file(self, buffer: SourceBuffer):
if not buffer: return
for i, file in enumerate(self):
for file in self:
if not buffer == file.buffer: continue
return file
@@ -45,15 +57,52 @@ class SourceFilesManager(list):
j = 0 if size == 1 else i - 1 if i > 1 else i + 1
sibling_file = self[j]
event = CodeEvent()
event.file = popped_file
event.etype = "popped_file"
self.notify_observers(event)
return popped_file, sibling_file
def swap_file(self, buffer: SourceBuffer):
if not buffer: return
for i, file in enumerate(self):
if not buffer == file.buffer: continue
swapped_file = self[i]
sibling_file = None
size = len(self)
if size == 0:
return swapped_file, sibling_file
j = 0 if size == 1 else i - 1 if i > 1 else i + 1
sibling_file = self[j]
return swapped_file, sibling_file
def remove_file(self, buffer: SourceBuffer):
if not buffer: return
for file in self:
for i, file in enumerate(self):
if not buffer == file.buffer: continue
self.remove(file)
event = CodeEvent()
event.file = file
event.etype = "removed_file"
self.notify_observers(event)
size = len(self)
if size == 0:
return None
j = 0 if size == 1 else i - 1 if i > 1 else i + 1
sibling_file = self[j]
file.close()
del file
break
return sibling_file

View File

@@ -0,0 +1,53 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
class TabWidget(Gtk.Box):
def __init__(self):
super(TabWidget, self).__init__()
self.file = None
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
self.show_all()
def _setup_styling(self):
ctx = self.get_style_context()
ctx.add_class("tab-widget")
def _setup_signals(self):
...
def _subscribe_to_events(self):
...
def _load_widgets(self):
self.label = Gtk.Label(label="")
self.close_btn = Gtk.Button(label="X")
ctx = self.label.get_style_context()
ctx.add_class("tab-label")
ctx = self.close_btn.get_style_context()
ctx.add_class("tab-close-bttn")
self.label.set_hexpand(True)
self.add(self.label)
self.add(self.close_btn)
def __del__(self):
# for handle_id in self._handler_ids:
# self.disconnect(handle_id)
...

View File

@@ -0,0 +1,100 @@
# Python imports
# Lib imports
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
# Application imports
from libs.dto.code_event import CodeEvent
from .view import SourceView
from .source_files_manager import SourceFilesManager
from .source_file import SourceFile
from .tab_widget import TabWidget
class TabsWidget(Gtk.ScrolledWindow):
def __init__(self):
super(TabsWidget, self).__init__()
self.active_view: SourceView = None
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
self._load_widgets()
def _setup_styling(self):
self.set_overlay_scrolling(False)
def _setup_signals(self):
event_system.subscribe("register-view-to-tabs-widget", self._register_view_to_tabs_widget)
def _subscribe_to_events(self):
self.files_manager: SourceFilesManager = SourceFilesManager()
self.files_manager.add_observer(self)
def _load_widgets(self):
self.viewport = Gtk.Viewport()
self.tabs = Gtk.ButtonBox()
self.tabs.set_layout(Gtk.ButtonBoxStyle.CENTER)
self.viewport.add(self.tabs)
self.add(self.viewport)
def _register_view_to_tabs_widget(self, view: SourceView):
view.add_observer(self)
view.set_files_manager(self.files_manager)
def notification(self, event: CodeEvent):
match event.etype:
case "focused_view_change":
logger.debug("SourceView.focused_view_change")
self.active_view = event.view
case "appended_file":
logger.debug("SourceFilesManager.appended")
self.add_tab(event)
case "popped_file":
logger.debug("SourceFilesManager.pop_file")
case "removed_file":
logger.debug("SourceFilesManager.remove_file")
self.remove_tab(event)
case "set_path":
logger.debug("SourceFile.set_path")
self.update_tab_label(event)
case _:
...
def add_tab(self, event: CodeEvent):
tab = TabWidget()
tab.file = event.file
tab.label.set_label(event.file.fname)
event.file.add_observer(self)
self.tabs.add(tab)
tab.show()
def remove_tab(self, event: CodeEvent):
for child in self.tabs.get_children():
if not child.file == event.file: continue
child.file.remove_observer(self)
self.tabs.remove(child)
del child.file
del child
return
def update_tab_label(self, event: CodeEvent):
for tab in self.tabs.get_children():
if not tab.file == event.file: continue
tab.label.set_label(event.file.fname)
return

View File

@@ -10,6 +10,8 @@ from gi.repository import GLib
from gi.repository import GtkSource
# Application imports
from libs.mixins.observable_mixin import ObservableMixin
from .mixins.source_view_events_mixin import SourceViewEventsMixin
from .mixins.source_view_dnd_mixin import SourceViewDnDMixin
@@ -20,13 +22,14 @@ from .key_mapper import KeyMapper
class SourceView(SourceViewEventsMixin, SourceViewDnDMixin, GtkSource.View):
class SourceView(GtkSource.View, ObservableMixin, SourceViewEventsMixin, SourceViewDnDMixin):
def __init__(self):
super(SourceView, self).__init__()
self.observers = []
self.sibling_right = None
self.sibling_left = None
self.key_mapper = KeyMapper()
self._setup_styles()
self._setup_signals()
@@ -57,6 +60,7 @@ class SourceView(SourceViewEventsMixin, SourceViewDnDMixin, GtkSource.View):
def _setup_signals(self):
self.map_id = self.connect("map", self._init_map)
self.connect("focus-in-event", self._focus_in_event)
self.connect("drag-data-received", self._on_drag_data_received)
self.connect("move-cursor", self._move_cursor)
self.connect("key-press-event", self._key_press_event)
@@ -69,6 +73,7 @@ class SourceView(SourceViewEventsMixin, SourceViewDnDMixin, GtkSource.View):
def _load_widgets(self):
self._set_up_dnd()
event_system.emit("register-view-to-tabs-widget", (self,))
def _init_map(self, view):
self.disconnect(self.map_id)
@@ -79,8 +84,9 @@ class SourceView(SourceViewEventsMixin, SourceViewDnDMixin, GtkSource.View):
def _init_show(self):
self.language_manager = GtkSource.LanguageManager()
self.style_scheme_manager = GtkSource.StyleSchemeManager()
self.key_mapper = KeyMapper()
self.command = CommandSystem()
self.files = SourceFilesManager()
self.completion = CompletionManager()
self.command.set_data(self)
@@ -93,13 +99,15 @@ class SourceView(SourceViewEventsMixin, SourceViewDnDMixin, GtkSource.View):
f"{settings_manager.settings.theming.syntax_theme}"
)
self.connect("focus-in-event", self._focus_in_event)
self.command.exec("new_file")
if not self.sibling_right: return
self.grab_focus()
self._focus_in_event(None, None)
self.command.exec("load_start_files")
return False
def set_files_manager(self, files_manager: SourceFilesManager):
self.files_manager = files_manager
# self.files_manager.add_observer(self)

View File

@@ -0,0 +1,16 @@
# Python imports
from dataclasses import dataclass, field
# Lib imports
# Application imports
from .observable_event import ObservableEvent
@dataclass
class CodeEvent(ObservableEvent):
etype: str = ""
view: any = None
file: any = None
buffer: any = None

View File

@@ -0,0 +1,10 @@
# Python imports
# Lib imports
# Application imports
class ObservableEvent:
...

View File

@@ -0,0 +1,26 @@
# Python imports
# Lib imports
# Application imports
from ..dto.observable_event import ObservableEvent
class ObservableMixin:
observers = []
def add_observer(self, observer: any):
if not hasattr(observer, 'notification') or not callable(getattr(observer, 'notification')):
raise ValueError(f"Observer '{observer}' must implement a `notification` method.")
self.observers.append(observer)
def remove_observer(self, observer: any):
if not observer in self.observers: return
self.observers.remove(observer)
def notify_observers(self, event: ObservableEvent):
for observer in self.observers:
observer.notification(event)

View File

@@ -15,8 +15,15 @@ class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance:
raise SingletonError(f"'{cls.__name__}' is a Singleton. Cannot create a new instance...")
if cls._instance is not None:
logger.debug(f"'{cls.__name__}' is a Singleton. Returning instance...")
return cls._instance
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
def __init__(self):
if self._instance is not None:
return
super(Singleton, self).__init__()

View File

@@ -0,0 +1,26 @@
# Python imports
# Lib imports
# Application imports
class SingletonError(Exception):
pass
class SingletonRaised:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is not None:
raise SingletonError(f"'{cls.__name__}' is a Singleton. Cannot create a new instance...")
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance
def __init__(self):
if cls._instance is not None:
return