From 824dd93696604b310664b3aa5e9772eb9a1c22af Mon Sep 17 00:00:00 2001 From: itdominator <1itdominator@gmail.com> Date: Mon, 23 Feb 2026 00:48:09 -0600 Subject: [PATCH] Add file deletion detection, WebKit improvements, and bug fixes - Add FileExternallyDeletedEvent with UI indicator in tabs for deleted files - Set minimum height (300px) for editors container - Add Developer Tools to WebKit context menu - Fix DnD URI handling when uris list is empty - Fix buffer replacement using freeze_notify and proper bounds handling - Move webkit_ui_settings to new path - Remove placeholders from APP_NAME and user config --- src/__builtins__.py | 2 +- src/core/containers/code/editors_container.py | 1 + .../commands/dnd_load_file_to_buffer.py | 1 + .../code/controllers/tabs_controller.py | 2 + .../code/mixins/source_view_dnd_mixin.py | 4 +- src/core/widgets/code/source_file.py | 43 ++++++++++++++---- src/core/widgets/code/tabs_widget.py | 8 ++++ src/core/widgets/webkit/webkit_ui.py | 42 ++++++++++++++--- src/libs/dto/code/__init__.py | 2 + .../dto/code/file_externally_deleted_event.py | 13 ++++++ .../code/file_externally_modified_event.py | 13 ++++++ .../settings/{other => webkit}/__init__.py | 0 .../{other => webkit}/webkit_ui_settings.py | 2 +- ...{.desktop => change_me.desktop} | 0 .../share/app_name/context_path/index.html | 17 ++++--- ...ange_me>-64x64.png => change_me-64x64.png} | Bin .../icons/{.png => change_me.png} | Bin 17 files changed, 123 insertions(+), 27 deletions(-) create mode 100644 src/libs/dto/code/file_externally_deleted_event.py create mode 100644 src/libs/dto/code/file_externally_modified_event.py rename src/libs/settings/{other => webkit}/__init__.py (100%) rename src/libs/settings/{other => webkit}/webkit_ui_settings.py (98%) rename user_config/usr/applications/{.desktop => change_me.desktop} (100%) rename user_config/usr/share/app_name/icons/{-64x64.png => change_me-64x64.png} (100%) rename user_config/usr/share/app_name/icons/{.png => change_me.png} (100%) diff --git a/src/__builtins__.py b/src/__builtins__.py index 2c41337..f8225ff 100644 --- a/src/__builtins__.py +++ b/src/__builtins__.py @@ -43,7 +43,7 @@ def call_chain_wrapper(fn): # NOTE: Just reminding myself we can add to builtins two different ways... # __builtins__.update({"event_system": Builtins()}) -builtins.APP_NAME = "" +builtins.APP_NAME = "".replace("<","").replace(">","") builtins.keybindings = Keybindings() builtins.event_system = EventSystem() diff --git a/src/core/containers/code/editors_container.py b/src/core/containers/code/editors_container.py index 06409a7..c9350fe 100644 --- a/src/core/containers/code/editors_container.py +++ b/src/core/containers/code/editors_container.py @@ -26,6 +26,7 @@ class EditorsContainer(Gtk.Paned): self.ctx = self.get_style_context() self.ctx.add_class("paned-editors-container") + self.set_size_request(-1, 300) self.set_hexpand(True) self.set_vexpand(True) self.set_wide_handle(True) diff --git a/src/core/widgets/code/command_system/commands/dnd_load_file_to_buffer.py b/src/core/widgets/code/command_system/commands/dnd_load_file_to_buffer.py index 653cc40..d596632 100644 --- a/src/core/widgets/code/command_system/commands/dnd_load_file_to_buffer.py +++ b/src/core/widgets/code/command_system/commands/dnd_load_file_to_buffer.py @@ -27,4 +27,5 @@ def execute( ) view.set_buffer(file.buffer) + update_info_bar_if_focused(view.command, view) diff --git a/src/core/widgets/code/controllers/tabs_controller.py b/src/core/widgets/code/controllers/tabs_controller.py index da233a6..4b7d6c8 100644 --- a/src/core/widgets/code/controllers/tabs_controller.py +++ b/src/core/widgets/code/controllers/tabs_controller.py @@ -31,6 +31,8 @@ class TabsController(ControllerBase): self.update_tab_label(event) elif isinstance(event, Code_Event_Types.ModifiedChangedEvent): self.tabs_widget.modified_changed( event.buffer ) + elif isinstance(event, Code_Event_Types.FileExternallyDeletedEvent): + self.tabs_widget.externally_deleted( event.buffer ) elif isinstance(event, Code_Event_Types.AddedNewFileEvent): self.add_tab(event) elif isinstance(event, Code_Event_Types.PoppedFileEvent): diff --git a/src/core/widgets/code/mixins/source_view_dnd_mixin.py b/src/core/widgets/code/mixins/source_view_dnd_mixin.py index bbe30be..46299b3 100644 --- a/src/core/widgets/code/mixins/source_view_dnd_mixin.py +++ b/src/core/widgets/code/mixins/source_view_dnd_mixin.py @@ -26,8 +26,8 @@ class SourceViewDnDMixin: if info == 80: uris = data.get_uris() - if not uris: return - uris = data.get_text().split("\n") + if not uris: + uris = data.get_text().split("\n") self._on_uri_data_received(uris) diff --git a/src/core/widgets/code/source_file.py b/src/core/widgets/code/source_file.py index a194f9c..be1054f 100644 --- a/src/core/widgets/code/source_file.py +++ b/src/core/widgets/code/source_file.py @@ -27,6 +27,7 @@ class SourceFile(GtkSource.File): self.fname: str = "buffer" self.fpath: str = "buffer" self.ftype: str = "buffer" + self.was_deleted: bool = False self.buffer: SourceBuffer = SourceBuffer() self._set_signals() @@ -56,17 +57,22 @@ class SourceFile(GtkSource.File): self.emit(event) if self.is_deleted(): - print("is_deleted") - # event = Event_Factory.create_event("file_deleted", buffer = buffer) - # event.file = self - # self.emit(event) + self.was_deleted = True + event = Event_Factory.create_event( + "file_externally_deleted", + file = self, + buffer = buffer + ) + self.emit(event) return if self.is_externally_modified(): - print("is_externally_modified") - # event = Event_Factory.create_event("file_externally_modified", buffer = buffer) - # event.file = self - # self.emit(event) +# event = Event_Factory.create_event( +# "file_externally_modified", +# file = self, +# buffer = buffer +# ) +# self.emit(event) return def _insert_text( @@ -128,6 +134,12 @@ class SourceFile(GtkSource.File): f.write(text) + if self.was_deleted: + self.was_deleted = False +# self.set_path(gfile) + self.set_location( None ) + self.set_location( gfile ) + return gfile @@ -135,11 +147,22 @@ class SourceFile(GtkSource.File): if not gfile: return self.set_path(gfile) - data = gfile.load_bytes()[0].get_data().decode("UTF-8") + text = gfile.load_bytes()[0].get_data().decode("UTF-8") undo_manager = self.buffer.get_undo_manager() + def move_insert_to_start(): + start_itr = self.buffer.get_start_iter() + self.buffer.place_cursor(start_itr) + undo_manager.begin_not_undoable_action() - self.buffer.insert_at_cursor(data) + + with self.buffer.freeze_notify(): + start_itr, end_itr = self.buffer.get_bounds() + + self.buffer.delete(start_itr, end_itr) + self.buffer.insert(start_itr, text, -1) + GLib.idle_add(move_insert_to_start) + undo_manager.end_not_undoable_action() self.buffer.set_modified(False) diff --git a/src/core/widgets/code/tabs_widget.py b/src/core/widgets/code/tabs_widget.py index 90198b2..3f7487f 100644 --- a/src/core/widgets/code/tabs_widget.py +++ b/src/core/widgets/code/tabs_widget.py @@ -122,11 +122,19 @@ class TabsWidget(Gtk.Notebook): if not buffer == tab.file.buffer: continue ctx = tab.label.get_style_context() + ctx.remove_class("file-deleted") if buffer.get_modified(): ctx.add_class("file-changed") else: ctx.remove_class("file-changed") + def externally_deleted(self, buffer): + for page_widget in self.get_children(): + tab = self.get_tab_label(page_widget) + if not buffer == tab.file.buffer: continue + ctx = tab.label.get_style_context() + ctx.add_class("file-deleted") + def close_item(self, menu_item, page_widget): tab = self.get_tab_label(page_widget) tab.close_bttn.clicked() diff --git a/src/core/widgets/webkit/webkit_ui.py b/src/core/widgets/webkit/webkit_ui.py index 3d2ede1..69d7faf 100644 --- a/src/core/widgets/webkit/webkit_ui.py +++ b/src/core/widgets/webkit/webkit_ui.py @@ -1,4 +1,5 @@ # Python imports +from pathlib import Path import json # Lib imports @@ -6,10 +7,12 @@ import gi gi.require_version('Gdk', '3.0') gi.require_version('WebKit2', '4.0') from gi.repository import Gdk +from gi.repository import Gtk +from gi.repository import Gio from gi.repository import WebKit2 # Application imports -from libs.settings.other.webkit_ui_settings import WebkitUISettings +from libs.settings.webkit.webkit_ui_settings import WebkitUISettings from libs.dto.base_event import BaseEvent @@ -17,7 +20,9 @@ class WebkitUI(WebKit2.WebView): def __init__(self): super(WebkitUI, self).__init__() + self._load_settings() self._setup_styling() + self._setup_signals() self._subscribe_to_events() self._setup_content_manager() @@ -29,6 +34,9 @@ class WebkitUI(WebKit2.WebView): self.set_hexpand(True) self.set_background_color( Gdk.RGBA(0, 0, 0, 0.0) ) + def _setup_signals(self): + self.connect("context-menu", self._on_context_menu) + def _subscribe_to_events(self): event_system.subscribe(f"ui-message", self.ui_message) @@ -50,6 +58,18 @@ class WebkitUI(WebKit2.WebView): except Exception as e: logger.info(e) + def _on_context_menu(self, web_view, context_menu, event, hit_test_result): + action = Gio.SimpleAction.new("Developer Tools", None) + item = WebKit2.ContextMenuItem.new_from_gaction(action, "Developer Tools") + + def show_developer_tools(action, parameter): + inspector = self.get_inspector() + inspector.show() + + action.connect("activate", show_developer_tools) + + context_menu.append(item) + def load_url(self, url: str = ""): if not url: url = "https://duckduckgo.com/" @@ -58,13 +78,23 @@ class WebkitUI(WebKit2.WebView): def load_context_base_path(self, path: str = ""): if not path: - path = settings_manager.path_manager.get_context_path() + path = settings_manager.path_manager.get_context_path() - data = None - with open(f"{path}/index.html", "r") as f: - data = f.read() + base_path = Path(path) + index_file = base_path / "index.html" - self.load_html(content = data, base_uri = f"file://{path}") + if not index_file.exists(): + raise FileNotFoundError(f"index.html not found in {base_path}") + + try: + data = index_file.read_text(encoding = "utf-8") + except Exception as e: + raise RuntimeError(f"Failed to read {index_file}: {e}") + + self.load_html( + content = data, + base_uri = index_file.as_uri() + ) def ui_message(self, message, mtype): command = f"displayMessage('{message}', '{mtype}', '3')" diff --git a/src/libs/dto/code/__init__.py b/src/libs/dto/code/__init__.py index aff9d7d..0616520 100644 --- a/src/libs/dto/code/__init__.py +++ b/src/libs/dto/code/__init__.py @@ -6,6 +6,8 @@ from .code_event import CodeEvent from .register_provider_event import RegisterProviderEvent from .register_command_event import RegisterCommandEvent +from .file_externally_modified_event import FileExternallyModifiedEvent +from .file_externally_deleted_event import FileExternallyDeletedEvent from .get_new_command_system_event import GetNewCommandSystemEvent from .request_completion_event import RequestCompletionEvent diff --git a/src/libs/dto/code/file_externally_deleted_event.py b/src/libs/dto/code/file_externally_deleted_event.py new file mode 100644 index 0000000..2751a47 --- /dev/null +++ b/src/libs/dto/code/file_externally_deleted_event.py @@ -0,0 +1,13 @@ +# Python imports +from dataclasses import dataclass, field + +# Lib imports + +# Application imports +from .code_event import CodeEvent + + + +@dataclass +class FileExternallyDeletedEvent(CodeEvent): + ... diff --git a/src/libs/dto/code/file_externally_modified_event.py b/src/libs/dto/code/file_externally_modified_event.py new file mode 100644 index 0000000..cbefacc --- /dev/null +++ b/src/libs/dto/code/file_externally_modified_event.py @@ -0,0 +1,13 @@ +# Python imports +from dataclasses import dataclass, field + +# Lib imports + +# Application imports +from .code_event import CodeEvent + + + +@dataclass +class FileExternallyModifiedEvent(CodeEvent): + ... diff --git a/src/libs/settings/other/__init__.py b/src/libs/settings/webkit/__init__.py similarity index 100% rename from src/libs/settings/other/__init__.py rename to src/libs/settings/webkit/__init__.py diff --git a/src/libs/settings/other/webkit_ui_settings.py b/src/libs/settings/webkit/webkit_ui_settings.py similarity index 98% rename from src/libs/settings/other/webkit_ui_settings.py rename to src/libs/settings/webkit/webkit_ui_settings.py index 548dd2f..0351fc6 100644 --- a/src/libs/settings/other/webkit_ui_settings.py +++ b/src/libs/settings/webkit/webkit_ui_settings.py @@ -95,7 +95,7 @@ class WebkitUISettings(WebKit2.Settings): self.set_property('javascript-can-open-windows-automatically', False) # Debugging - self.set_property('enable-developer-extras', False) + self.set_property('enable-developer-extras', True) self.set_property('enable-write-console-messages-to-stdout', False) self.set_property('draw-compositing-indicators', False) self.set_property('enable-mock-capture-devices', False) diff --git a/user_config/usr/applications/.desktop b/user_config/usr/applications/change_me.desktop similarity index 100% rename from user_config/usr/applications/.desktop rename to user_config/usr/applications/change_me.desktop diff --git a/user_config/usr/share/app_name/context_path/index.html b/user_config/usr/share/app_name/context_path/index.html index 6d92d85..a76b63b 100644 --- a/user_config/usr/share/app_name/context_path/index.html +++ b/user_config/usr/share/app_name/context_path/index.html @@ -3,14 +3,17 @@ Gtk + HTML + Python App - - - + + - - - - + + + + + + + + diff --git a/user_config/usr/share/app_name/icons/-64x64.png b/user_config/usr/share/app_name/icons/change_me-64x64.png similarity index 100% rename from user_config/usr/share/app_name/icons/-64x64.png rename to user_config/usr/share/app_name/icons/change_me-64x64.png diff --git a/user_config/usr/share/app_name/icons/.png b/user_config/usr/share/app_name/icons/change_me.png similarity index 100% rename from user_config/usr/share/app_name/icons/.png rename to user_config/usr/share/app_name/icons/change_me.png