Compare commits

..

2 Commits

Author SHA1 Message Date
7c7e88aaed Code cleanp scan through 2026-02-22 21:55:31 -06:00
67300bc180 Add debounced text change handling and modified file indicator for tabs
- Debounce word completer refresh with 1500ms timeout to reduce overhead
- Add visual indicator (file-changed class) for modified files in tabs
- Refactor buffer switching into signal_mapper for DRY code
- Fix handler ID indices after adding _after_changed signal
- Move set_modified(False) after successful file write in save()
2026-02-22 18:20:29 -06:00
17 changed files with 91 additions and 56 deletions

View File

@@ -20,6 +20,7 @@ class ProviderResponseCache(ProviderResponseCacheBase):
super(ProviderResponseCache, self).__init__()
self.matchers: dict = {}
self._temp_timeout_id: int = None
def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent):
@@ -36,9 +37,22 @@ class ProviderResponseCache(ProviderResponseCacheBase):
def process_file_change(self, event: Code_Event_Types.TextChangedEvent):
buffer = event.file.buffer
self._clear_temp_delay()
self._set_temp_delay(buffer)
def _clear_temp_delay(self):
if self._temp_timeout_id:
GLib.source_remove(self._temp_timeout_id)
def _set_temp_delay(self, buffer):
def run_refresh_update(buffer):
with ThreadPoolExecutor(max_workers = 1) as executor:
executor.submit(self._handle_change, buffer)
return False
self._temp_timeout_id = GLib.timeout_add(1500, run_refresh_update, buffer)
def _handle_change(self, buffer):
start_itr = buffer.get_start_iter()
end_itr = buffer.get_end_iter()

View File

@@ -8,9 +8,9 @@ import sys
# Application imports
# from libs.db import DB
from libs.logger import Logger
from libs.event_system import EventSystem
from libs.keybindings import Keybindings
from libs.logger import Logger
from libs.settings.manager import SettingsManager
from libs.widget_registery import WidgetRegisteryController

View File

@@ -29,7 +29,7 @@ class BaseControllerMixin:
logger.info(f"Not a File: {arg}")
if len(files) == 0: return
if not files: return
settings_manager.set_is_starting_with_file(True)
settings_manager.set_starting_files(files)

View File

@@ -19,7 +19,7 @@ def execute(
starting_files = settings_manager.get_starting_files()
if len(starting_files) == 0: return
if not starting_files: return
file = starting_files.pop()
file = file.replace("FILE|", "")
@@ -31,7 +31,7 @@ def execute(
(view, gfile, file)
)
if len(starting_files) == 0: return
if not starting_files: return
for file in starting_files:
file = file.replace("FILE|", "")

View File

@@ -101,7 +101,7 @@ class FilesController(ControllerBase, list):
eve = Event_Factory.create_event(
"popped_file",
view = view,
view = event.view,
file = popped_file,
next_file = next_file
)
@@ -137,9 +137,9 @@ class FilesController(ControllerBase, list):
def next_index(self, i):
size = len(self)
if (i == 0) & (size >= 2):
if (i == 0) and (size >= 2):
j = i + 1
elif (i == (size - 1)) & (size >= 2):
elif (i == (size - 1)) and (size >= 2):
j = i - 1
elif (size - 1) == 0:
j = -1

View File

@@ -26,11 +26,11 @@ class TabsController(ControllerBase):
def _controller_message(self, event: Code_Event_Types.CodeEvent):
if isinstance(event, Code_Event_Types.FocusedViewEvent):
self.tabs_widget.view_changed(
event.view.get_buffer()
)
self.tabs_widget.view_changed( event.view.get_buffer() )
elif isinstance(event, Code_Event_Types.FilePathSetEvent):
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.AddedNewFileEvent):
self.add_tab(event)
elif isinstance(event, Code_Event_Types.PoppedFileEvent):

View File

@@ -18,6 +18,10 @@ class SourceViewSignalMapper:
def set_state_manager(self, state_manager):
self.state_manager = state_manager
def set_buffer_to_active_view(self, buffer):
self.active_view.set_buffer(buffer)
self.active_view.command.exec("update_info_bar")
def connect_signals(self, source_view: SourceView):
signal_mappings = self._get_signal_mappings()
for signal, handler in signal_mappings.items():

View File

@@ -33,12 +33,9 @@ class SourceViewsController(ControllerBase, list):
if not self.signal_mapper.active_view: return
if isinstance(event, Code_Event_Types.TextChangedEvent):
if not self.signal_mapper.active_view: return
self.signal_mapper.active_view.command.exec("update_info_bar")
elif isinstance(event, Code_Event_Types.SetActiveFileEvent):
self.signal_mapper.active_view.set_buffer(
event.buffer
)
self.signal_mapper.set_buffer_to_active_view(event.buffer)
elif isinstance(event, Code_Event_Types.TextInsertedEvent):
self.signal_mapper.insert_text(event.file, event.text)

View File

@@ -111,13 +111,13 @@ class KeyMapper:
def _set_key_state(self, eve):
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
is_control = True if modifiers & Gdk.ModifierType.CONTROL_MASK else False
is_shift = True if modifiers & Gdk.ModifierType.SHIFT_MASK else False
is_control = modifiers & Gdk.ModifierType.CONTROL_MASK
is_shift = modifiers & Gdk.ModifierType.SHIFT_MASK
try:
is_alt = True if modifiers & Gdk.ModifierType.ALT_MASK else False
except Exception:
is_alt = True if modifiers & Gdk.ModifierType.MOD1_MASK else False
is_alt = modifiers & Gdk.ModifierType.ALT_MASK
except:
is_alt = modifiers & Gdk.ModifierType.MOD1_MASK
self.state = NoKeyState
if is_control:
@@ -129,11 +129,11 @@ class KeyMapper:
def is_control(self, eve):
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
return True if modifiers & Gdk.ModifierType.CONTROL_MASK else False
return modifiers & Gdk.ModifierType.CONTROL_MASK
def is_shift(self, eve):
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
return True if modifiers & Gdk.ModifierType.SHIFT_MASK else False
return modifiers & Gdk.ModifierType.SHIFT_MASK
def get_raw_keyname(self, eve):
return Gdk.keyval_name(eve.keyval)

View File

@@ -26,7 +26,7 @@ class SourceViewDnDMixin:
if info == 80:
uris = data.get_uris()
if len(uris) == 0:
if not uris: return
uris = data.get_text().split("\n")
self._on_uri_data_received(uris)
@@ -35,6 +35,6 @@ class SourceViewDnDMixin:
uri = uris.pop(0)
self.command.exec_with_args("dnd_load_file_to_buffer", (self, uri))
if len(uris) == 0: return
if not uris: return
self.command.exec_with_args("dnd_load_files", (self, uris))

View File

@@ -26,6 +26,7 @@ class SourceBuffer(GtkSource.Buffer):
def set_signals(
self,
_changed,
_after_changed,
_mark_set,
_insert_text,
_after_insert_text,
@@ -34,6 +35,7 @@ class SourceBuffer(GtkSource.Buffer):
self._handler_ids = [
self.connect("changed", _changed),
self.connect_after("changed", _after_changed),
self.connect("mark-set", _mark_set),
self.connect("insert-text", _insert_text),
self.connect_after("insert-text", _after_insert_text),
@@ -43,26 +45,30 @@ class SourceBuffer(GtkSource.Buffer):
def block_changed_signal(self):
self.handler_block(self._handler_ids[0])
def block_changed_after_signal(self):
self.handler_block(self._handler_ids[1])
def block_insert_after_signal(self):
self.handler_block(self._handler_ids[3])
self.handler_block(self._handler_ids[4])
def block_modified_changed_signal(self):
self.handler_block(self._handler_ids[4])
self.handler_block(self._handler_ids[5])
def unblock_changed_signal(self):
self.handler_unblock(self._handler_ids[0])
def unblock_changed_after_signal(self):
self.handler_unblock(self._handler_ids[1])
def unblock_insert_after_signal(self):
self.handler_unblock(self._handler_ids[3])
self.handler_unblock(self._handler_ids[4])
def unblock_modified_changed_signal(self):
self.handler_unblock(self._handler_ids[4])
self.handler_unblock(self._handler_ids[5])
def clear_signals(self):
for handle_id in self._handler_ids:
self.disconnect(handle_id)
def __del__(self):
for handle_id in self._handler_ids:
self.disconnect(handle_id)
self.clear_signals()

View File

@@ -27,7 +27,6 @@ class SourceFile(GtkSource.File):
self.fname: str = "buffer"
self.fpath: str = "buffer"
self.ftype: str = "buffer"
self.buffer: SourceBuffer = SourceBuffer()
self._set_signals()
@@ -36,6 +35,7 @@ class SourceFile(GtkSource.File):
def _set_signals(self):
self.buffer.set_signals(
self._changed,
self._after_changed,
self._mark_set,
self._insert_text,
self._after_insert_text,
@@ -43,6 +43,9 @@ class SourceFile(GtkSource.File):
)
def _changed(self, buffer: SourceBuffer):
...
def _after_changed(self, buffer: SourceBuffer):
self.check_file_on_disk()
event = Event_Factory.create_event(
@@ -53,7 +56,7 @@ class SourceFile(GtkSource.File):
self.emit(event)
if self.is_deleted():
print("deleted")
print("is_deleted")
# event = Event_Factory.create_event("file_deleted", buffer = buffer)
# event.file = self
# self.emit(event)
@@ -138,6 +141,7 @@ class SourceFile(GtkSource.File):
undo_manager.begin_not_undoable_action()
self.buffer.insert_at_cursor(data)
undo_manager.end_not_undoable_action()
self.buffer.set_modified(False)
def set_path(self, gfile: Gio.File):
if not gfile: return
@@ -150,13 +154,15 @@ class SourceFile(GtkSource.File):
self.emit(event)
def save(self):
self._write_file( self.get_location() )
self.buffer.set_modified(False)
event = Event_Factory.create_event(
"saved_file",
file = self, buffer = self.buffer
)
self.emit(event)
self._write_file( self.get_location() )
def save_as(self):
file = event_system.emit_and_await("save-file-dialog")

View File

@@ -17,7 +17,6 @@ class TabWidget(Gtk.Box):
self.file = None
self._close_tab = None
self._handler_id = None
self._eve_handler_id = None
@@ -63,7 +62,6 @@ class TabWidget(Gtk.Box):
def clear_signals_and_data(self):
self.close_bttn.disconnect(self._handler_id)
self.event_box.disconnect(self._eve_handler_id)
self._close_tab = None
self._handler_id = None
for child in self.get_children():

View File

@@ -65,19 +65,6 @@ class TabsWidget(Gtk.Notebook):
self.message(event)
def view_changed(self, buffer):
for page_widget in self.get_children():
tab = self.get_tab_label(page_widget)
if not buffer == tab.file.buffer: continue
self.handler_block(self.switch_page_id)
self.set_current_page(
self.page_num(page_widget)
)
self.handler_unblock(self.switch_page_id)
def _bind_tab_menu(self, tab, page_widget):
def do_context_menu(tab, eve, page_widget):
if eve.type == Gdk.EventType.BUTTON_RELEASE and eve.button == 3: # r-click
@@ -116,6 +103,29 @@ class TabsWidget(Gtk.Notebook):
return context_menu
def view_changed(self, buffer):
for page_widget in self.get_children():
tab = self.get_tab_label(page_widget)
if not buffer == tab.file.buffer: continue
self.handler_block(self.switch_page_id)
self.set_current_page(
self.page_num(page_widget)
)
self.handler_unblock(self.switch_page_id)
def modified_changed(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()
if buffer.get_modified():
ctx.add_class("file-changed")
else:
ctx.remove_class("file-changed")
def close_item(self, menu_item, page_widget):
tab = self.get_tab_label(page_widget)

View File

@@ -55,7 +55,7 @@ class DnDMixin:
uris = data.get_uris()
files = []
if len(uris) == 0:
if not uris:
uris = data.get_text().split("\n")
for uri in uris:

View File

@@ -15,7 +15,7 @@ class Config:
go_past_home: str = "true"
lock_folder: str = "false"
locked_folders: list = field(default_factory=lambda: [ "venv", "flasks" ])
mplayer_options: str = "-quiet -really-quiet -xy 1600 -geometry 50%:50%",
mplayer_options: str = "-quiet -really-quiet -xy 1600 -geometry 50%:50%"
music_app: str = "/opt/deadbeef/bin/deadbeef"
media_app: str = "mpv"
image_app: str = "mirage"

View File

@@ -2,7 +2,7 @@
from dataclasses import dataclass, field
from dataclasses import asdict
# Gtk imports
# Lib imports
# Application imports
from .config import Config