Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ff27fbdf6c | |||
| 619fae8a20 |
@@ -10,22 +10,22 @@ class Manifest:
|
||||
author: str = "John Doe"
|
||||
version: str = "0.0.1"
|
||||
support: str = ""
|
||||
pre_launch: bool = False
|
||||
requests: {} = {
|
||||
'pass_ui_objects': ["plugin_control_list"],
|
||||
'pass_events': True,
|
||||
'pass_events': "true",
|
||||
'bind_keys': []
|
||||
}
|
||||
pre_launch: bool = False
|
||||
```
|
||||
|
||||
|
||||
### Requests
|
||||
```
|
||||
requests: {} = {
|
||||
'pass_events': true, # If empty or not present will be ignored.
|
||||
"pass_ui_objects": [""], # Request reference to a UI component. Will be passed back as array to plugin.
|
||||
'pass_events': "true", # If empty or not present will be ignored.
|
||||
"pass_ui_objects": [""], # Request reference to a UI component. Will be passed back as array to plugin.
|
||||
'bind_keys': [f"{name}||send_message:<Control>f"],
|
||||
f"{name}||do_save:<Control>s"] # Bind keys with method and key pare using list. Must pass "name" like shown with delimiter to its right.
|
||||
f"{name}||do_save:<Control>s"] # Bind keys with method and key pare using list. Must pass "name" like shown with delimiter to its right.
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"support": "",
|
||||
"requests": {
|
||||
"ui_target": "plugin_control_list",
|
||||
"pass_events": true,
|
||||
"pass_events": "true",
|
||||
"bind_keys": ["Example Plugin||send_message:<Control>f"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"reportDuplicateImport": true,
|
||||
"executionEnvironments": [
|
||||
{
|
||||
"root": "./src/"
|
||||
"root": "./src/versions/solarfm-0.0.1/solarfm"
|
||||
}
|
||||
],
|
||||
"venvPath": ".",
|
||||
|
||||
@@ -57,10 +57,11 @@ builtins.settings_manager = SettingsManager()
|
||||
|
||||
settings_manager.load_settings()
|
||||
|
||||
builtins.settings = settings_manager.settings
|
||||
builtins.logger = Logger(
|
||||
settings_manager.path_manager.get_home_config_path(), \
|
||||
_ch_log_lvl = settings_manager.settings.debugging.ch_log_lvl, \
|
||||
_fh_log_lvl = settings_manager.settings.debugging.fh_log_lvl
|
||||
settings_manager.get_home_config_path(), \
|
||||
_ch_log_lvl = settings.debugging.ch_log_lvl, \
|
||||
_fh_log_lvl = settings.debugging.fh_log_lvl
|
||||
).get_logger()
|
||||
|
||||
builtins.threaded = threaded_wrapper
|
||||
|
||||
35
src/app.py
35
src/app.py
@@ -23,14 +23,13 @@ class Application:
|
||||
def __init__(self):
|
||||
super(Application, self).__init__()
|
||||
|
||||
if not settings_manager.is_trace_debug():
|
||||
self.load_ipc()
|
||||
|
||||
self.setup_debug_hook()
|
||||
|
||||
|
||||
def run(self):
|
||||
if not settings_manager.is_trace_debug():
|
||||
if not self.load_ipc():
|
||||
return
|
||||
|
||||
win = Window()
|
||||
win.start()
|
||||
|
||||
@@ -40,31 +39,23 @@ class Application:
|
||||
ipc_server = IPCServer()
|
||||
|
||||
self.ipc_realization_check(ipc_server)
|
||||
if ipc_server.is_ipc_alive:
|
||||
return True
|
||||
if not ipc_server.is_ipc_alive:
|
||||
for arg in unknownargs + [args.new_tab,]:
|
||||
if os.path.isfile(arg):
|
||||
message = f"FILE|{arg}"
|
||||
ipc_server.send_ipc_message(message)
|
||||
|
||||
logger.warning(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...")
|
||||
for arg in unknownargs + [args.new_tab,]:
|
||||
if os.path.isfile(arg):
|
||||
message = f"FILE|{arg}"
|
||||
ipc_server.send_ipc_message(message)
|
||||
|
||||
if os.path.isdir(arg):
|
||||
message = f"DIR|{arg}"
|
||||
ipc_server.send_ipc_message(message)
|
||||
|
||||
return False
|
||||
raise AppLaunchException(f"{APP_NAME} IPC Server Exists: Have sent path(s) to it and closing...")
|
||||
|
||||
def ipc_realization_check(self, ipc_server):
|
||||
try:
|
||||
ipc_server.create_ipc_listener()
|
||||
except (OSError, PermissionError) as e:
|
||||
logger.info(f"IPC listener creation failed: {e}, falling back to test message")
|
||||
ipc_server.send_test_ipc_message()
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected IPC setup error: {e}")
|
||||
except Exception:
|
||||
ipc_server.send_test_ipc_message()
|
||||
|
||||
with suppress(Exception):
|
||||
ipc_server.create_ipc_listener()
|
||||
|
||||
def setup_debug_hook(self):
|
||||
# Typically: ValueError: signal only works in main thread
|
||||
with suppress(ValueError):
|
||||
|
||||
@@ -16,6 +16,8 @@ class BaseContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(BaseContainer, self).__init__()
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
@@ -25,10 +27,8 @@ class BaseContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("base-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
self.ctx.add_class("base-container")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
@@ -38,12 +38,12 @@ class BaseContainer(Gtk.Box):
|
||||
event_system.subscribe("remove-transparency", self._remove_transparency)
|
||||
|
||||
def _load_widgets(self):
|
||||
self.add( HeaderContainer() )
|
||||
self.add( BodyContainer() )
|
||||
self.add( FooterContainer() )
|
||||
self.add(HeaderContainer())
|
||||
self.add(BodyContainer())
|
||||
self.add(FooterContainer())
|
||||
|
||||
def _update_transparency(self):
|
||||
self.ctx.add_class(f"mw_transparency_{settings_manager.settings.theming.transparency}")
|
||||
self.ctx.add_class(f"mw_transparency_{settings.theming.transparency}")
|
||||
|
||||
def _remove_transparency(self):
|
||||
self.ctx.remove_class(f"mw_transparency_{settings_manager.settings.theming.transparency}")
|
||||
self.ctx.remove_class(f"mw_transparency_{settings.theming.transparency}")
|
||||
@@ -16,6 +16,8 @@ class BodyContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(BodyContainer, self).__init__()
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
@@ -25,10 +27,8 @@ class BodyContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("body-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
self.ctx.add_class("body-container")
|
||||
self.set_homogeneous(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
@@ -37,7 +37,8 @@ class BodyContainer(Gtk.Box):
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
self.add( LeftContainer() )
|
||||
self.add( CenterContainer() )
|
||||
self.add( RightContainer() )
|
||||
self.add(LeftContainer())
|
||||
self.add(CenterContainer())
|
||||
self.add(RightContainer())
|
||||
@@ -25,13 +25,14 @@ class CenterContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("center-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
|
||||
self.set_hexpand(True)
|
||||
self.set_vexpand(True)
|
||||
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("center-container")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
@@ -40,7 +41,7 @@ class CenterContainer(Gtk.Box):
|
||||
|
||||
def _load_widgets(self):
|
||||
glade_box = self._builder.get_object("glade_box")
|
||||
button = Gtk.Button(label = "Click Me!")
|
||||
button = Gtk.Button(label = "Click Me!")
|
||||
|
||||
button.connect("clicked", self._hello_world)
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Containers Package
|
||||
"""
|
||||
@@ -1,38 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ...widgets.code.tabs_widget import TabsWidget
|
||||
|
||||
from .editors_container import EditorsContainer
|
||||
|
||||
|
||||
|
||||
class CodeContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(CodeContainer, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
self.add( TabsWidget() )
|
||||
self.add( EditorsContainer() )
|
||||
@@ -1,38 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from ...widgets.separator_widget import Separator
|
||||
from ...widgets.code.miniview_widget import MiniViewWidget
|
||||
from .paned_editors_container import PanedEditorsContainer
|
||||
|
||||
|
||||
|
||||
class EditorsContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(EditorsContainer, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
...
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
self.add( Separator("separator_left") )
|
||||
self.add( PanedEditorsContainer() )
|
||||
self.add( Separator("separator_right") )
|
||||
self.add( MiniViewWidget() )
|
||||
@@ -1,69 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from ...widgets.code.view import SourceView
|
||||
|
||||
|
||||
|
||||
class PanedEditorsContainer(Gtk.Paned):
|
||||
def __init__(self):
|
||||
super(PanedEditorsContainer, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("paned-editors-container")
|
||||
|
||||
self.set_hexpand(True)
|
||||
self.set_vexpand(True)
|
||||
# self.set_homogeneous(True)
|
||||
self.set_wide_handle(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
self.map_id = self.connect("map", self._init_map)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
scrolled_win1 = Gtk.ScrolledWindow()
|
||||
scrolled_win2 = Gtk.ScrolledWindow()
|
||||
source_view1 = SourceView()
|
||||
source_view2 = SourceView()
|
||||
|
||||
source_view1.sibling_right = source_view2
|
||||
source_view2.sibling_left = source_view1
|
||||
|
||||
scrolled_win1.add( source_view1 )
|
||||
scrolled_win2.add( source_view2 )
|
||||
|
||||
self.add1(scrolled_win1)
|
||||
self.add2(scrolled_win2)
|
||||
|
||||
def _init_map(self, view):
|
||||
def _first_show_init():
|
||||
self.disconnect(self.map_id)
|
||||
del self.map_id
|
||||
|
||||
self._handle_first_show()
|
||||
|
||||
return False
|
||||
|
||||
GLib.timeout_add(200, _first_show_init)
|
||||
|
||||
def _handle_first_show(self):
|
||||
self.set_position(
|
||||
self.get_allocated_width() / 2
|
||||
)
|
||||
|
||||
@@ -6,7 +6,6 @@ gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from .code.code_container import CodeContainer
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +13,8 @@ class FooterContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(FooterContainer, self).__init__()
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
@@ -23,17 +24,18 @@ class FooterContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("footer-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
self.set_hexpand(True)
|
||||
|
||||
self.ctx.add_class("footer-container")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
self.add( CodeContainer() )
|
||||
...
|
||||
|
||||
@@ -15,6 +15,8 @@ class HeaderContainer(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(HeaderContainer, self).__init__()
|
||||
|
||||
self.ctx = self.get_style_context()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
@@ -24,18 +26,19 @@ class HeaderContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("header-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
self.set_hexpand(True)
|
||||
|
||||
self.ctx.add_class("header-container")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("tggl-top-main-menubar", self.tggl_top_main_menubar)
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
button = Gtk.Button(label = "Interactive Debug")
|
||||
button.connect("clicked", self._interactive_debug)
|
||||
|
||||
@@ -22,12 +22,13 @@ class LeftContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("left-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
|
||||
self.set_vexpand(True)
|
||||
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("left-container")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
|
||||
@@ -23,12 +23,13 @@ class RightContainer(Gtk.Box):
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.ctx = self.get_style_context()
|
||||
self.ctx.add_class("right-container")
|
||||
|
||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||
|
||||
self.set_vexpand(True)
|
||||
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("right-container")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
|
||||
logger.debug("_tggl_top_main_menubar > stub...")
|
||||
|
||||
def _load_glade_file(self):
|
||||
self.builder.add_from_file( settings_manager.path_manager.get_glade_file() )
|
||||
self.builder.add_from_file( settings_manager.get_glade_file() )
|
||||
self.builder.expose_object("main_window", self.window)
|
||||
|
||||
settings_manager.set_builder(self.builder)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Code Package
|
||||
"""
|
||||
@@ -1,34 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from . import commands
|
||||
|
||||
|
||||
|
||||
class CommandSystem:
|
||||
def __init__(self):
|
||||
super(CommandSystem, self).__init__()
|
||||
|
||||
self.data: list = ()
|
||||
|
||||
|
||||
def set_data(self, *args, **kwargs):
|
||||
self.data = (args, kwargs)
|
||||
|
||||
def exec(self, command: str) -> any:
|
||||
if not hasattr(commands, command): return
|
||||
method = getattr(commands, command)
|
||||
|
||||
args, kwargs = self.data
|
||||
if kwargs:
|
||||
return method.execute(*args, kwargs)
|
||||
else:
|
||||
return method.execute(*args)
|
||||
|
||||
def exec_with_args(self, command: str, args: list) -> any:
|
||||
if not hasattr(commands, command): return
|
||||
|
||||
method = getattr(commands, command)
|
||||
return method.execute(*args)
|
||||
@@ -1,16 +0,0 @@
|
||||
"""
|
||||
Commands Package
|
||||
"""
|
||||
|
||||
import pkgutil
|
||||
import importlib
|
||||
|
||||
__all__ = []
|
||||
|
||||
for loader, module_name, is_pkg in pkgutil.walk_packages(__path__):
|
||||
module = importlib.import_module(f"{__name__}.{module_name}")
|
||||
globals()[module_name] = module # Add module to package namespace
|
||||
__all__.append(module_name)
|
||||
|
||||
del pkgutil
|
||||
del importlib
|
||||
@@ -1,23 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Buffer Redo Command")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
undo_manager = buffer.get_undo_manager()
|
||||
|
||||
if undo_manager.can_redo():
|
||||
buffer.redo()
|
||||
@@ -1,23 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Buffer Undo Command")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
undo_manager = buffer.get_undo_manager()
|
||||
|
||||
if undo_manager.can_undo():
|
||||
buffer.undo()
|
||||
@@ -1,26 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Close File Command")
|
||||
buffer = view.get_buffer()
|
||||
|
||||
next_file = view.files_manager.remove_file(buffer)
|
||||
if not next_file:
|
||||
view.command.exec("new_file")
|
||||
else:
|
||||
view.set_buffer(next_file.buffer)
|
||||
|
||||
view.command.exec("update_info_bar")
|
||||
@@ -1,36 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Cut to Temp Buffer Command")
|
||||
|
||||
view.clear_temp_cut_buffer_delayed()
|
||||
|
||||
buffer = view.get_buffer()
|
||||
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||
start_itr = itr.copy()
|
||||
end_itr = itr.copy()
|
||||
start_line = itr.get_line() + 1
|
||||
start_char = itr.get_line_offset()
|
||||
|
||||
start_itr.backward_visible_line()
|
||||
start_itr.forward_line()
|
||||
end_itr.forward_line()
|
||||
|
||||
line_str = buffer.get_slice(start_itr, end_itr, True)
|
||||
view._cut_buffer += f"{line_str}"
|
||||
buffer.delete(start_itr, end_itr)
|
||||
|
||||
view.set_temp_cut_buffer_delayed()
|
||||
@@ -1,35 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
uri: str
|
||||
):
|
||||
logger.debug("DnD Load File To Buffer Command")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
file = view.files_manager.get_file(buffer)
|
||||
|
||||
if not file.ftype == "buffer":
|
||||
file = view.command.exec("new_file")
|
||||
|
||||
gfile = Gio.File.new_for_uri(uri)
|
||||
view.command.exec_with_args(
|
||||
"load_file",
|
||||
(view, gfile, file)
|
||||
)
|
||||
|
||||
has_focus = view.command.exec("has_focus")
|
||||
if has_focus:
|
||||
view.command.exec("update_info_bar")
|
||||
@@ -1,27 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from ..source_file import SourceFile
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
uris: list = []
|
||||
):
|
||||
logger.debug("DnD Load Files Command")
|
||||
for uri in uris:
|
||||
try:
|
||||
gfile = Gio.File.new_for_uri(uri)
|
||||
except Exception as e:
|
||||
gfile = Gio.File.new_for_path(uri)
|
||||
|
||||
view.command.exec_with_args("load_file", (view, gfile))
|
||||
@@ -1,53 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Duplicate Line Command")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
|
||||
if not buffer.get_has_selection():
|
||||
had_selection = False
|
||||
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||
start_itr = itr.copy()
|
||||
end_itr = itr.copy()
|
||||
start_line = itr.get_line() + 1
|
||||
start_char = itr.get_line_offset()
|
||||
else:
|
||||
had_selection = True
|
||||
start_itr, end_itr = buffer.get_selection_bounds()
|
||||
sline = start_itr.get_line()
|
||||
eline = end_itr.get_line()
|
||||
start_line = eline + 1
|
||||
start_char = start_itr.get_line_offset()
|
||||
end_char = end_itr.get_line_offset()
|
||||
range_line_size = eline - sline
|
||||
|
||||
start_itr.backward_visible_line()
|
||||
start_itr.forward_line()
|
||||
end_itr.forward_line()
|
||||
end_itr.backward_char()
|
||||
|
||||
line_str = buffer.get_slice(start_itr, end_itr, True)
|
||||
end_itr.forward_char()
|
||||
buffer.insert(end_itr, f"{line_str}\n", -1)
|
||||
|
||||
if not had_selection:
|
||||
new_itr = buffer.get_iter_at_line_offset(start_line, start_char)
|
||||
buffer.place_cursor(new_itr)
|
||||
else:
|
||||
new_itr = buffer.get_iter_at_line_offset(start_line, start_char)
|
||||
new_end_itr = buffer.get_iter_at_line_offset((start_line + range_line_size), end_char)
|
||||
buffer.select_range(new_itr, new_end_itr)
|
||||
@@ -1,19 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Focus Left Sibling Command")
|
||||
if not view.sibling_left: return
|
||||
view.sibling_left.grab_focus()
|
||||
@@ -1,19 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Focus Right Sibling Command")
|
||||
if not view.sibling_right: return
|
||||
view.sibling_right.grab_focus()
|
||||
@@ -1,20 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Get Current File Command")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
return view.files_manager.get_file(buffer)
|
||||
@@ -1,21 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Get Text Command")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
start_itr, end_itr = buffer.get_bounds()
|
||||
return buffer.get_text(start_itr, end_itr, True)
|
||||
@@ -1,31 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Go-To Command")
|
||||
|
||||
file = view.command.exec("get_current_file")
|
||||
gfile = file.get_location()
|
||||
uri = gfile.get_uri()
|
||||
|
||||
buffer = view.get_buffer()
|
||||
iter = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||
line = iter.get_line()
|
||||
offset = iter.get_line_offset()
|
||||
|
||||
event_system.emit(
|
||||
"textDocument/definition",
|
||||
(view, file.ftype, uri, line, offset,)
|
||||
)
|
||||
@@ -1,19 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Has Focus Command")
|
||||
ctx = view.get_parent().get_style_context()
|
||||
return ctx.has_class("source-view-focused")
|
||||
@@ -1,18 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Line Up Command")
|
||||
view.emit("move-lines", True)
|
||||
@@ -1,18 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Line Up Command")
|
||||
view.emit("move-lines", False)
|
||||
@@ -1,32 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from ..source_file import SourceFile
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
gfile: Gio.File,
|
||||
file: SourceFile = None,
|
||||
):
|
||||
logger.debug("Load File Command")
|
||||
if not file:
|
||||
file = view.files_manager.new()
|
||||
|
||||
file.load_path(gfile)
|
||||
|
||||
language = view.language_manager \
|
||||
.guess_language(file.fname, None)
|
||||
file.ftype = language
|
||||
|
||||
file.buffer.set_language(language)
|
||||
file.buffer.set_style_scheme(view.syntax_theme)
|
||||
@@ -1,42 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from ..source_file import SourceFile
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
):
|
||||
logger.debug("Load Start File(s) Command")
|
||||
|
||||
starting_files = settings_manager.get_starting_files()
|
||||
|
||||
if len(starting_files) == 0: return
|
||||
|
||||
file = starting_files.pop()
|
||||
file = file.replace("FILE|", "")
|
||||
gfile = Gio.File.new_for_path(file)
|
||||
buffer = view.get_buffer()
|
||||
file = view.files_manager.get_file(buffer)
|
||||
|
||||
view.command.exec_with_args(
|
||||
"load_file",
|
||||
(view, gfile, file)
|
||||
)
|
||||
|
||||
if len(starting_files) == 0: return
|
||||
|
||||
for file in starting_files:
|
||||
file = file.replace("FILE|", "")
|
||||
gfile = Gio.File.new_for_path(file)
|
||||
|
||||
view.command.exec_with_args("load_file", (view, gfile))
|
||||
@@ -1,32 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Move To Left Sibling Command")
|
||||
if not view.sibling_left: return
|
||||
|
||||
buffer = view.get_buffer()
|
||||
popped_file, next_file = view.files_manager.swap_file(buffer)
|
||||
|
||||
popped_file.remove_observer(view)
|
||||
popped_file.add_observer(view.sibling_left)
|
||||
view.sibling_left.set_buffer(buffer)
|
||||
view.sibling_left.grab_focus()
|
||||
|
||||
if next_file:
|
||||
next_file.add_observer(view)
|
||||
view.set_buffer(next_file.buffer)
|
||||
else:
|
||||
view.command.exec("new_file")
|
||||
@@ -1,32 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Move To Right Sibling Command")
|
||||
if not view.sibling_right: return
|
||||
|
||||
buffer = view.get_buffer()
|
||||
popped_file, next_file = view.files_manager.swap_file(buffer)
|
||||
|
||||
popped_file.remove_observer(view)
|
||||
popped_file.add_observer(view.sibling_right)
|
||||
view.sibling_right.set_buffer(buffer)
|
||||
view.sibling_right.grab_focus()
|
||||
|
||||
if next_file:
|
||||
next_file.add_observer(view)
|
||||
view.set_buffer(next_file.buffer)
|
||||
else:
|
||||
view.command.exec("new_file")
|
||||
@@ -1,33 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("New File Command")
|
||||
file = view.files_manager.new()
|
||||
language = view.language_manager \
|
||||
.guess_language("file.txt", None)
|
||||
|
||||
file.buffer.set_language(language)
|
||||
file.buffer.set_style_scheme(view.syntax_theme)
|
||||
|
||||
view.set_buffer(file.buffer)
|
||||
file.add_observer(view)
|
||||
|
||||
has_focus = view.command.exec("has_focus")
|
||||
if not has_focus: return file
|
||||
|
||||
view.command.exec("update_info_bar")
|
||||
return file
|
||||
@@ -1,33 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Open File(s) Command")
|
||||
gfiles = event_system.emit_and_await("open-files")
|
||||
if not gfiles: return
|
||||
|
||||
size = len(gfiles)
|
||||
for i, gfile in enumerate(gfiles):
|
||||
file = view.files_manager.new()
|
||||
view.command.exec_with_args("load_file", (view, gfile, file))
|
||||
|
||||
if i == (size - 1):
|
||||
buffer = view.get_buffer()
|
||||
_file = view.files_manager.get_file(buffer)
|
||||
_file.remove_observer(view)
|
||||
|
||||
view.set_buffer(file.buffer)
|
||||
file.add_observer(view)
|
||||
view.command.exec("update_info_bar")
|
||||
@@ -1,28 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Paste Temp Buffer Command")
|
||||
|
||||
view.clear_temp_cut_buffer_delayed()
|
||||
|
||||
buffer = view.get_buffer()
|
||||
itr = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||
insert_itr = itr.copy()
|
||||
|
||||
buffer.insert(insert_itr, view._cut_buffer, -1)
|
||||
|
||||
view.set_temp_cut_buffer_delayed()
|
||||
@@ -1,30 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Save File Command")
|
||||
buffer = view.get_buffer()
|
||||
file = view.files_manager.get_file(buffer)
|
||||
|
||||
if file.ftype == "buffer":
|
||||
file.save_as()
|
||||
language = view.language_manager \
|
||||
.guess_language(file.fname, None)
|
||||
file.ftype = language
|
||||
file.buffer.set_language(language)
|
||||
return
|
||||
|
||||
file.save()
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.info("Save File As Command")
|
||||
buffer = view.get_buffer()
|
||||
file = view.files_manager.get_file(buffer)
|
||||
|
||||
file.save_as()
|
||||
|
||||
language = view.language_manager \
|
||||
.guess_language(file.fname, None)
|
||||
file.ftype = language
|
||||
file.buffer.set_language(language)
|
||||
file.add_observer(view)
|
||||
view.exec_command("update_info_bar")
|
||||
@@ -1,36 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from ..source_file import SourceFile
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
file: SourceFile
|
||||
):
|
||||
logger.debug("Set Buffer Command")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
_file = view.files_manager.get_file(buffer)
|
||||
_file.remove_observer(view)
|
||||
|
||||
if not file:
|
||||
view.command.exec("new_file")
|
||||
return
|
||||
|
||||
view.set_buffer(file.buffer)
|
||||
file.add_observer(view)
|
||||
|
||||
has_focus = view.command.exec("has_focus")
|
||||
if has_focus:
|
||||
view.command.exec("update_info_bar")
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
language: str
|
||||
):
|
||||
logger.debug("Set Buffer Language Command")
|
||||
|
||||
buffer = editor.get_buffer()
|
||||
buffer.set_language(
|
||||
view.language_manager.get_language(language)
|
||||
)
|
||||
@@ -1,23 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
style: str
|
||||
):
|
||||
logger.debug("Set Buffer Style Command")
|
||||
|
||||
buffer = editor.get_buffer()
|
||||
buffer.set_style_scheme(
|
||||
view.style_scheme_manager.get_scheme(style)
|
||||
)
|
||||
@@ -1,26 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Set Focus Border Command")
|
||||
ctx = view.get_parent().get_style_context()
|
||||
ctx.add_class("source-view-focused")
|
||||
|
||||
if view.sibling_right:
|
||||
ctx = view.sibling_right.get_parent().get_style_context()
|
||||
elif view.sibling_left:
|
||||
ctx = view.sibling_left.get_parent().get_style_context()
|
||||
|
||||
ctx.remove_class("source-view-focused")
|
||||
@@ -1,27 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from libs.dto.code_event import CodeEvent
|
||||
|
||||
from ..source_file import SourceFile
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
):
|
||||
logger.debug("Set MiniView Command")
|
||||
event_system.emit("set-mini-view", (view,))
|
||||
|
||||
event = CodeEvent()
|
||||
event.etype = "focused_view_change"
|
||||
event.view = view
|
||||
view.notify_observers(event)
|
||||
@@ -1,18 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Show Completion Command")
|
||||
view.completion.request_completion()
|
||||
@@ -1,33 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from ..source_file import SourceFile
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View,
|
||||
):
|
||||
logger.debug("Update Info Bar Command")
|
||||
buffer = view.get_buffer()
|
||||
file = view.files_manager.get_file(buffer)
|
||||
|
||||
if not file: return
|
||||
|
||||
iter = buffer.get_iter_at_mark( buffer.get_insert() )
|
||||
line = iter.get_line() + 1
|
||||
column = iter.get_line_offset()
|
||||
ftype = file.ftype.get_id() if hasattr(file.ftype, "get_id") else file.ftype
|
||||
|
||||
event_system.emit(
|
||||
"set-info-labels",
|
||||
(file.fpath, f"{line}:{column}", ftype, file.encoding)
|
||||
)
|
||||
@@ -1,23 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Zoom In Command")
|
||||
|
||||
ctx = view.get_style_context()
|
||||
if view.zoom_level < 99:
|
||||
ctx.remove_class(f"px{view.zoom_level}")
|
||||
view.zoom_level += 1
|
||||
ctx.add_class(f"px{view.zoom_level}")
|
||||
@@ -1,23 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Zoom Out Command")
|
||||
|
||||
ctx = view.get_style_context()
|
||||
if view.zoom_level > 1:
|
||||
ctx.remove_class(f"px{view.zoom_level}")
|
||||
view.zoom_level -= 1
|
||||
ctx.add_class(f"px{view.zoom_level}")
|
||||
@@ -1,66 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from .completion_providers.example_completion_provider import ExampleCompletionProvider
|
||||
from .completion_providers.lsp_completion_provider import LSPCompletionProvider
|
||||
|
||||
|
||||
|
||||
class CompletionManager():
|
||||
def __init__(self):
|
||||
super(CompletionManager, self).__init__()
|
||||
|
||||
self._lsp_provider = LSPCompletionProvider()
|
||||
self._timeout_id = None
|
||||
|
||||
|
||||
def set_completer(self, completer):
|
||||
self._completor = completer
|
||||
|
||||
def request_completion(self):
|
||||
if self._timeout_id:
|
||||
GLib.source_remove(self._timeout_id)
|
||||
|
||||
self._timeout_id = GLib.timeout_add(
|
||||
800,
|
||||
self._process_request_completion
|
||||
)
|
||||
|
||||
def _process_request_completion(self):
|
||||
self._start_completion()
|
||||
|
||||
self._timeout_id = None
|
||||
return False
|
||||
|
||||
def _do_completion(self):
|
||||
if self._completor.get_providers():
|
||||
self._mach_completion()
|
||||
else:
|
||||
self._start_completion()
|
||||
|
||||
def _mach_completion(self):
|
||||
"""
|
||||
Note: Use IF providers were added to completion...
|
||||
"""
|
||||
self._completion.match(
|
||||
self._completion.create_context()
|
||||
)
|
||||
|
||||
def _start_completion(self):
|
||||
"""
|
||||
Note: Use IF NO providers have been added to completion...
|
||||
print("here")
|
||||
"""
|
||||
self._completor.start(
|
||||
[
|
||||
ExampleCompletionProvider(),
|
||||
self._lsp_provider
|
||||
],
|
||||
self._completor.create_context()
|
||||
)
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Custom Completion Providers Module
|
||||
"""
|
||||
@@ -1,84 +0,0 @@
|
||||
# Python imports
|
||||
import re
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import GObject
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class ExampleCompletionProvider(GObject.GObject, GtkSource.CompletionProvider):
|
||||
"""
|
||||
This is a custom Completion Example Provider.
|
||||
# NOTE: used information from here --> https://warroom.rsmus.com/do-that-auto-complete/
|
||||
"""
|
||||
__gtype_name__ = 'ExampleCompletionProvider'
|
||||
|
||||
def __init__(self):
|
||||
GObject.Object.__init__(self)
|
||||
|
||||
def do_get_name(self):
|
||||
""" Returns: a new string containing the name of the provider. """
|
||||
return 'Example Completion Provider'
|
||||
|
||||
def do_match(self, context):
|
||||
""" Get whether the provider match the context of completion detailed in context. """
|
||||
# NOTE: True for debugging but context needs to normally get checked for actual usage needs.
|
||||
# TODO: Fix me
|
||||
return True
|
||||
|
||||
def do_get_priority(self):
|
||||
""" Determin position in result list along other providor results. """
|
||||
return 1
|
||||
|
||||
# def do_get_activation(self):
|
||||
# """ The context for when a provider will show results """
|
||||
# return GtkSource.CompletionActivation.NONE
|
||||
# return GtkSource.CompletionActivation.USER_REQUESTED
|
||||
# return GtkSource.CompletionActivation.INTERACTIVE
|
||||
|
||||
def do_populate(self, context):
|
||||
"""
|
||||
In this instance, it will do 2 things:
|
||||
1) always provide Hello World! (Not ideal but an option so its in the example)
|
||||
2) Utilizes the Gtk.TextIter from the TextBuffer to determine if there is a jinja
|
||||
example of '{{ custom.' if so it will provide you with the options of foo and bar.
|
||||
If selected it will insert foo }} or bar }}, completing your syntax...
|
||||
|
||||
PLEASE NOTE the GtkTextIter Logic and regex are really rough and should be adjusted and tuned
|
||||
"""
|
||||
|
||||
proposals = [
|
||||
GtkSource.CompletionItem(label='Hello World!', text = 'Hello World!', icon = None, info = None) # NOTE: Always proposed...
|
||||
]
|
||||
|
||||
# Gtk Versions differ on get_iter responses...
|
||||
end_iter = context.get_iter()
|
||||
if not isinstance(end_iter, Gtk.TextIter):
|
||||
_, end_iter = context.get_iter()
|
||||
|
||||
if end_iter:
|
||||
buf = end_iter.get_buffer()
|
||||
mov_iter = end_iter.copy()
|
||||
if mov_iter.backward_search('{{', Gtk.TextSearchFlags.VISIBLE_ONLY):
|
||||
mov_iter, _ = mov_iter.backward_search('{{', Gtk.TextSearchFlags.VISIBLE_ONLY)
|
||||
left_text = buf.get_text(mov_iter, end_iter, True)
|
||||
else:
|
||||
left_text = ''
|
||||
|
||||
if re.match(r'.*\{\{\s*custom\.$', left_text):
|
||||
proposals.append(
|
||||
GtkSource.CompletionItem(label='foo', text='foo }}') # optionally proposed based on left search via regex
|
||||
)
|
||||
proposals.append(
|
||||
GtkSource.CompletionItem(label='bar', text='bar }}') # optionally proposed based on left search via regex
|
||||
)
|
||||
|
||||
context.add_proposals(self, proposals, True)
|
||||
@@ -1,137 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import GObject
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class LSPCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
|
||||
"""
|
||||
This code is an LSP code completion plugin for Newton.
|
||||
# NOTE: Some code pulled/referenced from here --> https://github.com/isamert/gedi
|
||||
"""
|
||||
__gtype_name__ = 'LSPProvider'
|
||||
|
||||
def __init__(self):
|
||||
GObject.Object.__init__(self)
|
||||
|
||||
self._icon_theme = Gtk.IconTheme.get_default()
|
||||
|
||||
self.lsp_data = None
|
||||
|
||||
|
||||
def pre_populate(self, context):
|
||||
...
|
||||
|
||||
def do_get_name(self):
|
||||
return "LSP Code Completion"
|
||||
|
||||
def get_iter_correctly(self, context):
|
||||
return context.get_iter()[1] if isinstance(context.get_iter(), tuple) else context.get_iter()
|
||||
|
||||
def do_match(self, context):
|
||||
iter = self.get_iter_correctly(context)
|
||||
iter.backward_char()
|
||||
|
||||
buffer = iter.get_buffer()
|
||||
if buffer.get_context_classes_at_iter(iter) != ['no-spell-check']:
|
||||
return False
|
||||
|
||||
ch = iter.get_char()
|
||||
# NOTE: Look to re-add or apply supprting logic to use spaces
|
||||
# As is it slows down the editor in certain contexts...
|
||||
# if not (ch in ('_', '.', ' ') or ch.isalnum()):
|
||||
if not (ch in ('_', '.') or ch.isalnum()):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def do_get_priority(self):
|
||||
return 5
|
||||
|
||||
def do_populate(self, context, items = []):
|
||||
# self.lsp_data
|
||||
proposals = []
|
||||
|
||||
comp_item = GtkSource.CompletionItem.new()
|
||||
comp_item.set_label("LSP Class")
|
||||
comp_item.set_text("LSP Code")
|
||||
# comp_item.set_icon(self.get_icon_for_type(completion.type))
|
||||
comp_item.set_info("A test LSP completion item...")
|
||||
|
||||
context.add_proposals(self, [comp_item], True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# def do_populate(self, context, items = []):
|
||||
# if hasattr(self._source_view, "completion_items"):
|
||||
# items = self._source_view.completion_items
|
||||
|
||||
# proposals = []
|
||||
# for item in items:
|
||||
# proposals.append( self.create_completion_item(item) )
|
||||
|
||||
# context.add_proposals(self, proposals, True)
|
||||
|
||||
# def get_icon_for_type(self, _type):
|
||||
# try:
|
||||
# return self._theme.load_icon(icon_names[_type.lower()], 16, 0)
|
||||
# except:
|
||||
# ...
|
||||
|
||||
# try:
|
||||
# return self._theme.load_icon(Gtk.STOCK_ADD, 16, 0)
|
||||
# except:
|
||||
# ...
|
||||
|
||||
# return None
|
||||
|
||||
# def create_completion_item(self, item):
|
||||
# comp_item = GtkSource.CompletionItem.new()
|
||||
# keys = item.keys()
|
||||
# comp_item.set_label(item["label"])
|
||||
|
||||
# if "insertText" in keys:
|
||||
# comp_item.set_text(item["insertText"])
|
||||
|
||||
# if "additionalTextEdits" in keys:
|
||||
# comp_item.additionalTextEdits = item["additionalTextEdits"]
|
||||
|
||||
# return comp_item
|
||||
|
||||
|
||||
# def create_completion_item(self, item):
|
||||
# comp_item = GtkSource.CompletionItem.new()
|
||||
# comp_item.set_label(item.label)
|
||||
|
||||
# if item.textEdit:
|
||||
# if isinstance(item.textEdit, dict):
|
||||
# comp_item.set_text(item.textEdit["newText"])
|
||||
# else:
|
||||
# comp_item.set_text(item.textEdit)
|
||||
# else:
|
||||
# comp_item.set_text(item.insertText)
|
||||
|
||||
# comp_item.set_icon( self.get_icon_for_type(item.kind) )
|
||||
# comp_item.set_info(item.documentation)
|
||||
|
||||
# return comp_item
|
||||
@@ -1,107 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import GObject
|
||||
|
||||
import jedi
|
||||
from jedi.api import Script
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
# FIXME: Find real icon names...
|
||||
icon_names = {
|
||||
'import': '',
|
||||
'module': '',
|
||||
'class': '',
|
||||
'function': '',
|
||||
'statement': '',
|
||||
'param': ''
|
||||
}
|
||||
|
||||
|
||||
class Jedi:
|
||||
def get_script(file, doc_text):
|
||||
return Script(code = doc_text, path = file)
|
||||
|
||||
|
||||
class PythonCompletionProvider(GObject.Object, GtkSource.CompletionProvider):
|
||||
"""
|
||||
This code is A python code completion plugin for Newton.
|
||||
# NOTE: Some code pulled/referenced from here --> https://github.com/isamert/gedi
|
||||
"""
|
||||
__gtype_name__ = 'PythonProvider'
|
||||
|
||||
def __init__(self, file):
|
||||
GObject.Object.__init__(self)
|
||||
self._theme = Gtk.IconTheme.get_default()
|
||||
self._file = file
|
||||
|
||||
def do_get_name(self):
|
||||
return "Python Code Completion"
|
||||
|
||||
def get_iter_correctly(self, context):
|
||||
return context.get_iter()[1] if isinstance(context.get_iter(), tuple) else context.get_iter()
|
||||
|
||||
def do_match(self, context):
|
||||
iter = self.get_iter_correctly(context)
|
||||
iter.backward_char()
|
||||
|
||||
buffer = iter.get_buffer()
|
||||
if buffer.get_context_classes_at_iter(iter) != ['no-spell-check']:
|
||||
return False
|
||||
|
||||
ch = iter.get_char()
|
||||
# NOTE: Look to re-add or apply supprting logic to use spaces
|
||||
# As is it slows down the editor in certain contexts...
|
||||
# if not (ch in ('_', '.', ' ') or ch.isalnum()):
|
||||
if not (ch in ('_', '.') or ch.isalnum()):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def do_get_priority(self):
|
||||
return 1
|
||||
|
||||
def do_get_activation(self):
|
||||
return GtkSource.CompletionActivation.INTERACTIVE
|
||||
|
||||
def do_populate(self, context):
|
||||
# TODO: Maybe convert async?
|
||||
it = self.get_iter_correctly(context)
|
||||
buffer = it.get_buffer()
|
||||
proposals = []
|
||||
|
||||
doc_text = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter(), False)
|
||||
iter_cursor = buffer.get_iter_at_mark(buffer.get_insert())
|
||||
linenum = iter_cursor.get_line() + 1
|
||||
charnum = iter_cursor.get_line_index()
|
||||
|
||||
def create_generator():
|
||||
for completion in Jedi.get_script(self._file, doc_text).complete(line = linenum, column = None, fuzzy = False):
|
||||
comp_item = GtkSource.CompletionItem.new()
|
||||
comp_item.set_label(completion.name)
|
||||
comp_item.set_text(completion.name)
|
||||
comp_item.set_icon(self.get_icon_for_type(completion.type))
|
||||
comp_item.set_info(completion.docstring())
|
||||
yield comp_item
|
||||
|
||||
for item in create_generator():
|
||||
proposals.append(item)
|
||||
|
||||
context.add_proposals(self, proposals, True)
|
||||
|
||||
def get_icon_for_type(self, _type):
|
||||
try:
|
||||
return self._theme.load_icon(icon_names[_type.lower()], 16, 0)
|
||||
except (KeyError, AttributeError, GObject.GError) as e:
|
||||
return self._theme.load_icon(Gtk.STOCK_ADD, 16, 0)
|
||||
except (GObject.GError, AttributeError) as e:
|
||||
return None
|
||||
@@ -1,103 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Pango
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class GeneralInfoWidget(Gtk.Box):
|
||||
""" docstring for StatusInfoWidget. """
|
||||
|
||||
def __init__(self):
|
||||
super(GeneralInfoWidget, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_margin_start(25)
|
||||
self.set_margin_end(25)
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("set-info-labels", self._set_info_labels)
|
||||
event_system.subscribe("set-path-label", self._set_path_label)
|
||||
event_system.subscribe("set-encoding-label", self._set_encoding_label)
|
||||
event_system.subscribe("set-line-char-label", self._set_line_char_label)
|
||||
event_system.subscribe("set-file-type-label", self._set_file_type_label)
|
||||
|
||||
|
||||
def _load_widgets(self):
|
||||
self.path_label = Gtk.Label(label = "...")
|
||||
self.line_char_label = Gtk.Label(label = "1:0")
|
||||
self.encoding_label = Gtk.Label(label = "utf-8")
|
||||
self.file_type_label = Gtk.Label(label = "buffer")
|
||||
|
||||
self.add(self.path_label)
|
||||
self.add(self.line_char_label)
|
||||
self.add(self.encoding_label)
|
||||
self.add(self.file_type_label)
|
||||
|
||||
self.path_label.set_hexpand(True)
|
||||
self.path_label.set_ellipsize(Pango.EllipsizeMode.START)
|
||||
self.path_label.set_single_line_mode(True)
|
||||
self.path_label.set_max_width_chars(48)
|
||||
|
||||
self.line_char_label.set_hexpand(True)
|
||||
self.encoding_label.set_hexpand(True)
|
||||
self.file_type_label.set_hexpand(True)
|
||||
|
||||
def _set_info_labels(
|
||||
self,
|
||||
path: Gio.File or str = None,
|
||||
line_char: str = None,
|
||||
file_type: str = None,
|
||||
encoding_type: str = None
|
||||
):
|
||||
self._set_path_label(path)
|
||||
self._set_line_char_label(line_char)
|
||||
self._set_file_type_label(file_type)
|
||||
self._set_encoding_label(encoding_type)
|
||||
|
||||
def _set_path_label(self, gfile: Gio.File or str = "..."):
|
||||
gfile = "" if not gfile else gfile
|
||||
|
||||
if isinstance(gfile, str):
|
||||
# path = gfile
|
||||
# path = "..." + path[-120: -1] if len(path) >= 123 else path
|
||||
# self.path_label.set_text( path )
|
||||
self.path_label.set_text( gfile )
|
||||
self.path_label.set_tooltip_text( gfile )
|
||||
else:
|
||||
self.path_label.set_text( gfile.get_path() )
|
||||
self.path_label.set_tooltip_text( gfile.get_path() )
|
||||
|
||||
def _set_line_char_label(self, line_char = "1:1"):
|
||||
line_char = "1:1" if not line_char else line_char
|
||||
|
||||
self.line_char_label.set_text(line_char)
|
||||
|
||||
def _set_file_type_label(self, file_type = "buffer"):
|
||||
file_type = "buffer" if not file_type else file_type
|
||||
|
||||
self.file_type_label.set_text(file_type)
|
||||
|
||||
def _set_encoding_label(self, encoding_type = "utf-8"):
|
||||
encoding_type = "utf-8" if not encoding_type else encoding_type
|
||||
|
||||
self.encoding_label.set_text(encoding_type)
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def execute(
|
||||
view: GtkSource.View = None
|
||||
):
|
||||
logger.debug("Get File Type Command")
|
||||
|
||||
buffer = view.get_buffer()
|
||||
file = view.files_manager.get_file(buffer)
|
||||
return file.ftype
|
||||
@@ -1,127 +0,0 @@
|
||||
# Python imports
|
||||
import copy
|
||||
import json
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gdk', '3.0')
|
||||
from gi.repository import Gdk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class NoKeyState:
|
||||
held: dict = {}
|
||||
released: dict = {}
|
||||
|
||||
class CtrlKeyState:
|
||||
held: dict = {}
|
||||
released: dict = {}
|
||||
|
||||
class ShiftKeyState:
|
||||
held: dict = {}
|
||||
released: dict = {}
|
||||
|
||||
class AltKeyState:
|
||||
held: dict = {}
|
||||
released: dict = {}
|
||||
|
||||
class CtrlShiftKeyState:
|
||||
held: dict = {}
|
||||
released: dict = {}
|
||||
|
||||
class CtrlAltKeyState:
|
||||
held: dict = {}
|
||||
released: dict = {}
|
||||
|
||||
class AltShiftKeyState:
|
||||
held: dict = {}
|
||||
released: dict = {}
|
||||
|
||||
class CtrlShiftAltKeyState:
|
||||
held: dict = {}
|
||||
released: dict = {}
|
||||
|
||||
|
||||
|
||||
class KeyMapper:
|
||||
def __init__(self):
|
||||
super(KeyMapper, self).__init__()
|
||||
|
||||
self.state = NoKeyState
|
||||
self._map = {
|
||||
NoKeyState: NoKeyState(),
|
||||
NoKeyState | CtrlKeyState : CtrlKeyState(),
|
||||
NoKeyState | ShiftKeyState: ShiftKeyState(),
|
||||
NoKeyState | AltKeyState : AltKeyState(),
|
||||
NoKeyState | CtrlKeyState | ShiftKeyState : CtrlShiftKeyState(),
|
||||
NoKeyState | CtrlKeyState | AltKeyState : CtrlAltKeyState(),
|
||||
NoKeyState | AltKeyState | ShiftKeyState : AltShiftKeyState(),
|
||||
NoKeyState | CtrlKeyState | ShiftKeyState | AltKeyState: CtrlShiftAltKeyState(),
|
||||
}
|
||||
|
||||
self.load_map()
|
||||
|
||||
|
||||
def load_map(self):
|
||||
self.states = copy.deepcopy(self._map)
|
||||
bindings_file = f"{settings_manager.path_manager.get_home_config_path()}/code-key-bindings.json"
|
||||
|
||||
with open(bindings_file, 'r') as f:
|
||||
data = json.load(f)["keybindings"]
|
||||
|
||||
for command in data:
|
||||
press_state = "held" if "held" in data[command] else "released"
|
||||
keyname = data[command][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()
|
||||
|
||||
getattr(self.states[state], press_state)[keyname] = command
|
||||
|
||||
def re_map(self):
|
||||
self.states = copy.deepcopy(self._map)
|
||||
|
||||
def _key_press_event(self, eve):
|
||||
keyname = Gdk.keyval_name(eve.keyval).lower()
|
||||
|
||||
self._set_key_state(eve)
|
||||
if keyname in self.states[self.state].held:
|
||||
return self.states[self.state].held[keyname]
|
||||
|
||||
def _key_release_event(self, eve):
|
||||
keyname = Gdk.keyval_name(eve.keyval).lower()
|
||||
|
||||
self._set_key_state(eve)
|
||||
if keyname in self.states[self.state].released:
|
||||
return self.states[self.state].released[keyname]
|
||||
|
||||
def _set_key_state(self, eve):
|
||||
modifiers = Gdk.ModifierType(eve.get_state() & ~Gdk.ModifierType.LOCK_MASK)
|
||||
is_control = True if modifiers & Gdk.ModifierType.CONTROL_MASK else False
|
||||
is_shift = True if modifiers & Gdk.ModifierType.SHIFT_MASK else False
|
||||
|
||||
try:
|
||||
is_alt = True if modifiers & Gdk.ModifierType.ALT_MASK else False
|
||||
except Exception:
|
||||
is_alt = True if modifiers & Gdk.ModifierType.MOD1_MASK else False
|
||||
|
||||
self.state = NoKeyState
|
||||
if is_control:
|
||||
self.state = self.state | CtrlKeyState
|
||||
if is_shift:
|
||||
self.state = self.state | ShiftKeyState
|
||||
if is_alt:
|
||||
self.state = self.state | AltKeyState
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
from gi.repository.GtkSource import Map
|
||||
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class MiniViewWidget(Map):
|
||||
def __init__(self):
|
||||
super(MiniViewWidget, self).__init__()
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_hexpand(False)
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("mini-view")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe(f"set-mini-view", self.set_smini_view)
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
def set_smini_view(self, source_view):
|
||||
self.set_view(source_view)
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Code Mixins Package
|
||||
"""
|
||||
@@ -1,40 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class SourceViewDnDMixin:
|
||||
|
||||
def _set_up_dnd(self):
|
||||
PLAIN_TEXT_TARGET_TYPE = 70
|
||||
URI_TARGET_TYPE = 80
|
||||
text_target = Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags(0), PLAIN_TEXT_TARGET_TYPE)
|
||||
uri_target = Gtk.TargetEntry.new('text/uri-list', Gtk.TargetFlags(0), URI_TARGET_TYPE)
|
||||
targets = [ text_target, uri_target ]
|
||||
|
||||
self.drag_dest_set_target_list(targets)
|
||||
|
||||
def _on_drag_data_received(self, widget, drag_context, x, y, data, info, time):
|
||||
if info == 70: return
|
||||
|
||||
if info == 80:
|
||||
uris = data.get_uris()
|
||||
|
||||
if len(uris) == 0:
|
||||
uris = data.get_text().split("\n")
|
||||
|
||||
self._on_uri_data_received(uris)
|
||||
|
||||
def _on_uri_data_received(self, uris: []):
|
||||
uri = uris.pop(0)
|
||||
self.command.exec_with_args("dnd_load_file_to_buffer", (self, uri))
|
||||
|
||||
if len(uris) == 0: return
|
||||
|
||||
self.command.exec_with_args("dnd_load_files", (self, uris))
|
||||
@@ -1,63 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.dto.code_event import CodeEvent
|
||||
|
||||
|
||||
|
||||
class SourceViewEventsMixin:
|
||||
def _focus_in_event(self, view, eve):
|
||||
self.command.exec("set_miniview")
|
||||
self.command.exec("set_focus_border")
|
||||
self.command.exec("update_info_bar")
|
||||
|
||||
def _move_cursor(self, view, step, count, extend_selection):
|
||||
self.command.exec("update_info_bar")
|
||||
|
||||
def _button_press_event(self, view, eve):
|
||||
self.command.exec("update_info_bar")
|
||||
|
||||
def _button_release_event(self, view, eve):
|
||||
self.command.exec("update_info_bar")
|
||||
|
||||
def _key_press_event(self, view, eve):
|
||||
command = self.key_mapper._key_press_event(eve)
|
||||
if not command: return False
|
||||
|
||||
self.command.exec(command)
|
||||
return True
|
||||
|
||||
def _key_release_event(self, view, eve):
|
||||
command = self.key_mapper._key_release_event(eve)
|
||||
if not command: return False
|
||||
|
||||
self.command.exec(command)
|
||||
return True
|
||||
|
||||
def notification(self, event: CodeEvent):
|
||||
if not hasattr(self, "command"): return
|
||||
|
||||
has_focus = self.command.exec("has_focus")
|
||||
if not has_focus and not event.ignore_focus: return
|
||||
|
||||
match event.etype:
|
||||
case "removed_file":
|
||||
logger.debug("SourceFileManager.remove_file")
|
||||
if not event.file.buffer == self.get_buffer(): return
|
||||
self.command.exec_with_args("set_buffer", (self, event.next_file))
|
||||
return
|
||||
case "changed":
|
||||
logger.debug("SourceFile._changed")
|
||||
case "modified_changed":
|
||||
logger.debug("SourceFile._modified_changed")
|
||||
case "insert_text":
|
||||
logger.debug("SourceFile._insert_text")
|
||||
case "mark_set":
|
||||
# logger.debug("SourceFile._mark_set")
|
||||
...
|
||||
case _:
|
||||
...
|
||||
|
||||
self.command.exec("update_info_bar")
|
||||
@@ -1,40 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('GtkSource', '4')
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class SourceBuffer(GtkSource.Buffer):
|
||||
def __init__(self):
|
||||
super(SourceBuffer, self).__init__()
|
||||
|
||||
self._handler_ids = []
|
||||
|
||||
|
||||
def set_signals(
|
||||
self,
|
||||
_changed,
|
||||
_mark_set,
|
||||
_insert_text,
|
||||
_modified_changed,
|
||||
):
|
||||
|
||||
self._handler_ids = [
|
||||
self.connect("changed", _changed),
|
||||
self.connect("mark-set", _mark_set),
|
||||
self.connect("insert-text", _insert_text),
|
||||
self.connect("modified-changed", _modified_changed)
|
||||
]
|
||||
|
||||
def clear_signals(self):
|
||||
for handle_id in self._handler_ids:
|
||||
self.disconnect(handle_id)
|
||||
|
||||
def __del__(self):
|
||||
for handle_id in self._handler_ids:
|
||||
self.disconnect(handle_id)
|
||||
@@ -1,137 +0,0 @@
|
||||
# Python imports
|
||||
import os
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GtkSource
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from libs.mixins.observable_mixin import ObservableMixin
|
||||
from libs.dto.code_event import CodeEvent
|
||||
|
||||
from .source_buffer import SourceBuffer
|
||||
|
||||
|
||||
|
||||
class SourceFile(GtkSource.File, ObservableMixin):
|
||||
def __init__(self):
|
||||
super(SourceFile, self).__init__()
|
||||
|
||||
self.observers = []
|
||||
|
||||
self.encoding: str = "UTF-8"
|
||||
self.fname: str = "buffer"
|
||||
self.fpath: str = "buffer"
|
||||
self.ftype: str = "buffer"
|
||||
|
||||
self.buffer: SourceBuffer = SourceBuffer()
|
||||
|
||||
self._set_signals()
|
||||
|
||||
|
||||
def _set_signals(self):
|
||||
self.buffer.set_signals(
|
||||
self._changed,
|
||||
self._mark_set,
|
||||
self._insert_text,
|
||||
self._modified_changed
|
||||
)
|
||||
|
||||
|
||||
def _insert_text(self, buffer: SourceBuffer, location: Gtk.TextIter,
|
||||
text: str, length: int
|
||||
):
|
||||
event = CodeEvent()
|
||||
event.etype = "insert_text"
|
||||
event.file = self
|
||||
event.buffer = buffer
|
||||
|
||||
self.notify_observers(event)
|
||||
|
||||
def _changed(self, buffer: SourceBuffer):
|
||||
event = CodeEvent()
|
||||
event.etype = "changed"
|
||||
event.file = self
|
||||
event.buffer = buffer
|
||||
|
||||
self.notify_observers(event)
|
||||
|
||||
def _mark_set(self, buffer: SourceBuffer, location: Gtk.TextIter,
|
||||
mark: Gtk.TextMark
|
||||
):
|
||||
# event = CodeEvent()
|
||||
# event.etype = "mark_set"
|
||||
# event.file = self
|
||||
# event.buffer = buffer
|
||||
|
||||
# self.notify_observers(event)
|
||||
...
|
||||
|
||||
def _modified_changed(self, buffer: SourceBuffer):
|
||||
event = CodeEvent()
|
||||
event.etype = "modified_changed"
|
||||
event.file = self
|
||||
event.buffer = buffer
|
||||
|
||||
self.notify_observers(event)
|
||||
|
||||
|
||||
def _write_file(self, gfile: Gio.File):
|
||||
if not gfile: return
|
||||
|
||||
with open(gfile.get_path(), 'w') as f:
|
||||
start_itr, end_itr = self.buffer.get_bounds()
|
||||
text = self.buffer.get_text(start_itr, end_itr, True)
|
||||
|
||||
f.write(text)
|
||||
|
||||
return gfile
|
||||
|
||||
|
||||
def load_path(self, gfile: Gio.File):
|
||||
if not gfile: return
|
||||
|
||||
self.set_path(gfile)
|
||||
data = gfile.load_bytes()[0].get_data().decode("UTF-8")
|
||||
undo_manager = self.buffer.get_undo_manager()
|
||||
|
||||
undo_manager.begin_not_undoable_action()
|
||||
self.buffer.insert_at_cursor(data)
|
||||
undo_manager.end_not_undoable_action()
|
||||
|
||||
def set_path(self, gfile: Gio.File):
|
||||
if not gfile: return
|
||||
self.set_location(gfile)
|
||||
|
||||
self.fpath = gfile.get_path()
|
||||
self.fname = gfile.get_basename()
|
||||
|
||||
event = CodeEvent()
|
||||
event.etype = "set_path"
|
||||
event.file = self
|
||||
|
||||
self.notify_observers(event)
|
||||
|
||||
def save(self):
|
||||
self._write_file( self.get_location() )
|
||||
|
||||
def save_as(self):
|
||||
file = event_system.emit_and_await("save-file-dialog")
|
||||
if not file: return
|
||||
|
||||
self._write_file(file)
|
||||
self.set_path(file)
|
||||
|
||||
return file
|
||||
|
||||
def close(self):
|
||||
self.observers.clear()
|
||||
|
||||
del self.observers
|
||||
del self.buffer
|
||||
@@ -1,106 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.mixins.observable_mixin import ObservableMixin
|
||||
from libs.singleton import Singleton
|
||||
from libs.dto.code_event import CodeEvent
|
||||
|
||||
from .source_file import SourceFile
|
||||
from .source_buffer import SourceBuffer
|
||||
|
||||
|
||||
|
||||
class SourceFilesManager(Singleton, list, ObservableMixin):
|
||||
def __init__(self):
|
||||
super(SourceFilesManager, self).__init__()
|
||||
|
||||
self.observers = []
|
||||
|
||||
|
||||
def new(self):
|
||||
file = SourceFile()
|
||||
self.append(file)
|
||||
return file
|
||||
|
||||
def append(self, file: SourceFile):
|
||||
if not file: return
|
||||
super().append(file)
|
||||
|
||||
event = CodeEvent()
|
||||
event.etype = "appended_file"
|
||||
event.file = file
|
||||
|
||||
self.notify_observers(event)
|
||||
|
||||
def get_file(self, buffer: SourceBuffer):
|
||||
if not buffer: return
|
||||
|
||||
for file in self:
|
||||
if not buffer == file.buffer: continue
|
||||
return file
|
||||
|
||||
def pop_file(self, buffer: SourceBuffer):
|
||||
if not buffer: return
|
||||
|
||||
for i, file in enumerate(self):
|
||||
if not buffer == file.buffer: continue
|
||||
|
||||
j = self.next_index(i)
|
||||
next_file = self[j] if not j == -1 else None
|
||||
popped_file = self.pop(i)
|
||||
event = CodeEvent()
|
||||
event.etype = "popped_file"
|
||||
event.file = popped_file
|
||||
event.next_file = next_file
|
||||
|
||||
self.notify_observers(event)
|
||||
|
||||
return popped_file, next_file
|
||||
|
||||
def swap_file(self, buffer: SourceBuffer):
|
||||
if not buffer: return
|
||||
|
||||
for i, file in enumerate(self):
|
||||
if not buffer == file.buffer: continue
|
||||
|
||||
j = self.next_index(i)
|
||||
next_file = self[j]
|
||||
swapped_file = self[j] if not j == -1 else None
|
||||
|
||||
return swapped_file, next_file
|
||||
|
||||
def remove_file(self, buffer: SourceBuffer):
|
||||
if not buffer: return
|
||||
|
||||
for i, file in enumerate(self):
|
||||
if not buffer == file.buffer: continue
|
||||
|
||||
j = self.next_index(i)
|
||||
next_file = self[j] if not j == -1 else None
|
||||
event = CodeEvent()
|
||||
event.etype = "removed_file"
|
||||
event.ignore_focus = True
|
||||
event.file = file
|
||||
event.next_file = next_file
|
||||
self.notify_observers(event)
|
||||
|
||||
self.remove(file)
|
||||
file.close()
|
||||
|
||||
return next_file
|
||||
|
||||
def next_index(self, i):
|
||||
size = len(self)
|
||||
|
||||
if (i == 0) & (size >= 2):
|
||||
j = i + 1
|
||||
elif (i == (size - 1)) & (size >= 2):
|
||||
j = i - 1
|
||||
elif (size - 1) == 0:
|
||||
j = -1
|
||||
else:
|
||||
j = i + 1
|
||||
|
||||
return j
|
||||
@@ -1,61 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class TabWidget(Gtk.Box):
|
||||
def __init__(self):
|
||||
super(TabWidget, self).__init__()
|
||||
|
||||
self.file = None
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
self.show_all()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("tab-widget")
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
self._label_eve_box = Gtk.EventBox()
|
||||
self.label = Gtk.Label(label = "")
|
||||
self.close_btn = Gtk.Button(label = "X")
|
||||
|
||||
ctx = self.label.get_style_context()
|
||||
ctx.add_class("tab-label")
|
||||
ctx = self.close_btn.get_style_context()
|
||||
ctx.add_class("tab-close-bttn")
|
||||
|
||||
self.label.set_hexpand(True)
|
||||
|
||||
self._label_eve_box.add(self.label)
|
||||
self.add(self._label_eve_box)
|
||||
self.add(self.close_btn)
|
||||
|
||||
def clear_signals_and_data(self):
|
||||
del self.file
|
||||
self._label_eve_box.disconnect(self._label_eve_box_id)
|
||||
self.close_btn.disconnect(self.close_btn_id)
|
||||
|
||||
def set_select_signal(self, callback):
|
||||
self._label_eve_box_id = self._label_eve_box.connect('button-release-event', callback, self.file)
|
||||
|
||||
def set_close_signal(self, callback):
|
||||
self.close_btn_id = self.close_btn.connect('button-release-event', callback, self.file)
|
||||
@@ -1,107 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
from libs.dto.code_event import CodeEvent
|
||||
|
||||
from .view import SourceView
|
||||
from .source_files_manager import SourceFilesManager
|
||||
from .source_file import SourceFile
|
||||
|
||||
from .tab_widget import TabWidget
|
||||
|
||||
|
||||
|
||||
class TabsWidget(Gtk.ScrolledWindow):
|
||||
def __init__(self):
|
||||
super(TabsWidget, self).__init__()
|
||||
|
||||
self.active_view: SourceView = None
|
||||
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_overlay_scrolling(False)
|
||||
|
||||
def _setup_signals(self):
|
||||
event_system.subscribe("register-view-to-tabs-widget", self._register_view_to_tabs_widget)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
self.files_manager: SourceFilesManager = SourceFilesManager()
|
||||
self.files_manager.add_observer(self)
|
||||
|
||||
def _load_widgets(self):
|
||||
self.viewport = Gtk.Viewport()
|
||||
self.tabs = Gtk.ButtonBox()
|
||||
|
||||
self.tabs.set_layout(Gtk.ButtonBoxStyle.CENTER)
|
||||
|
||||
self.viewport.add(self.tabs)
|
||||
self.add(self.viewport)
|
||||
|
||||
def _register_view_to_tabs_widget(self, view: SourceView):
|
||||
view.add_observer(self)
|
||||
view.set_files_manager(self.files_manager)
|
||||
|
||||
def notification(self, event: CodeEvent):
|
||||
match event.etype:
|
||||
case "focused_view_change":
|
||||
logger.debug("SourceView.focused_view_change")
|
||||
self.active_view = event.view
|
||||
case "appended_file":
|
||||
logger.debug("SourceFilesManager.appended")
|
||||
self.add_tab(event)
|
||||
case "popped_file":
|
||||
logger.debug("SourceFilesManager.pop_file")
|
||||
case "removed_file":
|
||||
logger.debug("SourceFilesManager.remove_file")
|
||||
self.remove_tab(event)
|
||||
case "set_path":
|
||||
logger.debug("SourceFile.set_path")
|
||||
self.update_tab_label(event)
|
||||
case _:
|
||||
...
|
||||
|
||||
def add_tab(self, event: CodeEvent):
|
||||
tab = TabWidget()
|
||||
tab.file = event.file
|
||||
|
||||
tab.label.set_label(event.file.fname)
|
||||
event.file.add_observer(self)
|
||||
|
||||
def select_signal(widget, eve, file):
|
||||
self.active_view.command.exec_with_args("set_buffer", (self.active_view, file))
|
||||
|
||||
def close_signal(widget, eve, file):
|
||||
self.files_manager.remove_file(file.buffer)
|
||||
|
||||
tab.set_select_signal(select_signal)
|
||||
tab.set_close_signal(close_signal)
|
||||
|
||||
self.tabs.add(tab)
|
||||
|
||||
def remove_tab(self, event: CodeEvent):
|
||||
for child in self.tabs.get_children():
|
||||
if not child.file == event.file: continue
|
||||
|
||||
child.file.remove_observer(self)
|
||||
self.tabs.remove(child)
|
||||
child.clear_signals_and_data()
|
||||
del child
|
||||
|
||||
return
|
||||
|
||||
def update_tab_label(self, event: CodeEvent):
|
||||
for tab in self.tabs.get_children():
|
||||
if not tab.file == event.file: continue
|
||||
tab.label.set_label(event.file.fname)
|
||||
|
||||
return
|
||||
@@ -1,130 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('GtkSource', '4')
|
||||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import GtkSource
|
||||
|
||||
# Application imports
|
||||
from libs.mixins.observable_mixin import ObservableMixin
|
||||
|
||||
from .mixins.source_view_events_mixin import SourceViewEventsMixin
|
||||
from .mixins.source_view_dnd_mixin import SourceViewDnDMixin
|
||||
|
||||
from .source_files_manager import SourceFilesManager
|
||||
from .completion_manager import CompletionManager
|
||||
from .command_system import CommandSystem
|
||||
from .key_mapper import KeyMapper
|
||||
|
||||
|
||||
|
||||
class SourceView(GtkSource.View, ObservableMixin, SourceViewEventsMixin, SourceViewDnDMixin):
|
||||
def __init__(self):
|
||||
super(SourceView, self).__init__()
|
||||
|
||||
self.observers = []
|
||||
self._cut_temp_timeout_id = None
|
||||
self._cut_buffer = ""
|
||||
|
||||
self.sibling_right = None
|
||||
self.sibling_left = None
|
||||
|
||||
self._setup_styles()
|
||||
self._setup_signals()
|
||||
self._subscribe_to_events()
|
||||
self._load_widgets()
|
||||
|
||||
|
||||
def _setup_styles(self):
|
||||
self.zoom_level = settings_manager.settings.theming.default_zoom
|
||||
ctx = self.get_style_context()
|
||||
|
||||
ctx.add_class("source-view")
|
||||
ctx.add_class(f"px{self.zoom_level}")
|
||||
|
||||
self.set_vexpand(True)
|
||||
self.set_bottom_margin(800)
|
||||
|
||||
self.set_show_line_marks(True)
|
||||
self.set_show_line_numbers(True)
|
||||
self.set_smart_backspace(True)
|
||||
self.set_indent_on_tab(True)
|
||||
self.set_insert_spaces_instead_of_tabs(True)
|
||||
self.set_auto_indent(True)
|
||||
self.set_monospace(True)
|
||||
self.set_tab_width(4)
|
||||
self.set_show_right_margin(True)
|
||||
self.set_right_margin_position(80)
|
||||
self.set_background_pattern(0) # 0 = None, 1 = Grid
|
||||
self.set_highlight_current_line(True)
|
||||
|
||||
def _setup_signals(self):
|
||||
self.map_id = self.connect("map", self._init_map)
|
||||
|
||||
self.connect("focus-in-event", self._focus_in_event)
|
||||
self.connect("drag-data-received", self._on_drag_data_received)
|
||||
self.connect("move-cursor", self._move_cursor)
|
||||
self.connect("key-press-event", self._key_press_event)
|
||||
self.connect("key-release-event", self._key_release_event)
|
||||
self.connect("button-press-event", self._button_press_event)
|
||||
self.connect("button-release-event", self._button_release_event)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
self._set_up_dnd()
|
||||
event_system.emit("register-view-to-tabs-widget", (self,))
|
||||
|
||||
def _init_map(self, view):
|
||||
self.disconnect(self.map_id)
|
||||
del self.map_id
|
||||
|
||||
GLib.idle_add(self._init_show)
|
||||
|
||||
def _init_show(self):
|
||||
self.language_manager = GtkSource.LanguageManager()
|
||||
self.style_scheme_manager = GtkSource.StyleSchemeManager()
|
||||
|
||||
self.key_mapper = KeyMapper()
|
||||
self.command = CommandSystem()
|
||||
self.completion = CompletionManager()
|
||||
|
||||
self.command.set_data(self)
|
||||
self.completion.set_completer( self.get_completion() )
|
||||
|
||||
self.style_scheme_manager.append_search_path(
|
||||
f"{settings_manager.path_manager.get_home_config_path()}/code_styles"
|
||||
)
|
||||
self.syntax_theme = self.style_scheme_manager.get_scheme(
|
||||
f"{settings_manager.settings.theming.syntax_theme}"
|
||||
)
|
||||
|
||||
self.command.exec("new_file")
|
||||
|
||||
if not self.sibling_right: return
|
||||
|
||||
self.grab_focus()
|
||||
self.command.exec("load_start_files")
|
||||
|
||||
return False
|
||||
|
||||
def set_files_manager(self, files_manager: SourceFilesManager):
|
||||
self.files_manager = files_manager
|
||||
self.files_manager.add_observer(self)
|
||||
|
||||
def clear_temp_cut_buffer_delayed(self):
|
||||
if self._cut_temp_timeout_id:
|
||||
GLib.source_remove(self._cut_temp_timeout_id)
|
||||
|
||||
def set_temp_cut_buffer_delayed(self):
|
||||
def clear_temp_buffer():
|
||||
self._cut_buffer = ""
|
||||
self._cut_temp_timeout_id = None
|
||||
return False
|
||||
|
||||
self._cut_temp_timeout_id = GLib.timeout_add(15000, clear_temp_buffer)
|
||||
@@ -35,7 +35,7 @@ class OpenFilesButton(Gtk.Button):
|
||||
self.connect("button-release-event", self._open_files)
|
||||
|
||||
def _subscribe_to_events(self):
|
||||
event_system.subscribe("open-files", self._open_files)
|
||||
event_system.subscribe("open_files", self._open_files)
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
|
||||
@@ -38,11 +38,11 @@ class TransparencyScale(Gtk.Scale):
|
||||
adjust = self.get_adjustment()
|
||||
adjust.set_lower(0)
|
||||
adjust.set_upper(100)
|
||||
adjust.set_value(settings_manager.settings.theming.transparency)
|
||||
adjust.set_value(settings.theming.transparency)
|
||||
adjust.set_step_increment(1.0)
|
||||
|
||||
def _update_transparency(self, range):
|
||||
event_system.emit("remove-transparency")
|
||||
tp = int(range.get_value())
|
||||
settings_manager.settings.theming.transparency = tp
|
||||
settings.theming.transparency = tp
|
||||
event_system.emit("update-transparency")
|
||||
@@ -1,37 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class Separator(Gtk.Separator):
|
||||
def __init__(self, id: str = None, ORIENTATION: int = 0):
|
||||
super(Separator, self).__init__()
|
||||
|
||||
builder = settings_manager.get_builder()
|
||||
if id:
|
||||
builder.expose_object(id, self)
|
||||
|
||||
self.ORIENTATION = ORIENTATION
|
||||
self._setup_styling()
|
||||
self._setup_signals()
|
||||
self._load_widgets()
|
||||
|
||||
self.show()
|
||||
|
||||
|
||||
def _setup_styling(self):
|
||||
# HORIZONTAL = 0, VERTICAL = 1
|
||||
self.set_orientation(self.ORIENTATION)
|
||||
|
||||
|
||||
def _setup_signals(self):
|
||||
...
|
||||
|
||||
def _load_widgets(self):
|
||||
...
|
||||
@@ -61,7 +61,7 @@ class VteWidget(Vte.Terminal):
|
||||
def _do_session_spawn(self):
|
||||
self.spawn_sync(
|
||||
Vte.PtyFlags.DEFAULT,
|
||||
settings_manager.path_manager.get_home_path(),
|
||||
settings_manager.get_home_path(),
|
||||
["/bin/bash"],
|
||||
[],
|
||||
GLib.SpawnFlags.DEFAULT,
|
||||
@@ -76,8 +76,8 @@ class VteWidget(Vte.Terminal):
|
||||
"export LC_ALL=C\n",
|
||||
"export XDG_RUNTIME_DIR='/run/user/1000'\n",
|
||||
"export DISPLAY=:0\n",
|
||||
f"export XAUTHORITY='{settings_manager.path_manager.get_home_path()}/.Xauthority'\n",
|
||||
f"\nexport HOME='{settings_manager.path_manager.get_home_path()}'\n",
|
||||
f"export XAUTHORITY='{settings_manager.get_home_path()}/.Xauthority'\n",
|
||||
f"\nexport HOME='{settings_manager.get_home_path()}'\n",
|
||||
"export PS1='\\h@\\u \\W -->: '\n",
|
||||
"clear\n"
|
||||
]
|
||||
@@ -93,9 +93,6 @@ class VteWidget(Vte.Terminal):
|
||||
if not text.encode() == "\r".encode(): return
|
||||
|
||||
text, attributes = self.get_text()
|
||||
|
||||
if not text: return
|
||||
|
||||
lines = text.strip().splitlines()
|
||||
command_ran = None
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class WebkitUI(WebKit2.WebView):
|
||||
self.set_settings( WebkitUISettings() )
|
||||
|
||||
def _load_view(self):
|
||||
path = settings_manager.path_manager.get_context_path()
|
||||
path = settings_manager.get_context_path()
|
||||
data = None
|
||||
|
||||
with open(f"{path}/index.html", "r") as f:
|
||||
|
||||
@@ -21,7 +21,7 @@ from core.controllers.base_controller import BaseController
|
||||
|
||||
|
||||
|
||||
class ControllerStartException(Exception):
|
||||
class ControllerStartExceptiom(Exception):
|
||||
...
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ class Window(Gtk.ApplicationWindow):
|
||||
|
||||
def _setup_styling(self):
|
||||
self.set_title(f"{APP_NAME}")
|
||||
self.set_icon_from_file( settings_manager.path_manager.get_window_icon() )
|
||||
self.set_icon_from_file( settings_manager.get_window_icon() )
|
||||
self.set_decorated(True)
|
||||
self.set_skip_pager_hint(False)
|
||||
self.set_skip_taskbar_hint(False)
|
||||
@@ -62,7 +62,7 @@ class Window(Gtk.ApplicationWindow):
|
||||
|
||||
ctx = self.get_style_context()
|
||||
ctx.add_class("main-window")
|
||||
ctx.add_class(f"mw_transparency_{settings_manager.settings.theming.transparency}")
|
||||
ctx.add_class(f"mw_transparency_{settings.theming.transparency}")
|
||||
|
||||
def _setup_signals(self):
|
||||
self.connect("focus-in-event", self._on_focus_in_event)
|
||||
@@ -96,12 +96,12 @@ class Window(Gtk.ApplicationWindow):
|
||||
return 'X11'
|
||||
|
||||
def _set_size_constraints(self):
|
||||
_window_x = settings_manager.settings.config.main_window_x
|
||||
_window_y = settings_manager.settings.config.main_window_y
|
||||
_min_width = settings_manager.settings.config.main_window_min_width
|
||||
_min_height = settings_manager.settings.config.main_window_min_height
|
||||
_width = settings_manager.settings.config.main_window_width
|
||||
_height = settings_manager.settings.config.main_window_height
|
||||
_window_x = settings.config.main_window_x
|
||||
_window_y = settings.config.main_window_y
|
||||
_min_width = settings.config.main_window_min_width
|
||||
_min_height = settings.config.main_window_min_height
|
||||
_width = settings.config.main_window_width
|
||||
_height = settings.config.main_window_height
|
||||
|
||||
self.move(_window_x, _window_y - 28)
|
||||
self.set_size_request(_min_width, _min_height)
|
||||
@@ -111,15 +111,16 @@ class Window(Gtk.ApplicationWindow):
|
||||
screen = self.get_screen()
|
||||
visual = screen.get_rgba_visual()
|
||||
|
||||
if visual and screen.is_composited() and settings_manager.settings.config.make_transparent == 0:
|
||||
if visual and screen.is_composited() and settings.config.make_transparent == 0:
|
||||
self.set_visual(visual)
|
||||
self.set_app_paintable(True)
|
||||
# self.connect("draw", self._area_draw)
|
||||
|
||||
# bind css file
|
||||
cssProvider = Gtk.CssProvider()
|
||||
cssProvider.load_from_path( settings_manager.get_css_file() )
|
||||
screen = Gdk.Screen.get_default()
|
||||
styleContext = Gtk.StyleContext()
|
||||
cssProvider.load_from_path( settings_manager.path_manager.get_css_file() )
|
||||
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
|
||||
|
||||
def _area_draw(self, widget: Gtk.ApplicationWindow, cr: cairo.Context) -> None:
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .observable_event import ObservableEvent
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class CodeEvent(ObservableEvent):
|
||||
etype: str = ""
|
||||
ignore_focus: bool = False
|
||||
view: any = None
|
||||
file: any = None
|
||||
next_file: any = None
|
||||
buffer: any = None
|
||||
@@ -1,10 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class ObservableEvent:
|
||||
...
|
||||
@@ -2,7 +2,6 @@
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
from contextlib import suppress
|
||||
from multiprocessing.connection import Client
|
||||
from multiprocessing.connection import Listener
|
||||
|
||||
@@ -41,9 +40,8 @@ class IPCServer(Singleton):
|
||||
|
||||
def create_ipc_listener(self) -> None:
|
||||
if self._conn_type == "socket":
|
||||
if settings_manager.is_dirty_start():
|
||||
with suppress(FileNotFoundError, PermissionError):
|
||||
os.unlink(self._ipc_address)
|
||||
if os.path.exists(self._ipc_address) and settings_manager.is_dirty_start():
|
||||
os.unlink(self._ipc_address)
|
||||
|
||||
listener = Listener(address=self._ipc_address, family="AF_UNIX", authkey=self._ipc_authkey)
|
||||
elif "unsecured" not in self._conn_type:
|
||||
@@ -63,14 +61,8 @@ class IPCServer(Singleton):
|
||||
conn = listener.accept()
|
||||
start_time = time.perf_counter()
|
||||
self._handle_ipc_message(conn, start_time)
|
||||
except EOFError as e:
|
||||
logger.debug( repr(e) )
|
||||
except (OSError, ConnectionError, BrokenPipeError) as e:
|
||||
logger.debug( f"IPC connection error: {e}" )
|
||||
except Exception as e:
|
||||
logger.debug( f"Unexpected IPC error: {e}" )
|
||||
finally:
|
||||
conn.close()
|
||||
logger.debug( repr(e) )
|
||||
|
||||
listener.close()
|
||||
|
||||
@@ -96,7 +88,7 @@ class IPCServer(Singleton):
|
||||
break
|
||||
|
||||
|
||||
if msg in ['close connection', 'close server', 'Empty Data...']:
|
||||
if msg in ['close connection', 'close server']:
|
||||
conn.close()
|
||||
break
|
||||
|
||||
@@ -120,10 +112,8 @@ class IPCServer(Singleton):
|
||||
conn.close()
|
||||
except ConnectionRefusedError as e:
|
||||
logger.error("Connection refused...")
|
||||
except (OSError, ConnectionError, BrokenPipeError) as e:
|
||||
logger.error( f"IPC connection error: {e}" )
|
||||
except Exception as e:
|
||||
logger.error( f"Unexpected IPC error: {e}" )
|
||||
logger.error( repr(e) )
|
||||
|
||||
|
||||
def send_test_ipc_message(self, message: str = "Empty Data...") -> None:
|
||||
@@ -140,9 +130,6 @@ class IPCServer(Singleton):
|
||||
except ConnectionRefusedError as e:
|
||||
if self._conn_type == "socket":
|
||||
logger.error("IPC Socket no longer valid.... Removing.")
|
||||
with suppress(FileNotFoundError, PermissionError):
|
||||
os.unlink(self._ipc_address)
|
||||
except (OSError, ConnectionError, BrokenPipeError) as e:
|
||||
logger.error( f"IPC connection error: {e}" )
|
||||
os.unlink(self._ipc_address)
|
||||
except Exception as e:
|
||||
logger.error( f"Unexpected IPC error: {e}" )
|
||||
logger.error( repr(e) )
|
||||
@@ -1,26 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from ..dto.observable_event import ObservableEvent
|
||||
|
||||
|
||||
|
||||
class ObservableMixin:
|
||||
observers = []
|
||||
|
||||
def add_observer(self, observer: any):
|
||||
if not hasattr(observer, 'notification') or not callable(getattr(observer, 'notification')):
|
||||
raise ValueError(f"Observer '{observer}' must implement a `notification` method.")
|
||||
|
||||
self.observers.append(observer)
|
||||
|
||||
def remove_observer(self, observer: any):
|
||||
if not observer in self.observers: return
|
||||
|
||||
self.observers.remove(observer)
|
||||
|
||||
def notify_observers(self, event: ObservableEvent):
|
||||
for observer in self.observers:
|
||||
observer.notification(event)
|
||||
@@ -1,38 +1,138 @@
|
||||
# Python imports
|
||||
import inspect
|
||||
import time
|
||||
import json
|
||||
import zipfile
|
||||
|
||||
from os import path
|
||||
from os import mkdir
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from ..singleton import Singleton
|
||||
from .start_check_mixin import StartCheckMixin
|
||||
|
||||
from .path_manager import PathManager
|
||||
from .options.settings import Settings
|
||||
|
||||
|
||||
|
||||
class MissingConfigError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class SettingsManager(StartCheckMixin, Singleton):
|
||||
def __init__(self):
|
||||
self.path_manager: PathManager = PathManager()
|
||||
self.settings: Settings = None
|
||||
self._SCRIPT_PTH: str = path.dirname(path.realpath(__file__))
|
||||
self._USER_HOME: str = path.expanduser('~')
|
||||
self._HOME_CONFIG_PATH: str = f"{self._USER_HOME}/.config/{APP_NAME.lower()}"
|
||||
self._USR_PATH: str = f"/usr/share/{APP_NAME.lower()}"
|
||||
self._USR_CONFIG_FILE: str = f"{self._USR_PATH}/settings.json"
|
||||
|
||||
self._main_window = None
|
||||
self._builder = None
|
||||
self._CONTEXT_PATH: str = f"{self._HOME_CONFIG_PATH}/context_path"
|
||||
self._PLUGINS_PATH: str = f"{self._HOME_CONFIG_PATH}/plugins"
|
||||
self._DEFAULT_ICONS: str = f"{self._HOME_CONFIG_PATH}/icons"
|
||||
self._CONFIG_FILE: str = f"{self._HOME_CONFIG_PATH}/settings.json"
|
||||
self._GLADE_FILE: str = f"{self._HOME_CONFIG_PATH}/Main_Window.glade"
|
||||
self._CSS_FILE: str = f"{self._HOME_CONFIG_PATH}/stylesheet.css"
|
||||
self._KEY_BINDINGS_FILE: str = f"{self._HOME_CONFIG_PATH}/key-bindings.json"
|
||||
self._PID_FILE: str = f"{self._HOME_CONFIG_PATH}/{APP_NAME.lower()}.pid"
|
||||
self._UI_WIDEGTS_PATH: str = f"{self._HOME_CONFIG_PATH}/ui_widgets"
|
||||
self._CONTEXT_MENU: str = f"{self._HOME_CONFIG_PATH}/contexct_menu.json"
|
||||
self._WINDOW_ICON: str = f"{self._DEFAULT_ICONS}/{APP_NAME.lower()}.png"
|
||||
|
||||
self._trace_debug: bool = False
|
||||
self._debug: bool = False
|
||||
self._dirty_start: bool = False
|
||||
self._passed_in_file: bool = False
|
||||
self._starting_files: list = []
|
||||
# self._USR_CONFIG_FILE: str = f"{self._USR_PATH}/settings.json"
|
||||
# self._PLUGINS_PATH: str = f"plugins"
|
||||
# self._CONFIG_FILE: str = f"settings.json"
|
||||
# self._GLADE_FILE: str = f"Main_Window.glade"
|
||||
# self._CSS_FILE: str = f"stylesheet.css"
|
||||
# self._KEY_BINDINGS_FILE: str = f"key-bindings.json"
|
||||
# self._PID_FILE: str = f"{APP_NAME.lower()}.pid"
|
||||
# self._WINDOW_ICON: str = f"{APP_NAME.lower()}.png"
|
||||
# self._UI_WIDEGTS_PATH: str = f"ui_widgets"
|
||||
# self._CONTEXT_MENU: str = f"contexct_menu.json"
|
||||
# self._DEFAULT_ICONS: str = f"icons"
|
||||
|
||||
self.PAINT_BG_COLOR: tuple = (0, 0, 0, 0.0)
|
||||
|
||||
self.load_keybindings()
|
||||
self.load_context_menu_data()
|
||||
# with zipfile.ZipFile("files.zip", mode="r", allowZip64=True) as zf:
|
||||
# with io.TextIOWrapper(zf.open("text1.txt"), encoding="utf-8") as f:
|
||||
|
||||
|
||||
if not path.exists(self._HOME_CONFIG_PATH):
|
||||
mkdir(self._HOME_CONFIG_PATH)
|
||||
if not path.exists(self._PLUGINS_PATH):
|
||||
mkdir(self._PLUGINS_PATH)
|
||||
|
||||
if not path.exists(self._DEFAULT_ICONS):
|
||||
self._DEFAULT_ICONS = f"{self._USR_PATH}/icons"
|
||||
if not path.exists(self._DEFAULT_ICONS):
|
||||
raise MissingConfigError("Unable to find the application icons directory.")
|
||||
if not path.exists(self._GLADE_FILE):
|
||||
self._GLADE_FILE = f"{self._USR_PATH}/Main_Window.glade"
|
||||
if not path.exists(self._GLADE_FILE):
|
||||
raise MissingConfigError("Unable to find the application Glade file.")
|
||||
if not path.exists(self._KEY_BINDINGS_FILE):
|
||||
self._KEY_BINDINGS_FILE = f"{self._USR_PATH}/key-bindings.json"
|
||||
if not path.exists(self._KEY_BINDINGS_FILE):
|
||||
raise MissingConfigError("Unable to find the application Keybindings file.")
|
||||
if not path.exists(self._CSS_FILE):
|
||||
self._CSS_FILE = f"{self._USR_PATH}/stylesheet.css"
|
||||
if not path.exists(self._CSS_FILE):
|
||||
raise MissingConfigError("Unable to find the application Stylesheet file.")
|
||||
if not path.exists(self._WINDOW_ICON):
|
||||
self._WINDOW_ICON = f"{self._USR_PATH}/icons/{APP_NAME.lower()}.png"
|
||||
if not path.exists(self._WINDOW_ICON):
|
||||
raise MissingConfigError("Unable to find the application icon.")
|
||||
if not path.exists(self._UI_WIDEGTS_PATH):
|
||||
self._UI_WIDEGTS_PATH = f"{self._USR_PATH}/ui_widgets"
|
||||
if not path.exists(self._CONTEXT_MENU):
|
||||
self._CONTEXT_MENU = f"{self._USR_PATH}/contexct_menu.json"
|
||||
|
||||
|
||||
try:
|
||||
with open(self._KEY_BINDINGS_FILE) as file:
|
||||
bindings = json.load(file)["keybindings"]
|
||||
self._guake_key = bindings["guake_key"]
|
||||
|
||||
keybindings.configure(bindings)
|
||||
except Exception as e:
|
||||
print( f"Settings Manager: {self._KEY_BINDINGS_FILE}\n\t\t{repr(e)}" )
|
||||
|
||||
try:
|
||||
with open(self._CONTEXT_MENU) as file:
|
||||
self._context_menu_data = json.load(file)
|
||||
except Exception as e:
|
||||
print( f"Settings Manager: {self._CONTEXT_MENU}\n\t\t{repr(e)}" )
|
||||
|
||||
|
||||
self.settings: Settings = None
|
||||
self._main_window = None
|
||||
self._builder = None
|
||||
self.PAINT_BG_COLOR: tuple = (0, 0, 0, 0.0)
|
||||
|
||||
self._trace_debug: bool = False
|
||||
self._debug: bool = False
|
||||
self._dirty_start: bool = False
|
||||
self._passed_in_file: bool = False
|
||||
self._starting_files: list = []
|
||||
|
||||
|
||||
def register_signals_to_builder(self, classes = None):
|
||||
handlers = {}
|
||||
|
||||
for c in classes:
|
||||
methods = None
|
||||
try:
|
||||
methods = inspect.getmembers(c, predicate = inspect.ismethod)
|
||||
handlers.update(methods)
|
||||
except Exception as e:
|
||||
...
|
||||
|
||||
self._builder.connect_signals(handlers)
|
||||
|
||||
def set_main_window(self, window): self._main_window = window
|
||||
def set_builder(self, builder) -> any: self._builder = builder
|
||||
|
||||
def get_monitor_data(self) -> list:
|
||||
screen = self._main_window.get_screen()
|
||||
monitors = []
|
||||
@@ -45,18 +145,23 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||
def get_main_window(self) -> any: return self._main_window
|
||||
def get_builder(self) -> any: return self._builder
|
||||
def get_paint_bg_color(self) -> any: return self.PAINT_BG_COLOR
|
||||
def get_glade_file(self) -> str: return self._GLADE_FILE
|
||||
def get_ui_widgets_path(self) -> str: return self._UI_WIDEGTS_PATH
|
||||
def get_context_menu_data(self) -> str: return self._context_menu_data
|
||||
|
||||
def get_context_path(self) -> str: return self._CONTEXT_PATH
|
||||
def get_plugins_path(self) -> str: return self._PLUGINS_PATH
|
||||
def get_icon_theme(self) -> str: return self._ICON_THEME
|
||||
def get_css_file(self) -> str: return self._CSS_FILE
|
||||
def get_home_config_path(self) -> str: return self._HOME_CONFIG_PATH
|
||||
def get_window_icon(self) -> str: return self._WINDOW_ICON
|
||||
def get_home_path(self) -> str: return self._USER_HOME
|
||||
def get_starting_files(self) -> list: return self._starting_files
|
||||
def get_guake_key(self) -> tuple: return self._guake_key
|
||||
|
||||
def get_starting_args(self):
|
||||
return self.args, self.unknownargs
|
||||
|
||||
def set_main_window(self, window): self._main_window = window
|
||||
def set_builder(self, builder) -> any: self._builder = builder
|
||||
|
||||
def set_main_window_x(self, x: int = 0): self.settings.config.main_window_x = x
|
||||
def set_main_window_y(self, y: int = 0): self.settings.config.main_window_y = y
|
||||
def set_main_window_width(self, width: int = 800): self.settings.config.main_window_width = width
|
||||
@@ -86,41 +191,21 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||
|
||||
def log_load_time(self): logger.info( f"Load Time: {self._end_load_time - self._start_load_time}" )
|
||||
|
||||
|
||||
def register_signals_to_builder(self, classes = None):
|
||||
handlers = {}
|
||||
|
||||
for c in classes:
|
||||
methods = None
|
||||
try:
|
||||
methods = inspect.getmembers(c, predicate = inspect.ismethod)
|
||||
handlers.update(methods)
|
||||
except Exception as e:
|
||||
...
|
||||
|
||||
self._builder.connect_signals(handlers)
|
||||
|
||||
def call_method(self, target_class: any = None, _method_name: str = "", data: any = None):
|
||||
method_name = str(_method_name)
|
||||
method = getattr(target_class, method_name, lambda data: f"No valid key passed...\nkey={method_name}\nargs={data}")
|
||||
return method(data) if data else method()
|
||||
|
||||
def load_keybindings(self):
|
||||
bindings = self.path_manager.load_keybindings()
|
||||
self._guake_key = bindings["guake_key"]
|
||||
|
||||
keybindings.configure(bindings)
|
||||
|
||||
def load_context_menu_data(self):
|
||||
self._context_menu_data = self.path_manager.load_context_menu_data()
|
||||
|
||||
def load_settings(self):
|
||||
data = self.path_manager.load_settings()
|
||||
if not data:
|
||||
if not path.exists(self._CONFIG_FILE):
|
||||
self.settings = Settings()
|
||||
return
|
||||
|
||||
self.settings = Settings(**data)
|
||||
with open(self._CONFIG_FILE) as file:
|
||||
data = json.load(file)
|
||||
data["load_defaults"] = False
|
||||
self.settings = Settings(**data)
|
||||
|
||||
def save_settings(self):
|
||||
self.path_manager.save_settings(self.settings)
|
||||
with open(self._CONFIG_FILE, 'w') as outfile:
|
||||
json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4)
|
||||
@@ -9,8 +9,6 @@ from dataclasses import dataclass
|
||||
@dataclass
|
||||
class Theming:
|
||||
transparency: int = 64
|
||||
default_zoom: int = 12
|
||||
syntax_theme: str = "penguins-in-space"
|
||||
success_color: str = "#88cc27"
|
||||
warning_color: str = "#ffa800"
|
||||
error_color: str = "#ff0000"
|
||||
|
||||
@@ -1,123 +0,0 @@
|
||||
# Python imports
|
||||
import json
|
||||
import zipfile
|
||||
|
||||
from os import path
|
||||
from os import mkdir
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class MissingConfigError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class PathManager:
|
||||
def __init__(self):
|
||||
self._SCRIPT_PTH: str = path.dirname(path.realpath(__file__))
|
||||
self._USER_HOME: str = path.expanduser('~')
|
||||
self._HOME_CONFIG_PATH: str = f"{self._USER_HOME}/.config/{APP_NAME.lower()}"
|
||||
self._USR_PATH: str = f"/usr/share/{APP_NAME.lower()}"
|
||||
self._USR_CONFIG_FILE: str = f"{self._USR_PATH}/settings.json"
|
||||
|
||||
self._CONTEXT_PATH: str = f"{self._HOME_CONFIG_PATH}/context_path"
|
||||
self._PLUGINS_PATH: str = f"{self._HOME_CONFIG_PATH}/plugins"
|
||||
self._DEFAULT_ICONS: str = f"{self._HOME_CONFIG_PATH}/icons"
|
||||
self._CONFIG_FILE: str = f"{self._HOME_CONFIG_PATH}/settings.json"
|
||||
self._GLADE_FILE: str = f"{self._HOME_CONFIG_PATH}/Main_Window.glade"
|
||||
self._CSS_FILE: str = f"{self._HOME_CONFIG_PATH}/stylesheet.css"
|
||||
self._KEY_BINDINGS_FILE: str = f"{self._HOME_CONFIG_PATH}/key-bindings.json"
|
||||
self._PID_FILE: str = f"{self._HOME_CONFIG_PATH}/{APP_NAME.lower()}.pid"
|
||||
self._UI_WIDGETS_PATH: str = f"{self._HOME_CONFIG_PATH}/ui_widgets"
|
||||
self._CONTEXT_MENU: str = f"{self._HOME_CONFIG_PATH}/context_menu.json"
|
||||
self._WINDOW_ICON: str = f"{self._DEFAULT_ICONS}/{APP_NAME.lower()}.png"
|
||||
|
||||
# self._USR_CONFIG_FILE: str = f"{self._USR_PATH}/settings.json"
|
||||
# self._PLUGINS_PATH: str = f"plugins"
|
||||
# self._CONFIG_FILE: str = f"settings.json"
|
||||
# self._GLADE_FILE: str = f"Main_Window.glade"
|
||||
# self._CSS_FILE: str = f"stylesheet.css"
|
||||
# self._KEY_BINDINGS_FILE: str = f"key-bindings.json"
|
||||
# self._PID_FILE: str = f"{APP_NAME.lower()}.pid"
|
||||
# self._WINDOW_ICON: str = f"{APP_NAME.lower()}.png"
|
||||
# self._UI_WIDGETS_PATH: str = f"ui_widgets"
|
||||
# self._CONTEXT_MENU: str = f"context_menu.json"
|
||||
# self._DEFAULT_ICONS: str = f"icons"
|
||||
|
||||
|
||||
# with zipfile.ZipFile("files.zip", mode="r", allowZip64=True) as zf:
|
||||
# with io.TextIOWrapper(zf.open("text1.txt"), encoding="utf-8") as f:
|
||||
|
||||
|
||||
if not path.exists(self._HOME_CONFIG_PATH):
|
||||
mkdir(self._HOME_CONFIG_PATH)
|
||||
if not path.exists(self._PLUGINS_PATH):
|
||||
mkdir(self._PLUGINS_PATH)
|
||||
|
||||
if not path.exists(self._DEFAULT_ICONS):
|
||||
self._DEFAULT_ICONS = f"{self._USR_PATH}/icons"
|
||||
if not path.exists(self._DEFAULT_ICONS):
|
||||
raise MissingConfigError("Unable to find the application icons directory.")
|
||||
if not path.exists(self._GLADE_FILE):
|
||||
self._GLADE_FILE = f"{self._USR_PATH}/Main_Window.glade"
|
||||
if not path.exists(self._GLADE_FILE):
|
||||
raise MissingConfigError("Unable to find the application Glade file.")
|
||||
if not path.exists(self._KEY_BINDINGS_FILE):
|
||||
self._KEY_BINDINGS_FILE = f"{self._USR_PATH}/key-bindings.json"
|
||||
if not path.exists(self._KEY_BINDINGS_FILE):
|
||||
raise MissingConfigError("Unable to find the application Keybindings file.")
|
||||
if not path.exists(self._CSS_FILE):
|
||||
self._CSS_FILE = f"{self._USR_PATH}/stylesheet.css"
|
||||
if not path.exists(self._CSS_FILE):
|
||||
raise MissingConfigError("Unable to find the application Stylesheet file.")
|
||||
if not path.exists(self._WINDOW_ICON):
|
||||
self._WINDOW_ICON = f"{self._USR_PATH}/icons/{APP_NAME.lower()}.png"
|
||||
if not path.exists(self._WINDOW_ICON):
|
||||
raise MissingConfigError("Unable to find the application icon.")
|
||||
if not path.exists(self._UI_WIDGETS_PATH):
|
||||
self._UI_WIDGETS_PATH = f"{self._USR_PATH}/ui_widgets"
|
||||
if not path.exists(self._CONTEXT_MENU):
|
||||
self._CONTEXT_MENU = f"{self._USR_PATH}/context_menu.json"
|
||||
|
||||
|
||||
def get_glade_file(self) -> str: return self._GLADE_FILE
|
||||
def get_ui_widgets_path(self) -> str: return self._UI_WIDGETS_PATH
|
||||
def get_context_path(self) -> str: return self._CONTEXT_PATH
|
||||
def get_plugins_path(self) -> str: return self._PLUGINS_PATH
|
||||
def get_css_file(self) -> str: return self._CSS_FILE
|
||||
def get_home_config_path(self) -> str: return self._HOME_CONFIG_PATH
|
||||
def get_window_icon(self) -> str: return self._WINDOW_ICON
|
||||
def get_home_path(self) -> str: return self._USER_HOME
|
||||
|
||||
def load_keybindings(self):
|
||||
try:
|
||||
with open(self._KEY_BINDINGS_FILE) as file:
|
||||
return json.load(file)["keybindings"]
|
||||
except Exception as e:
|
||||
print( f"Settings Path Manager: {self._KEY_BINDINGS_FILE}\n\t\t{repr(e)}" )
|
||||
return {}
|
||||
|
||||
def load_context_menu_data(self):
|
||||
try:
|
||||
with open(self._CONTEXT_MENU) as file:
|
||||
return json.load(file)
|
||||
except Exception as e:
|
||||
print( f"Settings Path Manager: {self._CONTEXT_MENU}\n\t\t{repr(e)}" )
|
||||
return {}
|
||||
|
||||
def load_settings(self):
|
||||
if not path.exists(self._CONFIG_FILE):
|
||||
return None
|
||||
|
||||
with open(self._CONFIG_FILE) as file:
|
||||
data = json.load(file)
|
||||
data["load_defaults"] = False
|
||||
return data
|
||||
|
||||
def save_settings(self, settings: any):
|
||||
with open(self._CONFIG_FILE, 'w') as outfile:
|
||||
json.dump(settings.as_dict(), outfile, separators=(',', ':'), indent=4)
|
||||
@@ -2,7 +2,6 @@
|
||||
import os
|
||||
import json
|
||||
import inspect
|
||||
from contextlib import suppress
|
||||
|
||||
# Lib imports
|
||||
|
||||
@@ -25,8 +24,8 @@ class StartCheckMixin:
|
||||
self._print_pid(pid)
|
||||
return
|
||||
|
||||
if os.path.exists(self.path_manager._PID_FILE):
|
||||
with open(self.path_manager._PID_FILE, "r") as f:
|
||||
if os.path.exists(self._PID_FILE):
|
||||
with open(self._PID_FILE, "r") as f:
|
||||
pid = f.readline().strip()
|
||||
if pid not in ("", None):
|
||||
if self.is_pid_alive( int(pid) ):
|
||||
@@ -57,9 +56,8 @@ class StartCheckMixin:
|
||||
print(f"{APP_NAME} PID: {pid}")
|
||||
|
||||
def _clean_pid(self):
|
||||
with suppress(FileNotFoundError, PermissionError):
|
||||
os.unlink(self.path_manager._PID_FILE)
|
||||
os.unlink(self._PID_FILE)
|
||||
|
||||
def _write_pid(self, pid):
|
||||
with open(self.path_manager._PID_FILE, "w") as _pid:
|
||||
with open(self._PID_FILE, "w") as _pid:
|
||||
_pid.write(f"{pid}")
|
||||
@@ -15,15 +15,8 @@ class Singleton:
|
||||
_instance = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls._instance is not None:
|
||||
logger.debug(f"'{cls.__name__}' is a Singleton. Returning instance...")
|
||||
return cls._instance
|
||||
if cls._instance:
|
||||
raise SingletonError(f"'{cls.__name__}' is a Singleton. Cannot create a new instance...")
|
||||
|
||||
cls._instance = super(Singleton, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def __init__(self):
|
||||
if self._instance is not None:
|
||||
return
|
||||
|
||||
super(Singleton, self).__init__()
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class SingletonError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class SingletonRaised:
|
||||
_instance = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if cls._instance is not None:
|
||||
raise SingletonError(f"'{cls.__name__}' is a Singleton. Cannot create a new instance...")
|
||||
|
||||
cls._instance = super(Singleton, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def __init__(self):
|
||||
if cls._instance is not None:
|
||||
return
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Gtk Plugins DTO Module
|
||||
"""
|
||||
@@ -1,27 +0,0 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import asdict
|
||||
|
||||
# Gtk imports
|
||||
|
||||
# Application imports
|
||||
from .requests import Requests
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class Manifest:
|
||||
name: str = ""
|
||||
author: str = ""
|
||||
credit: str = ""
|
||||
version: str = "0.0.1"
|
||||
support: str = "support@mail.com"
|
||||
pre_launch: bool = False
|
||||
requests: Requests = field(default_factory = lambda: Requests())
|
||||
|
||||
def __post_init__(self):
|
||||
if isinstance(self.requests, dict):
|
||||
self.requests = Requests(**self.requests)
|
||||
|
||||
def as_dict(self):
|
||||
return asdict(self)
|
||||
@@ -1,19 +0,0 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass, field
|
||||
from dataclasses import asdict
|
||||
|
||||
# Gtk imports
|
||||
|
||||
# Application imports
|
||||
from .manifest import Manifest
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class ManifestMeta:
|
||||
folder: str = ""
|
||||
path: str = ""
|
||||
manifest: Manifest = field(default_factory = lambda: Manifest())
|
||||
|
||||
def as_dict(self):
|
||||
return asdict(self)
|
||||
@@ -1,16 +0,0 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
@dataclass
|
||||
class Requests:
|
||||
ui_target: str = ""
|
||||
ui_target_id: str = ""
|
||||
pass_events: bool = False
|
||||
pass_fm_events: bool = False
|
||||
pass_ui_objects: list = field(default_factory = lambda: [])
|
||||
bind_keys: list = field(default_factory = lambda: [])
|
||||
75
src/plugins/manifest.py
Normal file
75
src/plugins/manifest.py
Normal file
@@ -0,0 +1,75 @@
|
||||
# Python imports
|
||||
import os
|
||||
import json
|
||||
from os.path import join
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
|
||||
class ManifestProcessor(Exception):
|
||||
...
|
||||
|
||||
|
||||
class Plugin:
|
||||
path: str = None
|
||||
name: str = None
|
||||
author: str = None
|
||||
version: str = None
|
||||
support: str = None
|
||||
requests:{} = None
|
||||
reference: type = None
|
||||
pre_launch: bool = False
|
||||
|
||||
|
||||
class ManifestProcessor:
|
||||
def __init__(self, path, builder):
|
||||
manifest = join(path, "manifest.json")
|
||||
if not os.path.exists(manifest):
|
||||
raise Exception("Invalid Plugin Structure: Plugin doesn't have 'manifest.json'. Aboarting load...")
|
||||
|
||||
self._path = path
|
||||
self._builder = builder
|
||||
with open(manifest) as f:
|
||||
data = json.load(f)
|
||||
self._manifest = data["manifest"]
|
||||
self._plugin = self.collect_info()
|
||||
|
||||
def collect_info(self) -> Plugin:
|
||||
plugin = Plugin()
|
||||
plugin.path = self._path
|
||||
plugin.name = self._manifest["name"]
|
||||
plugin.author = self._manifest["author"]
|
||||
plugin.version = self._manifest["version"]
|
||||
plugin.support = self._manifest["support"]
|
||||
plugin.requests = self._manifest["requests"]
|
||||
|
||||
if "pre_launch" in self._manifest.keys():
|
||||
plugin.pre_launch = True if self._manifest["pre_launch"] == "true" else False
|
||||
|
||||
return plugin
|
||||
|
||||
def get_loading_data(self):
|
||||
loading_data = {}
|
||||
requests = self._plugin.requests
|
||||
|
||||
if "pass_events" in requests:
|
||||
if requests["pass_events"] in ["true"]:
|
||||
loading_data["pass_events"] = True
|
||||
|
||||
if "pass_ui_objects" in requests:
|
||||
if isinstance(requests["pass_ui_objects"], list):
|
||||
loading_data["pass_ui_objects"] = [ self._builder.get_object(obj) for obj in requests["pass_ui_objects"] ]
|
||||
|
||||
if "bind_keys" in requests:
|
||||
if isinstance(requests["bind_keys"], list):
|
||||
loading_data["bind_keys"] = requests["bind_keys"]
|
||||
|
||||
return self._plugin, loading_data
|
||||
|
||||
def is_pre_launch(self):
|
||||
return self._plugin.pre_launch
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
# Python imports
|
||||
import os
|
||||
import json
|
||||
from os.path import join
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .dto.manifest_meta import ManifestMeta
|
||||
from .dto.manifest import Manifest
|
||||
|
||||
|
||||
|
||||
class ManifestMapperException(Exception):
|
||||
...
|
||||
|
||||
|
||||
|
||||
class ManifestManager:
|
||||
def __init__(self):
|
||||
|
||||
self._plugins_path = settings_manager.path_manager.get_plugins_path()
|
||||
|
||||
self.pre_launch_manifests = []
|
||||
self.post_launch_manifests = []
|
||||
|
||||
self.load_manifests()
|
||||
|
||||
|
||||
def load_manifests(self):
|
||||
logger.info(f"Loading manifests...")
|
||||
|
||||
for path, folder in [
|
||||
[join(self._plugins_path, item), item]
|
||||
if
|
||||
os.path.isdir( join(self._plugins_path, item) )
|
||||
else
|
||||
None
|
||||
for item in os.listdir(self._plugins_path)
|
||||
]:
|
||||
self.load(folder, path)
|
||||
|
||||
def load(self, folder, path):
|
||||
manifest_pth = join(path, "manifest.json")
|
||||
|
||||
if not os.path.exists(manifest_pth):
|
||||
raise ManifestMapperException("Invalid Plugin Structure: Plugin doesn't have 'manifest.json'. Aboarting load...")
|
||||
|
||||
with open(manifest_pth) as f:
|
||||
data = json.load(f)
|
||||
manifest = Manifest(**data)
|
||||
manifest_meta = ManifestMeta()
|
||||
|
||||
manifest_meta.folder = folder
|
||||
manifest_meta.path = path
|
||||
manifest_meta.manifest = manifest
|
||||
|
||||
if manifest.pre_launch:
|
||||
self.pre_launch_manifests.append(manifest_meta)
|
||||
else:
|
||||
self.post_launch_manifests.append(manifest_meta)
|
||||
|
||||
def get_pre_launch_manifests(self) -> dict:
|
||||
return self.pre_launch_manifests
|
||||
|
||||
def get_post_launch_plugins(self) -> None:
|
||||
return self.post_launch_manifests
|
||||
|
||||
@@ -15,12 +15,12 @@ class PluginBaseException(Exception):
|
||||
class PluginBase:
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.name = "Example Plugin" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
|
||||
# where self.name should not be needed for message comms
|
||||
self.name = "Example Plugin" # NOTE: Need to remove after establishing private bidirectional 1-1 message bus
|
||||
# where self.name should not be needed for message comms
|
||||
|
||||
self._builder = None
|
||||
self._ui_objects = None
|
||||
self._event_system = None
|
||||
self._builder = None
|
||||
self._ui_objects = None
|
||||
self._event_system = None
|
||||
|
||||
|
||||
def run(self):
|
||||
@@ -48,8 +48,8 @@ class PluginBase:
|
||||
|
||||
def set_event_system(self, event_system):
|
||||
"""
|
||||
Requests Key: 'pass_events': true
|
||||
Must define in plugin if "pass_events" is set to true.
|
||||
Requests Key: 'pass_events': "true"
|
||||
Must define in plugin if "pass_events" is set to "true" string.
|
||||
"""
|
||||
self._event_system = event_system
|
||||
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
class PluginReloadMixin:
|
||||
_plugins_dir_watcher = None
|
||||
|
||||
def _set_plugins_watcher(self) -> None:
|
||||
self._plugins_dir_watcher = Gio.File.new_for_path(
|
||||
self._plugins_path
|
||||
).monitor_directory(
|
||||
Gio.FileMonitorFlags.WATCH_MOVES,
|
||||
Gio.Cancellable()
|
||||
)
|
||||
|
||||
self._plugins_dir_watcher.connect("changed", self._on_plugins_changed, ())
|
||||
|
||||
def _on_plugins_changed(self,
|
||||
file_monitor, file,
|
||||
other_file = None,
|
||||
eve_type = None,
|
||||
data = None
|
||||
):
|
||||
if eve_type in [Gio.FileMonitorEvent.CREATED, Gio.FileMonitorEvent.DELETED,
|
||||
Gio.FileMonitorEvent.RENAMED, Gio.FileMonitorEvent.MOVED_IN,
|
||||
Gio.FileMonitorEvent.MOVED_OUT]:
|
||||
self.reload_plugins(file)
|
||||
|
||||
def reload_plugins(self, file: str = None) -> None:
|
||||
logger.info(f"Reloading plugins... stub.")
|
||||
@@ -8,12 +8,15 @@ from os.path import isdir
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
|
||||
# Application imports
|
||||
from .dto.manifest_meta import ManifestMeta
|
||||
from .plugin_reload_mixin import PluginReloadMixin
|
||||
from .manifest_manager import ManifestManager
|
||||
from .manifest import Plugin
|
||||
from .manifest import ManifestProcessor
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,59 +24,95 @@ class InvalidPluginException(Exception):
|
||||
...
|
||||
|
||||
|
||||
|
||||
class PluginsController(PluginReloadMixin):
|
||||
class PluginsController:
|
||||
"""PluginsController controller"""
|
||||
|
||||
def __init__(self):
|
||||
# path = os.path.dirname(os.path.realpath(__file__))
|
||||
# sys.path.insert(0, path) # NOTE: I think I'm not using this correctly...
|
||||
path = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.insert(0, path) # NOTE: I think I'm not using this correctly...
|
||||
|
||||
self._builder = settings_manager.get_builder()
|
||||
self._plugins_path = settings_manager.get_plugins_path()
|
||||
|
||||
self._plugins_dir_watcher = None
|
||||
self._plugin_collection = []
|
||||
self._plugin_manifests = {}
|
||||
|
||||
self._plugins_path = settings_manager.path_manager.get_plugins_path()
|
||||
self._manifest_manager = ManifestManager()
|
||||
self._load_manifests()
|
||||
|
||||
|
||||
def _load_manifests(self):
|
||||
logger.info(f"Loading manifests...")
|
||||
|
||||
for path, folder in [[join(self._plugins_path, item), item] if os.path.isdir(join(self._plugins_path, item)) else None for item in os.listdir(self._plugins_path)]:
|
||||
manifest = ManifestProcessor(path, self._builder)
|
||||
self._plugin_manifests[path] = {
|
||||
"path": path,
|
||||
"folder": folder,
|
||||
"manifest": manifest
|
||||
}
|
||||
|
||||
self._set_plugins_watcher()
|
||||
|
||||
def _set_plugins_watcher(self) -> None:
|
||||
self._plugins_dir_watcher = Gio.File.new_for_path(self._plugins_path) \
|
||||
.monitor_directory(Gio.FileMonitorFlags.WATCH_MOVES, Gio.Cancellable())
|
||||
self._plugins_dir_watcher.connect("changed", self._on_plugins_changed, ())
|
||||
|
||||
def _on_plugins_changed(self, file_monitor, file, other_file=None, eve_type=None, data=None):
|
||||
if eve_type in [Gio.FileMonitorEvent.CREATED, Gio.FileMonitorEvent.DELETED,
|
||||
Gio.FileMonitorEvent.RENAMED, Gio.FileMonitorEvent.MOVED_IN,
|
||||
Gio.FileMonitorEvent.MOVED_OUT]:
|
||||
self.reload_plugins(file)
|
||||
|
||||
def pre_launch_plugins(self) -> None:
|
||||
logger.info(f"Loading pre-launch plugins...")
|
||||
manifest_metas: [] = self._manifest_manager.get_pre_launch_manifests()
|
||||
self._load_plugins(manifest_metas, is_pre_launch = True)
|
||||
plugin_manifests: {} = {}
|
||||
|
||||
for key in self._plugin_manifests:
|
||||
target_manifest = self._plugin_manifests[key]["manifest"]
|
||||
if target_manifest.is_pre_launch():
|
||||
plugin_manifests[key] = self._plugin_manifests[key]
|
||||
|
||||
self._load_plugins(plugin_manifests, is_pre_launch = True)
|
||||
|
||||
def post_launch_plugins(self) -> None:
|
||||
logger.info(f"Loading post-launch plugins...")
|
||||
manifest_metas: [] = self._manifest_manager.get_post_launch_plugins()
|
||||
self._load_plugins(manifest_metas)
|
||||
plugin_manifests: {} = {}
|
||||
|
||||
def _load_plugins(
|
||||
self,
|
||||
manifest_metas: [] = [],
|
||||
is_pre_launch: bool = False
|
||||
) -> None:
|
||||
for key in self._plugin_manifests:
|
||||
target_manifest = self._plugin_manifests[key]["manifest"]
|
||||
if not target_manifest.is_pre_launch():
|
||||
plugin_manifests[key] = self._plugin_manifests[key]
|
||||
|
||||
self._load_plugins(plugin_manifests)
|
||||
|
||||
def _load_plugins(self, plugin_manifests: {} = {}, is_pre_launch: bool = False) -> None:
|
||||
parent_path = os.getcwd()
|
||||
|
||||
for manifest_meta in manifest_metas:
|
||||
path, folder, manifest = manifest_meta.path, manifest_meta.folder, manifest_meta.manifest
|
||||
for key in plugin_manifests:
|
||||
target_manifest = plugin_manifests[key]
|
||||
path, folder, manifest = target_manifest["path"], target_manifest["folder"], target_manifest["manifest"]
|
||||
|
||||
try:
|
||||
target = join(path, "plugin.py")
|
||||
if not os.path.exists(target):
|
||||
raise InvalidPluginException("Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load...")
|
||||
|
||||
module = self.load_plugin_module(path, folder, target)
|
||||
plugin, loading_data = manifest.get_loading_data()
|
||||
module = self.load_plugin_module(path, folder, target)
|
||||
|
||||
if is_pre_launch:
|
||||
self.execute_plugin(module, manifest_meta)
|
||||
self.execute_plugin(module, plugin, loading_data)
|
||||
else:
|
||||
GLib.idle_add(self.execute_plugin, module, manifest_meta)
|
||||
GLib.idle_add(self.execute_plugin, *(module, plugin, loading_data))
|
||||
except Exception as e:
|
||||
logger.info(f"Malformed Plugin: Not loading -->: '{folder}' !")
|
||||
logger.debug("Trace: ", traceback.print_exc())
|
||||
|
||||
os.chdir(parent_path)
|
||||
|
||||
|
||||
def load_plugin_module(self, path, folder, target):
|
||||
os.chdir(path)
|
||||
|
||||
@@ -87,48 +126,33 @@ class PluginsController(PluginReloadMixin):
|
||||
|
||||
return module
|
||||
|
||||
def collect_search_locations(self, path: str, locations: list):
|
||||
def collect_search_locations(self, path, locations):
|
||||
locations.append(path)
|
||||
for file in os.listdir(path):
|
||||
_path = os.path.join(path, file)
|
||||
if os.path.isdir(_path):
|
||||
self.collect_search_locations(_path, locations)
|
||||
|
||||
def execute_plugin(self, module: type, manifest_meta: ManifestMeta):
|
||||
manifest = manifest_meta.manifest
|
||||
manifest_meta.instance = module.Plugin()
|
||||
def execute_plugin(self, module: type, plugin: Plugin, loading_data: []):
|
||||
plugin.reference = module.Plugin()
|
||||
keys = loading_data.keys()
|
||||
|
||||
if manifest.requests.ui_target:
|
||||
builder = settings_manager.get_builder()
|
||||
ui_target = manifest.requests.ui_target
|
||||
ui_target_id = manifest.requests.ui_target_id
|
||||
if "ui_target" in keys:
|
||||
loading_data["ui_target"].add( plugin.reference.generate_reference_ui_element() )
|
||||
loading_data["ui_target"].show()
|
||||
|
||||
if not ui_target == "other":
|
||||
ui_target = builder.get_object(ui_target)
|
||||
else:
|
||||
if not ui_target_id:
|
||||
raise InvalidPluginException('Invalid "ui_target_id" given in requests. Must have one if setting "ui_target" to "other"...')
|
||||
if "pass_ui_objects" in keys:
|
||||
plugin.reference.set_ui_object_collection( loading_data["pass_ui_objects"] )
|
||||
|
||||
ui_target = builder.get_object(ui_target_id)
|
||||
if "pass_events" in keys:
|
||||
plugin.reference.set_event_system(event_system)
|
||||
plugin.reference.subscribe_to_events()
|
||||
|
||||
if not ui_target:
|
||||
raise InvalidPluginException('Unknown "ui_target" given in requests.')
|
||||
if "bind_keys" in keys:
|
||||
keybindings.append_bindings( loading_data["bind_keys"] )
|
||||
|
||||
ui_element = manifest_meta.instance.generate_reference_ui_element()
|
||||
plugin.reference.run()
|
||||
self._plugin_collection.append(plugin)
|
||||
|
||||
ui_target.add(ui_element)
|
||||
|
||||
if manifest.requests.pass_ui_objects:
|
||||
manifest_meta.instance.set_ui_object_collection(
|
||||
[ builder.get_object(obj) for obj in manifest.requests.pass_ui_objects ]
|
||||
)
|
||||
|
||||
if manifest.requests.pass_events:
|
||||
manifest_meta.instance.set_event_system(event_system)
|
||||
manifest_meta.instance.subscribe_to_events()
|
||||
|
||||
if manifest.requests.bind_keys:
|
||||
keybindings.append_bindings( manifest.requests.bind_keys )
|
||||
|
||||
manifest_meta.instance.run()
|
||||
self._plugin_collection.append(manifest_meta)
|
||||
def reload_plugins(self, file: str = None) -> None:
|
||||
logger.info(f"Reloading plugins... stub.")
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
{
|
||||
"keybindings": {
|
||||
"show_completion": {
|
||||
"released": "<Control>space"
|
||||
},
|
||||
"line_up": {
|
||||
"held": "<Control>Up"
|
||||
},
|
||||
"line_down": {
|
||||
"held": "<Control>Down"
|
||||
},
|
||||
"zoom_in": {
|
||||
"held": "<Control>equal"
|
||||
},
|
||||
"zoom_out": {
|
||||
"held": "<Control>minus"
|
||||
},
|
||||
"cut_to_temp_buffer": {
|
||||
"held": "<Control>k"
|
||||
},
|
||||
"duplicate_line": {
|
||||
"held": "<Control>d"
|
||||
},
|
||||
"go_to": {
|
||||
"released": "<Control>g"
|
||||
},
|
||||
"paste_temp_buffer": {
|
||||
"held": "<Control>u"
|
||||
},
|
||||
"new_file": {
|
||||
"released": "<Control>t"
|
||||
},
|
||||
"buffer_undo": {
|
||||
"held": "<Control>z"
|
||||
},
|
||||
"buffer_redo": {
|
||||
"held": "<Control>y"
|
||||
},
|
||||
"open_files": {
|
||||
"released": "<Control>o"
|
||||
},
|
||||
"close_file": {
|
||||
"released": "<Control>w"
|
||||
},
|
||||
"save_file": {
|
||||
"released": "<Control>s"
|
||||
},
|
||||
"save_file_as": {
|
||||
"released": "<Control><Shift>s"
|
||||
},
|
||||
"focus_left_sibling": {
|
||||
"released": "<Control>Page_Up"
|
||||
},
|
||||
"focus_right_sibling": {
|
||||
"released": "<Control>Page_Down"
|
||||
},
|
||||
"move_to_left_sibling": {
|
||||
"released": "<Control><Shift>Up"
|
||||
},
|
||||
"move_to_right_sibling": {
|
||||
"released": "<Control><Shift>Down"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Catppuccin Gedit theme based on Oblivion theme and Cappuccin for Visual Studio Code.
|
||||
-->
|
||||
|
||||
<style-scheme id="catppuccin_frappe" _name="Catppuccin frappe" version="1.0">
|
||||
|
||||
<author>sacerdos</author>
|
||||
<_description>Soothing pastel theme for Gedit</_description>
|
||||
|
||||
<!-- Catppuccin Palette -->
|
||||
<color name="frappe_rosewater" value="#f2d5cf"/>
|
||||
<color name="frappe_flamingo" value="#eebebe"/>
|
||||
<color name="frappe_pink" value="#f4b8e4"/>
|
||||
<color name="frappe_mauve" value="#ca9ee6"/>
|
||||
<color name="frappe_red" value="#e78284"/>
|
||||
<color name="frappe_maroon" value="#ea999c"/>
|
||||
<color name="frappe_peach" value="#ef9f76"/>
|
||||
<color name="frappe_yellow" value="#e5c890"/>
|
||||
<color name="frappe_green" value="#a6d189"/>
|
||||
<color name="frappe_teal" value="#81c8be"/>
|
||||
<color name="frappe_sky" value="#99d1db"/>
|
||||
<color name="frappe_sapphire" value="#85c1dc"/>
|
||||
<color name="frappe_blue" value="#8caaee"/>
|
||||
<color name="frappe_lavender" value="#babbf1"/>
|
||||
<color name="frappe_text" value="#c6d0f5"/>
|
||||
<color name="frappe_subtext1" value="#b5bfe2"/>
|
||||
<color name="frappe_subtext0" value="#a5adce"/>
|
||||
<color name="frappe_overlay2" value="#949cbb"/>
|
||||
<color name="frappe_overlay1" value="#838ba7"/>
|
||||
<color name="frappe_overlay0" value="#737994"/>
|
||||
<color name="frappe_surface2" value="#626880"/>
|
||||
<color name="frappe_surface1" value="#51576d"/>
|
||||
<color name="frappe_surface0" value="#51576d"/>
|
||||
<color name="frappe_base" value="#303446"/>
|
||||
<color name="frappe_mantle" value="#292c3c"/>
|
||||
<color name="frappe_crust" value="#232634"/>
|
||||
|
||||
<!-- Global Settings -->
|
||||
<style name="text" foreground="frappe_text" background = "frappe_base"/>
|
||||
<style name="selection" foreground="frappe_text" background="frappe_surface2"/>
|
||||
<style name="cursor" foreground="frappe_rosewater"/>
|
||||
<style name="secondary-cursor" foreground="frappe_rosewater"/>
|
||||
<style name="current-line" background="frappe_surface0"/>
|
||||
<style name="line-numbers" foreground="frappe_text" background="frappe_crust"/>
|
||||
<style name="draw-spaces" foreground="frappe_text"/>
|
||||
<style name="background-pattern" background="frappe_base"/>
|
||||
|
||||
<!-- Bracket Matching -->
|
||||
<style name="bracket-match" foreground="frappe_mauve"/>
|
||||
<style name="bracket-mismatch" foreground="frappe_text" background="frappe_peach"/>
|
||||
|
||||
<!-- Right Margin -->
|
||||
<style name="right-margin" foreground="frappe_text" background="frappe_crust"/>
|
||||
|
||||
<!-- Search Matching -->
|
||||
<style name="search-match" foreground="frappe_text" background="frappe_blue"/>
|
||||
|
||||
<!-- Comments -->
|
||||
<style name="def:comment" foreground="frappe_overlay0"/>
|
||||
<style name="def:shebang" foreground="frappe_overlay0" bold="true"/>
|
||||
<style name="def:doc-comment-element" italic="true"/>
|
||||
|
||||
<!-- Constants -->
|
||||
<style name="def:constant" foreground="frappe_green"/>
|
||||
<style name="def:string" foreground="frappe_green"/>
|
||||
<style name="def:special-char" foreground="frappe_lavender"/>
|
||||
<style name="def:special-constant" foreground="frappe_lavender"/>
|
||||
<style name="def:floating-point" foreground="frappe_lavender"/>
|
||||
|
||||
<!-- Identifiers -->
|
||||
<style name="def:identifier" foreground="frappe_blue"/>
|
||||
|
||||
<!-- Statements -->
|
||||
<style name="def:statement" foreground="frappe_sapphire" bold="true"/>
|
||||
|
||||
<!-- Types -->
|
||||
<style name="def:type" foreground="frappe_maroon" bold="true"/>
|
||||
|
||||
<!-- Markup -->
|
||||
<style name="def:emphasis" italic="true"/>
|
||||
<style name="def:strong-emphasis" foreground="frappe_yellow" bold="true"/>
|
||||
<style name="def:inline-code" foreground="frappe_green"/>
|
||||
<style name="def:insertion" underline="single"/>
|
||||
<style name="def:deletion" strikethrough="true"/>
|
||||
<style name="def:link-text" foreground="frappe_rosewater"/>
|
||||
<style name="def:link-symbol" foreground="frappe_blue" bold="true"/>
|
||||
<style name="def:link-destination" foreground="frappe_blue" italic="true" underline="single"/>
|
||||
<style name="def:heading" foreground="frappe_teal" bold="true"/>
|
||||
<style name="def:thematic-break" foreground="frappe_green" bold="true"/>
|
||||
<style name="def:preformatted-section" foreground="frappe_green"/>
|
||||
<style name="def:list-marker" foreground="frappe_teal" bold="true"/>
|
||||
|
||||
<!-- Others -->
|
||||
<style name="def:preprocessor" foreground="frappe_teal"/>
|
||||
<style name="def:error" foreground="frappe_maroon" bold="true"/>
|
||||
<style name="def:warning" foreground="frappe_peach"/>
|
||||
<style name="def:note" foreground="frappe_blue" bold="true"/>
|
||||
<style name="def:net-address" italic="true" underline="single"/>
|
||||
</style-scheme>
|
||||
@@ -1,100 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Catppuccin Gedit theme based on Oblivion theme and Cappuccin for Visual Studio Code.
|
||||
-->
|
||||
|
||||
<style-scheme id="catppuccin_latte" _name="Catppuccin latte" version="1.0">
|
||||
|
||||
<author>sacerdos</author>
|
||||
<_description>Soothing pastel theme for Gedit</_description>
|
||||
|
||||
<!-- Catppuccin Palette -->
|
||||
<color name="latte_rosewater" value="#dc8a78"/>
|
||||
<color name="latte_flamingo" value="#dd7878"/>
|
||||
<color name="latte_pink" value="#ea76cb"/>
|
||||
<color name="latte_mauve" value="#8839ef"/>
|
||||
<color name="latte_red" value="#d20f39"/>
|
||||
<color name="latte_maroon" value="#e64553"/>
|
||||
<color name="latte_peach" value="#fe640b"/>
|
||||
<color name="latte_yellow" value="#df8e1d"/>
|
||||
<color name="latte_green" value="#40a02b"/>
|
||||
<color name="latte_teal" value="#179299"/>
|
||||
<color name="latte_sky" value="#04a5e5"/>
|
||||
<color name="latte_sapphire" value="#209fb5"/>
|
||||
<color name="latte_blue" value="#1e66f5"/>
|
||||
<color name="latte_lavender" value="#7287fd"/>
|
||||
<color name="latte_text" value="#4c4f69"/>
|
||||
<color name="latte_subtext1" value="#5c5f77"/>
|
||||
<color name="latte_subtext0" value="#6c6f85"/>
|
||||
<color name="latte_overlay2" value="#7c7f93"/>
|
||||
<color name="latte_overlay1" value="#8c8fa1"/>
|
||||
<color name="latte_overlay0" value="#9ca0b0"/>
|
||||
<color name="latte_surface2" value="#acb0be"/>
|
||||
<color name="latte_surface1" value="#bcc0cc"/>
|
||||
<color name="latte_surface0" value="#ccd0da"/>
|
||||
<color name="latte_base" value="#eff1f5"/>
|
||||
<color name="latte_mantle" value="#e6e9ef"/>
|
||||
<color name="latte_crust" value="#dce0e8"/>
|
||||
|
||||
<!-- Global Settings -->
|
||||
<style name="text" foreground="latte_text" background = "latte_base"/>
|
||||
<style name="selection" foreground="latte_text" background="latte_surface2"/>
|
||||
<style name="cursor" foreground="latte_rosewater"/>
|
||||
<style name="secondary-cursor" foreground="latte_rosewater"/>
|
||||
<style name="current-line" background="latte_surface0"/>
|
||||
<style name="line-numbers" foreground="latte_text" background="latte_crust"/>
|
||||
<style name="draw-spaces" foreground="latte_text"/>
|
||||
<style name="background-pattern" background="latte_base"/>
|
||||
|
||||
<!-- Bracket Matching -->
|
||||
<style name="bracket-match" foreground="latte_mauve"/>
|
||||
<style name="bracket-mismatch" foreground="latte_text" background="latte_peach"/>
|
||||
|
||||
<!-- Right Margin -->
|
||||
<style name="right-margin" foreground="latte_text" background="latte_crust"/>
|
||||
|
||||
<!-- Search Matching -->
|
||||
<style name="search-match" foreground="latte_text" background="latte_blue"/>
|
||||
|
||||
<!-- Comments -->
|
||||
<style name="def:comment" foreground="latte_overlay0"/>
|
||||
<style name="def:shebang" foreground="latte_overlay0" bold="true"/>
|
||||
<style name="def:doc-comment-element" italic="true"/>
|
||||
|
||||
<!-- Constants -->
|
||||
<style name="def:constant" foreground="latte_green"/>
|
||||
<style name="def:string" foreground="latte_green"/>
|
||||
<style name="def:special-char" foreground="latte_lavender"/>
|
||||
<style name="def:special-constant" foreground="latte_lavender"/>
|
||||
<style name="def:floating-point" foreground="latte_lavender"/>
|
||||
|
||||
<!-- Identifiers -->
|
||||
<style name="def:identifier" foreground="latte_blue"/>
|
||||
|
||||
<!-- Statements -->
|
||||
<style name="def:statement" foreground="latte_sapphire" bold="true"/>
|
||||
|
||||
<!-- Types -->
|
||||
<style name="def:type" foreground="latte_maroon" bold="true"/>
|
||||
|
||||
<!-- Markup -->
|
||||
<style name="def:emphasis" italic="true"/>
|
||||
<style name="def:strong-emphasis" foreground="latte_yellow" bold="true"/>
|
||||
<style name="def:inline-code" foreground="latte_green"/>
|
||||
<style name="def:insertion" underline="single"/>
|
||||
<style name="def:deletion" strikethrough="true"/>
|
||||
<style name="def:link-text" foreground="latte_rosewater"/>
|
||||
<style name="def:link-symbol" foreground="latte_blue" bold="true"/>
|
||||
<style name="def:link-destination" foreground="latte_blue" italic="true" underline="single"/>
|
||||
<style name="def:heading" foreground="latte_teal" bold="true"/>
|
||||
<style name="def:thematic-break" foreground="latte_green" bold="true"/>
|
||||
<style name="def:preformatted-section" foreground="latte_green"/>
|
||||
<style name="def:list-marker" foreground="latte_teal" bold="true"/>
|
||||
|
||||
<!-- Others -->
|
||||
<style name="def:preprocessor" foreground="latte_teal"/>
|
||||
<style name="def:error" foreground="latte_maroon" bold="true"/>
|
||||
<style name="def:warning" foreground="latte_peach"/>
|
||||
<style name="def:note" foreground="latte_blue" bold="true"/>
|
||||
<style name="def:net-address" italic="true" underline="single"/>
|
||||
</style-scheme>
|
||||
@@ -1,100 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Catppuccin Gedit theme based on Oblivion theme and Cappuccin for Visual Studio Code.
|
||||
-->
|
||||
|
||||
<style-scheme id="catppuccin_macchiato" _name="Catppuccin macchiato" version="1.0">
|
||||
|
||||
<author>sacerdos</author>
|
||||
<_description>Soothing pastel theme for Gedit</_description>
|
||||
|
||||
<!-- Catppuccin Palette -->
|
||||
<color name="macchiato_rosewater" value="#f4dbd6"/>
|
||||
<color name="macchiato_flamingo" value="#f0c6c6"/>
|
||||
<color name="macchiato_pink" value="#f5bde6"/>
|
||||
<color name="macchiato_mauve" value="#c6a0f6"/>
|
||||
<color name="macchiato_red" value="#ed8796"/>
|
||||
<color name="macchiato_maroon" value="#ee99a0"/>
|
||||
<color name="macchiato_peach" value="#f5a97f"/>
|
||||
<color name="macchiato_yellow" value="#eed49f"/>
|
||||
<color name="macchiato_green" value="#a6da95"/>
|
||||
<color name="macchiato_teal" value="#8bd5ca"/>
|
||||
<color name="macchiato_sky" value="#91d7e3"/>
|
||||
<color name="macchiato_sapphire" value="#7dc4e4"/>
|
||||
<color name="macchiato_blue" value="#8aadf4"/>
|
||||
<color name="macchiato_lavender" value="#b7bdf8"/>
|
||||
<color name="macchiato_text" value="#cad3f5"/>
|
||||
<color name="macchiato_subtext1" value="#b8c0e0"/>
|
||||
<color name="macchiato_subtext0" value="#a5adcb"/>
|
||||
<color name="macchiato_overlay2" value="#939ab7"/>
|
||||
<color name="macchiato_overlay1" value="#8087a2"/>
|
||||
<color name="macchiato_overlay0" value="#6e738d"/>
|
||||
<color name="macchiato_surface2" value="#5b6078"/>
|
||||
<color name="macchiato_surface1" value="#494d64"/>
|
||||
<color name="macchiato_surface0" value="#363a4f"/>
|
||||
<color name="macchiato_base" value="#24273a"/>
|
||||
<color name="macchiato_mantle" value="#1e2030"/>
|
||||
<color name="macchiato_crust" value="#181926"/>
|
||||
|
||||
<!-- Global Settings -->
|
||||
<style name="text" foreground="macchiato_text" background = "macchiato_base"/>
|
||||
<style name="selection" foreground="macchiato_text" background="macchiato_surface2"/>
|
||||
<style name="cursor" foreground="macchiato_rosewater"/>
|
||||
<style name="secondary-cursor" foreground="macchiato_rosewater"/>
|
||||
<style name="current-line" background="macchiato_surface0"/>
|
||||
<style name="line-numbers" foreground="macchiato_text" background="macchiato_crust"/>
|
||||
<style name="draw-spaces" foreground="macchiato_text"/>
|
||||
<style name="background-pattern" background="macchiato_mantle"/>
|
||||
|
||||
<!-- Bracket Matching -->
|
||||
<style name="bracket-match" foreground="macchiato_mauve"/>
|
||||
<style name="bracket-mismatch" foreground="macchiato_text" background="macchiato_peach"/>
|
||||
|
||||
<!-- Right Margin -->
|
||||
<style name="right-margin" foreground="macchiato_text" background="crust"/>
|
||||
|
||||
<!-- Search Matching -->
|
||||
<style name="search-match" foreground="macchiato_text" background="macchiato_blue"/>
|
||||
|
||||
<!-- Comments -->
|
||||
<style name="def:comment" foreground="macchiato_overlay0"/>
|
||||
<style name="def:shebang" foreground="macchiato_overlay0" bold="true"/>
|
||||
<style name="def:doc-comment-element" italic="true"/>
|
||||
|
||||
<!-- Constants -->
|
||||
<style name="def:constant" foreground="macchiato_green"/>
|
||||
<style name="def:string" foreground="macchiato_green"/>
|
||||
<style name="def:special-char" foreground="macchiato_lavender"/>
|
||||
<style name="def:special-constant" foreground="macchiato_lavender"/>
|
||||
<style name="def:floating-point" foreground="macchiato_lavender"/>
|
||||
|
||||
<!-- Identifiers -->
|
||||
<style name="def:identifier" foreground="macchiato_blue"/>
|
||||
|
||||
<!-- Statements -->
|
||||
<style name="def:statement" foreground="macchiato_sapphire" bold="true"/>
|
||||
|
||||
<!-- Types -->
|
||||
<style name="def:type" foreground="macchiato_maroon" bold="true"/>
|
||||
|
||||
<!-- Markup -->
|
||||
<style name="def:emphasis" italic="true"/>
|
||||
<style name="def:strong-emphasis" foreground="macchiato_yellow" bold="true"/>
|
||||
<style name="def:inline-code" foreground="macchiato_green"/>
|
||||
<style name="def:insertion" underline="single"/>
|
||||
<style name="def:deletion" strikethrough="true"/>
|
||||
<style name="def:link-text" foreground="macchiato_rosewater"/>
|
||||
<style name="def:link-symbol" foreground="macchiato_blue" bold="true"/>
|
||||
<style name="def:link-destination" foreground="macchiato_blue" italic="true" underline="single"/>
|
||||
<style name="def:heading" foreground="macchiato_teal" bold="true"/>
|
||||
<style name="def:thematic-break" foreground="macchiato_green" bold="true"/>
|
||||
<style name="def:preformatted-section" foreground="macchiato_green"/>
|
||||
<style name="def:list-marker" foreground="macchiato_teal" bold="true"/>
|
||||
|
||||
<!-- Others -->
|
||||
<style name="def:preprocessor" foreground="macchiato_teal"/>
|
||||
<style name="def:error" foreground="macchiato_maroon" bold="true"/>
|
||||
<style name="def:warning" foreground="macchiato_peach"/>
|
||||
<style name="def:note" foreground="macchiato_blue" bold="true"/>
|
||||
<style name="def:net-address" italic="true" underline="single"/>
|
||||
</style-scheme>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user