diff --git a/plugins/completers/words_completer/provider_response_cache.py b/plugins/completers/words_completer/provider_response_cache.py index 4194c28..00a20f6 100644 --- a/plugins/completers/words_completer/provider_response_cache.py +++ b/plugins/completers/words_completer/provider_response_cache.py @@ -1,5 +1,5 @@ # Python imports -from os import path +import asyncio # Lib imports import gi @@ -23,10 +23,11 @@ class ProviderResponseCache(ProviderResponseCacheBase): def process_file_load(self, event: Code_Event_Types.AddedNewFileEvent): - self.load_as_new_set(event.file.buffer) + buffer = event.file.buffer + asyncio.run( self._handle_change(buffer) ) def process_file_close(self, event: Code_Event_Types.RemovedFileEvent): - self.matchers[event.file.buffer] = [] + self.matchers[event.file.buffer] = set() del self.matchers[event.file.buffer] def process_file_save(self, event: Code_Event_Types.SavedFileEvent): @@ -34,9 +35,23 @@ class ProviderResponseCache(ProviderResponseCacheBase): def process_file_change(self, event: Code_Event_Types.TextChangedEvent): buffer = event.file.buffer - # if self.get_if_in_matched_word_set(buffer): return - self.load_as_new_set(buffer) + asyncio.run( self._handle_change(buffer) ) + async def _handle_change(self, buffer): + start_itr = buffer.get_start_iter() + end_itr = buffer.get_end_iter() + data = buffer.get_text(start_itr, end_itr, False) + + if not data: + GLib.idle_add(self.load_empty_set, buffer) + return + + if not buffer in self.matchers: + GLib.idle_add(self.load_as_new_set, buffer, data) + return + + new_words = self.get_all_words(data) + GLib.idle_add(self.load_into_set, buffer, new_words) def filter(self, word: str) -> list[dict]: response: list[dict] = [] @@ -67,44 +82,15 @@ class ProviderResponseCache(ProviderResponseCacheBase): return response - def load_as_new_set(self, buffer): - start_itr = buffer.get_start_iter() - end_itr = buffer.get_end_iter() - data = buffer.get_text(start_itr, end_itr, False) + def load_empty_set(self, buffer): + self.matchers[buffer] = set() - if not data: - self.matchers[buffer] = set() - return + def load_into_set(self, buffer, new_words): + self.matchers[buffer].update(new_words) + def load_as_new_set(self, buffer, data): self.matchers[buffer] = self.get_all_words(data) - def get_if_in_matched_word_set(self, buffer): - was_found = False - - if not buffer in self.matchers: return was_found - - insert_itr = buffer.get_iter_at_mark( buffer.get_insert() ) - end_itr = insert_itr.copy() - start_itr = end_itr.copy() - - if not start_itr.starts_word(): - start_itr.backward_word_start() - - if not end_itr.ends_word(): - end_itr.forward_word_end() - - word = buffer.get_text(start_itr, end_itr, False) - for _word in self.matchers[buffer]: - if not _word.startswith(word): continue - was_found = True - - if was_found: return was_found - - self.matchers[buffer].add(word) - - return was_found - - def get_all_words(self, data: str): words = set() diff --git a/src/core/containers/code/code_container.py b/src/core/containers/code/code_container.py index f0ae232..0e05c16 100644 --- a/src/core/containers/code/code_container.py +++ b/src/core/containers/code/code_container.py @@ -43,15 +43,16 @@ class CodeContainer(Gtk.Box): self.add( self._create_editor_widget(code_base) ) def _create_tabs_widgets(self, code_base: CodeBase): - scrolled_window = Gtk.ScrolledWindow() - viewport = Gtk.Viewport() + # scrolled_window = Gtk.ScrolledWindow() + # viewport = Gtk.Viewport() - scrolled_window.set_overlay_scrolling(False) + # scrolled_window.set_overlay_scrolling(False) - viewport.add( code_base.get_tabs_widget() ) - scrolled_window.add( viewport ) + # viewport.add( code_base.get_tabs_widget() ) + # scrolled_window.add( viewport ) - return scrolled_window + # return scrolled_window + return code_base.get_tabs_widget() def _create_editor_widget(self, code_base: CodeBase): editors_container = Gtk.Box() diff --git a/src/core/widgets/code/controllers/tabs_controller.py b/src/core/widgets/code/controllers/tabs_controller.py index cd40ffe..cb3302e 100644 --- a/src/core/widgets/code/controllers/tabs_controller.py +++ b/src/core/widgets/code/controllers/tabs_controller.py @@ -1,6 +1,9 @@ # Python imports # Lib imports +import gi + +from gi.repository import Gtk # Application imports from libs.controllers.controller_base import ControllerBase @@ -19,11 +22,15 @@ class TabsController(ControllerBase): self.active_view: SourceView = None self.tabs_widget: TabsWidget = TabsWidget() + self.tabs_widget.message = self.message def _controller_message(self, event: Code_Event_Types.CodeEvent): if isinstance(event, Code_Event_Types.FocusedViewEvent): self.active_view = event.view + 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.AddedNewFileEvent): @@ -37,48 +44,32 @@ class TabsController(ControllerBase): return self.tabs_widget def update_tab_label(self, event: Code_Event_Types.FilePathSetEvent): - for tab in self.tabs_widget.get_children(): + for page_widget in self.tabs_widget.get_children(): + tab = self.tabs_widget.get_tab_label(page_widget) if not event.file == tab.file: continue + tab.label.set_label(event.file.fname) + break def add_tab(self, event: Code_Event_Types.AddedNewFileEvent): - def set_active_tab(tab, eve, file): - event = Event_Factory.create_event( - "set_active_file", - buffer = tab.get_parent().file.buffer - ) - - self.active_view.set_buffer( - tab.get_parent().file.buffer - ) - - self.message(event) - - def close_tab(tab, eve, file): - event = Event_Factory.create_event( - "remove_file", - buffer = tab.get_parent().file.buffer - ) - - self.message(event) - + box = Gtk.Separator() tab = TabWidget() + tab.file = event.file tab.label.set_label(event.file.fname) - tab.set_select_signal(set_active_tab) - tab.set_close_signal(close_tab) - self.tabs_widget.add(tab) - tab.show() + self.tabs_widget.append_page(box, tab) + tab.show_all() def remove_tab(self, event: Code_Event_Types.RemovedFileEvent): - for tab in self.tabs_widget.get_children(): + for page_widget in self.tabs_widget.get_children(): + tab = self.tabs_widget.get_tab_label(page_widget) if not event.file == tab.file: continue tab.clear_signals_and_data() - tab.run_dispose() - tab.destroy() + self.tabs_widget.remove_page( + self.tabs_widget.page_num(page_widget) + ) - del tab break diff --git a/src/core/widgets/code/controllers/views/source_views_controller.py b/src/core/widgets/code/controllers/views/source_views_controller.py index 08c914e..f5c7e60 100644 --- a/src/core/widgets/code/controllers/views/source_views_controller.py +++ b/src/core/widgets/code/controllers/views/source_views_controller.py @@ -33,8 +33,10 @@ class SourceViewsController(ControllerBase, list): 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.TextChangedEvent): - 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 + ) elif isinstance(event, Code_Event_Types.TextInsertedEvent): self.signal_mapper.insert_text(event.file, event.text) diff --git a/src/core/widgets/code/tab_widget.py b/src/core/widgets/code/tab_widget.py index f1cc6c2..e677a61 100644 --- a/src/core/widgets/code/tab_widget.py +++ b/src/core/widgets/code/tab_widget.py @@ -10,52 +10,62 @@ from gi.repository import Gtk class TabWidget(Gtk.Box): + """docstring for TabWidget""" + def __init__(self): super(TabWidget, self).__init__() - self.file = None + self._close_tab = 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") + self.set_orientation(0) + self.set_hexpand(False) + def _setup_signals(self): ... - def _subscribe_to_events(self): - ... - def _load_widgets(self): - self._label_eve_box = Gtk.EventBox() - self.label = Gtk.Label(label = "") - self.close_btn = Gtk.Button(label = "X") + self.label = Gtk.Label() + self.close_btn = Gtk.Button() + icon = Gtk.Image(stock = Gtk.STOCK_CLOSE) 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_xalign(0.0) + self.label.set_margin_left(25) + self.label.set_margin_right(25) self.label.set_hexpand(True) - self._label_eve_box.add(self.label) - self.add(self._label_eve_box) + self.close_btn.add(icon) + self.add(self.label) self.add(self.close_btn) - def clear_signals_and_data(self): - del self.file - self._label_eve_box.disconnect(self._label_eve_box_id) - self.close_btn.disconnect(self.close_btn_id) + self.show_all() - def set_select_signal(self, callback): - self._label_eve_box_id = self._label_eve_box.connect('button-release-event', callback, self.file) + def clear_signals_and_data(self): + self.close_btn.disconnect(self._handler_id) + self._close_tab = None + self._handler_id = None + + for child in self.get_children(): + child.unparent() + child.run_dispose() + child.destroy() def set_close_signal(self, callback): - self.close_btn_id = self.close_btn.connect('button-release-event', callback, self.file) + self._handler_id = self.close_btn.connect( + 'button-release-event', + callback, + self.file + ) diff --git a/src/core/widgets/code/tabs_widget.py b/src/core/widgets/code/tabs_widget.py index 88840ca..bd16986 100644 --- a/src/core/widgets/code/tabs_widget.py +++ b/src/core/widgets/code/tabs_widget.py @@ -6,16 +6,13 @@ gi.require_version('Gtk', '3.0') from gi.repository import Gtk # Application imports -from libs.event_factory import Code_Event_Types - -from .source_view import SourceView -from .source_file import SourceFile +from libs.event_factory import Event_Factory, Code_Event_Types from .tab_widget import TabWidget -class TabsWidget(Gtk.ButtonBox): +class TabsWidget(Gtk.Notebook): def __init__(self): super(TabsWidget, self).__init__() @@ -26,10 +23,12 @@ class TabsWidget(Gtk.ButtonBox): def _setup_styling(self): - self.set_layout(Gtk.ButtonBoxStyle.CENTER) + ... def _setup_signals(self): - ... + self.connect("page-added", self._page_added) + self.switch_page_id = \ + self.connect_after("switch-page", self._switch_page) def _subscribe_to_events(self): ... @@ -37,51 +36,40 @@ class TabsWidget(Gtk.ButtonBox): def _load_widgets(self): ... - def add_tab(self, event: Code_Event_Types.CodeEvent): - """Add a tab widget for the given file event.""" - if not hasattr(self, 'tabs'): - return - - tab = TabWidget() - tab.file = event.file + def _page_added(self, notebook, page_widget, page_num): + tab = self.get_tab_label(page_widget) + tab.set_close_signal(self._close_tab) - tab.label.set_label(event.file.fname) + page_widget.show() + self.set_tab_detachable(page_widget, True) + self.set_tab_reorderable(page_widget, True) - def select_signal(widget, eve, file): - self.code_base.active_view.command.exec_with_args( - "set_buffer", - (self.code_base.active_view, file) + def _close_tab(self, tab, eve, file): + event = Event_Factory.create_event( + "remove_file", + buffer = tab.get_parent().file.buffer + ) + + self.message(event) + + def _switch_page(self, notebook, page_widget, page_num): + tab = self.get_tab_label(page_widget) + event = Event_Factory.create_event( + "set_active_file", + buffer = tab.file.buffer + ) + + 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) ) - def close_signal(widget, eve, file): - self.code_base.files_controller.remove_file(file.buffer) - - tab.set_select_signal(select_signal) - tab.set_close_signal(close_signal) - - self.tabs.add(tab) - - def remove_tab(self, event: Code_Event_Types.CodeEvent): - """Remove a tab widget for the given file event.""" - if not hasattr(self, 'tabs'): - return - - for child in self.tabs.get_children(): - if not child.file == event.file: continue - - self.tabs.remove(child) - child.clear_signals_and_data() - del child - - return - - def update_tab_label(self, event: Code_Event_Types.CodeEvent): - """Update tab label for the given file event.""" - if not hasattr(self, 'tabs'): - return - - for tab in self.tabs.get_children(): - if not tab.file == event.file: continue - tab.label.set_label(event.file.fname) - - return + self.handler_unblock(self.switch_page_id) diff --git a/user_config/usr/share/newton/stylesheet.css b/user_config/usr/share/newton/stylesheet.css index fef2246..3ebca1c 100644 --- a/user_config/usr/share/newton/stylesheet.css +++ b/user_config/usr/share/newton/stylesheet.css @@ -55,14 +55,6 @@ border { background: rgba(39, 43, 52, 0.84); } -tab { - color: rgba(255, 255, 255, 1); -} - -tab:checked { - border-bottom-color: rgba(125, 125, 125, 1); -} - .main-window, .base-container, @@ -101,24 +93,6 @@ tab:checked { border-width: 0.05em; } -.tab-widget { - padding-left: 0.2em; - padding-right: 0.2em; - margin-right: 0.8em; - - border-top-style: solid; - border-top-color: rgba(255, 255, 255, 0.64); - border-top-width: 2px; - - border-left-style: solid; - border-left-color: rgba(255, 255, 255, 0.64); - border-left-width: 2px; - - border-right-style: solid; - border-right-color: rgba(255, 255, 255, 0.64); - border-right-width: 2px; -} - .tab-label { margin-left: 2em; margin-right: 2em;