Remove tabs UI from code editor and move to plugin. Enhance plugin system.
- Remove tabs controller, tab widget, and tabs widget files and move to plugin - Delete plugins/README.txt - Add register_controller method to controller system for plugin use - Add error handling for plugin crashes via futures callback
This commit is contained in:
@@ -1,31 +0,0 @@
|
||||
### Note
|
||||
Copy the example and rename it to your desired name. Plugins define a ui target slot with the 'ui_target' requests data but don't have to if not directly interacted with.
|
||||
Plugins must have a run method defined; though, you do not need to necessarily do anything within it. The run method implies that the passed in event system or other data is ready for the plugin to use.
|
||||
|
||||
|
||||
### Manifest Example (All are required even if empty.)
|
||||
```
|
||||
class Manifest:
|
||||
name: str = "Example Plugin"
|
||||
author: str = "John Doe"
|
||||
version: str = "0.0.1"
|
||||
support: str = ""
|
||||
pre_launch: bool = False
|
||||
requests: {} = {
|
||||
'pass_ui_objects': ["plugin_control_list"],
|
||||
'pass_events': True,
|
||||
'bind_keys': []
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Requests
|
||||
```
|
||||
requests: {} = {
|
||||
'pass_events': true, # If empty or not present will be ignored.
|
||||
"pass_ui_objects": [""], # Request reference to a UI component. Will be passed back as array to plugin.
|
||||
'bind_keys': [f"{name}||send_message:<Control>f"],
|
||||
f"{name}||do_save:<Control>s"] # Bind keys with method and key pare using list. Must pass "name" like shown with delimiter to its right.
|
||||
|
||||
}
|
||||
```
|
||||
3
plugins/code/tabs_bar/__init__.py
Normal file
3
plugins/code/tabs_bar/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
3
plugins/code/tabs_bar/__main__.py
Normal file
3
plugins/code/tabs_bar/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
7
plugins/code/tabs_bar/manifest.json
Normal file
7
plugins/code/tabs_bar/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Tabs Bar",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
32
plugins/code/tabs_bar/plugin.py
Normal file
32
plugins/code/tabs_bar/plugin.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
from .tabs_controller import TabsController
|
||||
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
tabs_controller = TabsController()
|
||||
code_container = self.requests_ui_element("code-container")
|
||||
|
||||
self.register_controller("tabs", tabs_controller)
|
||||
|
||||
code_container.add( tabs_controller.tabs_widget )
|
||||
code_container.reorder_child(tabs_controller.tabs_widget, 0)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
@@ -9,10 +9,11 @@ from gi.repository import Gtk
|
||||
from libs.controllers.controller_base import ControllerBase
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from ..tabs_widget import TabsWidget
|
||||
from ..tab_widget import TabWidget
|
||||
from core.widgets.code.source_view import SourceView
|
||||
|
||||
from .tabs_widget import TabsWidget
|
||||
from .tab_widget import TabWidget
|
||||
|
||||
from ..source_view import SourceView
|
||||
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ class TabsWidget(Gtk.Notebook):
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
self.show()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_scrollable(True)
|
||||
@@ -36,18 +36,15 @@ class CodeContainer(Gtk.Box):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
widget_registery.expose_object("code-container", self)
|
||||
|
||||
code_base = CodeBase()
|
||||
|
||||
self.add( self._create_tabs_widgets(code_base) )
|
||||
self.add( self._create_editor_widget(code_base) )
|
||||
|
||||
def _create_tabs_widgets(self, code_base: CodeBase):
|
||||
return code_base.get_tabs_widget()
|
||||
|
||||
def _create_editor_widget(self, code_base: CodeBase):
|
||||
editors_container = Gtk.Box()
|
||||
|
||||
widget_registery.expose_object("code-container", self)
|
||||
widget_registery.expose_object("editors-container", editors_container)
|
||||
|
||||
editors_container.add( Separator("separator_left") )
|
||||
|
||||
@@ -8,7 +8,6 @@ from plugins import plugins_controller
|
||||
from libs.controllers.controller_manager import ControllerManager
|
||||
|
||||
from .controllers.files_controller import FilesController
|
||||
from .controllers.tabs_controller import TabsController
|
||||
from .controllers.commands_controller import CommandsController
|
||||
from .controllers.completion_controller import CompletionController
|
||||
from .controllers.views.source_views_controller import SourceViewsController
|
||||
@@ -31,23 +30,18 @@ class CodeBase:
|
||||
|
||||
def _load_controllers(self):
|
||||
files_controller = FilesController()
|
||||
tabs_controller = TabsController()
|
||||
commands_controller = CommandsController()
|
||||
completion_controller = CompletionController()
|
||||
source_views_controller = SourceViewsController()
|
||||
|
||||
# self.controller_manager.register_controller("base", self)
|
||||
self.controller_manager.register_controller("files", files_controller)
|
||||
self.controller_manager.register_controller("tabs", tabs_controller)
|
||||
self.controller_manager.register_controller("commands", commands_controller)
|
||||
self.controller_manager.register_controller("completion", completion_controller)
|
||||
self.controller_manager.register_controller("source_views", source_views_controller)
|
||||
self.controller_manager.register_controller("plugins", plugins_controller)
|
||||
self.controller_manager.register_controller("widgets", widget_registery)
|
||||
|
||||
def get_tabs_widget(self):
|
||||
return self.controller_manager["tabs"].get_tabs_widget()
|
||||
|
||||
def create_source_view(self):
|
||||
source_view = self.controller_manager["source_views"].create_source_view()
|
||||
self.controller_manager["completion"].register_completer(
|
||||
|
||||
@@ -39,3 +39,6 @@ class ControllerBase(Singleton, EmitDispatcher):
|
||||
def message_to_selected(self, names: list[str], event: BaseEvent):
|
||||
for name in names:
|
||||
self.controller_context.message_to_selected(name, event)
|
||||
|
||||
def register_controller(self, name: str, controller):
|
||||
self.controller_context.register_controller(name, controller)
|
||||
|
||||
@@ -25,3 +25,6 @@ class ControllerContext:
|
||||
|
||||
def message_to_selected(self, name: list, event: BaseEvent):
|
||||
raise ControllerContextException("Controller Context 'message_to_selected' must be overriden by Controller Manager...")
|
||||
|
||||
def register_controller(self, name: str, controller):
|
||||
raise ControllerContextException("Controller Context 'register_controller' must be overriden by Controller Manager...")
|
||||
|
||||
@@ -22,9 +22,10 @@ class ControllerManager(Singleton, dict):
|
||||
|
||||
|
||||
def _crete_controller_context(self) -> ControllerContext:
|
||||
controller_context = ControllerContext()
|
||||
controller_context.message_to = self.message_to
|
||||
controller_context.message = self.message
|
||||
controller_context = ControllerContext()
|
||||
controller_context.message_to = self.message_to
|
||||
controller_context.message = self.message
|
||||
controller_context.register_controller = self.register_controller
|
||||
|
||||
return controller_context
|
||||
|
||||
|
||||
@@ -67,31 +67,26 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
||||
parent_path = os.getcwd()
|
||||
|
||||
for manifest_meta in manifest_metas:
|
||||
path, folder, manifest = manifest_meta.path, manifest_meta.folder, manifest_meta.manifest
|
||||
|
||||
try:
|
||||
target = join(path, "plugin.py")
|
||||
path, \
|
||||
folder, \
|
||||
manifest = manifest_meta.path, manifest_meta.folder, manifest_meta.manifest
|
||||
target = join(path, "plugin.py")
|
||||
|
||||
if not os.path.exists(target):
|
||||
raise PluginsControllerException("Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load...")
|
||||
raise PluginsControllerException(
|
||||
"Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load..."
|
||||
)
|
||||
|
||||
module = self._load_plugin_module(path, folder, target)
|
||||
|
||||
if is_pre_launch:
|
||||
self._run_with_pool(module, manifest_meta)
|
||||
else:
|
||||
GLib.idle_add(
|
||||
self._run_with_pool, module, manifest_meta
|
||||
)
|
||||
except Exception as e:
|
||||
logger.info(f"Malformed Plugin: Not loading -->: '{folder}' !")
|
||||
self._handle_plugin_execute(is_pre_launch, module, manifest_meta)
|
||||
except PluginsControllerException as e:
|
||||
logger.info(f"Malformed Plugin: Not loading -->: '{manifest_meta.folder}' !")
|
||||
logger.debug(f"Trace: {traceback.print_exc()}")
|
||||
|
||||
os.chdir(parent_path)
|
||||
|
||||
def _run_with_pool(self, module: type, manifest_meta: ManifestMeta):
|
||||
with ThreadPoolExecutor(max_workers = 1) as executor:
|
||||
executor.submit(self.execute_plugin, module, manifest_meta)
|
||||
|
||||
def _load_plugin_module(self, path, folder, target):
|
||||
os.chdir(path)
|
||||
|
||||
@@ -105,17 +100,27 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
||||
|
||||
return module
|
||||
|
||||
def create_plugin_context(self):
|
||||
plugin_context: PluginContext = PluginContext()
|
||||
def _handle_plugin_execute(
|
||||
self, is_pre_launch: bool, module, manifest_meta
|
||||
):
|
||||
if not is_pre_launch:
|
||||
GLib.idle_add(
|
||||
self._run_with_pool, module, manifest_meta
|
||||
)
|
||||
return
|
||||
|
||||
plugin_context.requests_ui_element: callable = self.requests_ui_element
|
||||
plugin_context.message: callable = self.message
|
||||
plugin_context.message_to: callable = self.message_to
|
||||
plugin_context.message_to_selected: callable = self.message_to_selected
|
||||
plugin_context.emit: callable = event_system.emit
|
||||
plugin_context.emit_and_await: callable = event_system.emit_and_await
|
||||
self._run_with_pool(module, manifest_meta)
|
||||
|
||||
return plugin_context
|
||||
def _run_with_pool(self, module: type, manifest_meta: ManifestMeta):
|
||||
with ThreadPoolExecutor(max_workers = 1) as executor:
|
||||
future = executor.submit(self.execute_plugin, module, manifest_meta)
|
||||
future.add_done_callback(self._handle_future_exception)
|
||||
|
||||
def _handle_future_exception(self, future):
|
||||
try:
|
||||
future.result()
|
||||
except Exception:
|
||||
logger.exception("Plugin crashed during execution...")
|
||||
|
||||
def pre_launch_plugins(self) -> None:
|
||||
logger.info(f"Loading pre-launch plugins...")
|
||||
@@ -142,6 +147,18 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
||||
|
||||
self._plugin_collection.append(manifest_meta)
|
||||
|
||||
def create_plugin_context(self):
|
||||
plugin_context: PluginContext = PluginContext()
|
||||
|
||||
plugin_context.requests_ui_element: callable = self.requests_ui_element
|
||||
plugin_context.message: callable = self.message
|
||||
plugin_context.message_to: callable = self.message_to
|
||||
plugin_context.message_to_selected: callable = self.message_to_selected
|
||||
plugin_context.emit: callable = event_system.emit
|
||||
plugin_context.emit_and_await: callable = event_system.emit_and_await
|
||||
plugin_context.register_controller: callable = self.register_controller
|
||||
|
||||
return plugin_context
|
||||
|
||||
|
||||
plugins_controller = PluginsController()
|
||||
|
||||
@@ -38,3 +38,7 @@ class PluginContext:
|
||||
|
||||
def emit_and_await(self, event_type: str, data: tuple = ()):
|
||||
raise PluginContextException("Plugin Context 'emit_and_await' must be overridden...")
|
||||
|
||||
def register_controller(self, name: str, controller):
|
||||
raise PluginContextException("Plugin Context 'register_controller' must be overridden...")
|
||||
|
||||
|
||||
@@ -42,3 +42,6 @@ class PluginCode(PluginBase):
|
||||
|
||||
def message_to_selected(self, names: list[str], event: BaseEvent):
|
||||
return self.plugin_context.message_to_selected(names, event)
|
||||
|
||||
def register_controller(self, name: str, controller):
|
||||
return self.plugin_context.register_controller(name, controller)
|
||||
|
||||
Reference in New Issue
Block a user