feat: Complete plugin lifecycle management with lazy loading and runtime reload
Major changes: - Add unload() method to all plugins for proper cleanup (unregister commands/providers/LSP clients, destroy widgets, clear state) - Implement lazy widget loading via "show" signal across all containers - Add autoload: false manifest option for manual/conditional plugin loading - Add Plugins UI with runtime load/unload toggle via Ctrl+Shift+p - Implement controller unregistration system with proper signal disconnection - Add new events: UnregisterCommandEvent, GetFilesEvent, GetSourceViewsEvent, TogglePluginsUiEvent - Fix signal leaks by tracking and disconnecting handlers in widgets (search/replace, LSP manager, tabs, telescope, markdown preview) - Add Save/Save As to tabs context menu - Improve search/replace behavior (selection handling, focus management) - Add telescope file initialization from existing loaded files - Refactor plugin reload watcher to dynamically add/remove plugins on filesystem changes - Add new plugins: file_history, extend_source_view_menu, godot_lsp_client - Fix bug in prettify_json (undefined variable reference)
This commit is contained in:
22
TODO.md
Normal file
22
TODO.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
___
|
||||||
|
### Add
|
||||||
|
1. Add Godot LSP Client
|
||||||
|
1. Add Collapsable code blocks
|
||||||
|
1. Add Plugin to <Shift\><Ctrl\>| and <Ctrl\>| to split views up, down, left, right
|
||||||
|
1. Add <Ctrl\>i to **lsp_manager** to list who implements xyz
|
||||||
|
|
||||||
|
___
|
||||||
|
### Change
|
||||||
|
1. Make **telescope** plugin a generic base to allow query mode additions through plugins
|
||||||
|
1. Make **lsp_manager** hard coded values configurable, plus add fields to UI
|
||||||
|
___
|
||||||
|
### Fix
|
||||||
|
- Fix **telescope** search selection when items hidden such that
|
||||||
|
hidden items don't get selected on up/down key
|
||||||
|
- Fix to make acive tab on **tabs_bar** scroll to center
|
||||||
|
- Fix **file_state_watcher** to prompt refrsh if external changes applied
|
||||||
|
- Fix on lsp client unload to close files lsp side and unload server endpoint
|
||||||
|
- Fix multi-select <Shift\><Ctrl\> left/right block select movement de-sync
|
||||||
|
from leader when '_' in word
|
||||||
|
|
||||||
|
___
|
||||||
@@ -39,6 +39,24 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_command",
|
||||||
|
command_name = "autopairs",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "held",
|
||||||
|
binding = [
|
||||||
|
"'", "`", "[", "]",
|
||||||
|
'<Shift>"',
|
||||||
|
'<Shift>(',
|
||||||
|
'<Shift>)',
|
||||||
|
'<Shift>{',
|
||||||
|
'<Shift>}'
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
autopairs = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,19 @@ class Plugin(PluginCode):
|
|||||||
colorize.handle_colorize(event.buffer)
|
colorize.handle_colorize(event.buffer)
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
event = Event_Factory.create_event("register_command",
|
self._manage_signals("register_command")
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
self._manage_signals("unregister_command")
|
||||||
|
event = Event_Factory.create_event("get_source_views")
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
for view in event.response:
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
colorize.clear_color_tags(buffer)
|
||||||
|
|
||||||
|
def _manage_signals(self, action: str):
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
command_name = "tggle_colorize",
|
command_name = "tggle_colorize",
|
||||||
command = Handler,
|
command = Handler,
|
||||||
binding_mode = "released",
|
binding_mode = "released",
|
||||||
@@ -36,6 +48,7 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,16 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_command",
|
||||||
|
command_name = "keyboard_tggl_comment",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Control>slash"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|||||||
3
plugins/code/commands/file_history/__init__.py
Normal file
3
plugins/code/commands/file_history/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Module
|
||||||
|
"""
|
||||||
3
plugins/code/commands/file_history/__main__.py
Normal file
3
plugins/code/commands/file_history/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Package
|
||||||
|
"""
|
||||||
97
plugins/code/commands/file_history/autopairs.py
Normal file
97
plugins/code/commands/file_history/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/commands/file_history/manifest.json
Normal file
7
plugins/code/commands/file_history/manifest.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "File History",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
65
plugins/code/commands/file_history/plugin.py
Normal file
65
plugins/code/commands/file_history/plugin.py
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
history: list = []
|
||||||
|
history_size: int = 30
|
||||||
|
|
||||||
|
|
||||||
|
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.RemovedFileEvent):
|
||||||
|
if event.file.ftype == "buffer": return
|
||||||
|
|
||||||
|
if len(history) == history_size:
|
||||||
|
history.pop(0)
|
||||||
|
|
||||||
|
history.append(event.file)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self._manage_signals("register_command")
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
self._manage_signals("unregister_command")
|
||||||
|
|
||||||
|
def _manage_signals(self, action: str):
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
|
command_name = "file_history_pop",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Shift><Control>t"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
class Handler:
|
||||||
|
@staticmethod
|
||||||
|
def execute(
|
||||||
|
view: any,
|
||||||
|
char_str: str,
|
||||||
|
*args,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
logger.debug("Command: File History")
|
||||||
|
if len(history) == 0: return
|
||||||
|
|
||||||
|
view._on_uri_data_received(
|
||||||
|
[
|
||||||
|
history.pop().replace("file://", "")
|
||||||
|
]
|
||||||
|
)
|
||||||
@@ -21,7 +21,13 @@ class Plugin(PluginCode):
|
|||||||
...
|
...
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
event = Event_Factory.create_event("register_command",
|
self._manage_signals("register_command")
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
self._manage_signals("unregister_command")
|
||||||
|
|
||||||
|
def _manage_signals(self, action: str):
|
||||||
|
event = Event_Factory.create_event(action,
|
||||||
command_name = "cut_to_temp_buffer",
|
command_name = "cut_to_temp_buffer",
|
||||||
command = Handler,
|
command = Handler,
|
||||||
binding_mode = "held",
|
binding_mode = "held",
|
||||||
@@ -30,7 +36,7 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
event = Event_Factory.create_event("register_command",
|
event = Event_Factory.create_event(action,
|
||||||
command_name = "paste_temp_buffer",
|
command_name = "paste_temp_buffer",
|
||||||
command = Handler2,
|
command = Handler2,
|
||||||
binding_mode = "held",
|
binding_mode = "held",
|
||||||
|
|||||||
@@ -26,6 +26,16 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_command",
|
||||||
|
command_name = "toggle_source_view",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Shift><Control>h"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|||||||
@@ -35,5 +35,15 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"unregister_provider",
|
||||||
|
provider_name = "Example Completer"
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
self.provider = None
|
||||||
|
del self.provider
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -35,5 +35,15 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"register_provider",
|
||||||
|
provider_name = "Python Completer"
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
self.provider = None
|
||||||
|
del self.provider
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -35,5 +35,15 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"unregister_provider",
|
||||||
|
provider_name = "Snippets Completer"
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
self.provider = None
|
||||||
|
del self.provider
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -35,5 +35,15 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"unregister_provider",
|
||||||
|
provider_name = "Words Completer"
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
self.provider = None
|
||||||
|
del self.provider
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Module
|
||||||
|
"""
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Plugin Package
|
||||||
|
"""
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "Extend Source View Menu",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .source_view_menu import extend_source_view_menu
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
extend_source_view_menu(event.buffer, event.menu)
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
# Python imports
|
||||||
|
import json
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def on_case_handle(menuitem, buffer, action):
|
||||||
|
start_itr, \
|
||||||
|
end_itr = buffer.get_selection_bounds()
|
||||||
|
data = buffer.get_text(start_itr, end_itr, False)
|
||||||
|
text = data
|
||||||
|
|
||||||
|
if action == "on_all_upper":
|
||||||
|
text = data.upper()
|
||||||
|
elif action == "on_all_lower":
|
||||||
|
text = data.lower()
|
||||||
|
elif action == "on_invert":
|
||||||
|
text = data.swapcase()
|
||||||
|
elif action == "on_title":
|
||||||
|
text = data.title()
|
||||||
|
elif action == "on_title_strip":
|
||||||
|
text = data.title().replace("-", "").replace("_", "").replace(" ", "")
|
||||||
|
|
||||||
|
buffer.begin_user_action()
|
||||||
|
buffer.delete(start_itr, end_itr)
|
||||||
|
buffer.insert(start_itr, text)
|
||||||
|
buffer.end_user_action()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def extend_source_view_menu(buffer, menu):
|
||||||
|
if not buffer.get_selection_bounds(): return
|
||||||
|
|
||||||
|
for child in menu.get_children():
|
||||||
|
if not child.get_label() == "C_hange Case": continue
|
||||||
|
menu.remove(child)
|
||||||
|
|
||||||
|
change_case_item = Gtk.MenuItem(label = "Change Case")
|
||||||
|
|
||||||
|
case_menu = Gtk.Menu()
|
||||||
|
au_case_item = Gtk.MenuItem(label = "All Upper Case")
|
||||||
|
al_case_item = Gtk.MenuItem(label = "All Lower Case")
|
||||||
|
inver_case_item = Gtk.MenuItem(label = "Invert Case")
|
||||||
|
title_case_item = Gtk.MenuItem(label = "Title Case")
|
||||||
|
title_strip_case_item = Gtk.MenuItem(label = "Title Strip Case")
|
||||||
|
|
||||||
|
au_case_item.connect("activate", on_case_handle, buffer, "on_all_upper")
|
||||||
|
al_case_item.connect("activate", on_case_handle, buffer, "on_all_lower")
|
||||||
|
inver_case_item.connect("activate", on_case_handle, buffer, "on_invert")
|
||||||
|
title_case_item.connect("activate", on_case_handle, buffer, "on_title")
|
||||||
|
title_strip_case_item.connect("activate", on_case_handle, buffer, "on_title_strip")
|
||||||
|
|
||||||
|
case_menu.append(au_case_item)
|
||||||
|
case_menu.append(al_case_item)
|
||||||
|
case_menu.append(inver_case_item)
|
||||||
|
case_menu.append(title_case_item)
|
||||||
|
case_menu.append(title_strip_case_item)
|
||||||
|
change_case_item.set_submenu(case_menu)
|
||||||
|
|
||||||
|
menu.append(change_case_item)
|
||||||
@@ -21,12 +21,15 @@ class Plugin(PluginCode):
|
|||||||
event.file.check_file_on_disk()
|
event.file.check_file_on_disk()
|
||||||
|
|
||||||
if event.file.is_deleted():
|
if event.file.is_deleted():
|
||||||
file_is_deleted(event)
|
file_is_deleted(event, self.emit)
|
||||||
elif event.file.is_externally_modified():
|
elif event.file.is_externally_modified():
|
||||||
file_is_externally_modified(event)
|
file_is_externally_modified(event, self.emit)
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
...
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -10,23 +10,23 @@ from libs.event_factory import Event_Factory, Code_Event_Types
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def file_is_deleted(event):
|
def file_is_deleted(event, emit):
|
||||||
event.file.was_deleted = True
|
event.file.was_deleted = True
|
||||||
event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
"file_externally_deleted",
|
"file_externally_deleted",
|
||||||
file = event.file,
|
file = event.file,
|
||||||
buffer = event.buffer
|
buffer = event.buffer
|
||||||
)
|
)
|
||||||
self.emit(event)
|
emit(event)
|
||||||
|
|
||||||
|
|
||||||
def file_is_externally_modified(event):
|
def file_is_externally_modified(event, emit):
|
||||||
# event = Event_Factory.create_event(
|
# event = Event_Factory.create_event(
|
||||||
# "file_externally_modified",
|
# "file_externally_modified",
|
||||||
# file = event.file,
|
# file = event.file,
|
||||||
# buffer = event.buffer
|
# buffer = event.buffer
|
||||||
# )
|
# )
|
||||||
# self.emit(event)
|
# emit(event)
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|||||||
@@ -32,5 +32,8 @@ class Plugin(PluginCode):
|
|||||||
def load(self):
|
def load(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
...
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from gi.repository import Gtk
|
|||||||
|
|
||||||
|
|
||||||
def add_prettify_json(buffer, menu):
|
def add_prettify_json(buffer, menu):
|
||||||
menu.append( Gtk.SeparatorMenuItem() )
|
menu.append(separator)
|
||||||
|
|
||||||
def on_prettify_json(menuitem, buffer):
|
def on_prettify_json(menuitem, buffer):
|
||||||
start_itr, \
|
start_itr, \
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Module
|
||||||
|
"""
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""
|
||||||
|
Pligin Package
|
||||||
|
"""
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"info": "https://github.com/godotengine/godot/blob/4a280218fcfdd69408cceb74577c9e69086be23a/editor/settings/editor_settings.cpp#L1132",
|
||||||
|
"command": "lsp-ws-proxy -- godot",
|
||||||
|
"alt-command": "godot",
|
||||||
|
"alt-command2": "lsp-ws-proxy --listen 4114 -- godot --headless",
|
||||||
|
"alt-command3": "godot --headless --lsp-port 7766",
|
||||||
|
"socket": "ws://127.0.0.1:9999/gdscript",
|
||||||
|
"socket-two": "ws://127.0.0.1:9999/?name=gdscript",
|
||||||
|
"initialization-options": {
|
||||||
|
"processId": ,
|
||||||
|
"clientInfo": {
|
||||||
|
"name": "Godot",
|
||||||
|
"version": "4.4"
|
||||||
|
},
|
||||||
|
"rootUri": "file://{workspace.folder}",
|
||||||
|
"capabilities": {
|
||||||
|
"workspace": {
|
||||||
|
"applyEdit": true,
|
||||||
|
"workspaceEdit": {
|
||||||
|
"documentChanges": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"textDocument": {
|
||||||
|
"synchronization": {
|
||||||
|
"dynamicRegistration": true,
|
||||||
|
"willSave": false,
|
||||||
|
"didSave": true,
|
||||||
|
"willSaveWaitUntil": false
|
||||||
|
},
|
||||||
|
"completion": {
|
||||||
|
"dynamicRegistration": true,
|
||||||
|
"completionItem": {
|
||||||
|
"snippetSupport": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hover": {
|
||||||
|
"dynamicRegistration": true
|
||||||
|
},
|
||||||
|
"definition": {
|
||||||
|
"dynamicRegistration": true
|
||||||
|
},
|
||||||
|
"references": {
|
||||||
|
"dynamicRegistration": true
|
||||||
|
},
|
||||||
|
"documentSymbol": {
|
||||||
|
"dynamicRegistration": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"trace": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"name": "Godot LSP Client",
|
||||||
|
"author": "ITDominator",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"support": "",
|
||||||
|
"autoload": false,
|
||||||
|
"requests": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Python imports
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from plugins.plugin_types import PluginCode
|
||||||
|
|
||||||
|
from .response_handler import GodotHandler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin(PluginCode):
|
||||||
|
def __init__(self):
|
||||||
|
super(Plugin, self).__init__()
|
||||||
|
|
||||||
|
|
||||||
|
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||||
|
...
|
||||||
|
|
||||||
|
def load(self):
|
||||||
|
dirPth = path.dirname( path.realpath(__file__) )
|
||||||
|
with open(f"{dirPth}/config/lsp-server-config.json", "r") as f:
|
||||||
|
config = f.read()
|
||||||
|
event = Event_Factory.create_event("register_lsp_client",
|
||||||
|
lang_id = "gdscript",
|
||||||
|
lang_config = config,
|
||||||
|
handler = GodotHandler
|
||||||
|
)
|
||||||
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_lsp_client",
|
||||||
|
lang_id = "gdscript"
|
||||||
|
)
|
||||||
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
...
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
from .python import PythonHandler
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from lsp_manager.response_handlers.default import DefaultHandler
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class GodotHandler(DefaultHandler):
|
||||||
|
"""Uses default handling, can override if Godot needs special logic."""
|
||||||
|
...
|
||||||
@@ -3,5 +3,6 @@
|
|||||||
"author": "ITDominator",
|
"author": "ITDominator",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"support": "",
|
"support": "",
|
||||||
|
"autoload": false,
|
||||||
"requests": {}
|
"requests": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,5 +33,11 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("lsp_manager", event)
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_lsp_client",
|
||||||
|
lang_id = "java"
|
||||||
|
)
|
||||||
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class LSPManager(ControllerBase):
|
|||||||
self.lsp_manager_ui.connect('close-client', self._on_close_client)
|
self.lsp_manager_ui.connect('close-client', self._on_close_client)
|
||||||
|
|
||||||
def _do_bind_mapping(self):
|
def _do_bind_mapping(self):
|
||||||
self.response_cache.set_lsp_client(self.lsp_manager_client)
|
self.response_cache.set_lsp_manager_client(self.lsp_manager_client)
|
||||||
self.provider.response_cache = self.response_cache
|
self.provider.response_cache = self.response_cache
|
||||||
self.response_registry.set_event_hub(
|
self.response_registry.set_event_hub(
|
||||||
self.emit, self.emit_to, self.provider
|
self.emit, self.emit_to, self.provider
|
||||||
@@ -52,6 +52,7 @@ class LSPManager(ControllerBase):
|
|||||||
self.lsp_manager_ui.add_client_listing(event.lang_id, event.lang_config)
|
self.lsp_manager_ui.add_client_listing(event.lang_id, event.lang_config)
|
||||||
elif isinstance(event, Code_Event_Types.UnregisterLspClientEvent):
|
elif isinstance(event, Code_Event_Types.UnregisterLspClientEvent):
|
||||||
self.response_registry.unregister_handler(event.lang_id)
|
self.response_registry.unregister_handler(event.lang_id)
|
||||||
|
self.lsp_manager_ui.remove_client_listing(event.lang_id)
|
||||||
|
|
||||||
def _on_create_client(self, ui, lang_id: str, workspace_uri: str) -> bool:
|
def _on_create_client(self, ui, lang_id: str, workspace_uri: str) -> bool:
|
||||||
init_opts = ui.get_init_opts(lang_id)
|
init_opts = ui.get_init_opts(lang_id)
|
||||||
@@ -66,6 +67,10 @@ class LSPManager(ControllerBase):
|
|||||||
ui.toggle_client_buttons(show_close=False)
|
ui.toggle_client_buttons(show_close=False)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def handle_destroy(self):
|
||||||
|
self.lsp_manager_ui.disconnect_by_func(self._on_create_client)
|
||||||
|
self.lsp_manager_ui.disconnect_by_func(self._on_close_client)
|
||||||
|
|
||||||
def create_client(
|
def create_client(
|
||||||
self,
|
self,
|
||||||
lang_id: str = "python",
|
lang_id: str = "python",
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ class LSPManagerUI(Gtk.Dialog):
|
|||||||
self.set_hexpand(True)
|
self.set_hexpand(True)
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("show", self._show)
|
self.connect("show", self._handle_show)
|
||||||
|
self.connect("destroy", self._handle_destroy)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
@@ -68,7 +69,7 @@ class LSPManagerUI(Gtk.Dialog):
|
|||||||
|
|
||||||
self.path_bttn.connect("file-set", self._file_set)
|
self.path_bttn.connect("file-set", self._file_set)
|
||||||
self.combo_box.connect("changed", self._on_combo_changed)
|
self.combo_box.connect("changed", self._on_combo_changed)
|
||||||
self.hide_bttn.connect("clicked", lambda widget: self.hide())
|
self.hide_bttn_id = self.hide_bttn.connect("clicked", lambda widget: self.hide())
|
||||||
self.create_client_bttn.connect("clicked", self._create_client, self.close_client_bttn)
|
self.create_client_bttn.connect("clicked", self._create_client, self.close_client_bttn)
|
||||||
self.close_client_bttn.connect("clicked", self._close_client, self.create_client_bttn)
|
self.close_client_bttn.connect("clicked", self._close_client, self.create_client_bttn)
|
||||||
|
|
||||||
@@ -92,9 +93,18 @@ class LSPManagerUI(Gtk.Dialog):
|
|||||||
self.close_client_bttn.hide()
|
self.close_client_bttn.hide()
|
||||||
bttn_box.hide()
|
bttn_box.hide()
|
||||||
|
|
||||||
def _show(self, widget):
|
def _handle_show(self, widget):
|
||||||
GLib.idle_add(self.path_entry.grab_focus)
|
GLib.idle_add(self.path_entry.grab_focus)
|
||||||
|
|
||||||
|
def _handle_destroy(self, widget):
|
||||||
|
self.disconnect_by_func(self._show)
|
||||||
|
self.disconnect_by_func(self._handle_destroy)
|
||||||
|
self.path_bttn.disconnect_by_func(self._file_set)
|
||||||
|
self.combo_box.disconnect_by_func(self._on_combo_changed)
|
||||||
|
self.hide_bttn.disconnect(self.hide_bttn_id)
|
||||||
|
self.create_client_bttn.disconnect_by_func(self._create_client)
|
||||||
|
self.close_client_bttn.disconnect_by_func(self._close_client)
|
||||||
|
|
||||||
def _map_resize(self, widget, parent):
|
def _map_resize(self, widget, parent):
|
||||||
parent_x, parent_y = parent.get_position()
|
parent_x, parent_y = parent.get_position()
|
||||||
parent_width, parent_height = parent.get_size()
|
parent_width, parent_height = parent.get_size()
|
||||||
@@ -163,7 +173,10 @@ class LSPManagerUI(Gtk.Dialog):
|
|||||||
buffer.set_text(json_str, -1)
|
buffer.set_text(json_str, -1)
|
||||||
|
|
||||||
def map_parent_resize_event(self, parent):
|
def map_parent_resize_event(self, parent):
|
||||||
parent.connect("size-allocate", lambda w, r: self._map_resize(self, parent))
|
self.size_allocate_id = parent.connect("size-allocate", lambda w, r: self._map_resize(self, parent))
|
||||||
|
|
||||||
|
def unmap_parent_resize_event(self, parent):
|
||||||
|
parent.disconnect(self.size_allocate_id)
|
||||||
|
|
||||||
def set_source_view(self, source_view):
|
def set_source_view(self, source_view):
|
||||||
scrolled_win = Gtk.ScrolledWindow()
|
scrolled_win = Gtk.ScrolledWindow()
|
||||||
@@ -187,6 +200,17 @@ class LSPManagerUI(Gtk.Dialog):
|
|||||||
self.combo_box.append_text(lang_id)
|
self.combo_box.append_text(lang_id)
|
||||||
self.client_configs[lang_id] = lang_config
|
self.client_configs[lang_id] = lang_config
|
||||||
|
|
||||||
|
def remove_client_listing(self, lang_id: str):
|
||||||
|
model = self.combo_box.get_model()
|
||||||
|
|
||||||
|
for i, row in enumerate(model):
|
||||||
|
if row[0] == lang_id: # assuming text is in column 0
|
||||||
|
self.combo_box.remove(i)
|
||||||
|
break
|
||||||
|
|
||||||
|
if lang_id in self.client_configs:
|
||||||
|
del self.client_configs[lang_id]
|
||||||
|
|
||||||
def get_init_opts(self, lang_id: str) -> dict:
|
def get_init_opts(self, lang_id: str) -> dict:
|
||||||
if not lang_id or lang_id not in self.client_configs: return {}
|
if not lang_id or lang_id not in self.client_configs: return {}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
"author": "ITDominator",
|
"author": "ITDominator",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"support": "",
|
"support": "",
|
||||||
"pre_launch": true,
|
"autoload": false,
|
||||||
"requests": {}
|
"requests": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,31 @@ class Plugin(PluginCode):
|
|||||||
source_view = event.response
|
source_view = event.response
|
||||||
lsp_manager.lsp_manager_ui.set_source_view(source_view)
|
lsp_manager.lsp_manager_ui.set_source_view(source_view)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
Event_Factory.unregister_events( lsp_events.__dict__.items() )
|
||||||
|
|
||||||
|
self.unregister_controller("lsp_manager")
|
||||||
|
|
||||||
|
window = self.request_ui_element("main-window")
|
||||||
|
|
||||||
|
lsp_manager.lsp_manager_ui.unmap_parent_resize_event(window)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event("unregister_command",
|
||||||
|
command_name = "LSP Manager",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = ["<Shift><Control>l", "<Control>g", "<Control>i"]
|
||||||
|
)
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"unregister_provider",
|
||||||
|
provider_name = "LSP Completer"
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
lsp_manager.handle_destroy()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|||||||
@@ -15,27 +15,27 @@ class ProviderResponseCache(ProviderResponseCacheBase):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(ProviderResponseCache, self).__init__()
|
super(ProviderResponseCache, self).__init__()
|
||||||
|
|
||||||
self.matchers: dict = {}
|
self.matchers: dict = {}
|
||||||
self._lsp_client = None
|
self.lsp_manager_client = None
|
||||||
|
|
||||||
def set_lsp_client(self, lsp_client):
|
def set_lsp_manager_client(self, lsp_client):
|
||||||
self._lsp_client = lsp_client
|
self.lsp_manager_client = lsp_client
|
||||||
|
|
||||||
def process_file_load(self, event):
|
def process_file_load(self, event):
|
||||||
if self._lsp_client:
|
if self.lsp_manager_client:
|
||||||
self._lsp_client.process_file_load(event)
|
self.lsp_manager_client.process_file_load(event)
|
||||||
|
|
||||||
def process_file_close(self, event):
|
def process_file_close(self, event):
|
||||||
if self._lsp_client:
|
if self.lsp_manager_client:
|
||||||
self._lsp_client.process_file_close(event)
|
self.lsp_manager_client.process_file_close(event)
|
||||||
|
|
||||||
def process_file_save(self, event):
|
def process_file_save(self, event):
|
||||||
if self._lsp_client:
|
if self.lsp_manager_client:
|
||||||
self._lsp_client.process_file_save(event)
|
self.lsp_manager_client.process_file_save(event)
|
||||||
|
|
||||||
def process_file_change(self, event):
|
def process_file_change(self, event):
|
||||||
if self._lsp_client:
|
if self.lsp_manager_client:
|
||||||
self._lsp_client.process_file_change(event)
|
self.lsp_manager_client.process_file_change(event)
|
||||||
|
|
||||||
def filter(self, word: str) -> list[dict]:
|
def filter(self, word: str) -> list[dict]:
|
||||||
return []
|
return []
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class ResponseRegistry:
|
|||||||
def register_handler(self, lang_id: str, handler_cls: type[BaseHandler]):
|
def register_handler(self, lang_id: str, handler_cls: type[BaseHandler]):
|
||||||
self._lang_handlers[lang_id] = handler_cls
|
self._lang_handlers[lang_id] = handler_cls
|
||||||
|
|
||||||
def unregister_handler(self, lang_id: str, handler_cls: type[BaseHandler]):
|
def unregister_handler(self, lang_id: str):
|
||||||
del self._lang_handlers[lang_id]
|
del self._lang_handlers[lang_id]
|
||||||
|
|
||||||
def get_handler(self, lang_id: str = "", method: str = ""):
|
def get_handler(self, lang_id: str = "", method: str = ""):
|
||||||
|
|||||||
@@ -3,5 +3,6 @@
|
|||||||
"author": "ITDominator",
|
"author": "ITDominator",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"support": "",
|
"support": "",
|
||||||
|
"autoload": false,
|
||||||
"requests": {}
|
"requests": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,5 +33,11 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("lsp_manager", event)
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_lsp_client",
|
||||||
|
lang_id = "python"
|
||||||
|
)
|
||||||
|
self.emit_to("lsp_manager", event)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -28,5 +28,12 @@ class Plugin(PluginCode):
|
|||||||
editors_container = self.request_ui_element("editors-container")
|
editors_container = self.request_ui_element("editors-container")
|
||||||
editors_container.add( code_minimap )
|
editors_container.add( code_minimap )
|
||||||
|
|
||||||
|
event = Event_Factory.create_event("get_active_view")
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
code_minimap.set_smini_view(event.response)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
code_minimap.destroy()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class InfoBarWidget(Gtk.Box):
|
|||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
self.path_label = Gtk.Label(label = "...")
|
self.path_label = Gtk.Label(label = "...")
|
||||||
self.line_char_label = Gtk.Label(label = "1:0")
|
self.line_char_label = Gtk.Label(label = "1:0")
|
||||||
@@ -92,5 +91,3 @@ class InfoBarWidget(Gtk.Box):
|
|||||||
encoding_type = "utf-8" if not encoding_type else encoding_type
|
encoding_type = "utf-8" if not encoding_type else encoding_type
|
||||||
|
|
||||||
self.encoding_label.set_text(encoding_type)
|
self.encoding_label.set_text(encoding_type)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,5 +28,8 @@ class Plugin(PluginCode):
|
|||||||
header = self.request_ui_element("header-container")
|
header = self.request_ui_element("header-container")
|
||||||
header.add( info_bar_widget )
|
header.add( info_bar_widget )
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
info_bar_widget.destroy()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -3,5 +3,6 @@
|
|||||||
"author": "ITDominator",
|
"author": "ITDominator",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"support": "",
|
"support": "",
|
||||||
|
"autoload": false,
|
||||||
"requests": {}
|
"requests": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ gi.require_version('Gdk', '3.0')
|
|||||||
|
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
from gi.repository import Gdk
|
from gi.repository import Gdk
|
||||||
|
from gi.repository import GLib
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from core.widgets.webkit.webkit_ui import WebkitUI
|
from core.widgets.webkit.webkit_ui import WebkitUI
|
||||||
@@ -47,6 +48,7 @@ class MarkdownPreview(Gtk.Popover, MarkdownPreviewMixin):
|
|||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("hide", self._handle_hide)
|
self.connect("hide", self._handle_hide)
|
||||||
self.connect("show", self._handle_show)
|
self.connect("show", self._handle_show)
|
||||||
|
self.connect("destroy", self._handle_destroy)
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
box = Gtk.Box()
|
box = Gtk.Box()
|
||||||
@@ -71,7 +73,6 @@ class MarkdownPreview(Gtk.Popover, MarkdownPreviewMixin):
|
|||||||
box.set_orientation(Gtk.Orientation.VERTICAL)
|
box.set_orientation(Gtk.Orientation.VERTICAL)
|
||||||
|
|
||||||
self.start_stop_bttn.connect("clicked", self._tggle_preview_updates)
|
self.start_stop_bttn.connect("clicked", self._tggle_preview_updates)
|
||||||
settings_bttn.connect("clicked", self._handle_settings)
|
|
||||||
|
|
||||||
bttn_box.pack_end(self.start_stop_bttn, expand = False, fill = False, padding = 1)
|
bttn_box.pack_end(self.start_stop_bttn, expand = False, fill = False, padding = 1)
|
||||||
bttn_box.pack_end(settings_bttn, expand = False, fill = False, padding = 1)
|
bttn_box.pack_end(settings_bttn, expand = False, fill = False, padding = 1)
|
||||||
@@ -98,5 +99,8 @@ class MarkdownPreview(Gtk.Popover, MarkdownPreviewMixin):
|
|||||||
def _tggle_preview_updates(self, widget):
|
def _tggle_preview_updates(self, widget):
|
||||||
self.is_preview_paused = not self.is_preview_paused
|
self.is_preview_paused = not self.is_preview_paused
|
||||||
|
|
||||||
def _handle_settings(self, widget):
|
def _handle_destroy(self):
|
||||||
...
|
self.disconnect_by_func(self._handle_hide)
|
||||||
|
self.disconnect_by_func(self._handle_show)
|
||||||
|
self.disconnect_by_func(self._handle_destroy)
|
||||||
|
self.start_stop_bttn.disconnect_by_func(self._tggle_preview_updates)
|
||||||
|
|||||||
@@ -51,6 +51,18 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_command",
|
||||||
|
command_name = "tggle_markdown_preview",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Shift><Control>m"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
markdown_preview.destroy()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@@ -67,4 +79,14 @@ class Handler:
|
|||||||
if not markdown_preview.can_hide:
|
if not markdown_preview.can_hide:
|
||||||
markdown_preview.can_hide = True
|
markdown_preview.can_hide = True
|
||||||
|
|
||||||
markdown_preview.popdown() if markdown_preview.is_visible() else markdown_preview.popup()
|
if markdown_preview.is_visible():
|
||||||
|
markdown_preview.popdown()
|
||||||
|
return
|
||||||
|
|
||||||
|
file = view.command.exec("get_current_file")
|
||||||
|
if not file or not file.get_location(): return
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
|
||||||
|
markdown_preview.popup()
|
||||||
|
markdown_preview.fpath = file.get_location().get_path()
|
||||||
|
markdown_preview._do_markdown_translate(buffer)
|
||||||
|
|||||||
@@ -17,19 +17,17 @@ class SearchReplaceMixin(SearchMixin, ReplaceMixin):
|
|||||||
search_text = entry.get_text()
|
search_text = entry.get_text()
|
||||||
buffer = self.active_view.get_buffer()
|
buffer = self.active_view.get_buffer()
|
||||||
|
|
||||||
if buffer.get_has_selection() and not search_text:
|
if not buffer.get_has_selection() and search_text: return
|
||||||
if not self.mode_bttn_box.in_selection:
|
if self.mode_bttn_box.in_selection: return
|
||||||
start_itr, end_itr = buffer.get_selection_bounds()
|
|
||||||
|
|
||||||
entry.set_text(
|
start_itr, end_itr = buffer.get_selection_bounds()
|
||||||
buffer.get_text(
|
entry.set_text(
|
||||||
start_itr,
|
buffer.get_text(
|
||||||
end_itr,
|
start_itr,
|
||||||
include_hidden_chars = False
|
end_itr,
|
||||||
)
|
include_hidden_chars = False
|
||||||
)
|
)
|
||||||
|
)
|
||||||
return
|
|
||||||
|
|
||||||
def _find_entry_search_change(self, entry):
|
def _find_entry_search_change(self, entry):
|
||||||
search_text = entry.get_text()
|
search_text = entry.get_text()
|
||||||
|
|||||||
@@ -33,44 +33,44 @@ class ModeButtons(Gtk.ButtonBox):
|
|||||||
ctx.add_class("search-replace-mode-buttons")
|
ctx.add_class("search-replace-mode-buttons")
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
self.connect("destroy", self._handle_destroy)
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
use_regex_bttn = Gtk.ToggleButton(label = ".*")
|
self.use_regex_bttn = Gtk.ToggleButton(label = ".*")
|
||||||
match_case_bttn = Gtk.ToggleButton(label = "Aa")
|
self.match_case_bttn = Gtk.ToggleButton(label = "Aa")
|
||||||
in_selection_bttn = Gtk.ToggleButton()
|
self.in_selection_bttn = Gtk.ToggleButton()
|
||||||
whole_word_bttn = Gtk.ToggleButton()
|
self.whole_word_bttn = Gtk.ToggleButton()
|
||||||
hide_bttn = Gtk.Button(label = "X")
|
self.hide_bttn = Gtk.Button(label = "X")
|
||||||
|
|
||||||
use_regex_bttn.set_sensitive(False)
|
self.use_regex_bttn.set_sensitive(False)
|
||||||
|
|
||||||
use_regex_bttn.set_tooltip_text("Use Regex")
|
self.use_regex_bttn.set_tooltip_text("Use Regex")
|
||||||
match_case_bttn.set_tooltip_text("Match Case")
|
self.match_case_bttn.set_tooltip_text("Match Case")
|
||||||
in_selection_bttn.set_tooltip_text("Only In Selection")
|
self.in_selection_bttn.set_tooltip_text("Only In Selection")
|
||||||
whole_word_bttn.set_tooltip_text("Whole Word")
|
self.whole_word_bttn.set_tooltip_text("Whole Word")
|
||||||
|
|
||||||
use_regex_bttn.connect("toggled", self._toggled_button, "use_regex")
|
self.use_regex_bttn.connect("toggled", self._toggled_button, "use_regex")
|
||||||
match_case_bttn.connect("toggled", self._toggled_button, "match_case")
|
self.match_case_bttn.connect("toggled", self._toggled_button, "match_case")
|
||||||
in_selection_bttn.connect("toggled", self._toggled_button, "in_selection")
|
self.in_selection_bttn.connect("toggled", self._toggled_button, "in_selection")
|
||||||
whole_word_bttn.connect("toggled", self._toggled_button, "whole_word")
|
self.whole_word_bttn.connect("toggled", self._toggled_button, "whole_word")
|
||||||
|
|
||||||
hide_bttn.connect(
|
self.hide_bttn_id = self.hide_bttn.connect(
|
||||||
"clicked",
|
"clicked",
|
||||||
lambda widget: self.get_parent().hide()
|
lambda widget: self.get_parent().hide()
|
||||||
)
|
)
|
||||||
|
|
||||||
in_selection_bttn.set_image(
|
self.in_selection_bttn.set_image(
|
||||||
Gtk.Image.new_from_file("images/only-in-selection.png")
|
Gtk.Image.new_from_file("images/only-in-selection.png")
|
||||||
)
|
)
|
||||||
whole_word_bttn.set_image(
|
self.whole_word_bttn.set_image(
|
||||||
Gtk.Image.new_from_file("images/whole-word.png")
|
Gtk.Image.new_from_file("images/whole-word.png")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.add(use_regex_bttn)
|
self.add(self.use_regex_bttn)
|
||||||
self.add(match_case_bttn)
|
self.add(self.match_case_bttn)
|
||||||
self.add(in_selection_bttn)
|
self.add(self.in_selection_bttn)
|
||||||
self.add(whole_word_bttn)
|
self.add(self.whole_word_bttn)
|
||||||
self.add(hide_bttn)
|
self.add(self.hide_bttn)
|
||||||
|
|
||||||
def _toggled_button(self, toggle_button, mode: str):
|
def _toggled_button(self, toggle_button, mode: str):
|
||||||
setattr(self, mode, not getattr(self, mode))
|
setattr(self, mode, not getattr(self, mode))
|
||||||
@@ -79,4 +79,12 @@ class ModeButtons(Gtk.ButtonBox):
|
|||||||
def request_update(self):
|
def request_update(self):
|
||||||
raise ModeException("Must by 'monkey' patched from search_replace.py")
|
raise ModeException("Must by 'monkey' patched from search_replace.py")
|
||||||
|
|
||||||
|
def _handle_destroy(self, widget):
|
||||||
|
self.disconnect_by_func(self._handle_destroy)
|
||||||
|
|
||||||
|
self.use_regex_bttn.disconnect_by_func(self._toggled_button)
|
||||||
|
self.match_case_bttn.disconnect_by_func(self._toggled_button)
|
||||||
|
self.in_selection_bttn.disconnect_by_func(self._toggled_button)
|
||||||
|
self.whole_word_bttn.disconnect_by_func(self._toggled_button)
|
||||||
|
|
||||||
|
self.hide_bttn.disconnect(self.hide_bttn_id)
|
||||||
|
|||||||
@@ -49,6 +49,17 @@ class Plugin(PluginCode):
|
|||||||
|
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
event = Event_Factory.create_event("unregister_command",
|
||||||
|
command_name = "search_replace",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = ["<Control>f", "<Control>r"]
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
search_replace.destroy()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
@@ -63,4 +74,7 @@ class Handler:
|
|||||||
logger.debug("Command: Search/Replace")
|
logger.debug("Command: Search/Replace")
|
||||||
|
|
||||||
search_replace.last_key = args[0]
|
search_replace.last_key = args[0]
|
||||||
|
if not search_replace.active_view:
|
||||||
|
search_replace.active_view = view
|
||||||
|
|
||||||
search_replace.hide() if search_replace.is_visible() else search_replace.show()
|
search_replace.hide() if search_replace.is_visible() else search_replace.show()
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class SearchReplace(Gtk.Grid, SearchReplaceMixin):
|
|||||||
self.active_view = None
|
self.active_view = None
|
||||||
self.highlight_tag: Gtk.TextTag = None
|
self.highlight_tag: Gtk.TextTag = None
|
||||||
self.matches: list[tuple] = []
|
self.matches: list[tuple] = []
|
||||||
self.last_key: str = None
|
self.last_key: str = "f"
|
||||||
|
|
||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
@@ -48,6 +48,7 @@ class SearchReplace(Gtk.Grid, SearchReplaceMixin):
|
|||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("show", self._handle_show)
|
self.connect("show", self._handle_show)
|
||||||
self.connect("hide", self._handle_hide)
|
self.connect("hide", self._handle_hide)
|
||||||
|
self.connect("destroy", self._handle_destroy)
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
self.status_lbl = Gtk.Label(label = "Find in Current Buffer")
|
self.status_lbl = Gtk.Label(label = "Find in Current Buffer")
|
||||||
@@ -57,10 +58,10 @@ class SearchReplace(Gtk.Grid, SearchReplaceMixin):
|
|||||||
self.find_entry = Gtk.SearchEntry()
|
self.find_entry = Gtk.SearchEntry()
|
||||||
self.replace_entry = Gtk.SearchEntry()
|
self.replace_entry = Gtk.SearchEntry()
|
||||||
|
|
||||||
find_bttn = Gtk.Button(label = "Find")
|
self.find_bttn = Gtk.Button(label = "Find")
|
||||||
find_all_bttn = Gtk.Button(label = "Find All")
|
self.find_all_bttn = Gtk.Button(label = "Find All")
|
||||||
replace_bttn = Gtk.Button(label = "Replace")
|
self.replace_bttn = Gtk.Button(label = "Replace")
|
||||||
replace_all_bttn = Gtk.Button(label = "Replace All")
|
self.replace_all_bttn = Gtk.Button(label = "Replace All")
|
||||||
|
|
||||||
self.find_entry.set_hexpand(True)
|
self.find_entry.set_hexpand(True)
|
||||||
self.replace_entry.set_hexpand(True)
|
self.replace_entry.set_hexpand(True)
|
||||||
@@ -81,21 +82,24 @@ class SearchReplace(Gtk.Grid, SearchReplaceMixin):
|
|||||||
self.replace_entry.connect("key-release-event", self._replace_entry_key_release_event)
|
self.replace_entry.connect("key-release-event", self._replace_entry_key_release_event)
|
||||||
self.replace_entry.connect("activate", self._replace_entry_activate)
|
self.replace_entry.connect("activate", self._replace_entry_activate)
|
||||||
|
|
||||||
find_bttn.connect(
|
self.find_handler_id = self.find_bttn.connect(
|
||||||
"clicked",
|
"clicked",
|
||||||
lambda button: self._find_entry_next_match(self.find_entry)
|
lambda button: self._find_entry_next_match(self.find_entry)
|
||||||
)
|
)
|
||||||
find_all_bttn.connect(
|
|
||||||
|
self.find_all_handler_id = self.find_all_bttn.connect(
|
||||||
"clicked",
|
"clicked",
|
||||||
lambda button: self._find_entry_search_change(self.find_entry)
|
lambda button: self._find_entry_search_change(self.find_entry)
|
||||||
)
|
)
|
||||||
replace_bttn.connect(
|
|
||||||
|
self.replace_handler_id = self.replace_bttn.connect(
|
||||||
"clicked",
|
"clicked",
|
||||||
lambda button: self._replace_entry_activate(self.replace_entry)
|
lambda button: self._replace_entry_activate(self.replace_entry)
|
||||||
)
|
)
|
||||||
replace_all_bttn.connect(
|
|
||||||
|
self.replace_all_handler_id = self.replace_all_bttn.connect(
|
||||||
"clicked",
|
"clicked",
|
||||||
lambda button: self._replace_all_activate(self.replace_entry)
|
lambda button: self._replace_all_activate(self.replace_entry)
|
||||||
)
|
)
|
||||||
|
|
||||||
self.attach(child = self.status_lbl, left = 0, top = 0, width = 3, height = 1)
|
self.attach(child = self.status_lbl, left = 0, top = 0, width = 3, height = 1)
|
||||||
@@ -103,12 +107,12 @@ class SearchReplace(Gtk.Grid, SearchReplaceMixin):
|
|||||||
self.attach(child = self.mode_bttn_box, left = 5, top = 0, width = 2, height = 1)
|
self.attach(child = self.mode_bttn_box, left = 5, top = 0, width = 2, height = 1)
|
||||||
|
|
||||||
self.attach(child = self.find_entry, left = 0, top = 1, width = 5, height = 1)
|
self.attach(child = self.find_entry, left = 0, top = 1, width = 5, height = 1)
|
||||||
self.attach(child = find_bttn, left = 5, top = 1, width = 1, height = 1)
|
self.attach(child = self.find_bttn, left = 5, top = 1, width = 1, height = 1)
|
||||||
self.attach(child = find_all_bttn, left = 6, top = 1, width = 1, height = 1)
|
self.attach(child = self.find_all_bttn, left = 6, top = 1, width = 1, height = 1)
|
||||||
|
|
||||||
self.attach(child = self.replace_entry, left = 0, top = 2, width = 5, height = 1)
|
self.attach(child = self.replace_entry, left = 0, top = 2, width = 5, height = 1)
|
||||||
self.attach(child = replace_bttn, left = 5, top = 2, width = 1, height = 1)
|
self.attach(child = self.replace_bttn, left = 5, top = 2, width = 1, height = 1)
|
||||||
self.attach(child = replace_all_bttn, left = 6, top = 2, width = 1, height = 1)
|
self.attach(child = self.replace_all_bttn, left = 6, top = 2, width = 1, height = 1)
|
||||||
|
|
||||||
|
|
||||||
def _handle_show(self, widget):
|
def _handle_show(self, widget):
|
||||||
@@ -117,9 +121,9 @@ class SearchReplace(Gtk.Grid, SearchReplaceMixin):
|
|||||||
self.find_entry.grab_focus()
|
self.find_entry.grab_focus()
|
||||||
return
|
return
|
||||||
|
|
||||||
self.replace_entry.grab_focus()
|
|
||||||
# Fake focus call to prompt search
|
# Fake focus call to prompt search
|
||||||
self._find_entry_focus_in_event(self.find_entry, None)
|
self._find_entry_focus_in_event(self.find_entry, None)
|
||||||
|
self.replace_entry.grab_focus()
|
||||||
|
|
||||||
def _handle_hide(self, widget):
|
def _handle_hide(self, widget):
|
||||||
if not self.active_view: return
|
if not self.active_view: return
|
||||||
@@ -197,3 +201,22 @@ class SearchReplace(Gtk.Grid, SearchReplaceMixin):
|
|||||||
start_itr, end_itr = buffer.get_bounds()
|
start_itr, end_itr = buffer.get_bounds()
|
||||||
buffer.remove_tag(self.highlight_tag, start_itr, end_itr)
|
buffer.remove_tag(self.highlight_tag, start_itr, end_itr)
|
||||||
|
|
||||||
|
def _handle_destroy(self, widget):
|
||||||
|
self.disconnect_by_func(self._handle_show)
|
||||||
|
self.disconnect_by_func(self._handle_hide)
|
||||||
|
self.disconnect_by_func(self._handle_destroy)
|
||||||
|
|
||||||
|
self.find_entry.disconnect_by_func(self._find_entry_focus_in_event)
|
||||||
|
self.find_entry.disconnect_by_func(self._find_entry_key_release_event)
|
||||||
|
self.find_entry.disconnect_by_func(self._find_entry_activate)
|
||||||
|
self.find_entry.disconnect_by_func(self._find_entry_search_change)
|
||||||
|
self.find_entry.disconnect_by_func(self._find_entry_next_match)
|
||||||
|
self.find_entry.disconnect_by_func(self._find_entry_previous_match)
|
||||||
|
|
||||||
|
self.replace_entry.disconnect_by_func(self._replace_entry_key_release_event)
|
||||||
|
self.replace_entry.disconnect_by_func(self._replace_entry_activate)
|
||||||
|
|
||||||
|
self.find_bttn.disconnect(self.find_handler_id)
|
||||||
|
self.find_all_bttn.disconnect(self.find_all_handler_id)
|
||||||
|
self.replace_bttn.disconnect(self.replace_handler_id)
|
||||||
|
self.replace_all_bttn.disconnect(self.replace_all_handler_id)
|
||||||
|
|||||||
@@ -20,13 +20,27 @@ class Plugin(PluginCode):
|
|||||||
...
|
...
|
||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
tabs_controller = TabsController()
|
self.tabs_controller = TabsController()
|
||||||
code_container = self.request_ui_element("code-container")
|
code_container = self.request_ui_element("code-container")
|
||||||
|
|
||||||
self.register_controller("tabs", tabs_controller)
|
self.register_controller("tabs", self.tabs_controller)
|
||||||
|
|
||||||
code_container.add( tabs_controller.tabs_widget )
|
code_container.add( self.tabs_controller.tabs_widget )
|
||||||
code_container.reorder_child(tabs_controller.tabs_widget, 0)
|
code_container.reorder_child(self.tabs_controller.tabs_widget, 0)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event("get_files")
|
||||||
|
self.emit_to("files", event)
|
||||||
|
for file in event.response:
|
||||||
|
self.tabs_controller.add_tab(file)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
self.unregister_controller("tabs")
|
||||||
|
self.tabs_controller.unload_tabs()
|
||||||
|
self.tabs_controller.tabs_widget.destroy()
|
||||||
|
|
||||||
|
self.tabs_controller.tabs_widget = None
|
||||||
|
self.tabs_controller = None
|
||||||
|
del self.tabs_controller
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ class TabWidget(Gtk.Box):
|
|||||||
self.set_orientation(0)
|
self.set_orientation(0)
|
||||||
self.set_hexpand(False)
|
self.set_hexpand(False)
|
||||||
self.set_vexpand(False)
|
self.set_vexpand(False)
|
||||||
self.set_can_focus(False)
|
|
||||||
self.set_size_request(-1, 12)
|
self.set_size_request(-1, 12)
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
@@ -44,10 +43,6 @@ class TabWidget(Gtk.Box):
|
|||||||
self.close_bttn = Gtk.Button()
|
self.close_bttn = Gtk.Button()
|
||||||
icon = Gtk.Image(stock = Gtk.STOCK_CLOSE)
|
icon = Gtk.Image(stock = Gtk.STOCK_CLOSE)
|
||||||
|
|
||||||
self.event_box.set_can_focus(False)
|
|
||||||
self.label.set_can_focus(False)
|
|
||||||
self.close_bttn.set_can_focus(False)
|
|
||||||
|
|
||||||
self.event_box.set_above_child(True)
|
self.event_box.set_above_child(True)
|
||||||
ctx = self.label.get_style_context()
|
ctx = self.label.get_style_context()
|
||||||
ctx.add_class("tab-label")
|
ctx.add_class("tab-label")
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ from .tab_widget import TabWidget
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TabsController(ControllerBase):
|
class TabsController(ControllerBase):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(TabsController, self).__init__()
|
super(TabsController, self).__init__()
|
||||||
@@ -35,7 +34,7 @@ class TabsController(ControllerBase):
|
|||||||
elif isinstance(event, Code_Event_Types.FileExternallyDeletedEvent):
|
elif isinstance(event, Code_Event_Types.FileExternallyDeletedEvent):
|
||||||
self.tabs_widget.externally_deleted( event.buffer )
|
self.tabs_widget.externally_deleted( event.buffer )
|
||||||
elif isinstance(event, Code_Event_Types.AddedNewFileEvent):
|
elif isinstance(event, Code_Event_Types.AddedNewFileEvent):
|
||||||
self.add_tab(event)
|
self.add_tab(event.file)
|
||||||
elif isinstance(event, Code_Event_Types.PoppedFileEvent):
|
elif isinstance(event, Code_Event_Types.PoppedFileEvent):
|
||||||
...
|
...
|
||||||
elif isinstance(event, Code_Event_Types.RemovedFileEvent):
|
elif isinstance(event, Code_Event_Types.RemovedFileEvent):
|
||||||
@@ -53,11 +52,11 @@ class TabsController(ControllerBase):
|
|||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
def add_tab(self, event: Code_Event_Types.AddedNewFileEvent):
|
def add_tab(self, file):
|
||||||
tab = TabWidget()
|
tab = TabWidget()
|
||||||
tab.file = event.file
|
tab.file = file
|
||||||
|
|
||||||
tab.label.set_label(event.file.fname)
|
tab.label.set_label(file.fname)
|
||||||
|
|
||||||
self.tabs_widget.append_page(Gtk.Separator(), tab)
|
self.tabs_widget.append_page(Gtk.Separator(), tab)
|
||||||
tab.show_all()
|
tab.show_all()
|
||||||
@@ -73,3 +72,13 @@ class TabsController(ControllerBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|
||||||
|
def unload_tabs(self):
|
||||||
|
for page_widget in self.tabs_widget.get_children():
|
||||||
|
tab = self.tabs_widget.get_tab_label(page_widget)
|
||||||
|
|
||||||
|
tab.clear_signals_and_data()
|
||||||
|
self.tabs_widget.remove_page(
|
||||||
|
self.tabs_widget.page_num(page_widget)
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class TabsWidget(Gtk.Notebook):
|
|||||||
self.connect("page-added", self._page_added)
|
self.connect("page-added", self._page_added)
|
||||||
self.switch_page_id = \
|
self.switch_page_id = \
|
||||||
self.connect_after("switch-page", self._switch_page)
|
self.connect_after("switch-page", self._switch_page)
|
||||||
|
self.connect("destroy", self._handle_destroy)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
@@ -81,25 +82,38 @@ class TabsWidget(Gtk.Notebook):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create_menu(self, page_widget) -> Gtk.Menu:
|
def create_menu(self, page_widget) -> Gtk.Menu:
|
||||||
context_menu = Gtk.Menu()
|
context_menu = Gtk.Menu()
|
||||||
|
close_submenu = Gtk.Menu()
|
||||||
|
save_item = Gtk.MenuItem(label = "Save")
|
||||||
|
save_as_item = Gtk.MenuItem(label = "Save As")
|
||||||
|
|
||||||
close_item = Gtk.MenuItem(label = "Close Tab")
|
close_actions_menu = Gtk.MenuItem(label = "Close Actions")
|
||||||
close_left_item = Gtk.MenuItem(label = "Close Tabs Left")
|
close_item = Gtk.MenuItem(label = "Close Tab")
|
||||||
close_right_item = Gtk.MenuItem(label = "Close Tabs Right")
|
close_left_item = Gtk.MenuItem(label = "Close Tabs Left")
|
||||||
close_other_item = Gtk.MenuItem(label = "Close Other Tabs")
|
close_right_item = Gtk.MenuItem(label = "Close Tabs Right")
|
||||||
close_all_item = Gtk.MenuItem(label = "Close All Tabs")
|
close_other_item = Gtk.MenuItem(label = "Close Other Tabs")
|
||||||
|
close_all_item = Gtk.MenuItem(label = "Close All Tabs")
|
||||||
|
|
||||||
close_item.connect("activate", self.close_item, page_widget)
|
save_item.connect("activate", self.save_item, page_widget)
|
||||||
close_left_item.connect("activate", self.close_left_items, page_widget)
|
save_as_item.connect("activate", self.save_as_item, page_widget)
|
||||||
|
|
||||||
|
close_item.connect("activate", self.close_item, page_widget)
|
||||||
|
close_left_item.connect("activate", self.close_left_items, page_widget)
|
||||||
close_right_item.connect("activate", self.close_right_items, page_widget)
|
close_right_item.connect("activate", self.close_right_items, page_widget)
|
||||||
close_other_item.connect("activate", self.close_other_items, page_widget)
|
close_other_item.connect("activate", self.close_other_items, page_widget)
|
||||||
close_all_item.connect("activate", self.close_all_items, page_widget)
|
close_all_item.connect("activate", self.close_all_items, page_widget)
|
||||||
|
|
||||||
context_menu.append(close_item)
|
close_submenu.append(close_item)
|
||||||
context_menu.append(close_left_item)
|
close_submenu.append(close_left_item)
|
||||||
context_menu.append(close_right_item)
|
close_submenu.append(close_right_item)
|
||||||
context_menu.append(close_other_item)
|
close_submenu.append(close_other_item)
|
||||||
context_menu.append(close_all_item)
|
close_submenu.append(close_all_item)
|
||||||
|
|
||||||
|
close_actions_menu.set_submenu(close_submenu)
|
||||||
|
|
||||||
|
context_menu.append(save_item)
|
||||||
|
context_menu.append(save_as_item)
|
||||||
|
context_menu.append(close_actions_menu)
|
||||||
|
|
||||||
context_menu.show_all()
|
context_menu.show_all()
|
||||||
|
|
||||||
@@ -142,6 +156,14 @@ class TabsWidget(Gtk.Notebook):
|
|||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def save_item(self, menu_item, page_widget):
|
||||||
|
tab = self.get_tab_label(page_widget)
|
||||||
|
tab.file.save()
|
||||||
|
|
||||||
|
def save_as_item(self, menu_item, page_widget):
|
||||||
|
tab = self.get_tab_label(page_widget)
|
||||||
|
tab.file.save_as()
|
||||||
|
|
||||||
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)
|
||||||
tab.close_bttn.clicked()
|
tab.close_bttn.clicked()
|
||||||
@@ -176,3 +198,9 @@ class TabsWidget(Gtk.Notebook):
|
|||||||
for widget in children[ : ]:
|
for widget in children[ : ]:
|
||||||
tab = self.get_tab_label(widget)
|
tab = self.get_tab_label(widget)
|
||||||
tab.close_bttn.clicked()
|
tab.close_bttn.clicked()
|
||||||
|
|
||||||
|
def _handle_destroy(self, widget):
|
||||||
|
self.disconnect_by_func(self._page_added)
|
||||||
|
self.disconnect_by_func(self._switch_page)
|
||||||
|
self.disconnect_by_func(self._handle_destroy)
|
||||||
|
|
||||||
|
|||||||
@@ -115,9 +115,9 @@ class ListBox(Gtk.ListBox):
|
|||||||
|
|
||||||
self.select_row(next_row)
|
self.select_row(next_row)
|
||||||
|
|
||||||
def add_row(self, event):
|
def add_row(self, file):
|
||||||
label = Gtk.Label(label = event.file.fname)
|
label = Gtk.Label(label = file.fname)
|
||||||
label.file = event.file
|
label.file = file
|
||||||
label.show()
|
label.show()
|
||||||
self.add(label)
|
self.add(label)
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class Plugin(PluginCode):
|
|||||||
if isinstance(event, Code_Event_Types.FocusedViewEvent):
|
if isinstance(event, Code_Event_Types.FocusedViewEvent):
|
||||||
...
|
...
|
||||||
elif isinstance(event, Code_Event_Types.AddedNewFileEvent):
|
elif isinstance(event, Code_Event_Types.AddedNewFileEvent):
|
||||||
telescope.list_box.add_row(event)
|
telescope.list_box.add_row(event.file)
|
||||||
elif isinstance(event, Code_Event_Types.RemovedFileEvent):
|
elif isinstance(event, Code_Event_Types.RemovedFileEvent):
|
||||||
telescope.list_box.remove_row(event)
|
telescope.list_box.remove_row(event)
|
||||||
elif isinstance(event, Code_Event_Types.FilePathSetEvent):
|
elif isinstance(event, Code_Event_Types.FilePathSetEvent):
|
||||||
@@ -46,7 +46,7 @@ class Plugin(PluginCode):
|
|||||||
)
|
)
|
||||||
self.emit_to("source_views", event)
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
"create_source_view",
|
"create_source_view",
|
||||||
state = SourceViewStates.INDEPENDENT
|
state = SourceViewStates.INDEPENDENT
|
||||||
)
|
)
|
||||||
@@ -55,12 +55,38 @@ class Plugin(PluginCode):
|
|||||||
source_view = event.response
|
source_view = event.response
|
||||||
telescope.set_source_view(source_view)
|
telescope.set_source_view(source_view)
|
||||||
|
|
||||||
event = Event_Factory.create_event(
|
event = Event_Factory.create_event(
|
||||||
"register_completer",
|
"register_completer",
|
||||||
completer = source_view.get_completion()
|
completer = source_view.get_completion()
|
||||||
)
|
)
|
||||||
self.emit_to("completion", event)
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event("get_files")
|
||||||
|
self.emit_to("files", event)
|
||||||
|
for file in event.response:
|
||||||
|
telescope.list_box.add_row(file)
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
window = self.request_ui_element("main-window")
|
||||||
|
|
||||||
|
telescope.unmap_parent_resize_event(window)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event("unregister_command",
|
||||||
|
command_name = "telescope",
|
||||||
|
command = Handler,
|
||||||
|
binding_mode = "released",
|
||||||
|
binding = "<Control>b"
|
||||||
|
)
|
||||||
|
self.emit_to("source_views", event)
|
||||||
|
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"unregister_completer",
|
||||||
|
completer = telescope.source_view.get_completion()
|
||||||
|
)
|
||||||
|
self.emit_to("completion", event)
|
||||||
|
|
||||||
|
telescope.destroy()
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
...
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class Telescope(Gtk.Dialog):
|
|||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("focus-out-event", self._focus_out_event)
|
self.connect("focus-out-event", self._focus_out_event)
|
||||||
self.connect("show", self._show)
|
self.connect("show", self._show)
|
||||||
|
self.connect("destroy", self._handle_destroy)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
@@ -93,7 +94,10 @@ class Telescope(Gtk.Dialog):
|
|||||||
self.source_view.set_buffer(buffer)
|
self.source_view.set_buffer(buffer)
|
||||||
|
|
||||||
def map_parent_resize_event(self, parent):
|
def map_parent_resize_event(self, parent):
|
||||||
parent.connect("size-allocate", lambda w, r: self._map_resize(self, parent))
|
self.size_allocate_id = parent.connect("size-allocate", lambda w, r: self._map_resize(self, parent))
|
||||||
|
|
||||||
|
def unmap_parent_resize_event(self, parent):
|
||||||
|
parent.disconnect(self.size_allocate_id)
|
||||||
|
|
||||||
def set_source_view(self, source_view):
|
def set_source_view(self, source_view):
|
||||||
scrolled_win = Gtk.ScrolledWindow()
|
scrolled_win = Gtk.ScrolledWindow()
|
||||||
@@ -103,3 +107,8 @@ class Telescope(Gtk.Dialog):
|
|||||||
self.main_box.pack_end(scrolled_win, True, True, 0)
|
self.main_box.pack_end(scrolled_win, True, True, 0)
|
||||||
|
|
||||||
scrolled_win.show_all()
|
scrolled_win.show_all()
|
||||||
|
|
||||||
|
def _handle_destroy(self, widget):
|
||||||
|
self.disconnect_by_func(self._focus_out_event)
|
||||||
|
self.disconnect_by_func(self._show)
|
||||||
|
self.disconnect_by_func(self._handle_destroy)
|
||||||
|
|||||||
@@ -24,8 +24,16 @@ class Plugin(PluginUI):
|
|||||||
ui_element = self.request_ui_element("header-container")
|
ui_element = self.request_ui_element("header-container")
|
||||||
ui_element.add( self.generate_plugin_element() )
|
ui_element.add( self.generate_plugin_element() )
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
ui_element = self.request_ui_element("header-container")
|
||||||
|
self.button = self.generate_plugin_element()
|
||||||
|
|
||||||
|
ui_element.add( self.button )
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
...
|
self.button.disconnect_by_func(self.send_message)
|
||||||
|
self.button.destroy()
|
||||||
|
del button
|
||||||
|
|
||||||
def generate_plugin_element(self):
|
def generate_plugin_element(self):
|
||||||
button = Gtk.Button(label = "Hello, World!")
|
button = Gtk.Button(label = "Hello, World!")
|
||||||
|
|||||||
@@ -65,12 +65,12 @@ builtins.call_chain = call_chain_wrapper
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# def custom_except_hook(exc_type, exc_value, exc_traceback):
|
def custom_except_hook(exc_type, exc_value, exc_traceback):
|
||||||
# if issubclass(exc_type, KeyboardInterrupt):
|
if issubclass(exc_type, KeyboardInterrupt):
|
||||||
# sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
||||||
# sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
||||||
# return
|
return
|
||||||
|
#
|
||||||
# logger.error("Uncaught exception", exc_info = (exc_type, exc_value, exc_traceback))
|
logger.error("Uncaught exception", exc_info = (exc_type, exc_value, exc_traceback))
|
||||||
|
#
|
||||||
# sys.excepthook = custom_except_hook
|
sys.excepthook = custom_except_hook
|
||||||
@@ -29,8 +29,7 @@ class Application:
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if not settings_manager.is_trace_debug():
|
if not settings_manager.is_trace_debug():
|
||||||
if not self.load_ipc():
|
if not self.load_ipc(): return
|
||||||
return
|
|
||||||
|
|
||||||
win = Window()
|
win = Window()
|
||||||
win.start()
|
win.start()
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ class BaseContainer(Gtk.Box):
|
|||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
@@ -32,12 +31,16 @@ class BaseContainer(Gtk.Box):
|
|||||||
self._update_transparency()
|
self._update_transparency()
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
self.connect("show", self._handle_show)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("update-transparency", self._update_transparency)
|
event_system.subscribe("update-transparency", self._update_transparency)
|
||||||
event_system.subscribe("remove-transparency", self._remove_transparency)
|
event_system.subscribe("remove-transparency", self._remove_transparency)
|
||||||
|
|
||||||
|
def _handle_show(self, widget):
|
||||||
|
self.disconnect_by_func( self._handle_show )
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
widget_registery.expose_object("base-container", self)
|
widget_registery.expose_object("base-container", self)
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ class BodyContainer(Gtk.Box):
|
|||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
@@ -31,11 +30,15 @@ class BodyContainer(Gtk.Box):
|
|||||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
self.connect("show", self._handle_show)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def _handle_show(self, widget):
|
||||||
|
self.disconnect_by_func( self._handle_show )
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
widget_registery.expose_object("body-container", self)
|
widget_registery.expose_object("body-container", self)
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ class CenterContainer(Gtk.Box):
|
|||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
@@ -32,13 +31,16 @@ class CenterContainer(Gtk.Box):
|
|||||||
self.set_hexpand(True)
|
self.set_hexpand(True)
|
||||||
self.set_vexpand(True)
|
self.set_vexpand(True)
|
||||||
|
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
self.connect("show", self._handle_show)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def _handle_show(self, widget):
|
||||||
|
self.disconnect_by_func( self._handle_show )
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
widget_registery.expose_object("center-container", self)
|
widget_registery.expose_object("center-container", self)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
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
|
||||||
from gi.repository import GLib
|
#from gi.repository import GLib
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ class EditorsContainer(Gtk.Paned):
|
|||||||
self.set_wide_handle(True)
|
self.set_wide_handle(True)
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.map_id = self.connect("map", self._init_map)
|
self.connect("map", self._init_map)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
@@ -59,13 +59,7 @@ class EditorsContainer(Gtk.Paned):
|
|||||||
return scrolled_win1, scrolled_win2
|
return scrolled_win1, scrolled_win2
|
||||||
|
|
||||||
def _init_map(self, view):
|
def _init_map(self, view):
|
||||||
def _first_show_init():
|
self.disconnect_by_func( self._init_map )
|
||||||
self.disconnect(self.map_id)
|
self.code_base.first_map_load()
|
||||||
del self.map_id
|
self.code_base = None
|
||||||
|
del self.code_base
|
||||||
self.code_base.first_map_load()
|
|
||||||
|
|
||||||
del self.code_base
|
|
||||||
return False
|
|
||||||
|
|
||||||
GLib.timeout_add(100, _first_show_init)
|
|
||||||
|
|||||||
@@ -15,11 +15,9 @@ class FooterContainer(Gtk.Box):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(FooterContainer, self).__init__()
|
super(FooterContainer, 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.show()
|
self.show()
|
||||||
|
|
||||||
@@ -32,11 +30,15 @@ class FooterContainer(Gtk.Box):
|
|||||||
self.set_hexpand(True)
|
self.set_hexpand(True)
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
self.connect("show", self._handle_show)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def _handle_show(self, widget):
|
||||||
|
self.disconnect_by_func( self._handle_show )
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
widget_registery.expose_object("footer-container", self)
|
widget_registery.expose_object("footer-container", self)
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ class HeaderContainer(Gtk.Box):
|
|||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
@@ -30,11 +29,15 @@ class HeaderContainer(Gtk.Box):
|
|||||||
self.set_hexpand(True)
|
self.set_hexpand(True)
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
self.connect("show", self._handle_show)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def _handle_show(self, widget):
|
||||||
|
self.disconnect_by_func( self._handle_show )
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
widget_registery.expose_object("header-container", self)
|
widget_registery.expose_object("header-container", self)
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ class LeftContainer(Gtk.Box):
|
|||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
@@ -30,11 +29,15 @@ class LeftContainer(Gtk.Box):
|
|||||||
self.set_vexpand(True)
|
self.set_vexpand(True)
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
self.connect("show", self._handle_show)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def _handle_show(self, widget):
|
||||||
|
self.disconnect_by_func( self._handle_show )
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
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) )
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ class RightContainer(Gtk.Box):
|
|||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._setup_signals()
|
self._setup_signals()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
|
||||||
|
|
||||||
self.show()
|
self.show()
|
||||||
|
|
||||||
@@ -30,11 +29,15 @@ class RightContainer(Gtk.Box):
|
|||||||
self.set_vexpand(True)
|
self.set_vexpand(True)
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
self.connect("show", self._handle_show)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
...
|
||||||
|
|
||||||
|
def _handle_show(self, widget):
|
||||||
|
self.disconnect_by_func( self._handle_show )
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
widget_registery.expose_object("right-container", self)
|
widget_registery.expose_object("right-container", self)
|
||||||
self.add( Separator("separator-right", 1) )
|
self.add( Separator("separator-right", 1) )
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerMixin)
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self._setup_controller_data()
|
self._setup_controller_data()
|
||||||
|
self.plugins_controller.manual_launch_plugins()
|
||||||
|
|
||||||
self._load_plugins(is_pre = True)
|
self._load_plugins(is_pre = True)
|
||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
@@ -43,7 +44,6 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerMixin)
|
|||||||
self.base_container = BaseContainer()
|
self.base_container = BaseContainer()
|
||||||
self.plugins_controller = plugins_controller
|
self.plugins_controller = plugins_controller
|
||||||
|
|
||||||
widget_registery.expose_object("main-window", self.window)
|
|
||||||
settings_manager.register_signals_to_builder([self, self.base_container])
|
settings_manager.register_signals_to_builder([self, self.base_container])
|
||||||
|
|
||||||
self._collect_files_dirs()
|
self._collect_files_dirs()
|
||||||
|
|||||||
@@ -5,13 +5,14 @@
|
|||||||
# Application imports
|
# Application imports
|
||||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from ..mixins.command_system_mixin import CommandSystemMixin
|
||||||
from ..source_view import SourceView
|
from ..source_view import SourceView
|
||||||
|
|
||||||
from . import commands
|
from . import commands
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CommandSystem:
|
class CommandSystem(CommandSystemMixin):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(CommandSystem, self).__init__()
|
super(CommandSystem, self).__init__()
|
||||||
|
|
||||||
@@ -37,6 +38,10 @@ class CommandSystem:
|
|||||||
def add_command(self, command_name: str, command: callable):
|
def add_command(self, command_name: str, command: callable):
|
||||||
setattr(commands, command_name, command)
|
setattr(commands, command_name, command)
|
||||||
|
|
||||||
|
def remove_command(self, command_name: str, command: callable):
|
||||||
|
if hasattr(commands, command_name):
|
||||||
|
delattr(commands, command_name)
|
||||||
|
|
||||||
|
|
||||||
def emit(self, event: Code_Event_Types.CodeEvent):
|
def emit(self, event: Code_Event_Types.CodeEvent):
|
||||||
""" Monkey patch 'emit' from command controller... """
|
""" Monkey patch 'emit' from command controller... """
|
||||||
@@ -47,69 +52,69 @@ class CommandSystem:
|
|||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
def filter_out_loaded_files(self, uris: list[str]):
|
# def filter_out_loaded_files(self, uris: list[str]):
|
||||||
event = Event_Factory.create_event(
|
# event = Event_Factory.create_event(
|
||||||
"filter_out_loaded_files",
|
# "filter_out_loaded_files",
|
||||||
uris = uris
|
# uris = uris
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
self.emit_to("files", event)
|
# self.emit_to("files", event)
|
||||||
|
#
|
||||||
return event.response
|
# return event.response
|
||||||
|
#
|
||||||
def set_info_labels(self, data: tuple[str]):
|
# def set_info_labels(self, data: tuple[str]):
|
||||||
event = Event_Factory.create_event(
|
# event = Event_Factory.create_event(
|
||||||
"set_info_labels",
|
# "set_info_labels",
|
||||||
info = data
|
# info = data
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
self.emit_to("plugins", event)
|
# 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",
|
||||||
view = view,
|
# view = view,
|
||||||
buffer = view.get_buffer()
|
# buffer = view.get_buffer()
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
self.emit_to("files", event)
|
# self.emit_to("files", event)
|
||||||
|
#
|
||||||
return event.response
|
# return event.response
|
||||||
|
#
|
||||||
def get_swap_file(self, view: SourceView):
|
# def get_swap_file(self, view: SourceView):
|
||||||
event = Event_Factory.create_event(
|
# event = Event_Factory.create_event(
|
||||||
"get_swap_file",
|
# "get_swap_file",
|
||||||
view = view,
|
# view = view,
|
||||||
buffer = view.get_buffer()
|
# buffer = view.get_buffer()
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
self.emit_to("files", event)
|
# self.emit_to("files", event)
|
||||||
|
#
|
||||||
return event.response
|
# return event.response
|
||||||
|
#
|
||||||
def new_file(self, view: SourceView):
|
# def new_file(self, view: SourceView):
|
||||||
event = Event_Factory.create_event("add_new_file", view = view)
|
# event = Event_Factory.create_event("add_new_file", view = view)
|
||||||
|
#
|
||||||
self.emit_to("files", event)
|
# self.emit_to("files", event)
|
||||||
|
#
|
||||||
return event.response
|
# return event.response
|
||||||
|
#
|
||||||
def remove_file(self, view: SourceView):
|
# def remove_file(self, view: SourceView):
|
||||||
event = Event_Factory.create_event(
|
# event = Event_Factory.create_event(
|
||||||
"remove_file",
|
# "remove_file",
|
||||||
view = view,
|
# view = view,
|
||||||
buffer = view.get_buffer()
|
# buffer = view.get_buffer()
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
self.emit_to("files", event)
|
# self.emit_to("files", event)
|
||||||
|
#
|
||||||
return event.response
|
# return event.response
|
||||||
|
#
|
||||||
def request_completion(self, view: SourceView):
|
# def request_completion(self, view: SourceView):
|
||||||
event = Event_Factory.create_event(
|
# event = Event_Factory.create_event(
|
||||||
"request_completion",
|
# "request_completion",
|
||||||
view = view,
|
# view = view,
|
||||||
buffer = view.get_buffer()
|
# buffer = view.get_buffer()
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
self.emit_to("completion", event)
|
# self.emit_to("completion", event)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def execute(
|
||||||
|
view: GtkSource.View,
|
||||||
|
*args,
|
||||||
|
**kwargs
|
||||||
|
):
|
||||||
|
logger.debug("Command: Toggle Plugins UI")
|
||||||
|
view.command.toggle_plugins_ui()
|
||||||
@@ -28,6 +28,8 @@ class FilesController(ControllerBase, list):
|
|||||||
self.remove_file(event)
|
self.remove_file(event)
|
||||||
elif isinstance(event, Code_Event_Types.GetFileEvent):
|
elif isinstance(event, Code_Event_Types.GetFileEvent):
|
||||||
self.get_file(event)
|
self.get_file(event)
|
||||||
|
elif isinstance(event, Code_Event_Types.GetFilesEvent):
|
||||||
|
event.response = self
|
||||||
elif isinstance(event, Code_Event_Types.GetSwapFileEvent):
|
elif isinstance(event, Code_Event_Types.GetSwapFileEvent):
|
||||||
self.get_swap_file(event)
|
self.get_swap_file(event)
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,11 @@ class SourceViewSignalMapper:
|
|||||||
def connect_signals(self, source_view: SourceView):
|
def connect_signals(self, source_view: SourceView):
|
||||||
signal_mappings = self._get_signal_mappings()
|
signal_mappings = self._get_signal_mappings()
|
||||||
for signal, handler in signal_mappings.items():
|
for signal, handler in signal_mappings.items():
|
||||||
source_view.connect(signal, handler)
|
if not signal == "populate-popup":
|
||||||
|
source_view.connect(signal, handler)
|
||||||
|
continue
|
||||||
|
|
||||||
|
source_view.connect_after(signal, handler)
|
||||||
|
|
||||||
def disconnect_signals(self, source_view: SourceView):
|
def disconnect_signals(self, source_view: SourceView):
|
||||||
signal_mappings = self._get_signal_mappings()
|
signal_mappings = self._get_signal_mappings()
|
||||||
|
|||||||
@@ -33,11 +33,15 @@ class SourceViewsController(ControllerBase, list):
|
|||||||
self._remove_file(event)
|
self._remove_file(event)
|
||||||
elif isinstance(event, Code_Event_Types.RegisterCommandEvent):
|
elif isinstance(event, Code_Event_Types.RegisterCommandEvent):
|
||||||
self._register_command(event)
|
self._register_command(event)
|
||||||
|
elif isinstance(event, Code_Event_Types.UnregisterCommandEvent):
|
||||||
|
self._unregister_command(event)
|
||||||
|
|
||||||
if not self.signal_mapper.active_view: return
|
if not self.signal_mapper.active_view: return
|
||||||
|
|
||||||
if isinstance(event, Code_Event_Types.GetActiveViewEvent):
|
if isinstance(event, Code_Event_Types.GetActiveViewEvent):
|
||||||
event.response = self.signal_mapper.active_view
|
event.response = self.signal_mapper.active_view
|
||||||
|
elif isinstance(event, Code_Event_Types.GetSourceViewsEvent):
|
||||||
|
event.response = self
|
||||||
elif isinstance(event, Code_Event_Types.TextChangedEvent):
|
elif isinstance(event, Code_Event_Types.TextChangedEvent):
|
||||||
self.signal_mapper.active_view.command.exec("update_info_bar")
|
self.signal_mapper.active_view.command.exec("update_info_bar")
|
||||||
elif isinstance(event, Code_Event_Types.SetActiveFileEvent):
|
elif isinstance(event, Code_Event_Types.SetActiveFileEvent):
|
||||||
@@ -63,6 +67,24 @@ class SourceViewsController(ControllerBase, list):
|
|||||||
event.command
|
event.command
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _unregister_command(self, event: Code_Event_Types.UnregisterCommandEvent):
|
||||||
|
if not isinstance(event.binding, list):
|
||||||
|
event.binding = [ event.binding ]
|
||||||
|
|
||||||
|
for binding in event.binding:
|
||||||
|
self.state_manager.key_mapper.unmap_command(
|
||||||
|
event.command_name,
|
||||||
|
{
|
||||||
|
f"{event.binding_mode}": binding
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for view in self:
|
||||||
|
view.command.remove_command(
|
||||||
|
event.command_name,
|
||||||
|
event.command
|
||||||
|
)
|
||||||
|
|
||||||
def _get_command_system(self):
|
def _get_command_system(self):
|
||||||
event = Event_Factory.create_event("get_new_command_system")
|
event = Event_Factory.create_event("get_new_command_system")
|
||||||
self.message_to("commands", event)
|
self.message_to("commands", event)
|
||||||
|
|||||||
@@ -95,6 +95,28 @@ class KeyMapper:
|
|||||||
|
|
||||||
getattr(self.states[state], press_state)[keyname] = command
|
getattr(self.states[state], press_state)[keyname] = command
|
||||||
|
|
||||||
|
def unmap_command(self, command, entry):
|
||||||
|
press_state = "held" if "held" in entry else "released"
|
||||||
|
keyname = entry[press_state]
|
||||||
|
|
||||||
|
state = NoKeyState
|
||||||
|
if "<Control>" in keyname:
|
||||||
|
state = state | CtrlKeyState
|
||||||
|
if "<Shift>" in keyname:
|
||||||
|
state = state | ShiftKeyState
|
||||||
|
if "<Alt>" in keyname:
|
||||||
|
state = state | AltKeyState
|
||||||
|
|
||||||
|
keyname = keyname.replace("<Control>", "") \
|
||||||
|
.replace("<Shift>", "") \
|
||||||
|
.replace("<Alt>", "") \
|
||||||
|
.lower()
|
||||||
|
|
||||||
|
mapping = getattr(self.states[state], press_state)
|
||||||
|
|
||||||
|
if keyname in mapping and mapping[keyname] == command:
|
||||||
|
del mapping[keyname]
|
||||||
|
|
||||||
def _key_press_event(self, eve):
|
def _key_press_event(self, eve):
|
||||||
keyname = self.get_keyname(eve)
|
keyname = self.get_keyname(eve)
|
||||||
char_str = self.get_char(eve)
|
char_str = self.get_char(eve)
|
||||||
|
|||||||
83
src/core/widgets/code/mixins/command_system_mixin.py
Normal file
83
src/core/widgets/code/mixins/command_system_mixin.py
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
|
|
||||||
|
from ..source_view import SourceView
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class CommandSystemMixin:
|
||||||
|
def toggle_plugins_ui(self):
|
||||||
|
event = Event_Factory.create_event( "toggle_plugins_ui" )
|
||||||
|
|
||||||
|
self.emit_to("plugins", event)
|
||||||
|
|
||||||
|
def filter_out_loaded_files(self, uris: list[str]):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"filter_out_loaded_files",
|
||||||
|
uris = uris
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("files", event)
|
||||||
|
|
||||||
|
return event.response
|
||||||
|
|
||||||
|
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):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"get_file",
|
||||||
|
view = view,
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("files", event)
|
||||||
|
|
||||||
|
return event.response
|
||||||
|
|
||||||
|
def get_swap_file(self, view: SourceView):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"get_swap_file",
|
||||||
|
view = view,
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("files", event)
|
||||||
|
|
||||||
|
return event.response
|
||||||
|
|
||||||
|
def new_file(self, view: SourceView):
|
||||||
|
event = Event_Factory.create_event("add_new_file", view = view)
|
||||||
|
|
||||||
|
self.emit_to("files", event)
|
||||||
|
|
||||||
|
return event.response
|
||||||
|
|
||||||
|
def remove_file(self, view: SourceView):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"remove_file",
|
||||||
|
view = view,
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("files", event)
|
||||||
|
|
||||||
|
return event.response
|
||||||
|
|
||||||
|
def request_completion(self, view: SourceView):
|
||||||
|
event = Event_Factory.create_event(
|
||||||
|
"request_completion",
|
||||||
|
view = view,
|
||||||
|
buffer = view.get_buffer()
|
||||||
|
)
|
||||||
|
|
||||||
|
self.emit_to("completion", event)
|
||||||
@@ -67,6 +67,7 @@ class Window(Gtk.ApplicationWindow):
|
|||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
self.connect("focus-in-event", self._on_focus_in_event)
|
self.connect("focus-in-event", self._on_focus_in_event)
|
||||||
self.connect("focus-out-event", self._on_focus_out_event)
|
self.connect("focus-out-event", self._on_focus_out_event)
|
||||||
|
# self.connect("show", self._handle_show)
|
||||||
|
|
||||||
self.connect("delete-event", self.stop)
|
self.connect("delete-event", self.stop)
|
||||||
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self.stop)
|
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self.stop)
|
||||||
@@ -75,6 +76,10 @@ class Window(Gtk.ApplicationWindow):
|
|||||||
event_system.subscribe("tear-down", self.stop)
|
event_system.subscribe("tear-down", self.stop)
|
||||||
event_system.subscribe("load-interactive-debug", self._load_interactive_debug)
|
event_system.subscribe("load-interactive-debug", self._load_interactive_debug)
|
||||||
|
|
||||||
|
def _handle_show(self, widget):
|
||||||
|
self.disconnect_by_func( self._handle_show )
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
widget_registery.expose_object("main-window", self)
|
widget_registery.expose_object("main-window", self)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# Lib imports
|
# Lib imports
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from ..singleton_raised import SingletonRaised
|
from ..singleton import Singleton
|
||||||
|
|
||||||
from ..dto.base_event import BaseEvent
|
from ..dto.base_event import BaseEvent
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ class ControllerBaseException(Exception):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ControllerBase(SingletonRaised, EmitDispatcher):
|
class ControllerBase(Singleton, EmitDispatcher):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(ControllerBase, self).__init__()
|
super(ControllerBase, self).__init__()
|
||||||
|
|
||||||
@@ -42,3 +42,6 @@ class ControllerBase(SingletonRaised, EmitDispatcher):
|
|||||||
|
|
||||||
def register_controller(self, name: str, controller):
|
def register_controller(self, name: str, controller):
|
||||||
self.controller_message_bus.register_controller(name, controller)
|
self.controller_message_bus.register_controller(name, controller)
|
||||||
|
|
||||||
|
def unregister_controller(self, name: str):
|
||||||
|
self.controller_message_bus.unregister_controller(name)
|
||||||
|
|||||||
@@ -31,10 +31,11 @@ class ControllerManager(Singleton, dict):
|
|||||||
|
|
||||||
|
|
||||||
def _crete_controller_message_bus(self) -> ControllerMessageBus:
|
def _crete_controller_message_bus(self) -> ControllerMessageBus:
|
||||||
controller_message_bus = ControllerMessageBus()
|
controller_message_bus = ControllerMessageBus()
|
||||||
controller_message_bus.message_to = self.message_to
|
controller_message_bus.message_to = self.message_to
|
||||||
controller_message_bus.message = self.message
|
controller_message_bus.message = self.message
|
||||||
controller_message_bus.register_controller = self.register_controller
|
controller_message_bus.register_controller = self.register_controller
|
||||||
|
controller_message_bus.unregister_controller = self.unregister_controller
|
||||||
|
|
||||||
return controller_message_bus
|
return controller_message_bus
|
||||||
|
|
||||||
@@ -51,6 +52,17 @@ class ControllerManager(Singleton, dict):
|
|||||||
|
|
||||||
self[name] = controller
|
self[name] = controller
|
||||||
|
|
||||||
|
def unregister_controller(self, name: str):
|
||||||
|
if not name:
|
||||||
|
raise ControllerManagerException("Must pass in a 'name'...")
|
||||||
|
|
||||||
|
if not name in self.keys():
|
||||||
|
raise ControllerManagerException(
|
||||||
|
f"Can't find controller registered with name of '{name}'..."
|
||||||
|
)
|
||||||
|
|
||||||
|
self.pop(name, None)
|
||||||
|
|
||||||
def get_controllers_key_list(self) -> list[str]:
|
def get_controllers_key_list(self) -> list[str]:
|
||||||
return self.keys()
|
return self.keys()
|
||||||
|
|
||||||
|
|||||||
@@ -28,3 +28,6 @@ class ControllerMessageBus:
|
|||||||
|
|
||||||
def register_controller(self, name: str, controller):
|
def register_controller(self, name: str, controller):
|
||||||
raise ControllerMessageBusException("Controller Message Bus 'register_controller' must be overriden by Controller Manager...")
|
raise ControllerMessageBusException("Controller Message Bus 'register_controller' must be overriden by Controller Manager...")
|
||||||
|
|
||||||
|
def unregister_controller(self, name: str):
|
||||||
|
raise ControllerMessageBusException("Controller Message Bus 'unregister_controller' must be overriden by Controller Manager...")
|
||||||
|
|||||||
@@ -4,18 +4,21 @@
|
|||||||
|
|
||||||
|
|
||||||
from .code_event import CodeEvent
|
from .code_event import CodeEvent
|
||||||
|
from .toggle_plugins_ui_event import TogglePluginsUiEvent
|
||||||
from .create_source_view_event import CreateSourceViewEvent
|
from .create_source_view_event import CreateSourceViewEvent
|
||||||
from .register_completer_event import RegisterCompleterEvent
|
from .register_completer_event import RegisterCompleterEvent
|
||||||
from .unregister_completer_event import UnregisterCompleterEvent
|
from .unregister_completer_event import UnregisterCompleterEvent
|
||||||
from .register_provider_event import RegisterProviderEvent
|
from .register_provider_event import RegisterProviderEvent
|
||||||
from .unregister_provider_event import UnregisterProviderEvent
|
from .unregister_provider_event import UnregisterProviderEvent
|
||||||
from .register_command_event import RegisterCommandEvent
|
from .register_command_event import RegisterCommandEvent
|
||||||
|
from .unregister_command_event import UnregisterCommandEvent
|
||||||
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 .set_info_labels_event import SetInfoLabelsEvent
|
||||||
from .populate_source_view_popup_event import PopulateSourceViewPopupEvent
|
from .populate_source_view_popup_event import PopulateSourceViewPopupEvent
|
||||||
from .filter_out_loaded_files_event import FilterOutLoadedFilesEvent
|
from .filter_out_loaded_files_event import FilterOutLoadedFilesEvent
|
||||||
from .get_active_view_event import GetActiveViewEvent
|
from .get_active_view_event import GetActiveViewEvent
|
||||||
|
from .get_source_views_event import GetSourceViewsEvent
|
||||||
|
|
||||||
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
|
||||||
@@ -34,6 +37,7 @@ from .removed_file_event import RemovedFileEvent
|
|||||||
from .saved_file_event import SavedFileEvent
|
from .saved_file_event import SavedFileEvent
|
||||||
|
|
||||||
from .get_file_event import GetFileEvent
|
from .get_file_event import GetFileEvent
|
||||||
|
from .get_files_event import GetFilesEvent
|
||||||
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 .pop_file_event import PopFileEvent
|
from .pop_file_event import PopFileEvent
|
||||||
|
|||||||
13
src/libs/dto/code/events/get_files_event.py
Normal file
13
src/libs/dto/code/events/get_files_event.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .code_event import CodeEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GetFilesEvent(CodeEvent):
|
||||||
|
...
|
||||||
13
src/libs/dto/code/events/get_source_views_event.py
Normal file
13
src/libs/dto/code/events/get_source_views_event.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .code_event import CodeEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class GetSourceViewsEvent(CodeEvent):
|
||||||
|
...
|
||||||
17
src/libs/dto/code/events/toggle_plugins_ui_event.py
Normal file
17
src/libs/dto/code/events/toggle_plugins_ui_event.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .code_event import CodeEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TogglePluginsUiEvent(CodeEvent):
|
||||||
|
...
|
||||||
20
src/libs/dto/code/events/unregister_command_event.py
Normal file
20
src/libs/dto/code/events/unregister_command_event.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Python imports
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('GtkSource', '4')
|
||||||
|
|
||||||
|
from gi.repository import GtkSource
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .code_event import CodeEvent
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class UnregisterCommandEvent(CodeEvent):
|
||||||
|
command_name: str = ""
|
||||||
|
command: callable = None
|
||||||
|
binding_mode: str = ""
|
||||||
|
binding: str or list = ""
|
||||||
@@ -17,6 +17,7 @@ class Manifest:
|
|||||||
version: str = "0.0.1"
|
version: str = "0.0.1"
|
||||||
support: str = "support@mail.com"
|
support: str = "support@mail.com"
|
||||||
pre_launch: bool = False
|
pre_launch: bool = False
|
||||||
|
autoload: bool = True
|
||||||
requests: Requests = field(default_factory = lambda: Requests())
|
requests: Requests = field(default_factory = lambda: Requests())
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ from .manifest import Manifest
|
|||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ManifestMeta:
|
class ManifestMeta:
|
||||||
folder: str = ""
|
folder: str = ""
|
||||||
path: str = ""
|
path: str = ""
|
||||||
manifest: Manifest = field(default_factory = lambda: Manifest())
|
manifest: Manifest = field(default_factory = lambda: Manifest())
|
||||||
|
instance: object | None = None
|
||||||
|
|
||||||
def as_dict(self):
|
def as_dict(self):
|
||||||
return asdict(self)
|
return asdict(self)
|
||||||
|
|||||||
@@ -36,6 +36,19 @@ class EventFactory(Singleton):
|
|||||||
|
|
||||||
logger.debug(f"Registered {i} event types:")
|
logger.debug(f"Registered {i} event types:")
|
||||||
|
|
||||||
|
def unregister_events(self, events: dict):
|
||||||
|
i = 0
|
||||||
|
for name, obj in events:
|
||||||
|
if not self._is_valid_event_class(obj): continue
|
||||||
|
|
||||||
|
event_type = self._class_name_to_event_type(name)
|
||||||
|
|
||||||
|
del self._event_classes[event_type]
|
||||||
|
Code_Event_Types.remove_event_class(name)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
logger.debug(f"Unregistered {i} event types:")
|
||||||
|
|
||||||
def create_event(self, event_type: str, **kwargs) -> BaseEvent:
|
def create_event(self, event_type: str, **kwargs) -> BaseEvent:
|
||||||
if event_type not in self._event_classes:
|
if event_type not in self._event_classes:
|
||||||
raise ValueError(f"Unknown event type: {event_type}")
|
raise ValueError(f"Unknown event type: {event_type}")
|
||||||
@@ -80,6 +93,9 @@ class EventNamespace:
|
|||||||
def add_event_class(self, name: str, event_class: Type[BaseEvent]):
|
def add_event_class(self, name: str, event_class: Type[BaseEvent]):
|
||||||
setattr(self, name, event_class)
|
setattr(self, name, event_class)
|
||||||
|
|
||||||
|
def remove_event_class(self, name: str):
|
||||||
|
delattr(self, name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Code_Event_Types = EventNamespace()
|
Code_Event_Types = EventNamespace()
|
||||||
|
|||||||
@@ -12,21 +12,21 @@ class SingletonError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
T = TypeVar('T', bound='Singleton')
|
T = TypeVar('T', bound = 'Singleton')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Singleton:
|
class Singleton:
|
||||||
__instance = None
|
_instances = {}
|
||||||
|
|
||||||
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 in cls._instances: return cls._instances[cls]
|
||||||
logger.debug(f"'{cls.__name__}' is a Singleton. Returning instance...")
|
|
||||||
return cls.__instance
|
|
||||||
|
|
||||||
cls.__instance = super(Singleton, cls).__new__(cls)
|
instance = super().__new__(cls)
|
||||||
return cls.__instance
|
cls._instances[cls] = instance
|
||||||
|
return instance
|
||||||
|
|
||||||
def __init__(self) -> None:
|
@classmethod
|
||||||
if self.__instance is not None:
|
def destroy(cls):
|
||||||
return
|
if cls in cls._instances:
|
||||||
|
del cls._instances[cls]
|
||||||
super(Singleton, self).__init__()
|
|
||||||
|
|||||||
@@ -4,25 +4,25 @@ import sys
|
|||||||
import importlib
|
import importlib
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
import gi
|
import gi
|
||||||
|
from gi.repository import Gtk
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
|
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||||
from libs.controllers.controller_base import ControllerBase
|
from libs.controllers.controller_base import ControllerBase
|
||||||
|
|
||||||
from libs.dto.plugins.manifest_meta import ManifestMeta
|
from libs.dto.plugins.manifest_meta import ManifestMeta
|
||||||
|
|
||||||
from libs.dto.base_event import BaseEvent
|
from libs.dto.base_event import BaseEvent
|
||||||
|
|
||||||
from .manifest_manager import ManifestManager
|
from .manifest_manager import ManifestManager
|
||||||
from .plugins_controller_mixin import PluginsControllerMixin
|
from .plugins_controller_mixin import PluginsControllerMixin
|
||||||
from .plugin_reload_mixin import PluginReloadMixin
|
from .plugin_reload_mixin import PluginReloadMixin
|
||||||
from .plugin_context import PluginContext
|
from .plugin_context import PluginContext
|
||||||
|
from .plugins_ui import PluginsUI
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -40,11 +40,12 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
|||||||
# path = os.path.dirname(os.path.realpath(__file__))
|
# path = os.path.dirname(os.path.realpath(__file__))
|
||||||
# sys.path.insert(0, path) # NOTE: I think I'm not using this correctly...
|
# sys.path.insert(0, path) # NOTE: I think I'm not using this correctly...
|
||||||
|
|
||||||
self._plugin_collection: list = []
|
self.plugins_ui: PluginsUI = PluginsUI()
|
||||||
|
|
||||||
self._plugins_path: str = settings_manager.path_manager.get_plugins_path()
|
|
||||||
self._manifest_manager: ManifestManager = ManifestManager()
|
self._manifest_manager: ManifestManager = ManifestManager()
|
||||||
|
|
||||||
|
self._plugin_collection: list = []
|
||||||
|
self._plugins_path: str = settings_manager.path_manager.get_plugins_path()
|
||||||
|
|
||||||
self._set_plugins_watcher()
|
self._set_plugins_watcher()
|
||||||
|
|
||||||
|
|
||||||
@@ -52,6 +53,14 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
|||||||
for manifest_meta in self._plugin_collection:
|
for manifest_meta in self._plugin_collection:
|
||||||
manifest_meta.instance._controller_message(event)
|
manifest_meta.instance._controller_message(event)
|
||||||
|
|
||||||
|
if isinstance(event, Code_Event_Types.PopulateSourceViewPopupEvent):
|
||||||
|
event.menu.append( Gtk.SeparatorMenuItem() )
|
||||||
|
item = Gtk.MenuItem(label = "Plugins")
|
||||||
|
item.connect("activate", self.toggle_plugins_ui)
|
||||||
|
event.menu.append(item)
|
||||||
|
elif isinstance(event, Code_Event_Types.TogglePluginsUiEvent):
|
||||||
|
self.toggle_plugins_ui()
|
||||||
|
|
||||||
def _collect_search_locations(self, path: str, locations: list):
|
def _collect_search_locations(self, path: str, locations: list):
|
||||||
locations.append(path)
|
locations.append(path)
|
||||||
for file in os.listdir(path):
|
for file in os.listdir(path):
|
||||||
@@ -105,33 +114,46 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
|||||||
):
|
):
|
||||||
if not is_pre_launch:
|
if not is_pre_launch:
|
||||||
GLib.idle_add(
|
GLib.idle_add(
|
||||||
self._run_with_pool, module, manifest_meta
|
self.execute_plugin, module, manifest_meta
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._run_with_pool(module, manifest_meta)
|
self.execute_plugin(module, manifest_meta)
|
||||||
|
|
||||||
def _run_with_pool(self, module: type, manifest_meta: ManifestMeta):
|
def pre_launch_plugins(self):
|
||||||
with ThreadPoolExecutor(max_workers = 1) as executor:
|
|
||||||
future = executor.submit(self.execute_plugin, module, manifest_meta)
|
|
||||||
future.add_done_callback(self._handle_future_exception)
|
|
||||||
|
|
||||||
def _handle_future_exception(self, future):
|
|
||||||
try:
|
|
||||||
future.result()
|
|
||||||
except Exception:
|
|
||||||
logger.exception("Plugin crashed during execution...")
|
|
||||||
|
|
||||||
def pre_launch_plugins(self) -> None:
|
|
||||||
logger.info(f"Loading pre-launch plugins...")
|
logger.info(f"Loading pre-launch plugins...")
|
||||||
manifest_metas: list = self._manifest_manager.get_pre_launch_plugins()
|
manifest_metas: list = self._manifest_manager.get_pre_launch_plugins()
|
||||||
self._load_plugins(manifest_metas, is_pre_launch = True)
|
self._load_plugins(manifest_metas, is_pre_launch = True)
|
||||||
|
|
||||||
def post_launch_plugins(self) -> None:
|
for manifest_meta in manifest_metas:
|
||||||
|
self.plugins_ui.add_row(manifest_meta, self.toggle_plugin_load_state)
|
||||||
|
|
||||||
|
def post_launch_plugins(self):
|
||||||
logger.info(f"Loading post-launch plugins...")
|
logger.info(f"Loading post-launch plugins...")
|
||||||
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)
|
||||||
|
|
||||||
|
for manifest_meta in manifest_metas:
|
||||||
|
self.plugins_ui.add_row(manifest_meta, self.toggle_plugin_load_state)
|
||||||
|
|
||||||
|
def manual_launch_plugins(self):
|
||||||
|
logger.info(f"Collecting manual-launch plugins...")
|
||||||
|
manifest_metas: list = self._manifest_manager.get_manual_launch_plugins()
|
||||||
|
|
||||||
|
for manifest_meta in manifest_metas:
|
||||||
|
self.plugins_ui.add_row(manifest_meta, self.toggle_plugin_load_state)
|
||||||
|
|
||||||
|
def toggle_plugin_load_state(self, widget, manifest_meta):
|
||||||
|
if manifest_meta.instance:
|
||||||
|
self._plugin_collection.remove(manifest_meta)
|
||||||
|
manifest_meta.instance.unload()
|
||||||
|
manifest_meta.instance = None
|
||||||
|
widget.set_label("Load")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._load_plugins( [manifest_meta] )
|
||||||
|
widget.set_label("Unload")
|
||||||
|
|
||||||
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()
|
||||||
@@ -148,15 +170,18 @@ class PluginsController(ControllerBase, PluginsControllerMixin, PluginReloadMixi
|
|||||||
self._plugin_collection.append(manifest_meta)
|
self._plugin_collection.append(manifest_meta)
|
||||||
|
|
||||||
def create_plugin_context(self):
|
def create_plugin_context(self):
|
||||||
plugin_context: PluginContext = PluginContext()
|
plugin_context: PluginContext = PluginContext()
|
||||||
|
|
||||||
plugin_context.request_ui_element: callable = self.request_ui_element
|
plugin_context.request_ui_element: callable = self.request_ui_element
|
||||||
plugin_context.emit: callable = self.emit
|
plugin_context.emit: callable = self.emit
|
||||||
plugin_context.emit_to: callable = self.emit_to
|
plugin_context.emit_to: callable = self.emit_to
|
||||||
plugin_context.emit_to_selected: callable = self.emit_to_selected
|
plugin_context.emit_to_selected: callable = self.emit_to_selected
|
||||||
plugin_context.register_controller: callable = self.register_controller
|
plugin_context.register_controller: callable = self.register_controller
|
||||||
|
plugin_context.unregister_controller: callable = self.unregister_controller
|
||||||
|
|
||||||
return plugin_context
|
return plugin_context
|
||||||
|
|
||||||
|
def toggle_plugins_ui(self, widget = None):
|
||||||
|
self.plugins_ui.hide() if self.plugins_ui.is_visible() else self.plugins_ui.show()
|
||||||
|
|
||||||
plugins_controller = PluginsController()
|
plugins_controller = PluginsController()
|
||||||
|
|||||||
@@ -19,10 +19,12 @@ class ManifestMapperException(Exception):
|
|||||||
class ManifestManager:
|
class ManifestManager:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
self._plugins_path = settings_manager.path_manager.get_plugins_path()
|
self._plugins_path: str = \
|
||||||
|
settings_manager.path_manager.get_plugins_path()
|
||||||
|
|
||||||
self.pre_launch_manifests: list = []
|
self.pre_launch_manifests: list = []
|
||||||
self.post_launch_manifests: list = []
|
self.post_launch_manifests: list = []
|
||||||
|
self.manual_launch_manifests: list = []
|
||||||
|
|
||||||
self.load_manifests()
|
self.load_manifests()
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ class ManifestManager:
|
|||||||
]:
|
]:
|
||||||
self.load(folder, path)
|
self.load(folder, path)
|
||||||
|
|
||||||
def load(self, folder, path):
|
def load(self, folder, path) -> ManifestMeta:
|
||||||
manifest_pth = join(path, "manifest.json")
|
manifest_pth = join(path, "manifest.json")
|
||||||
|
|
||||||
if not os.path.exists(manifest_pth):
|
if not os.path.exists(manifest_pth):
|
||||||
@@ -52,14 +54,22 @@ class ManifestManager:
|
|||||||
manifest_meta.path = path
|
manifest_meta.path = path
|
||||||
manifest_meta.manifest = manifest
|
manifest_meta.manifest = manifest
|
||||||
|
|
||||||
|
if not manifest.autoload:
|
||||||
|
self.manual_launch_manifests.append(manifest_meta)
|
||||||
|
return
|
||||||
|
|
||||||
if manifest.pre_launch:
|
if manifest.pre_launch:
|
||||||
self.pre_launch_manifests.append(manifest_meta)
|
self.pre_launch_manifests.append(manifest_meta)
|
||||||
else:
|
else:
|
||||||
self.post_launch_manifests.append(manifest_meta)
|
self.post_launch_manifests.append(manifest_meta)
|
||||||
|
|
||||||
def get_pre_launch_plugins(self) -> dict:
|
return manifest_meta
|
||||||
|
|
||||||
|
def get_pre_launch_plugins(self) -> list:
|
||||||
return self.pre_launch_manifests
|
return self.pre_launch_manifests
|
||||||
|
|
||||||
def get_post_launch_plugins(self) -> None:
|
def get_post_launch_plugins(self) -> list:
|
||||||
return self.post_launch_manifests
|
return self.post_launch_manifests
|
||||||
|
|
||||||
|
def get_manual_launch_plugins(self) -> list:
|
||||||
|
return self.manual_launch_manifests
|
||||||
|
|||||||
@@ -37,3 +37,6 @@ class PluginContext:
|
|||||||
def register_controller(self, name: str, controller):
|
def register_controller(self, name: str, controller):
|
||||||
raise PluginContextException("Plugin Context 'register_controller' must be overridden...")
|
raise PluginContextException("Plugin Context 'register_controller' must be overridden...")
|
||||||
|
|
||||||
|
def unregister_controller(self, name: str):
|
||||||
|
raise PluginContextException("Plugin Context 'unregister_controller' must be overridden...")
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ class PluginReloadMixin:
|
|||||||
_plugins_dir_watcher = None
|
_plugins_dir_watcher = None
|
||||||
|
|
||||||
def _set_plugins_watcher(self) -> None:
|
def _set_plugins_watcher(self) -> None:
|
||||||
self._plugins_dir_watcher = Gio.File.new_for_path(
|
self._plugins_dir_watcher = \
|
||||||
self._plugins_path
|
Gio.File.new_for_path( self._plugins_path ) \
|
||||||
).monitor_directory(
|
.monitor_directory(
|
||||||
Gio.FileMonitorFlags.WATCH_MOVES,
|
Gio.FileMonitorFlags.WATCH_MOVES,
|
||||||
Gio.Cancellable()
|
Gio.Cancellable()
|
||||||
)
|
)
|
||||||
|
|
||||||
self._plugins_dir_watcher.connect("changed", self._on_plugins_changed, ())
|
self._plugins_dir_watcher.connect("changed", self._on_plugins_changed, ())
|
||||||
|
|
||||||
@@ -27,10 +27,40 @@ class PluginReloadMixin:
|
|||||||
eve_type = None,
|
eve_type = None,
|
||||||
data = None
|
data = None
|
||||||
):
|
):
|
||||||
if eve_type in [Gio.FileMonitorEvent.CREATED, Gio.FileMonitorEvent.DELETED,
|
if eve_type is Gio.FileMonitorEvent.RENAMED:
|
||||||
Gio.FileMonitorEvent.RENAMED, Gio.FileMonitorEvent.MOVED_IN,
|
...
|
||||||
Gio.FileMonitorEvent.MOVED_OUT]:
|
|
||||||
self.reload_plugins(file)
|
|
||||||
|
|
||||||
def reload_plugins(self, file: str = None) -> None:
|
if eve_type in [Gio.FileMonitorEvent.CREATED, Gio.FileMonitorEvent.MOVED_IN]:
|
||||||
logger.info(f"Reloading plugins... stub.")
|
self.add_plugin(file)
|
||||||
|
|
||||||
|
if eve_type in [Gio.FileMonitorEvent.DELETED, Gio.FileMonitorEvent.MOVED_OUT]:
|
||||||
|
self.remove_plugin(file)
|
||||||
|
|
||||||
|
def add_plugin(self, file: str) -> None:
|
||||||
|
logger.info(f"Adding plugin: {file.get_uri()}")
|
||||||
|
uri = file.get_uri()
|
||||||
|
path = uri.replace("file://", "")
|
||||||
|
folder = path.split("/")[-1]
|
||||||
|
manifest_meta = self._manifest_manager.load(folder, path)
|
||||||
|
|
||||||
|
self._load_plugins( [manifest_meta] )
|
||||||
|
self.plugins_ui.add_row(manifest_meta, self.toggle_plugin_load_state)
|
||||||
|
|
||||||
|
def remove_plugin(self, file: str) -> None:
|
||||||
|
logger.info(f"Removing plugin: {file.get_uri()}")
|
||||||
|
for manifest_meta in self._plugin_collection[:]:
|
||||||
|
if not manifest_meta.folder in file.get_uri(): continue
|
||||||
|
|
||||||
|
manifest_meta.instance.unload()
|
||||||
|
manifest_meta.instance = None
|
||||||
|
self._plugin_collection.remove(manifest_meta)
|
||||||
|
self.plugins_ui.remove_row(manifest_meta)
|
||||||
|
|
||||||
|
if manifest_meta in self._manifest_manager.pre_launch_manifests:
|
||||||
|
self._manifest_manager.pre_launch_manifests.remove(manifest_meta)
|
||||||
|
elif manifest_meta in self._manifest_manager.post_launch_manifests:
|
||||||
|
self._manifest_manager.post_launch_manifests.remove(manifest_meta)
|
||||||
|
elif manifest_meta in self._manifest_manager.manual_launch_manifests:
|
||||||
|
self._manifest_manager.manual_launch_manifests.remove(manifest_meta)
|
||||||
|
|
||||||
|
break
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ class PluginBase:
|
|||||||
def load(self):
|
def load(self):
|
||||||
raise PluginBaseException("Plugin Base 'load' must be overriden by Plugin")
|
raise PluginBaseException("Plugin Base 'load' must be overriden by Plugin")
|
||||||
|
|
||||||
|
def unload(self):
|
||||||
|
raise PluginBaseException("Plugin Base 'unload' must be overriden by Plugin")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
raise PluginBaseException("Plugin Base 'run' must be overriden by Plugin")
|
raise PluginBaseException("Plugin Base 'run' must be overriden by Plugin")
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ class PluginCode(PluginBase):
|
|||||||
def register_controller(self, name: str, controller):
|
def register_controller(self, name: str, controller):
|
||||||
return self.plugin_context.register_controller(name, controller)
|
return self.plugin_context.register_controller(name, controller)
|
||||||
|
|
||||||
|
def unregister_controller(self, name: str):
|
||||||
|
return self.plugin_context.unregister_controller(name)
|
||||||
|
|
||||||
def request_ui_element(self, element_id: str):
|
def request_ui_element(self, element_id: str):
|
||||||
return self.plugin_context.request_ui_element(element_id)
|
return self.plugin_context.request_ui_element(element_id)
|
||||||
|
|
||||||
|
|||||||
100
src/plugins/plugins_ui.py
Normal file
100
src/plugins/plugins_ui.py
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PluginsUI(Gtk.Dialog):
|
||||||
|
def __init__(self):
|
||||||
|
super(PluginsUI, self).__init__()
|
||||||
|
|
||||||
|
self._setup_styling()
|
||||||
|
self._setup_signals()
|
||||||
|
self._subscribe_to_events()
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
|
|
||||||
|
def _setup_styling(self):
|
||||||
|
header = Gtk.HeaderBar()
|
||||||
|
self.ctx = self.get_style_context()
|
||||||
|
self.ctx.add_class("plugin-ui")
|
||||||
|
|
||||||
|
self.set_title("Plugins")
|
||||||
|
self.set_size_request(450, 530)
|
||||||
|
self.set_deletable(False)
|
||||||
|
self.set_skip_pager_hint(True)
|
||||||
|
self.set_skip_taskbar_hint(True)
|
||||||
|
|
||||||
|
header.set_title("Plugins")
|
||||||
|
self.set_titlebar(header)
|
||||||
|
header.show()
|
||||||
|
|
||||||
|
window = widget_registery.get_object("main-window")
|
||||||
|
self.set_transient_for(window)
|
||||||
|
|
||||||
|
def _setup_signals(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _subscribe_to_events(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _load_widgets(self):
|
||||||
|
widget_registery.expose_object("plugin-ui", self)
|
||||||
|
|
||||||
|
content_area = self.get_content_area()
|
||||||
|
scrolled_win = Gtk.ScrolledWindow()
|
||||||
|
viewport = Gtk.Viewport()
|
||||||
|
self.list_box = Gtk.ListBox()
|
||||||
|
|
||||||
|
self.list_box.set_selection_mode( Gtk.SelectionMode.NONE )
|
||||||
|
scrolled_win.set_vexpand(True)
|
||||||
|
|
||||||
|
viewport.add(self.list_box)
|
||||||
|
scrolled_win.add(viewport)
|
||||||
|
content_area.add(scrolled_win)
|
||||||
|
|
||||||
|
scrolled_win.show_all()
|
||||||
|
|
||||||
|
def add_row(self, manifest_meta, callback: callable):
|
||||||
|
box = Gtk.Box()
|
||||||
|
plugin_lbl = Gtk.Label(label = manifest_meta.manifest.name)
|
||||||
|
author_lbl = Gtk.Label(label = manifest_meta.manifest.author)
|
||||||
|
version_lbl = Gtk.Label(label = manifest_meta.manifest.version)
|
||||||
|
is_autoload = manifest_meta.manifest.autoload
|
||||||
|
toggle_bttn = Gtk.ToggleButton(label = "Unload" if is_autoload else "Load")
|
||||||
|
|
||||||
|
toggle_bttn.set_active(is_autoload)
|
||||||
|
plugin_lbl.set_hexpand(True)
|
||||||
|
box.set_hexpand(True)
|
||||||
|
version_lbl.set_margin_left(15)
|
||||||
|
version_lbl.set_margin_right(15)
|
||||||
|
toggle_bttn.set_size_request(120, -1)
|
||||||
|
|
||||||
|
toggle_bttn.toggle_id = \
|
||||||
|
toggle_bttn.connect("toggled", callback, manifest_meta)
|
||||||
|
|
||||||
|
box.add(plugin_lbl)
|
||||||
|
box.add(author_lbl)
|
||||||
|
box.add(version_lbl)
|
||||||
|
box.add(toggle_bttn)
|
||||||
|
box.manifest_meta = manifest_meta
|
||||||
|
|
||||||
|
box.show_all()
|
||||||
|
self.list_box.add(box)
|
||||||
|
|
||||||
|
def remove_row(self, manifest_meta):
|
||||||
|
for row in self.list_box.get_children():
|
||||||
|
child = row.get_children()[0]
|
||||||
|
if not child.manifest_meta == manifest_meta: continue
|
||||||
|
|
||||||
|
child.manifest_meta = None
|
||||||
|
toggle_bttn = getattr(child, "toggle_bttn", None)
|
||||||
|
toggle_bttn.disconnect(toggle_bttn.toggle_id)
|
||||||
|
|
||||||
|
self.list_box.remove(row)
|
||||||
|
box.destroy()
|
||||||
|
break
|
||||||
@@ -42,6 +42,9 @@
|
|||||||
"save_file_as": {
|
"save_file_as": {
|
||||||
"released": "<Control><Shift>s"
|
"released": "<Control><Shift>s"
|
||||||
},
|
},
|
||||||
|
"toggle_plugins_ui": {
|
||||||
|
"released": "<Control><Shift>p"
|
||||||
|
},
|
||||||
"focus_left_sibling": {
|
"focus_left_sibling": {
|
||||||
"released": "<Control>Page_Up"
|
"released": "<Control>Page_Up"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user