Compare commits
8 Commits
24bf1e471b
...
1447a68fb0
| Author | SHA1 | Date | |
|---|---|---|---|
| 1447a68fb0 | |||
| b724d41f6c | |||
| 597ac2b06a | |||
| 2e84ad9fc1 | |||
| a2b8232d5e | |||
| 0b3579d485 | |||
| ec571ffa90 | |||
| 3b205e28e6 |
@@ -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/autopairs/__init__.py
Normal file
3
plugins/code/autopairs/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Module
|
||||||
|
"""
|
||||||
3
plugins/code/autopairs/__main__.py
Normal file
3
plugins/code/autopairs/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Package
|
||||||
|
"""
|
||||||
97
plugins/code/autopairs/autopairs.py
Normal file
97
plugins/code/autopairs/autopairs.py
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Autopairs:
|
||||||
|
def __init__(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def handle_word_wrap(self, buffer, char_str: str):
|
||||||
|
wrap_block = self.get_wrap_block(char_str)
|
||||||
|
if not wrap_block: return
|
||||||
|
|
||||||
|
selection = buffer.get_selection_bounds()
|
||||||
|
if not selection:
|
||||||
|
self.insert_pair(buffer, char_str, wrap_block)
|
||||||
|
return True
|
||||||
|
|
||||||
|
self.wrap_selection(buffer, char_str, wrap_block, selection)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def insert_pair(
|
||||||
|
self, buffer, char_str: str, wrap_block: tuple
|
||||||
|
):
|
||||||
|
buffer.begin_user_action()
|
||||||
|
|
||||||
|
left_block, right_block = wrap_block
|
||||||
|
insert_mark = buffer.get_insert()
|
||||||
|
|
||||||
|
insert_itr = buffer.get_iter_at_mark(insert_mark)
|
||||||
|
buffer.insert(insert_itr, f"{left_block}{right_block}")
|
||||||
|
insert_itr = buffer.get_iter_at_mark( insert_mark )
|
||||||
|
insert_itr.backward_char()
|
||||||
|
|
||||||
|
buffer.place_cursor(insert_itr)
|
||||||
|
|
||||||
|
buffer.end_user_action()
|
||||||
|
|
||||||
|
def wrap_selection(
|
||||||
|
self, buffer, char_str: str, wrap_block: tuple, selection
|
||||||
|
):
|
||||||
|
left_block, \
|
||||||
|
right_block = wrap_block
|
||||||
|
start_itr, \
|
||||||
|
end_itr = selection
|
||||||
|
data = buffer.get_text(
|
||||||
|
start_itr, end_itr, include_hidden_chars = False
|
||||||
|
)
|
||||||
|
start_mark = buffer.create_mark("startclose", start_itr, False)
|
||||||
|
end_mark = buffer.create_mark("endclose", end_itr, True)
|
||||||
|
|
||||||
|
buffer.begin_user_action()
|
||||||
|
|
||||||
|
buffer.insert(start_itr, left_block)
|
||||||
|
end_itr = buffer.get_iter_at_mark(end_mark)
|
||||||
|
buffer.insert(end_itr, right_block)
|
||||||
|
|
||||||
|
start = buffer.get_iter_at_mark(start_mark)
|
||||||
|
end = buffer.get_iter_at_mark(end_mark)
|
||||||
|
|
||||||
|
buffer.select_range(start, end)
|
||||||
|
buffer.delete_mark_by_name("startclose")
|
||||||
|
buffer.delete_mark_by_name("endclose")
|
||||||
|
|
||||||
|
buffer.end_user_action()
|
||||||
|
|
||||||
|
def get_wrap_block(self, char_str) -> tuple:
|
||||||
|
left_block = ""
|
||||||
|
right_block = ""
|
||||||
|
|
||||||
|
match char_str:
|
||||||
|
case "(" | ")":
|
||||||
|
left_block = "("
|
||||||
|
right_block = ")"
|
||||||
|
case "[" | "]":
|
||||||
|
left_block = "["
|
||||||
|
right_block = "]"
|
||||||
|
case "{" | "}":
|
||||||
|
left_block = "{"
|
||||||
|
right_block = "}"
|
||||||
|
case '"':
|
||||||
|
left_block = '"'
|
||||||
|
right_block = '"'
|
||||||
|
case "'":
|
||||||
|
left_block = "'"
|
||||||
|
right_block = "'"
|
||||||
|
case "`":
|
||||||
|
left_block = "`"
|
||||||
|
right_block = "`"
|
||||||
|
case _:
|
||||||
|
return ()
|
||||||
|
|
||||||
|
return left_block, right_block
|
||||||
7
plugins/code/autopairs/manifest.json
Normal file
7
plugins/code/autopairs/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Autopairs",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
55
plugins/code/autopairs/plugin.py
Normal file
55
plugins/code/autopairs/plugin.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .autopairs import Autopairs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
autopairs = Autopairs()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
event = Event_Factory.create_event("register_command",
|
||||||
|
command_name = "autopairs",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "held",
|
||||||
|
binding = [
|
||||||
|
"'", "`", "[", "]",
|
||||||
|
'<Shift>"',
|
||||||
|
'<Shift>(',
|
||||||
|
'<Shift>)',
|
||||||
|
'<Shift>{',
|
||||||
|
'<Shift>}'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.message_to("source_views", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class Handler:
|
||||||
|
@staticmethod
|
||||||
|
def execute(
|
||||||
|
view: any,
|
||||||
|
char_str: str,
|
||||||
|
*args,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
logger.debug("Command: Autopairs")
|
||||||
|
autopairs.handle_word_wrap(view.get_buffer(), char_str)
|
||||||
3
plugins/code/code_minimap/__init__.py
Normal file
3
plugins/code/code_minimap/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/code/code_minimap/__main__.py
Normal file
3
plugins/code/code_minimap/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
@@ -10,15 +10,17 @@ from gi.repository import Pango
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MiniViewWidget(Map):
|
class CodeMiniMap(Map):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(MiniViewWidget, self).__init__()
|
super(CodeMiniMap, self).__init__()
|
||||||
|
|
||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
ctx = self.get_style_context()
|
ctx = self.get_style_context()
|
||||||
7
plugins/code/code_minimap/manifest.json
Normal file
7
plugins/code/code_minimap/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Code MiniMap",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
32
plugins/code/code_minimap/plugin.py
Normal file
32
plugins/code/code_minimap/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 .code_minimap import CodeMiniMap
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
code_minimap = CodeMiniMap()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
if isinstance(event, Code_Event_Types.FocusedViewEvent):
|
||||||
|
code_minimap.set_smini_view(event.view)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
editors_container = self.requests_ui_element("editors-container")
|
||||||
|
editors_container.add( code_minimap )
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
3
plugins/code/info_bar/__init__.py
Normal file
3
plugins/code/info_bar/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/code/info_bar/__main__.py
Normal file
3
plugins/code/info_bar/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
@@ -33,11 +33,7 @@ class InfoBarWidget(Gtk.Box):
|
|||||||
...
|
...
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("set-info-labels", self._set_info_labels)
|
...
|
||||||
event_system.subscribe("set-path-label", self._set_path_label)
|
|
||||||
event_system.subscribe("set-encoding-label", self._set_encoding_label)
|
|
||||||
event_system.subscribe("set-line-char-label", self._set_line_char_label)
|
|
||||||
event_system.subscribe("set-file-type-label", self._set_file_type_label)
|
|
||||||
|
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
@@ -63,9 +59,9 @@ class InfoBarWidget(Gtk.Box):
|
|||||||
def _set_info_labels(
|
def _set_info_labels(
|
||||||
self,
|
self,
|
||||||
path: Gio.File or str = None,
|
path: Gio.File or str = None,
|
||||||
line_char: str = None,
|
line_char: str = None,
|
||||||
file_type: str = None,
|
file_type: str = None,
|
||||||
encoding_type: str = None
|
encoding_type: str = None
|
||||||
):
|
):
|
||||||
self._set_path_label(path)
|
self._set_path_label(path)
|
||||||
self._set_line_char_label(line_char)
|
self._set_line_char_label(line_char)
|
||||||
7
plugins/code/info_bar/manifest.json
Normal file
7
plugins/code/info_bar/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Info Bar",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
32
plugins/code/info_bar/plugin.py
Normal file
32
plugins/code/info_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 .info_bar_widget import InfoBarWidget
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
info_bar_widget = InfoBarWidget()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
if isinstance(event, Code_Event_Types.SetInfoLabelsEvent):
|
||||||
|
info_bar_widget._set_info_labels(*event.info)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
header = self.requests_ui_element("header-container")
|
||||||
|
header.add( info_bar_widget )
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
3
plugins/code/prettify_json/__init__.py
Normal file
3
plugins/code/prettify_json/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
3
plugins/code/prettify_json/__main__.py
Normal file
3
plugins/code/prettify_json/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
7
plugins/code/prettify_json/manifest.json
Normal file
7
plugins/code/prettify_json/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Prettify JSON",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
55
plugins/code/prettify_json/plugin.py
Normal file
55
plugins/code/prettify_json/plugin.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# Python imports
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _load_prettify_json(buffer, menu):
|
||||||
|
menu.append( Gtk.SeparatorMenuItem() )
|
||||||
|
|
||||||
|
def on_prettify_json(menuitem, buffer):
|
||||||
|
start_itr, \
|
||||||
|
end_itr = buffer.get_start_iter(), buffer.get_end_iter()
|
||||||
|
data = buffer.get_text(start_itr, end_itr, False)
|
||||||
|
text = json.dumps(json.loads(data), separators = (',', ':'), indent = 4)
|
||||||
|
|
||||||
|
buffer.begin_user_action()
|
||||||
|
buffer.delete(start_itr, end_itr)
|
||||||
|
buffer.insert(start_itr, text)
|
||||||
|
buffer.end_user_action()
|
||||||
|
|
||||||
|
item = Gtk.MenuItem(label = "Prettify JSON")
|
||||||
|
item.connect("activate", on_prettify_json, buffer)
|
||||||
|
menu.append(item)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
if isinstance(event, Code_Event_Types.PopulateSourceViewPopupEvent):
|
||||||
|
language = event.buffer.get_language()
|
||||||
|
if not language: return
|
||||||
|
|
||||||
|
if language.get_id() == "json":
|
||||||
|
_load_prettify_json(event.buffer, event.menu)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
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.controllers.controller_base import ControllerBase
|
||||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
from ..tabs_widget import TabsWidget
|
from core.widgets.code.source_view import SourceView
|
||||||
from ..tab_widget import TabWidget
|
|
||||||
|
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._subscribe_to_events()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_scrollable(True)
|
self.set_scrollable(True)
|
||||||
@@ -116,6 +118,8 @@ class TabsWidget(Gtk.Notebook):
|
|||||||
|
|
||||||
self.handler_unblock(self.switch_page_id)
|
self.handler_unblock(self.switch_page_id)
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
def modified_changed(self, buffer):
|
def modified_changed(self, buffer):
|
||||||
for page_widget in self.get_children():
|
for page_widget in self.get_children():
|
||||||
tab = self.get_tab_label(page_widget)
|
tab = self.get_tab_label(page_widget)
|
||||||
@@ -128,12 +132,16 @@ class TabsWidget(Gtk.Notebook):
|
|||||||
else:
|
else:
|
||||||
ctx.remove_class("file-changed")
|
ctx.remove_class("file-changed")
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
def externally_deleted(self, buffer):
|
def externally_deleted(self, buffer):
|
||||||
for page_widget in self.get_children():
|
for page_widget in self.get_children():
|
||||||
tab = self.get_tab_label(page_widget)
|
tab = self.get_tab_label(page_widget)
|
||||||
if not buffer == tab.file.buffer: continue
|
if not buffer == tab.file.buffer: continue
|
||||||
ctx = tab.label.get_style_context()
|
ctx = tab.label.get_style_context()
|
||||||
ctx.add_class("file-deleted")
|
ctx.add_class("file-deleted")
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
def close_item(self, menu_item, page_widget):
|
def close_item(self, menu_item, page_widget):
|
||||||
tab = self.get_tab_label(page_widget)
|
tab = self.get_tab_label(page_widget)
|
||||||
3
plugins/code/toggle_source_view/__init__.py
Normal file
3
plugins/code/toggle_source_view/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Module
|
||||||
|
"""
|
||||||
3
plugins/code/toggle_source_view/__main__.py
Normal file
3
plugins/code/toggle_source_view/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Package
|
||||||
|
"""
|
||||||
7
plugins/code/toggle_source_view/manifest.json
Normal file
7
plugins/code/toggle_source_view/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Toggle Source View",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
54
plugins/code/toggle_source_view/plugin.py
Normal file
54
plugins/code/toggle_source_view/plugin.py
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
event = Event_Factory.create_event("register_command",
|
||||||
|
command_name = "toggle_source_view",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Shift><Control>h"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.message_to("source_views", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class Handler:
|
||||||
|
@staticmethod
|
||||||
|
def execute(
|
||||||
|
view: any,
|
||||||
|
char_str: str,
|
||||||
|
*args,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
logger.debug("Command: Toggle Source View")
|
||||||
|
target = view.get_parent()
|
||||||
|
target.hide() if target.is_visible() else target.show()
|
||||||
|
|
||||||
|
if view.sibling_left:
|
||||||
|
target = view.sibling_left.get_parent()
|
||||||
|
target.show()
|
||||||
|
view.sibling_left.grab_focus()
|
||||||
|
|
||||||
|
if view.sibling_right:
|
||||||
|
target = view.sibling_right.get_parent()
|
||||||
|
target.show()
|
||||||
|
view.sibling_right.grab_focus()
|
||||||
|
|
||||||
15
src/app.py
15
src/app.py
@@ -2,6 +2,7 @@
|
|||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
import signal
|
import signal
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
|
|
||||||
@@ -44,25 +45,25 @@ class Application:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
logger.warning(f"{APP_NAME} IPC Server Exists: Have sent path(s) to it and closing...")
|
logger.warning(f"{APP_NAME} IPC Server Exists: Have sent path(s) to it and closing...")
|
||||||
|
files: list = []
|
||||||
for arg in unknownargs + [args.new_tab,]:
|
for arg in unknownargs + [args.new_tab,]:
|
||||||
if os.path.isfile(arg):
|
if os.path.isfile(arg):
|
||||||
message = f"FILE|{arg}"
|
files.append(f"file://{arg}")
|
||||||
ipc_server.send_ipc_message(message)
|
|
||||||
|
|
||||||
if os.path.isdir(arg):
|
if os.path.isdir(arg):
|
||||||
message = f"DIR|{arg}"
|
message = f"DIR|{arg}"
|
||||||
ipc_server.send_ipc_message(message)
|
ipc_server.send_ipc_message(message)
|
||||||
|
|
||||||
|
if files:
|
||||||
|
message = f"FILES|{json.dumps(files)}"
|
||||||
|
ipc_server.send_ipc_message(message)
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def ipc_realization_check(self, ipc_server):
|
def ipc_realization_check(self, ipc_server):
|
||||||
try:
|
try:
|
||||||
ipc_server.create_ipc_listener()
|
ipc_server.create_ipc_listener()
|
||||||
except (OSError, PermissionError) as e:
|
except Exception:
|
||||||
logger.info(f"IPC listener creation failed: {e}, falling back to test message")
|
|
||||||
ipc_server.send_test_ipc_message()
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Unexpected IPC setup error: {e}")
|
|
||||||
ipc_server.send_test_ipc_message()
|
ipc_server.send_test_ipc_message()
|
||||||
|
|
||||||
def setup_debug_hook(self):
|
def setup_debug_hook(self):
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ class BaseContainer(Gtk.Box):
|
|||||||
self.ctx.add_class("base-container")
|
self.ctx.add_class("base-container")
|
||||||
|
|
||||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||||
|
self._update_transparency()
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from gi.repository import Gtk
|
|||||||
from ...widgets.code.code_base import CodeBase
|
from ...widgets.code.code_base import CodeBase
|
||||||
|
|
||||||
from ...widgets.separator_widget import Separator
|
from ...widgets.separator_widget import Separator
|
||||||
from ...widgets.code.mini_view_widget import MiniViewWidget
|
|
||||||
|
|
||||||
from .editors_container import EditorsContainer
|
from .editors_container import EditorsContainer
|
||||||
|
|
||||||
@@ -37,20 +36,19 @@ class CodeContainer(Gtk.Box):
|
|||||||
...
|
...
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
|
widget_registery.expose_object("code-container", self)
|
||||||
|
|
||||||
code_base = CodeBase()
|
code_base = CodeBase()
|
||||||
|
|
||||||
self.add( self._create_tabs_widgets(code_base) )
|
|
||||||
self.add( self._create_editor_widget(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):
|
def _create_editor_widget(self, code_base: CodeBase):
|
||||||
editors_container = Gtk.Box()
|
editors_container = Gtk.Box()
|
||||||
|
|
||||||
|
widget_registery.expose_object("editors-container", editors_container)
|
||||||
|
|
||||||
editors_container.add( Separator("separator_left") )
|
editors_container.add( Separator("separator_left") )
|
||||||
editors_container.add( EditorsContainer(code_base) )
|
editors_container.add( EditorsContainer(code_base) )
|
||||||
editors_container.add( Separator("separator_right") )
|
editors_container.add( Separator("separator_right") )
|
||||||
editors_container.add( code_base.get_mini_view_widget() )
|
|
||||||
|
|
||||||
return editors_container
|
return editors_container
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ class EditorsContainer(Gtk.Paned):
|
|||||||
self.ctx = self.get_style_context()
|
self.ctx = self.get_style_context()
|
||||||
self.ctx.add_class("paned-editors-container")
|
self.ctx.add_class("paned-editors-container")
|
||||||
|
|
||||||
self.set_size_request(-1, 300)
|
|
||||||
self.set_hexpand(True)
|
self.set_hexpand(True)
|
||||||
self.set_vexpand(True)
|
self.set_vexpand(True)
|
||||||
self.set_wide_handle(True)
|
self.set_wide_handle(True)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ from gi.repository import Gtk
|
|||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from ..widgets.separator_widget import Separator
|
from ..widgets.separator_widget import Separator
|
||||||
from .code.code_container import CodeContainer
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -39,6 +38,4 @@ class FooterContainer(Gtk.Box):
|
|||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
widget_registery.expose_object("footer-container", self)
|
widget_registery.expose_object("footer-container", self)
|
||||||
|
|
||||||
self.add( CodeContainer() )
|
|
||||||
|
|
||||||
self.add( Separator("separator-footer", 0) )
|
self.add( Separator("separator-footer", 0) )
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from gi.repository import Gtk
|
|||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from ..widgets.separator_widget import Separator
|
from ..widgets.separator_widget import Separator
|
||||||
|
from .code.code_container import CodeContainer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -39,3 +40,4 @@ class LeftContainer(Gtk.Box):
|
|||||||
widget_registery.expose_object("left-container", self)
|
widget_registery.expose_object("left-container", self)
|
||||||
|
|
||||||
self.add( Separator("separator-left", 1) )
|
self.add( Separator("separator-left", 1) )
|
||||||
|
self.add( CodeContainer() )
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerMixin)
|
|||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("shutting-down", lambda: print("Shutting down..."))
|
event_system.subscribe("shutting-down", lambda: print("Shutting down..."))
|
||||||
event_system.subscribe("handle-file-from-ipc", self.handle_file_from_ipc)
|
event_system.subscribe("handle-file-from-ipc", self.handle_file_from_ipc)
|
||||||
|
event_system.subscribe("handle-files-from-ipc", self.handle_files_from_ipc)
|
||||||
event_system.subscribe("handle-dir-from-ipc", self.handle_dir_from_ipc)
|
event_system.subscribe("handle-dir-from-ipc", self.handle_dir_from_ipc)
|
||||||
event_system.subscribe("tggl-top-main-menubar", self._tggl_top_main_menubar)
|
event_system.subscribe("tggl-top-main-menubar", self._tggl_top_main_menubar)
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,10 @@ from plugins import plugins_controller
|
|||||||
from libs.controllers.controller_manager import ControllerManager
|
from libs.controllers.controller_manager import ControllerManager
|
||||||
|
|
||||||
from .controllers.files_controller import FilesController
|
from .controllers.files_controller import FilesController
|
||||||
from .controllers.tabs_controller import TabsController
|
|
||||||
from .controllers.commands_controller import CommandsController
|
from .controllers.commands_controller import CommandsController
|
||||||
from .controllers.completion_controller import CompletionController
|
from .controllers.completion_controller import CompletionController
|
||||||
from .controllers.views.source_views_controller import SourceViewsController
|
from .controllers.views.source_views_controller import SourceViewsController
|
||||||
|
|
||||||
from .mini_view_widget import MiniViewWidget
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CodeBase:
|
class CodeBase:
|
||||||
@@ -22,7 +19,6 @@ class CodeBase:
|
|||||||
super(CodeBase, self).__init__()
|
super(CodeBase, self).__init__()
|
||||||
|
|
||||||
self.controller_manager: ControllerManager = ControllerManager()
|
self.controller_manager: ControllerManager = ControllerManager()
|
||||||
self.miniview_widget: MiniViewWidget = MiniViewWidget()
|
|
||||||
|
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_controllers()
|
self._load_controllers()
|
||||||
@@ -30,29 +26,22 @@ class CodeBase:
|
|||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("handle-file", self._load_ipc_file)
|
event_system.subscribe("handle-file", self._load_ipc_file)
|
||||||
|
event_system.subscribe("handle-files", self._load_ipc_files)
|
||||||
|
|
||||||
def _load_controllers(self):
|
def _load_controllers(self):
|
||||||
files_controller = FilesController()
|
files_controller = FilesController()
|
||||||
tabs_controller = TabsController()
|
|
||||||
commands_controller = CommandsController()
|
commands_controller = CommandsController()
|
||||||
completion_controller = CompletionController()
|
completion_controller = CompletionController()
|
||||||
source_views_controller = SourceViewsController()
|
source_views_controller = SourceViewsController()
|
||||||
|
|
||||||
# self.controller_manager.register_controller("base", self)
|
# self.controller_manager.register_controller("base", self)
|
||||||
self.controller_manager.register_controller("files", files_controller)
|
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("commands", commands_controller)
|
||||||
self.controller_manager.register_controller("completion", completion_controller)
|
self.controller_manager.register_controller("completion", completion_controller)
|
||||||
self.controller_manager.register_controller("source_views", source_views_controller)
|
self.controller_manager.register_controller("source_views", source_views_controller)
|
||||||
self.controller_manager.register_controller("plugins", plugins_controller)
|
self.controller_manager.register_controller("plugins", plugins_controller)
|
||||||
self.controller_manager.register_controller("widgets", widget_registery)
|
self.controller_manager.register_controller("widgets", widget_registery)
|
||||||
|
|
||||||
def get_tabs_widget(self):
|
|
||||||
return self.controller_manager["tabs"].get_tabs_widget()
|
|
||||||
|
|
||||||
def get_mini_view_widget(self):
|
|
||||||
return self.miniview_widget
|
|
||||||
|
|
||||||
def create_source_view(self):
|
def create_source_view(self):
|
||||||
source_view = self.controller_manager["source_views"].create_source_view()
|
source_view = self.controller_manager["source_views"].create_source_view()
|
||||||
self.controller_manager["completion"].register_completer(
|
self.controller_manager["completion"].register_completer(
|
||||||
@@ -68,3 +57,7 @@ class CodeBase:
|
|||||||
active_view = self.controller_manager["source_views"].signal_mapper.active_view
|
active_view = self.controller_manager["source_views"].signal_mapper.active_view
|
||||||
uris = [ f"file://{fpath}" ]
|
uris = [ f"file://{fpath}" ]
|
||||||
active_view._on_uri_data_received(uris)
|
active_view._on_uri_data_received(uris)
|
||||||
|
|
||||||
|
def _load_ipc_files(self, uris: list):
|
||||||
|
active_view = self.controller_manager["source_views"].signal_mapper.active_view
|
||||||
|
active_view._on_uri_data_received(uris)
|
||||||
|
|||||||
@@ -47,6 +47,14 @@ class CommandSystem:
|
|||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def set_info_labels(self, data: tuple[str]):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"set_info_labels",
|
||||||
|
info = data
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("plugins", event)
|
||||||
|
|
||||||
def get_file(self, view: SourceView):
|
def get_file(self, view: SourceView):
|
||||||
event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
"get_file",
|
"get_file",
|
||||||
@@ -78,7 +86,7 @@ class CommandSystem:
|
|||||||
|
|
||||||
def remove_file(self, view: SourceView):
|
def remove_file(self, view: SourceView):
|
||||||
event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
"removed_file",
|
"remove_file",
|
||||||
view = view,
|
view = view,
|
||||||
buffer = view.get_buffer()
|
buffer = view.get_buffer()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,4 +18,5 @@ def execute(
|
|||||||
):
|
):
|
||||||
logger.debug("Command: Focus Left Sibling")
|
logger.debug("Command: Focus Left Sibling")
|
||||||
if not view.sibling_left: return
|
if not view.sibling_left: return
|
||||||
|
view.sibling_left.get_parent().show()
|
||||||
view.sibling_left.grab_focus()
|
view.sibling_left.grab_focus()
|
||||||
|
|||||||
@@ -18,4 +18,5 @@ def execute(
|
|||||||
):
|
):
|
||||||
logger.debug("Command: Focus Right Sibling")
|
logger.debug("Command: Focus Right Sibling")
|
||||||
if not view.sibling_right: return
|
if not view.sibling_right: return
|
||||||
|
view.sibling_right.get_parent().show()
|
||||||
view.sibling_right.grab_focus()
|
view.sibling_right.grab_focus()
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ def execute(
|
|||||||
popped_file, next_file = view.command.get_swap_file(view)
|
popped_file, next_file = view.command.get_swap_file(view)
|
||||||
|
|
||||||
view.sibling_left.set_buffer(buffer)
|
view.sibling_left.set_buffer(buffer)
|
||||||
|
view.sibling_left.get_parent().show()
|
||||||
view.sibling_left.grab_focus()
|
view.sibling_left.grab_focus()
|
||||||
|
|
||||||
if next_file:
|
if next_file:
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ def execute(
|
|||||||
popped_file, next_file = view.command.get_swap_file(view)
|
popped_file, next_file = view.command.get_swap_file(view)
|
||||||
|
|
||||||
view.sibling_right.set_buffer(buffer)
|
view.sibling_right.set_buffer(buffer)
|
||||||
|
view.sibling_right.get_parent().show()
|
||||||
view.sibling_right.grab_focus()
|
view.sibling_right.grab_focus()
|
||||||
|
|
||||||
if next_file:
|
if next_file:
|
||||||
|
|||||||
@@ -18,10 +18,14 @@ def execute(
|
|||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
logger.debug("Command: Open File(s)")
|
logger.debug("Command: Open File(s)")
|
||||||
gfiles = event_system.emit_and_await("open-files")
|
file = view.command.get_file(view)
|
||||||
|
start_path = None
|
||||||
|
if not file.ftype == "buffer":
|
||||||
|
start_path = file.get_location()
|
||||||
|
|
||||||
|
gfiles = event_system.emit_and_await("open-files", (None, None, start_path))
|
||||||
if not gfiles: return
|
if not gfiles: return
|
||||||
|
|
||||||
file = view.command.get_file(view)
|
|
||||||
if file.ftype == "buffer":
|
if file.ftype == "buffer":
|
||||||
gfile = gfiles.pop()
|
gfile = gfiles.pop()
|
||||||
view.command.exec_with_args("load_file", view, gfile, file)
|
view.command.exec_with_args("load_file", view, gfile, file)
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ def execute(
|
|||||||
column = iter.get_line_offset()
|
column = iter.get_line_offset()
|
||||||
ftype = file.ftype.get_id() if hasattr(file.ftype, "get_id") else file.ftype
|
ftype = file.ftype.get_id() if hasattr(file.ftype, "get_id") else file.ftype
|
||||||
|
|
||||||
event_system.emit(
|
view.command.set_info_labels(
|
||||||
"set-info-labels",
|
|
||||||
(file.fpath, f"{line}:{column}", ftype, file.encoding)
|
(file.fpath, f"{line}:{column}", ftype, file.encoding)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ class FilesController(ControllerBase, list):
|
|||||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
if isinstance(event, Code_Event_Types.AddNewFileEvent):
|
if isinstance(event, Code_Event_Types.AddNewFileEvent):
|
||||||
self.new_file(event)
|
self.new_file(event)
|
||||||
elif isinstance(event, Code_Event_Types.SwapFileEvent):
|
|
||||||
self.swap_file(event)
|
|
||||||
elif isinstance(event, Code_Event_Types.PopFileEvent):
|
elif isinstance(event, Code_Event_Types.PopFileEvent):
|
||||||
self.pop_file(event)
|
self.pop_file(event)
|
||||||
elif isinstance(event, Code_Event_Types.RemoveFileEvent):
|
elif isinstance(event, Code_Event_Types.RemoveFileEvent):
|
||||||
@@ -31,29 +29,6 @@ class FilesController(ControllerBase, list):
|
|||||||
elif isinstance(event, Code_Event_Types.GetSwapFileEvent):
|
elif isinstance(event, Code_Event_Types.GetSwapFileEvent):
|
||||||
self.get_swap_file(event)
|
self.get_swap_file(event)
|
||||||
|
|
||||||
def get_file(self, event: Code_Event_Types.GetFileEvent):
|
|
||||||
if not event.buffer: return
|
|
||||||
|
|
||||||
for file in self:
|
|
||||||
if not event.buffer == file.buffer: continue
|
|
||||||
|
|
||||||
event.response = file
|
|
||||||
|
|
||||||
return file
|
|
||||||
|
|
||||||
def get_swap_file(self, event: Code_Event_Types.GetSwapFileEvent):
|
|
||||||
if not event.buffer: return
|
|
||||||
|
|
||||||
for i, file in enumerate(self):
|
|
||||||
if not event.buffer == file.buffer: continue
|
|
||||||
|
|
||||||
j = self.next_index(i)
|
|
||||||
next_file = self[j]
|
|
||||||
swapped_file = self[j] if not j == -1 else None
|
|
||||||
|
|
||||||
event.response = [swapped_file, next_file]
|
|
||||||
|
|
||||||
return swapped_file, next_file
|
|
||||||
|
|
||||||
def new_file(self, event: Code_Event_Types.AddNewFileEvent):
|
def new_file(self, event: Code_Event_Types.AddNewFileEvent):
|
||||||
file = SourceFile()
|
file = SourceFile()
|
||||||
@@ -73,20 +48,6 @@ class FilesController(ControllerBase, list):
|
|||||||
|
|
||||||
return file
|
return file
|
||||||
|
|
||||||
def swap_file(self, event: Code_Event_Types.GetSwapFileEvent):
|
|
||||||
if not event.buffer: return
|
|
||||||
|
|
||||||
for i, file in enumerate(self):
|
|
||||||
if not event.buffer == file.buffer: continue
|
|
||||||
|
|
||||||
j = self.next_index(i)
|
|
||||||
next_file = self[j]
|
|
||||||
swapped_file = self[j] if not j == -1 else None
|
|
||||||
|
|
||||||
event.response = [swapped_file, next_file]
|
|
||||||
|
|
||||||
return swapped_file, next_file
|
|
||||||
|
|
||||||
def pop_file(self, event: Code_Event_Types.PopFileEvent):
|
def pop_file(self, event: Code_Event_Types.PopFileEvent):
|
||||||
if not event.buffer: return
|
if not event.buffer: return
|
||||||
|
|
||||||
@@ -134,6 +95,30 @@ class FilesController(ControllerBase, list):
|
|||||||
|
|
||||||
return next_file
|
return next_file
|
||||||
|
|
||||||
|
def get_file(self, event: Code_Event_Types.GetFileEvent):
|
||||||
|
if not event.buffer: return
|
||||||
|
|
||||||
|
for file in self:
|
||||||
|
if not event.buffer == file.buffer: continue
|
||||||
|
|
||||||
|
event.response = file
|
||||||
|
|
||||||
|
return file
|
||||||
|
|
||||||
|
def get_swap_file(self, event: Code_Event_Types.GetSwapFileEvent):
|
||||||
|
if not event.buffer: return
|
||||||
|
|
||||||
|
for i, file in enumerate(self):
|
||||||
|
if not event.buffer == file.buffer: continue
|
||||||
|
|
||||||
|
j = self.next_index(i)
|
||||||
|
next_file = self[j]
|
||||||
|
swapped_file = self[j] if not j == -1 else None
|
||||||
|
|
||||||
|
event.response = [swapped_file, next_file]
|
||||||
|
|
||||||
|
return swapped_file, next_file
|
||||||
|
|
||||||
def next_index(self, i):
|
def next_index(self, i):
|
||||||
size = len(self)
|
size = len(self)
|
||||||
|
|
||||||
|
|||||||
137
src/core/widgets/code/controllers/views/marker_manager.py
Normal file
137
src/core/widgets/code/controllers/views/marker_manager.py
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from ...mixins.mark_support_mixin import MarkSupportMixin
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MarkerManager(MarkSupportMixin):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.buffer_markers: dict = {}
|
||||||
|
|
||||||
|
self.selection_tag: Gtk.TextTag = Gtk.TextTag.new("selection")
|
||||||
|
self.selection_tag.props.background = "rgba(111, 168, 220, 0.64)"
|
||||||
|
self.selection_tag.props.foreground = "#ffffff"
|
||||||
|
|
||||||
|
|
||||||
|
def move_by_char(self, buffer, is_forward: bool, is_selection: bool):
|
||||||
|
self._move(buffer, is_forward, is_selection, mode = "char")
|
||||||
|
|
||||||
|
def move_by_word(self, buffer, is_forward: bool, is_selection: bool):
|
||||||
|
self._move(buffer, is_forward, is_selection, mode = "word")
|
||||||
|
|
||||||
|
def move_by_line(self, buffer, is_forward: bool, is_selection: bool):
|
||||||
|
self._move(buffer, is_forward, is_selection, mode = "line")
|
||||||
|
|
||||||
|
def _move(self, buffer, is_forward: bool, is_selection: bool, mode: str):
|
||||||
|
self.clear_highlight(buffer)
|
||||||
|
self.insert_selection_tag(buffer)
|
||||||
|
|
||||||
|
for mark_hash in self.buffer_markers:
|
||||||
|
marker = self.buffer_markers[mark_hash]
|
||||||
|
start_mark = marker["start_mark"]
|
||||||
|
end_mark = marker["end_mark"]
|
||||||
|
has_selection = marker["is_selection"]
|
||||||
|
|
||||||
|
start_itr = buffer.get_iter_at_mark(start_mark)
|
||||||
|
end_itr = buffer.get_iter_at_mark(end_mark)
|
||||||
|
|
||||||
|
if is_selection:
|
||||||
|
self.buffer_markers[mark_hash]["is_selection"] = True
|
||||||
|
|
||||||
|
self._move_iter(buffer, end_itr, mode, is_forward)
|
||||||
|
buffer.move_mark(end_mark, end_itr)
|
||||||
|
|
||||||
|
self._apply_selection(buffer, start_itr, end_itr)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if has_selection:
|
||||||
|
self.collapse_selection(buffer, mark_hash, start_mark, end_mark, is_forward)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# No selection — move both anchor and caret together
|
||||||
|
self._move_iter(buffer, end_itr, mode, is_forward)
|
||||||
|
|
||||||
|
buffer.move_mark(start_mark, end_itr)
|
||||||
|
buffer.move_mark(end_mark, end_itr)
|
||||||
|
|
||||||
|
def collapse_selection(self,
|
||||||
|
buffer, mark_hash, start_mark, end_mark, is_forward: bool
|
||||||
|
):
|
||||||
|
self.buffer_markers[mark_hash]["is_selection"] = False
|
||||||
|
|
||||||
|
start_itr = buffer.get_iter_at_mark(start_mark)
|
||||||
|
end_itr = buffer.get_iter_at_mark(end_mark)
|
||||||
|
|
||||||
|
# Determine which side is visually the caret
|
||||||
|
if start_itr.compare(end_itr) <= 0:
|
||||||
|
left = start_itr
|
||||||
|
right = end_itr
|
||||||
|
else:
|
||||||
|
left = end_itr
|
||||||
|
right = start_itr
|
||||||
|
|
||||||
|
# If moving forward → collapse to right edge
|
||||||
|
collapse_itr = right if is_forward else left
|
||||||
|
|
||||||
|
buffer.move_mark(start_mark, collapse_itr)
|
||||||
|
buffer.move_mark(end_mark, collapse_itr)
|
||||||
|
|
||||||
|
def _move_iter(self, buffer, itr_, mode: str, is_forward: bool):
|
||||||
|
if mode == "char":
|
||||||
|
itr_.forward_char() if is_forward else itr_.backward_char()
|
||||||
|
elif mode == "word":
|
||||||
|
itr_.forward_word_end() if is_forward else itr_.backward_word_start()
|
||||||
|
elif mode == "line":
|
||||||
|
line = itr_.get_line()
|
||||||
|
offset = itr_.get_line_offset()
|
||||||
|
|
||||||
|
max_line = buffer.get_line_count() - 1
|
||||||
|
new_line = line + 1 if is_forward else line - 1
|
||||||
|
new_line = max(0, min(max_line, new_line))
|
||||||
|
|
||||||
|
itr_.set_line(new_line)
|
||||||
|
self.move_to_offset(offset, itr_)
|
||||||
|
|
||||||
|
def _apply_selection(self, buffer, start_itr, end_itr):
|
||||||
|
if start_itr.compare(end_itr) <= 0:
|
||||||
|
buffer.apply_tag(self.selection_tag, start_itr, end_itr)
|
||||||
|
else:
|
||||||
|
buffer.apply_tag(self.selection_tag, end_itr, start_itr)
|
||||||
|
|
||||||
|
|
||||||
|
def button_release_event(self, source_view, event):
|
||||||
|
buffer = source_view.get_buffer()
|
||||||
|
|
||||||
|
coords = source_view.window_to_buffer_coords(
|
||||||
|
Gtk.TextWindowType.TEXT,
|
||||||
|
event.x,
|
||||||
|
event.y,
|
||||||
|
)
|
||||||
|
|
||||||
|
is_over_text, target_itr, _ = source_view.get_iter_at_position(
|
||||||
|
coords.buffer_x,
|
||||||
|
coords.buffer_y,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not is_over_text:
|
||||||
|
target_itr.forward_visible_line()
|
||||||
|
target_itr.backward_char()
|
||||||
|
|
||||||
|
if self.remove_mark_set(target_itr, buffer):
|
||||||
|
return
|
||||||
|
|
||||||
|
self.insert_mark_set(target_itr, buffer)
|
||||||
|
|
||||||
|
def key_press_event(self, source_view, event, key_mapper):
|
||||||
|
...
|
||||||
@@ -42,7 +42,8 @@ class SourceViewSignalMapper:
|
|||||||
"key-press-event": self._key_press_event,
|
"key-press-event": self._key_press_event,
|
||||||
"key-release-event": self._key_release_event,
|
"key-release-event": self._key_release_event,
|
||||||
"button-press-event": self._button_press_event,
|
"button-press-event": self._button_press_event,
|
||||||
"button-release-event": self._button_release_event
|
"button-release-event": self._button_release_event,
|
||||||
|
"populate-popup": self._populate_popup
|
||||||
}
|
}
|
||||||
|
|
||||||
def _focus_in_event(self, source_view: SourceView, eve):
|
def _focus_in_event(self, source_view: SourceView, eve):
|
||||||
@@ -54,14 +55,17 @@ class SourceViewSignalMapper:
|
|||||||
source_view, step, count, extend_selection, self.emit
|
source_view, step, count, extend_selection, self.emit
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _key_press_event(self, source_view: SourceView, eve):
|
||||||
|
return self.state_manager.handle_key_press_event(source_view, eve)
|
||||||
|
|
||||||
|
def _key_release_event(self, source_view: SourceView, eve):
|
||||||
|
return self.state_manager.handle_key_release_event(source_view, eve)
|
||||||
|
|
||||||
def _button_press_event(self, source_view: SourceView, eve):
|
def _button_press_event(self, source_view: SourceView, eve):
|
||||||
return self.state_manager.handle_button_press_event(source_view, eve)
|
return self.state_manager.handle_button_press_event(source_view, eve)
|
||||||
|
|
||||||
def _button_release_event(self, source_view: SourceView, eve):
|
def _button_release_event(self, source_view: SourceView, eve):
|
||||||
return self.state_manager.handle_button_release_event(source_view, eve)
|
return self.state_manager.handle_button_release_event(source_view, eve)
|
||||||
|
|
||||||
def _key_press_event(self, source_view: SourceView, eve):
|
def _populate_popup(self, source_view, menu):
|
||||||
return self.state_manager.handle_key_press_event(source_view, eve)
|
return self.state_manager.handle_populate_popup(source_view, menu, self.emit)
|
||||||
|
|
||||||
def _key_release_event(self, source_view: SourceView, eve):
|
|
||||||
return self.state_manager.handle_key_release_event(source_view, eve)
|
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ class SourceViewsController(ControllerBase, list):
|
|||||||
def first_map_load(self):
|
def first_map_load(self):
|
||||||
for source_view in self:
|
for source_view in self:
|
||||||
source_view.command.exec("new_file")
|
source_view.command.exec("new_file")
|
||||||
|
if not source_view.sibling_left: continue
|
||||||
|
source_view.get_parent().hide()
|
||||||
|
|
||||||
source_view = self[0]
|
source_view = self[0]
|
||||||
source_view.grab_focus()
|
source_view.grab_focus()
|
||||||
|
|||||||
@@ -34,15 +34,6 @@ class SourceViewStateManager:
|
|||||||
source_view, step, count, extend_selection, emit
|
source_view, step, count, extend_selection, emit
|
||||||
)
|
)
|
||||||
|
|
||||||
def handle_button_press_event(self, source_view, eve):
|
|
||||||
return self.states[source_view.state].button_press_event(source_view, eve)
|
|
||||||
|
|
||||||
def handle_button_release_event(self, source_view, eve):
|
|
||||||
# Handle state transitions (multi-insert toggling)
|
|
||||||
self._handle_multi_insert_toggle(source_view, eve)
|
|
||||||
|
|
||||||
return self.states[source_view.state].button_release_event(source_view, eve)
|
|
||||||
|
|
||||||
def handle_key_press_event(self, source_view, eve):
|
def handle_key_press_event(self, source_view, eve):
|
||||||
return self.states[source_view.state].key_press_event(
|
return self.states[source_view.state].key_press_event(
|
||||||
source_view, eve, self.key_mapper
|
source_view, eve, self.key_mapper
|
||||||
@@ -53,6 +44,17 @@ class SourceViewStateManager:
|
|||||||
source_view, eve, self.key_mapper
|
source_view, eve, self.key_mapper
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def handle_button_press_event(self, source_view, eve):
|
||||||
|
self._handle_multi_insert_toggle(source_view, eve)
|
||||||
|
|
||||||
|
return self.states[source_view.state].button_press_event(source_view, eve)
|
||||||
|
|
||||||
|
def handle_button_release_event(self, source_view, eve):
|
||||||
|
return self.states[source_view.state].button_release_event(source_view, eve)
|
||||||
|
|
||||||
|
def handle_populate_popup(self, source_view, menu, emit):
|
||||||
|
return self.states[source_view.state].populate_popup(source_view, menu, emit)
|
||||||
|
|
||||||
def _handle_multi_insert_toggle(self, source_view, eve):
|
def _handle_multi_insert_toggle(self, source_view, eve):
|
||||||
is_control = self.key_mapper.is_control(eve)
|
is_control = self.key_mapper.is_control(eve)
|
||||||
if is_control and not source_view.state == SourceViewStates.MULTIINSERT:
|
if is_control and not source_view.state == SourceViewStates.MULTIINSERT:
|
||||||
@@ -61,6 +63,7 @@ class SourceViewStateManager:
|
|||||||
|
|
||||||
if not is_control and source_view.state == SourceViewStates.MULTIINSERT:
|
if not is_control and source_view.state == SourceViewStates.MULTIINSERT:
|
||||||
logger.debug("Entered Regular Insert Mode...")
|
logger.debug("Entered Regular Insert Mode...")
|
||||||
self.states[source_view.state].clear_markers(source_view)
|
self.states[source_view.state].marker_manager.clear_mark_sets(source_view)
|
||||||
|
|
||||||
source_view.state = SourceViewStates.INSERT
|
source_view.state = SourceViewStates.INSERT
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from libs.dto.states import SourceViewStates
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SourceViewsBaseState:
|
||||||
|
def __init__(self):
|
||||||
|
super(SourceViewsBaseState, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def focus_in_event(self, source_view, eve, emit):
|
||||||
|
source_view.command.exec("set_miniview")
|
||||||
|
source_view.command.exec("set_focus_border")
|
||||||
|
source_view.command.exec("update_info_bar")
|
||||||
|
|
||||||
|
event = Event_Factory.create_event("focused_view", view = source_view)
|
||||||
|
emit(event)
|
||||||
|
|
||||||
|
def insert_text(self, file, text: str):
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def move_cursor(self, source_view, step, count, extend_selection, emit):
|
||||||
|
buffer = source_view.get_buffer()
|
||||||
|
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||||
|
line = itr.get_line()
|
||||||
|
char = itr.get_line_offset()
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"cursor_moved",
|
||||||
|
view = source_view,
|
||||||
|
buffer = buffer,
|
||||||
|
line = line,
|
||||||
|
char = char
|
||||||
|
)
|
||||||
|
|
||||||
|
emit(event)
|
||||||
|
|
||||||
|
source_view.command.exec("update_info_bar")
|
||||||
|
|
||||||
|
def button_press_event(self, source_view, eve):
|
||||||
|
source_view.command.exec("update_info_bar")
|
||||||
|
|
||||||
|
def button_release_event(self, source_view, eve):
|
||||||
|
source_view.command.exec("update_info_bar")
|
||||||
|
|
||||||
|
def key_press_event(self, source_view, eve, key_mapper):
|
||||||
|
command = key_mapper._key_press_event(eve)
|
||||||
|
is_future = key_mapper._key_release_event(eve)
|
||||||
|
char_str = key_mapper.get_char(eve)
|
||||||
|
modkeys_states = key_mapper.get_modkeys_states(eve)
|
||||||
|
|
||||||
|
if is_future: return True
|
||||||
|
if not command: return False
|
||||||
|
|
||||||
|
response = source_view.command.exec_with_args(
|
||||||
|
command, source_view, char_str, modkeys_states
|
||||||
|
)
|
||||||
|
|
||||||
|
return True if not response else response
|
||||||
|
|
||||||
|
def key_release_event(self, source_view, eve, key_mapper):
|
||||||
|
command = key_mapper._key_release_event(eve)
|
||||||
|
is_past = key_mapper._key_press_event(eve)
|
||||||
|
char_str = key_mapper.get_char(eve)
|
||||||
|
modkeys_states = key_mapper.get_modkeys_states(eve)
|
||||||
|
|
||||||
|
if is_past: return True
|
||||||
|
if not command: return False
|
||||||
|
|
||||||
|
response = source_view.command.exec_with_args(
|
||||||
|
command, source_view, char_str, modkeys_states
|
||||||
|
)
|
||||||
|
|
||||||
|
return True if not response else response
|
||||||
|
|
||||||
|
def populate_popup(self, source_view, menu, emit):
|
||||||
|
buffer = source_view.get_buffer()
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"populate_source_view_popup",
|
||||||
|
buffer = buffer,
|
||||||
|
menu = menu
|
||||||
|
)
|
||||||
|
|
||||||
|
emit(event)
|
||||||
|
|
||||||
|
menu.show_all()
|
||||||
@@ -7,9 +7,11 @@ from libs.event_factory import Event_Factory, Code_Event_Types
|
|||||||
|
|
||||||
from libs.dto.states import SourceViewStates
|
from libs.dto.states import SourceViewStates
|
||||||
|
|
||||||
|
from .source_view_base_state import SourceViewsBaseState
|
||||||
|
|
||||||
|
|
||||||
class SourceViewsCommandState:
|
|
||||||
|
class SourceViewsCommandState(SourceViewsBaseState):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(SourceViewsCommandState, self).__init__()
|
super(SourceViewsCommandState, self).__init__()
|
||||||
|
|
||||||
@@ -17,10 +19,10 @@ class SourceViewsCommandState:
|
|||||||
def focus_in_event(self, source_view, eve, emit):
|
def focus_in_event(self, source_view, eve, emit):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def move_cursor(self, source_view, step, count, extend_selection, emit):
|
def insert_text(self, file, text):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def insert_text(self, file, text):
|
def move_cursor(self, source_view, step, count, extend_selection, emit):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def button_press_event(self, source_view, eve):
|
def button_press_event(self, source_view, eve):
|
||||||
|
|||||||
@@ -7,68 +7,10 @@ from libs.event_factory import Event_Factory, Code_Event_Types
|
|||||||
|
|
||||||
from libs.dto.states import SourceViewStates
|
from libs.dto.states import SourceViewStates
|
||||||
|
|
||||||
|
from .source_view_base_state import SourceViewsBaseState
|
||||||
|
|
||||||
|
|
||||||
class SourceViewsInsertState:
|
|
||||||
|
class SourceViewsInsertState(SourceViewsBaseState):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(SourceViewsInsertState, self).__init__()
|
super(SourceViewsInsertState, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
def focus_in_event(self, source_view, eve, emit):
|
|
||||||
source_view.command.exec("set_miniview")
|
|
||||||
source_view.command.exec("set_focus_border")
|
|
||||||
source_view.command.exec("update_info_bar")
|
|
||||||
|
|
||||||
event = Event_Factory.create_event("focused_view", view = source_view)
|
|
||||||
emit(event)
|
|
||||||
|
|
||||||
def insert_text(self, file, text: str):
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def move_cursor(self, source_view, step, count, extend_selection, emit):
|
|
||||||
buffer = source_view.get_buffer()
|
|
||||||
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
|
||||||
line = itr.get_line()
|
|
||||||
char = itr.get_line_offset()
|
|
||||||
event = Event_Factory.create_event(
|
|
||||||
"cursor_moved",
|
|
||||||
view = source_view,
|
|
||||||
buffer = buffer,
|
|
||||||
line = line,
|
|
||||||
char = char
|
|
||||||
)
|
|
||||||
|
|
||||||
emit(event)
|
|
||||||
|
|
||||||
source_view.command.exec("update_info_bar")
|
|
||||||
|
|
||||||
def button_press_event(self, source_view, eve):
|
|
||||||
source_view.command.exec("update_info_bar")
|
|
||||||
|
|
||||||
def button_release_event(self, source_view, eve):
|
|
||||||
source_view.command.exec("update_info_bar")
|
|
||||||
|
|
||||||
def key_press_event(self, source_view, eve, key_mapper):
|
|
||||||
command = key_mapper._key_press_event(eve)
|
|
||||||
is_future = key_mapper._key_release_event(eve)
|
|
||||||
char_str = key_mapper.get_char(eve)
|
|
||||||
|
|
||||||
if is_future: return True
|
|
||||||
if not command: return False
|
|
||||||
|
|
||||||
source_view.command.exec_with_args(command, source_view, char_str)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def key_release_event(self, source_view, eve, key_mapper):
|
|
||||||
command = key_mapper._key_release_event(eve)
|
|
||||||
is_past = key_mapper._key_press_event(eve)
|
|
||||||
char_str = key_mapper.get_char(eve)
|
|
||||||
|
|
||||||
if is_past: return True
|
|
||||||
if not command: return False
|
|
||||||
|
|
||||||
source_view.command.exec_with_args(command, source_view, char_str)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|||||||
@@ -2,153 +2,108 @@
|
|||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
from libs.event_factory import Event_Factory
|
||||||
from libs.dto.states import SourceViewStates, MoveDirection, CursorAction
|
from libs.dto.states import CursorAction
|
||||||
|
|
||||||
from ....mixins.source_mark_events_mixin import MarkEventsMixin
|
from ..marker_manager import MarkerManager
|
||||||
|
|
||||||
|
from .source_view_base_state import SourceViewsBaseState
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SourceViewsMultiInsertState(MarkEventsMixin):
|
class SourceViewsMultiInsertState(SourceViewsBaseState):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(SourceViewsMultiInsertState, self).__init__()
|
super(SourceViewsMultiInsertState, self).__init__()
|
||||||
|
|
||||||
self.cursor_action: CursorAction = 0
|
self.cursor_action: CursorAction = None
|
||||||
self.move_direction: MoveDirection = 0
|
self.marker_manager: MarkerManager = MarkerManager()
|
||||||
self.insert_markers: list = []
|
|
||||||
|
|
||||||
|
|
||||||
def focus_in_event(self, source_view, eve, emit):
|
def insert_text(self, file, text: str) -> bool:
|
||||||
source_view.command.exec("set_miniview")
|
if not self.marker_manager.buffer_markers: return False
|
||||||
source_view.command.exec("set_focus_border")
|
|
||||||
source_view.command.exec("update_info_bar")
|
|
||||||
|
|
||||||
event = Event_Factory.create_event("focused_view", view = source_view)
|
|
||||||
emit(event)
|
|
||||||
|
|
||||||
def insert_text(self, file, text):
|
|
||||||
if not self.insert_markers: return False
|
|
||||||
|
|
||||||
buffer = file.buffer
|
buffer = file.buffer
|
||||||
|
|
||||||
if buffer.is_processing_completion:
|
if buffer.is_processing_completion:
|
||||||
self.insert_completion_text(buffer, text)
|
return self._insert_completion_text(buffer, text)
|
||||||
return True
|
|
||||||
|
|
||||||
# freeze buffer and insert to each mark (if any)
|
def insert_text(start_itr, end_itr = None):
|
||||||
buffer.block_insert_after_signal()
|
if not end_itr:
|
||||||
buffer.begin_user_action()
|
buffer.insert(start_itr, text, -1)
|
||||||
|
return
|
||||||
|
|
||||||
with buffer.freeze_notify():
|
buffer.delete(start_itr, end_itr)
|
||||||
for mark in self.insert_markers:
|
buffer.insert(start_itr, text, -1)
|
||||||
itr = buffer.get_iter_at_mark(mark)
|
|
||||||
buffer.insert(itr, text, -1)
|
|
||||||
|
|
||||||
buffer.end_user_action()
|
|
||||||
buffer.unblock_insert_after_signal()
|
|
||||||
|
|
||||||
|
self.marker_manager.apply_to_marks(buffer, insert_text)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def insert_completion_text(self, buffer, text):
|
def _insert_completion_text(self, buffer, text: str) -> bool:
|
||||||
buffer.is_processing_completion = False
|
buffer.is_processing_completion = False
|
||||||
|
|
||||||
# freeze buffer and insert to each mark (if any)
|
def replace_word(start_itr, end_itr = None):
|
||||||
buffer.block_insert_after_signal()
|
if not end_itr:
|
||||||
buffer.begin_user_action()
|
end_itr = start_itr.copy()
|
||||||
|
|
||||||
with buffer.freeze_notify():
|
if not start_itr.starts_word():
|
||||||
for mark in self.insert_markers:
|
start_itr.backward_word_start()
|
||||||
end_itr = buffer.get_iter_at_mark(mark)
|
|
||||||
start_itr = end_itr.copy()
|
|
||||||
|
|
||||||
if not start_itr.starts_word():
|
if not end_itr.ends_word():
|
||||||
start_itr.backward_word_start()
|
end_itr.forward_word_end()
|
||||||
|
|
||||||
if not end_itr.ends_word():
|
buffer.delete(start_itr, end_itr)
|
||||||
end_itr.forward_word_end()
|
buffer.insert(start_itr, text, -1)
|
||||||
|
|
||||||
buffer.delete(start_itr, end_itr)
|
|
||||||
buffer.insert(start_itr, text, -1)
|
|
||||||
|
|
||||||
buffer.end_user_action()
|
|
||||||
buffer.unblock_insert_after_signal()
|
|
||||||
|
|
||||||
|
self.marker_manager.apply_to_marks(buffer, replace_word)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def move_cursor(self, source_view, step, count, extend_selection, emit):
|
|
||||||
buffer = source_view.get_buffer()
|
|
||||||
|
|
||||||
self._process_move_direction(buffer)
|
def move_cursor(self, source_view, step, count, is_selection, emit):
|
||||||
|
is_forward = count > 0
|
||||||
|
buffer = source_view.get_buffer()
|
||||||
|
|
||||||
|
if step in [
|
||||||
|
Gtk.MovementStep.LOGICAL_POSITIONS,
|
||||||
|
Gtk.MovementStep.VISUAL_POSITIONS
|
||||||
|
]:
|
||||||
|
self.marker_manager.move_by_char(buffer, is_forward, is_selection)
|
||||||
|
elif step == Gtk.MovementStep.WORDS:
|
||||||
|
self.marker_manager.move_by_word(buffer, is_forward, is_selection)
|
||||||
|
elif step == Gtk.MovementStep.DISPLAY_LINES:
|
||||||
|
self.marker_manager.move_by_line(buffer, is_forward, is_selection)
|
||||||
|
|
||||||
self._signal_cursor_moved(source_view, emit)
|
self._signal_cursor_moved(source_view, emit)
|
||||||
source_view.command.exec("update_info_bar")
|
|
||||||
|
|
||||||
def button_press_event(self, source_view, eve):
|
def key_press_event(self, source_view, event, key_mapper):
|
||||||
source_view.command.exec("update_info_bar")
|
char = key_mapper.get_raw_keyname(event).upper()
|
||||||
return True
|
self.is_control = key_mapper.is_control(event)
|
||||||
|
self.is_shift = key_mapper.is_shift(event)
|
||||||
def button_release_event(self, source_view, eve):
|
|
||||||
buffer = source_view.get_buffer()
|
|
||||||
insert_iter = buffer.get_iter_at_mark( buffer.get_insert() )
|
|
||||||
data = source_view.window_to_buffer_coords(
|
|
||||||
Gtk.TextWindowType.TEXT,
|
|
||||||
eve.x,
|
|
||||||
eve.y
|
|
||||||
)
|
|
||||||
is_over_text, \
|
|
||||||
target_iter, \
|
|
||||||
is_trailing = source_view.get_iter_at_position(data.buffer_x, data.buffer_y)
|
|
||||||
|
|
||||||
if not is_over_text:
|
|
||||||
# NOTE: Trying to put at very end of line if not over text (aka, clicking right of text)
|
|
||||||
target_iter.forward_visible_line()
|
|
||||||
target_iter.backward_char()
|
|
||||||
|
|
||||||
self._insert_mark(insert_iter, target_iter, buffer)
|
|
||||||
|
|
||||||
def key_press_event(self, source_view, eve, key_mapper):
|
|
||||||
char = key_mapper.get_raw_keyname(eve)
|
|
||||||
|
|
||||||
for action in CursorAction:
|
|
||||||
if not action.name == char.upper(): continue
|
|
||||||
self.cursor_action = action.value
|
|
||||||
self._process_cursor_action(source_view.get_buffer())
|
|
||||||
|
|
||||||
|
if char.upper() in ["BACKSPACE", "DELETE", "ENTER"]:
|
||||||
|
self.marker_manager.process_cursor_action(
|
||||||
|
source_view.get_buffer(),
|
||||||
|
char.upper()
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
for direction in MoveDirection:
|
return super().key_press_event(source_view, event, key_mapper)
|
||||||
if not direction.name == char.upper(): continue
|
|
||||||
self.move_direction = direction.value
|
|
||||||
return False
|
|
||||||
|
|
||||||
is_future = key_mapper._key_release_event(eve)
|
|
||||||
if is_future: return True
|
|
||||||
|
|
||||||
command = key_mapper._key_press_event(eve)
|
|
||||||
if not command: return False
|
|
||||||
|
|
||||||
source_view.command.exec(command)
|
|
||||||
|
|
||||||
|
def button_press_event(self, source_view, event):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def key_release_event(self, source_view, eve, key_mapper):
|
def button_release_event(self, source_view, event):
|
||||||
command = key_mapper._key_release_event(eve)
|
self.marker_manager.button_release_event(source_view, event)
|
||||||
is_past = key_mapper._key_press_event(eve)
|
|
||||||
|
|
||||||
if is_past: return True
|
|
||||||
if not command: return False
|
|
||||||
|
|
||||||
source_view.command.exec(command)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _signal_cursor_moved(self, source_view, emit):
|
def _signal_cursor_moved(self, source_view, emit):
|
||||||
buffer = source_view.get_buffer()
|
buffer = source_view.get_buffer()
|
||||||
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||||
line = itr.get_line()
|
line = itr.get_line()
|
||||||
char = itr.get_line_offset()
|
char = itr.get_line_offset()
|
||||||
|
|
||||||
event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
"cursor_moved",
|
"cursor_moved",
|
||||||
view = source_view,
|
view = source_view,
|
||||||
@@ -158,3 +113,4 @@ class SourceViewsMultiInsertState(MarkEventsMixin):
|
|||||||
)
|
)
|
||||||
|
|
||||||
emit(event)
|
emit(event)
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ from libs.event_factory import Event_Factory, Code_Event_Types
|
|||||||
|
|
||||||
from libs.dto.states import SourceViewStates
|
from libs.dto.states import SourceViewStates
|
||||||
|
|
||||||
|
from .source_view_base_state import SourceViewsBaseState
|
||||||
|
|
||||||
|
|
||||||
class SourceViewsReadOnlyState:
|
|
||||||
|
class SourceViewsReadOnlyState(SourceViewsBaseState):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(SourceViewsReadOnlyState, self).__init__()
|
super(SourceViewsReadOnlyState, self).__init__()
|
||||||
|
|
||||||
@@ -17,10 +19,10 @@ class SourceViewsReadOnlyState:
|
|||||||
def focus_in_event(self, source_view, eve, emit):
|
def focus_in_event(self, source_view, eve, emit):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def move_cursor(self, source_view, step, count, extend_selection, emit):
|
def insert_text(self, file, text):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def insert_text(self, file, text):
|
def move_cursor(self, source_view, step, count, extend_selection, emit):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def button_press_event(self, source_view, eve):
|
def button_press_event(self, source_view, eve):
|
||||||
|
|||||||
@@ -119,14 +119,9 @@ class KeyMapper:
|
|||||||
return self.states[self.state].released[char_str]
|
return self.states[self.state].released[char_str]
|
||||||
|
|
||||||
def _set_key_state(self, eve):
|
def _set_key_state(self, eve):
|
||||||
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
|
is_control, \
|
||||||
is_control = modifiers & Gdk.ModifierType.CONTROL_MASK
|
is_shift, \
|
||||||
is_shift = modifiers & Gdk.ModifierType.SHIFT_MASK
|
is_alt = self.get_modkeys_states(eve)
|
||||||
|
|
||||||
try:
|
|
||||||
is_alt = modifiers & Gdk.ModifierType.ALT_MASK
|
|
||||||
except:
|
|
||||||
is_alt = modifiers & Gdk.ModifierType.MOD1_MASK
|
|
||||||
|
|
||||||
self.state = NoKeyState
|
self.state = NoKeyState
|
||||||
if is_control:
|
if is_control:
|
||||||
@@ -144,11 +139,23 @@ class KeyMapper:
|
|||||||
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
|
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
|
||||||
return modifiers & Gdk.ModifierType.SHIFT_MASK
|
return modifiers & Gdk.ModifierType.SHIFT_MASK
|
||||||
|
|
||||||
def get_raw_keyname(self, eve):
|
def get_raw_keyname(self, eve) -> str:
|
||||||
return Gdk.keyval_name(eve.keyval)
|
return Gdk.keyval_name(eve.keyval)
|
||||||
|
|
||||||
def get_keyname(self, eve):
|
def get_modkeys_states(self, eve) -> tuple:
|
||||||
|
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
|
||||||
|
is_control = modifiers & Gdk.ModifierType.CONTROL_MASK
|
||||||
|
is_shift = modifiers & Gdk.ModifierType.SHIFT_MASK
|
||||||
|
|
||||||
|
try:
|
||||||
|
is_alt = modifiers & Gdk.ModifierType.ALT_MASK
|
||||||
|
except:
|
||||||
|
is_alt = modifiers & Gdk.ModifierType.MOD1_MASK
|
||||||
|
|
||||||
|
return is_control, is_shift, is_alt
|
||||||
|
|
||||||
|
def get_keyname(self, eve) -> str:
|
||||||
return Gdk.keyval_name(eve.keyval).lower()
|
return Gdk.keyval_name(eve.keyval).lower()
|
||||||
|
|
||||||
def get_char(self, eve):
|
def get_char(self, eve) -> str:
|
||||||
return chr( Gdk.keyval_to_unicode(eve.keyval) )
|
return chr( Gdk.keyval_to_unicode(eve.keyval) )
|
||||||
|
|||||||
134
src/core/widgets/code/mixins/mark_support_mixin.py
Normal file
134
src/core/widgets/code/mixins/mark_support_mixin.py
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
# Python imports
|
||||||
|
import random
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MarkSupportMixin:
|
||||||
|
def clear_mark_sets(self, source_view):
|
||||||
|
buffer = source_view.get_buffer()
|
||||||
|
self.clear_highlight(buffer)
|
||||||
|
|
||||||
|
for mark_set in self.buffer_markers.values():
|
||||||
|
start_mark, end_mark, is_selection = mark_set.values()
|
||||||
|
start_mark.set_visible(False)
|
||||||
|
buffer.delete_mark(start_mark)
|
||||||
|
buffer.delete_mark(end_mark)
|
||||||
|
|
||||||
|
self.buffer_markers.clear()
|
||||||
|
|
||||||
|
def insert_selection_tag(self, buffer):
|
||||||
|
tag_table = buffer.get_tag_table()
|
||||||
|
if not tag_table.lookup("selection"):
|
||||||
|
tag_table.add(self.selection_tag)
|
||||||
|
|
||||||
|
def clear_highlight(self, buffer):
|
||||||
|
if not self.selection_tag: return
|
||||||
|
start_itr, end_itr = buffer.get_bounds()
|
||||||
|
buffer.remove_tag(self.selection_tag, start_itr, end_itr)
|
||||||
|
|
||||||
|
def apply_to_marks(self, buffer, operation):
|
||||||
|
buffer.block_insert_after_signal()
|
||||||
|
buffer.begin_user_action()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with buffer.freeze_notify():
|
||||||
|
for mark_hash in self.buffer_markers:
|
||||||
|
marker = self.buffer_markers[mark_hash]
|
||||||
|
start_mark = marker["start_mark"]
|
||||||
|
end_mark = marker["end_mark"]
|
||||||
|
has_selection = marker["is_selection"]
|
||||||
|
|
||||||
|
start_itr = buffer.get_iter_at_mark(start_mark)
|
||||||
|
end_itr = buffer.get_iter_at_mark(end_mark)
|
||||||
|
|
||||||
|
if has_selection:
|
||||||
|
operation(start_itr, end_itr)
|
||||||
|
self.collapse_selection(
|
||||||
|
buffer, mark_hash, start_mark, end_mark, False
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
operation(start_itr)
|
||||||
|
finally:
|
||||||
|
buffer.end_user_action()
|
||||||
|
buffer.unblock_insert_after_signal()
|
||||||
|
|
||||||
|
def process_cursor_action(self, buffer, action):
|
||||||
|
def remove_text(start_itr, end_itr = None):
|
||||||
|
if end_itr:
|
||||||
|
buffer.delete(start_itr, end_itr)
|
||||||
|
return
|
||||||
|
|
||||||
|
buffer.backspace(start_itr, interactive = True, default_editable = True)
|
||||||
|
|
||||||
|
def delete_text(start_itr, end_itr = None):
|
||||||
|
if end_itr:
|
||||||
|
buffer.delete(start_itr, end_itr)
|
||||||
|
return
|
||||||
|
|
||||||
|
start_itr.forward_char()
|
||||||
|
buffer.backspace(start_itr, interactive = True, default_editable = True)
|
||||||
|
|
||||||
|
if action == "BACKSPACE":
|
||||||
|
self.apply_to_marks(buffer, remove_text)
|
||||||
|
elif action == "DELETE":
|
||||||
|
self.apply_to_marks(buffer, delete_text)
|
||||||
|
elif action == "ENTER":
|
||||||
|
...
|
||||||
|
|
||||||
|
def move_to_offset(self, offset, start_itr):
|
||||||
|
line_itr = start_itr.copy()
|
||||||
|
|
||||||
|
line_itr.forward_to_line_end()
|
||||||
|
|
||||||
|
next_line_length = line_itr.get_line_offset()
|
||||||
|
new_offset = min(offset, next_line_length)
|
||||||
|
start_itr.set_line_offset(new_offset)
|
||||||
|
|
||||||
|
def insert_mark_set(self, target_iter, buffer):
|
||||||
|
random_bits = random.getrandbits(128)
|
||||||
|
hash = "%032x" % random_bits
|
||||||
|
|
||||||
|
start_mark = Gtk.TextMark.new(
|
||||||
|
name = f"multi-insert-start-{hash}",
|
||||||
|
left_gravity = False
|
||||||
|
)
|
||||||
|
|
||||||
|
end_mark = Gtk.TextMark.new(
|
||||||
|
name = f"multi-insert-end-{hash}",
|
||||||
|
left_gravity = False
|
||||||
|
)
|
||||||
|
# left_gravity = True
|
||||||
|
|
||||||
|
buffer.add_mark(start_mark, target_iter)
|
||||||
|
buffer.add_mark(end_mark, target_iter)
|
||||||
|
start_mark.set_visible(True)
|
||||||
|
self.buffer_markers[f"{hash}"] = {
|
||||||
|
"start_mark": start_mark,
|
||||||
|
"end_mark": end_mark,
|
||||||
|
"is_selection": False
|
||||||
|
}
|
||||||
|
|
||||||
|
def remove_mark_set(self, target_iter, buffer) -> bool:
|
||||||
|
marks = target_iter.get_marks()
|
||||||
|
|
||||||
|
for mark_hash in self.buffer_markers:
|
||||||
|
start_mark, end_mark, is_selection = self.buffer_markers[mark_hash].values()
|
||||||
|
if not start_mark in marks: continue
|
||||||
|
|
||||||
|
start_mark.set_visible(False)
|
||||||
|
buffer.delete_mark(start_mark)
|
||||||
|
buffer.delete_mark(end_mark)
|
||||||
|
del self.buffer_markers[mark_hash]
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
# Python imports
|
|
||||||
import random
|
|
||||||
|
|
||||||
# Lib imports
|
|
||||||
import gi
|
|
||||||
gi.require_version('Gtk', '3.0')
|
|
||||||
from gi.repository import Gtk
|
|
||||||
|
|
||||||
# Application imports
|
|
||||||
from libs.dto.states import SourceViewStates, MoveDirection, CursorAction
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MarkEventsMixin:
|
|
||||||
def clear_markers(self, source_view):
|
|
||||||
buffer = source_view.get_buffer()
|
|
||||||
|
|
||||||
for mark in self.insert_markers:
|
|
||||||
mark.set_visible(False)
|
|
||||||
buffer.delete_mark(mark)
|
|
||||||
|
|
||||||
self.insert_markers.clear()
|
|
||||||
|
|
||||||
def _insert_mark(self, insert_iter, target_iter, buffer):
|
|
||||||
mark_found = self._check_for_insert_marks(target_iter, buffer)
|
|
||||||
|
|
||||||
if mark_found: return
|
|
||||||
|
|
||||||
random_bits = random.getrandbits(128)
|
|
||||||
hash = "%032x" % random_bits
|
|
||||||
|
|
||||||
mark = Gtk.TextMark.new(
|
|
||||||
name = f"multi_insert_{hash}",
|
|
||||||
left_gravity = False
|
|
||||||
)
|
|
||||||
|
|
||||||
buffer.add_mark(mark, target_iter)
|
|
||||||
mark.set_visible(True)
|
|
||||||
self.insert_markers.append(mark)
|
|
||||||
|
|
||||||
|
|
||||||
def _check_for_insert_marks(self, target_iter, buffer):
|
|
||||||
marks = target_iter.get_marks()
|
|
||||||
|
|
||||||
for mark in marks:
|
|
||||||
if mark in self.insert_markers[:]:
|
|
||||||
mark.set_visible(False)
|
|
||||||
self.insert_markers.remove(mark)
|
|
||||||
buffer.delete_mark(mark)
|
|
||||||
return True
|
|
||||||
|
|
||||||
insert_itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
|
||||||
if target_iter.equal(insert_itr): return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _process_cursor_action(self, buffer):
|
|
||||||
if not self.insert_markers: return
|
|
||||||
if self.cursor_action == CursorAction.NONE.value: return
|
|
||||||
|
|
||||||
action = self.cursor_action
|
|
||||||
for mark in self.insert_markers:
|
|
||||||
itr = buffer.get_iter_at_mark(mark)
|
|
||||||
|
|
||||||
if action == CursorAction.BACKSPACE.value:
|
|
||||||
buffer.backspace(itr, interactive = True, default_editable = True)
|
|
||||||
elif action == CursorAction.DELETE.value:
|
|
||||||
itr.forward_char()
|
|
||||||
buffer.backspace(itr, interactive = True, default_editable = True)
|
|
||||||
elif action == CursorAction.ENTER.value:
|
|
||||||
...
|
|
||||||
|
|
||||||
self.cursor_action = CursorAction.NONE.value
|
|
||||||
|
|
||||||
def _process_move_direction(self, buffer):
|
|
||||||
if not self.insert_markers: return
|
|
||||||
if self.move_direction == MoveDirection.NONE.value: return
|
|
||||||
|
|
||||||
direction = self.move_direction
|
|
||||||
for mark in self.insert_markers:
|
|
||||||
itr = buffer.get_iter_at_mark(mark)
|
|
||||||
|
|
||||||
if direction == MoveDirection.UP.value:
|
|
||||||
new_line = itr.get_line() - 1
|
|
||||||
new_itr = buffer.get_iter_at_line_offset(
|
|
||||||
new_line,
|
|
||||||
itr.get_line_index()
|
|
||||||
)
|
|
||||||
|
|
||||||
elif direction == MoveDirection.DOWN.value:
|
|
||||||
new_line = itr.get_line() + 1
|
|
||||||
new_itr = buffer.get_iter_at_line_offset(
|
|
||||||
new_line,
|
|
||||||
itr.get_line_index()
|
|
||||||
)
|
|
||||||
elif direction == MoveDirection.LEFT.value:
|
|
||||||
if not itr.backward_char(): break
|
|
||||||
new_itr = itr
|
|
||||||
elif direction == MoveDirection.RIGHT.value:
|
|
||||||
if not itr.forward_char(): break
|
|
||||||
new_itr = itr
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
buffer.move_mark_by_name(mark.get_name(), new_itr)
|
|
||||||
|
|
||||||
self.move_direction = MoveDirection.NONE
|
|
||||||
@@ -33,8 +33,9 @@ class SourceViewDnDMixin:
|
|||||||
|
|
||||||
def _on_uri_data_received(self, uris: []):
|
def _on_uri_data_received(self, uris: []):
|
||||||
uri = uris.pop(0)
|
uri = uris.pop(0)
|
||||||
|
|
||||||
self.command.exec_with_args("dnd_load_file_to_buffer", self, uri)
|
self.command.exec_with_args("dnd_load_file_to_buffer", self, uri)
|
||||||
|
|
||||||
if not uris: return
|
if not uris: return
|
||||||
|
|
||||||
self.command.exec_with_args("dnd_load_files", (self, uris))
|
self.command.exec_with_args("dnd_load_files", self, uris)
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ class SourceView(GtkSource.View, SourceViewDnDMixin):
|
|||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("drag-data-received", self._on_drag_data_received)
|
self.connect("drag-data-received", self._on_drag_data_received)
|
||||||
self.connect("populate-popup", self._on_populate_popup)
|
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
@@ -76,37 +75,6 @@ class SourceView(GtkSource.View, SourceViewDnDMixin):
|
|||||||
|
|
||||||
self._set_up_dnd()
|
self._set_up_dnd()
|
||||||
|
|
||||||
def _on_populate_popup(self, view, menu):
|
|
||||||
buffer = self.get_buffer()
|
|
||||||
language = buffer.get_language()
|
|
||||||
|
|
||||||
if language.get_id() == "json":
|
|
||||||
self._load_prettify_json(view, menu)
|
|
||||||
|
|
||||||
menu.show_all()
|
|
||||||
|
|
||||||
def _load_prettify_json(self, view, menu):
|
|
||||||
menu.append( Gtk.SeparatorMenuItem() )
|
|
||||||
|
|
||||||
def on_prettify_json(menuitem):
|
|
||||||
import json
|
|
||||||
|
|
||||||
buffer = self.get_buffer()
|
|
||||||
start_itr, \
|
|
||||||
end_itr = buffer.get_start_iter(), buffer.get_end_iter()
|
|
||||||
data = buffer.get_text(start_itr, end_itr, False)
|
|
||||||
text = json.dumps(json.loads(data), separators = (',', ':'), indent = 4)
|
|
||||||
|
|
||||||
buffer.begin_user_action()
|
|
||||||
buffer.delete(start_itr, end_itr)
|
|
||||||
buffer.insert(start_itr, text)
|
|
||||||
buffer.end_user_action()
|
|
||||||
|
|
||||||
item = Gtk.MenuItem(label = "Prettify JSON")
|
|
||||||
item.connect("activate", on_prettify_json)
|
|
||||||
menu.append(item)
|
|
||||||
|
|
||||||
|
|
||||||
def clear_temp_cut_buffer_delayed(self):
|
def clear_temp_cut_buffer_delayed(self):
|
||||||
if self._cut_temp_timeout_id:
|
if self._cut_temp_timeout_id:
|
||||||
GLib.source_remove(self._cut_temp_timeout_id)
|
GLib.source_remove(self._cut_temp_timeout_id)
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
# Lib imports
|
# Lib imports
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from ..singleton import Singleton
|
from ..singleton_raised import SingletonRaised
|
||||||
|
|
||||||
from ..dto.base_event import BaseEvent
|
from ..dto.base_event import BaseEvent
|
||||||
|
|
||||||
from .emit_dispatcher import EmitDispatcher
|
from .emit_dispatcher import EmitDispatcher
|
||||||
from .controller_context import ControllerContext
|
from .controller_message_bus import ControllerMessageBus
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -17,25 +17,28 @@ class ControllerBaseException(Exception):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ControllerBase(Singleton, EmitDispatcher):
|
class ControllerBase(SingletonRaised, EmitDispatcher):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(ControllerBase, self).__init__()
|
super(ControllerBase, self).__init__()
|
||||||
|
|
||||||
self.controller_context: ControllerContext = None
|
self.controller_message_bus: ControllerMessageBus = None
|
||||||
|
|
||||||
|
|
||||||
def _controller_message(self, event: BaseEvent):
|
def _controller_message(self, event: BaseEvent):
|
||||||
raise ControllerBaseException("Controller Base '_controller_message' must be overridden...")
|
raise ControllerBaseException("Controller Base '_controller_message' must be overridden...")
|
||||||
|
|
||||||
def set_controller_context(self, controller_context: ControllerContext):
|
def set_controller_message_bus(self, controller_message_bus: ControllerMessageBus):
|
||||||
self.controller_context = controller_context
|
self.controller_message_bus = controller_message_bus
|
||||||
|
|
||||||
def message(self, event: BaseEvent):
|
def message(self, event: BaseEvent):
|
||||||
return self.controller_context.message(event)
|
return self.controller_message_bus.message(event)
|
||||||
|
|
||||||
def message_to(self, name: str, event: BaseEvent):
|
def message_to(self, name: str, event: BaseEvent):
|
||||||
return self.controller_context.message_to(name, event)
|
return self.controller_message_bus.message_to(name, event)
|
||||||
|
|
||||||
def message_to_selected(self, names: list[str], event: BaseEvent):
|
def message_to_selected(self, names: list[str], event: BaseEvent):
|
||||||
for name in names:
|
for name in names:
|
||||||
self.controller_context.message_to_selected(name, event)
|
self.controller_message_bus.message_to_selected(name, event)
|
||||||
|
|
||||||
|
def register_controller(self, name: str, controller):
|
||||||
|
self.controller_message_bus.register_controller(name, controller)
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
# Python imports
|
|
||||||
|
|
||||||
# Lib imports
|
|
||||||
|
|
||||||
# Application imports
|
|
||||||
from ..dto.base_event import BaseEvent
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ControllerContextException(Exception):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ControllerContext:
|
|
||||||
def __init__(self):
|
|
||||||
super(ControllerContext, self).__init__()
|
|
||||||
|
|
||||||
|
|
||||||
def message(self, event: BaseEvent):
|
|
||||||
raise ControllerContextException("Controller Context 'message' must be overriden by Controller Manager...")
|
|
||||||
|
|
||||||
def message_to(self, name: str, event: BaseEvent):
|
|
||||||
raise ControllerContextException("Controller Context 'message_to' must be overriden by Controller Manager...")
|
|
||||||
|
|
||||||
def message_to_selected(self, name: list, event: BaseEvent):
|
|
||||||
raise ControllerContextException("Controller Context 'message_to_selected' must be overriden by Controller Manager...")
|
|
||||||
@@ -7,7 +7,7 @@ from ..singleton import Singleton
|
|||||||
from ..event_factory import Code_Event_Types
|
from ..event_factory import Code_Event_Types
|
||||||
|
|
||||||
from .controller_base import ControllerBase
|
from .controller_base import ControllerBase
|
||||||
from .controller_context import ControllerContext
|
from .controller_message_bus import ControllerMessageBus
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -17,16 +17,26 @@ class ControllerManagerException(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class ControllerManager(Singleton, dict):
|
class ControllerManager(Singleton, dict):
|
||||||
|
"""
|
||||||
|
ControllerManager registers controllers by key/value pair.
|
||||||
|
It binds the message bus methods methods each controller has
|
||||||
|
due to extending ControllerBase.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(ControllerManager, self).__init__()
|
super(ControllerManager, self).__init__()
|
||||||
|
|
||||||
|
self.message_bus: ControllerMessageBus \
|
||||||
|
= self._crete_controller_message_bus()
|
||||||
|
|
||||||
def _crete_controller_context(self) -> ControllerContext:
|
|
||||||
controller_context = ControllerContext()
|
|
||||||
controller_context.message_to = self.message_to
|
|
||||||
controller_context.message = self.message
|
|
||||||
|
|
||||||
return controller_context
|
def _crete_controller_message_bus(self) -> ControllerMessageBus:
|
||||||
|
controller_message_bus = ControllerMessageBus()
|
||||||
|
controller_message_bus.message_to = self.message_to
|
||||||
|
controller_message_bus.message = self.message
|
||||||
|
controller_message_bus.register_controller = self.register_controller
|
||||||
|
|
||||||
|
return controller_message_bus
|
||||||
|
|
||||||
def register_controller(self, name: str, controller: ControllerBase):
|
def register_controller(self, name: str, controller: ControllerBase):
|
||||||
if not name or controller == None:
|
if not name or controller == None:
|
||||||
@@ -37,7 +47,7 @@ class ControllerManager(Singleton, dict):
|
|||||||
f"Can't bind controller to existing registered name of '{name}'..."
|
f"Can't bind controller to existing registered name of '{name}'..."
|
||||||
)
|
)
|
||||||
|
|
||||||
controller.set_controller_context( self._crete_controller_context() )
|
controller.set_controller_message_bus( self.message_bus )
|
||||||
|
|
||||||
self[name] = controller
|
self[name] = controller
|
||||||
|
|
||||||
|
|||||||
30
src/libs/controllers/controller_message_bus.py
Normal file
30
src/libs/controllers/controller_message_bus.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from ..dto.base_event import BaseEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerMessageBusException(Exception):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ControllerMessageBus:
|
||||||
|
def __init__(self):
|
||||||
|
super(ControllerMessageBus, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def message(self, event: BaseEvent):
|
||||||
|
raise ControllerMessageBusException("Controller Message Bus 'message' must be overriden by Controller Manager...")
|
||||||
|
|
||||||
|
def message_to(self, name: str, event: BaseEvent):
|
||||||
|
raise ControllerMessageBusException("Controller Message Bus 'message_to' must be overriden by Controller Manager...")
|
||||||
|
|
||||||
|
def message_to_selected(self, name: list, event: BaseEvent):
|
||||||
|
raise ControllerMessageBusException("Controller Message Bus 'message_to_selected' must be overriden by Controller Manager...")
|
||||||
|
|
||||||
|
def register_controller(self, name: str, controller):
|
||||||
|
raise ControllerMessageBusException("Controller Message Bus 'register_controller' must be overriden by Controller Manager...")
|
||||||
@@ -8,6 +8,13 @@ from ..dto.base_event import BaseEvent
|
|||||||
|
|
||||||
|
|
||||||
class EmitDispatcher:
|
class EmitDispatcher:
|
||||||
|
"""
|
||||||
|
EmitDispatcher is used for allowing controllers to pass/hook in
|
||||||
|
their message system to children that need to signal events.
|
||||||
|
Note how we are not handling return info from the 'message' methods
|
||||||
|
whereas a controller would or could do so.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(EmitDispatcher, self).__init__()
|
super(EmitDispatcher, self).__init__()
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ from dataclasses import dataclass, field
|
|||||||
|
|
||||||
@dataclass(slots = True)
|
@dataclass(slots = True)
|
||||||
class BaseEvent:
|
class BaseEvent:
|
||||||
topic: str = None
|
topic: str = None
|
||||||
content: any = None
|
content: any = None
|
||||||
raw_content: any = None
|
raw_content: any = None
|
||||||
|
success: callable = None
|
||||||
|
fail: callable = None
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
from .code_event import CodeEvent
|
from .code_event import CodeEvent
|
||||||
from .register_provider_event import RegisterProviderEvent
|
from .register_provider_event import RegisterProviderEvent
|
||||||
from .register_command_event import RegisterCommandEvent
|
from .register_command_event import RegisterCommandEvent
|
||||||
from .file_externally_modified_event import FileExternallyModifiedEvent
|
from .file_externally_modified_event import FileExternallyModifiedEvent
|
||||||
from .file_externally_deleted_event import FileExternallyDeletedEvent
|
from .file_externally_deleted_event import FileExternallyDeletedEvent
|
||||||
|
from .set_info_labels_event import SetInfoLabelsEvent
|
||||||
|
from .populate_source_view_popup_event import PopulateSourceViewPopupEvent
|
||||||
|
|
||||||
from .get_new_command_system_event import GetNewCommandSystemEvent
|
from .get_new_command_system_event import GetNewCommandSystemEvent
|
||||||
from .request_completion_event import RequestCompletionEvent
|
from .request_completion_event import RequestCompletionEvent
|
||||||
@@ -20,7 +22,6 @@ from .set_active_file_event import SetActiveFileEvent
|
|||||||
|
|
||||||
from .file_path_set_event import FilePathSetEvent
|
from .file_path_set_event import FilePathSetEvent
|
||||||
from .added_new_file_event import AddedNewFileEvent
|
from .added_new_file_event import AddedNewFileEvent
|
||||||
from .swapped_file_event import SwappedFileEvent
|
|
||||||
from .popped_file_event import PoppedFileEvent
|
from .popped_file_event import PoppedFileEvent
|
||||||
from .removed_file_event import RemovedFileEvent
|
from .removed_file_event import RemovedFileEvent
|
||||||
from .saved_file_event import SavedFileEvent
|
from .saved_file_event import SavedFileEvent
|
||||||
@@ -28,6 +29,5 @@ from .saved_file_event import SavedFileEvent
|
|||||||
from .get_file_event import GetFileEvent
|
from .get_file_event import GetFileEvent
|
||||||
from .get_swap_file_event import GetSwapFileEvent
|
from .get_swap_file_event import GetSwapFileEvent
|
||||||
from .add_new_file_event import AddNewFileEvent
|
from .add_new_file_event import AddNewFileEvent
|
||||||
from .swap_file_event import SwapFileEvent
|
|
||||||
from .pop_file_event import PopFileEvent
|
from .pop_file_event import PopFileEvent
|
||||||
from .remove_file_event import RemoveFileEvent
|
from .remove_file_event import RemoveFileEvent
|
||||||
|
|||||||
18
src/libs/dto/code/populate_source_view_popup_event.py
Normal file
18
src/libs/dto/code/populate_source_view_popup_event.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .code_event import CodeEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PopulateSourceViewPopupEvent(CodeEvent):
|
||||||
|
menu: Gtk.Widget = None
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
from gi.repository import Gio
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from .code_event import CodeEvent
|
from .code_event import CodeEvent
|
||||||
@@ -9,5 +11,5 @@ from .code_event import CodeEvent
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class SwapFileEvent(CodeEvent):
|
class SetInfoLabelsEvent(CodeEvent):
|
||||||
...
|
info: tuple[str or Gio.File] = None
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
# Python imports
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
|
|
||||||
# Lib imports
|
|
||||||
|
|
||||||
# Application imports
|
|
||||||
from .code_event import CodeEvent
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class SwappedFileEvent(CodeEvent):
|
|
||||||
...
|
|
||||||
@@ -4,4 +4,3 @@
|
|||||||
|
|
||||||
from .source_view_states import SourceViewStates
|
from .source_view_states import SourceViewStates
|
||||||
from .cursor_action import CursorAction
|
from .cursor_action import CursorAction
|
||||||
from .move_direction import MoveDirection
|
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
# Python imports
|
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
# Lib imports
|
|
||||||
|
|
||||||
# Application imports
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class MoveDirection(Enum):
|
|
||||||
NONE = 0
|
|
||||||
UP = 1
|
|
||||||
DOWN = 2
|
|
||||||
LEFT = 3
|
|
||||||
RIGHT = 4
|
|
||||||
@@ -87,6 +87,16 @@ class IPCServer(Singleton):
|
|||||||
conn.close()
|
conn.close()
|
||||||
break
|
break
|
||||||
|
|
||||||
|
if "FILES|" in msg:
|
||||||
|
import json
|
||||||
|
data = msg.split("FILES|")[1].strip()
|
||||||
|
files = json.loads(data)
|
||||||
|
if files:
|
||||||
|
event_system.emit("handle-files-from-ipc", (files,))
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
break
|
||||||
|
|
||||||
if "DIR|" in msg:
|
if "DIR|" in msg:
|
||||||
file = msg.split("DIR|")[1].strip()
|
file = msg.split("DIR|")[1].strip()
|
||||||
if file:
|
if file:
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ class IPCSignalsMixin:
|
|||||||
self.broadcast_message, "handle-file", (fpath,)
|
self.broadcast_message, "handle-file", (fpath,)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def handle_files_from_ipc(self, uris: list) -> None:
|
||||||
|
logger.debug(f"Files From IPC: {uris}")
|
||||||
|
GLib.idle_add(
|
||||||
|
self.broadcast_message, "handle-files", (uris,)
|
||||||
|
)
|
||||||
|
|
||||||
def handle_dir_from_ipc(self, fpath: str) -> None:
|
def handle_dir_from_ipc(self, fpath: str) -> None:
|
||||||
logger.debug(f"Dir From IPC: {fpath}")
|
logger.debug(f"Dir From IPC: {fpath}")
|
||||||
GLib.idle_add(
|
GLib.idle_add(
|
||||||
|
|||||||
@@ -15,18 +15,18 @@ class SingletonError(Exception):
|
|||||||
T = TypeVar('T', bound='Singleton')
|
T = TypeVar('T', bound='Singleton')
|
||||||
|
|
||||||
class Singleton:
|
class Singleton:
|
||||||
_instance = None
|
__instance = None
|
||||||
|
|
||||||
def __new__(cls: Type[T], *args: Any, **kwargs: Any) -> T:
|
def __new__(cls: Type[T], *args: Any, **kwargs: Any) -> T:
|
||||||
if cls._instance is not None:
|
if cls.__instance is not None:
|
||||||
logger.debug(f"'{cls.__name__}' is a Singleton. Returning instance...")
|
logger.debug(f"'{cls.__name__}' is a Singleton. Returning instance...")
|
||||||
return cls._instance
|
return cls.__instance
|
||||||
|
|
||||||
cls._instance = super(Singleton, cls).__new__(cls)
|
cls.__instance = super(Singleton, cls).__new__(cls)
|
||||||
return cls._instance
|
return cls.__instance
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
if self._instance is not None:
|
if self.__instance is not None:
|
||||||
return
|
return
|
||||||
|
|
||||||
super(Singleton, self).__init__()
|
super(Singleton, self).__init__()
|
||||||
|
|||||||
@@ -15,15 +15,15 @@ class SingletonError(Exception):
|
|||||||
T = TypeVar('T', bound='SingletonRaised')
|
T = TypeVar('T', bound='SingletonRaised')
|
||||||
|
|
||||||
class SingletonRaised:
|
class SingletonRaised:
|
||||||
_instance = None
|
__instance = None
|
||||||
|
|
||||||
def __new__(cls: Type[T], *args: Any, **kwargs: Any) -> T:
|
def __new__(cls: Type[T], *args: Any, **kwargs: Any) -> T:
|
||||||
if cls._instance is not None:
|
if cls.__instance is not None:
|
||||||
raise SingletonError(f"'{cls.__name__}' is a Singleton. Cannot create a new instance...")
|
raise SingletonError(f"'{cls.__name__}' is a Singleton. Cannot create a new instance...")
|
||||||
|
|
||||||
cls._instance = super(SingletonRaised, cls).__new__(cls)
|
cls.__instance = super(SingletonRaised, cls).__new__(cls)
|
||||||
return cls._instance
|
return cls.__instance
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
if self._instance is not None:
|
if self.__instance is not None:
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import importlib
|
import importlib
|
||||||
import traceback
|
import traceback
|
||||||
import asyncio
|
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from os.path import join
|
from os.path import join
|
||||||
from os.path import isdir
|
from os.path import isdir
|
||||||
|
|
||||||
@@ -66,26 +67,22 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
|||||||
parent_path = os.getcwd()
|
parent_path = os.getcwd()
|
||||||
|
|
||||||
for manifest_meta in manifest_metas:
|
for manifest_meta in manifest_metas:
|
||||||
path, folder, manifest = manifest_meta.path, manifest_meta.folder, manifest_meta.manifest
|
|
||||||
|
|
||||||
try:
|
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):
|
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)
|
module = self._load_plugin_module(path, folder, target)
|
||||||
|
|
||||||
if is_pre_launch:
|
self._handle_plugin_execute(is_pre_launch, module, manifest_meta)
|
||||||
asyncio.run(
|
except PluginsControllerException as e:
|
||||||
self.execute_plugin(module, manifest_meta)
|
logger.info(f"Malformed Plugin: Not loading -->: '{manifest_meta.folder}' !")
|
||||||
)
|
|
||||||
else:
|
|
||||||
GLib.idle_add(
|
|
||||||
asyncio.run,
|
|
||||||
self.execute_plugin(module, manifest_meta)
|
|
||||||
)
|
|
||||||
except Exception as e:
|
|
||||||
logger.info(f"Malformed Plugin: Not loading -->: '{folder}' !")
|
|
||||||
logger.debug(f"Trace: {traceback.print_exc()}")
|
logger.debug(f"Trace: {traceback.print_exc()}")
|
||||||
|
|
||||||
os.chdir(parent_path)
|
os.chdir(parent_path)
|
||||||
@@ -103,17 +100,27 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
|||||||
|
|
||||||
return module
|
return module
|
||||||
|
|
||||||
def create_plugin_context(self):
|
def _handle_plugin_execute(
|
||||||
plugin_context: PluginContext = PluginContext()
|
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
|
self._run_with_pool(module, manifest_meta)
|
||||||
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
|
|
||||||
|
|
||||||
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:
|
def pre_launch_plugins(self) -> None:
|
||||||
logger.info(f"Loading pre-launch plugins...")
|
logger.info(f"Loading pre-launch plugins...")
|
||||||
@@ -125,7 +132,7 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
|||||||
manifest_metas: list = self._manifest_manager.get_post_launch_plugins()
|
manifest_metas: list = self._manifest_manager.get_post_launch_plugins()
|
||||||
self._load_plugins(manifest_metas)
|
self._load_plugins(manifest_metas)
|
||||||
|
|
||||||
async def execute_plugin(self, module: type, manifest_meta: ManifestMeta):
|
def execute_plugin(self, module: type, manifest_meta: ManifestMeta):
|
||||||
plugin = module.Plugin()
|
plugin = module.Plugin()
|
||||||
plugin.plugin_context: PluginContext = self.create_plugin_context()
|
plugin.plugin_context: PluginContext = self.create_plugin_context()
|
||||||
|
|
||||||
@@ -140,6 +147,18 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
|||||||
|
|
||||||
self._plugin_collection.append(manifest_meta)
|
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()
|
plugins_controller = PluginsController()
|
||||||
|
|||||||
@@ -38,3 +38,7 @@ class PluginContext:
|
|||||||
|
|
||||||
def emit_and_await(self, event_type: str, data: tuple = ()):
|
def emit_and_await(self, event_type: str, data: tuple = ()):
|
||||||
raise PluginContextException("Plugin Context 'emit_and_await' must be overridden...")
|
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...")
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ class PluginCode(PluginBase):
|
|||||||
def run(self):
|
def run(self):
|
||||||
raise PluginCodeException("Plugin Code 'run' must be overriden by Plugin")
|
raise PluginCodeException("Plugin Code 'run' must be overriden by Plugin")
|
||||||
|
|
||||||
|
def requests_ui_element(self, element_id: str):
|
||||||
|
return self.plugin_context.requests_ui_element(element_id)
|
||||||
|
|
||||||
def message(self, event: BaseEvent):
|
def message(self, event: BaseEvent):
|
||||||
return self.plugin_context.message(event)
|
return self.plugin_context.message(event)
|
||||||
|
|
||||||
@@ -39,3 +42,6 @@ class PluginCode(PluginBase):
|
|||||||
|
|
||||||
def message_to_selected(self, names: list[str], event: BaseEvent):
|
def message_to_selected(self, names: list[str], event: BaseEvent):
|
||||||
return self.plugin_context.message_to_selected(names, event)
|
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