initial push
20
README.md
|
@ -1,23 +1,11 @@
|
||||||
# Python-With-Gtk-Template
|
# LSP Manager
|
||||||
A template project for Python with Gtk applications.
|
A helpful tool to handle LSPs (Language Server Protocols) by creating the LSP process, sending client initialize and initialized messages, and allowing crafting of messages.
|
||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
* PyGObject (Gtk introspection library)
|
* PyGObject (Gtk introspection library)
|
||||||
* pyxdg (Desktop ".desktop" file parser)
|
* pyxdg (Desktop ".desktop" file parser)
|
||||||
* setproctitle (Define process title to search and kill more easily)
|
* setproctitle (Define process title to search and kill more easily)
|
||||||
* sqlmodel (SQL databases and is powered by Pydantic and SQLAlchemy)
|
|
||||||
|
|
||||||
### Note
|
### Note
|
||||||
* Move respetive sub folder content under user_config to the same places in Linux. Though, user/share/<app name> can go to ~/.config folder if prefered.
|
WIP
|
||||||
* In additiion, place the plugins folder in the same app folder you moved to /usr/share/<app name> or ~/.config/<app name> .
|
|
||||||
There are a "\<change_me\>" strings and files that need to be set according to your app's name located at:
|
|
||||||
* \_\_builtins\_\_.py
|
|
||||||
* user_config/bin/app_name
|
|
||||||
* user_config/usr/share/app_name
|
|
||||||
* user_config/usr/share/app_name/icons/app_name.png
|
|
||||||
* user_config/usr/share/app_name/icons/app_name-64x64.png
|
|
||||||
* user_config/usr/share/applications/app_name.desktop
|
|
||||||
|
|
||||||
|
|
||||||
For the user_config, after changing names and files, copy all content to their respective destinations.
|
|
||||||
The logic follows Debian Dpkg packaging and its placement logic.
|
|
|
@ -11,7 +11,7 @@ from libs.event_system import EventSystem
|
||||||
from libs.endpoint_registry import EndpointRegistry
|
from libs.endpoint_registry import EndpointRegistry
|
||||||
from libs.keybindings import Keybindings
|
from libs.keybindings import Keybindings
|
||||||
from libs.logger import Logger
|
from libs.logger import Logger
|
||||||
from libs.settings_manager.manager import SettingsManager
|
from libs.settings.manager import SettingsManager
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ def daemon_threaded_wrapper(fn):
|
||||||
|
|
||||||
# NOTE: Just reminding myself we can add to builtins two different ways...
|
# NOTE: Just reminding myself we can add to builtins two different ways...
|
||||||
# __builtins__.update({"event_system": Builtins()})
|
# __builtins__.update({"event_system": Builtins()})
|
||||||
builtins.app_name = "<change_me>"
|
builtins.APP_NAME = "LSP_Manager"
|
||||||
|
|
||||||
builtins.keybindings = Keybindings()
|
builtins.keybindings = Keybindings()
|
||||||
builtins.event_system = EventSystem()
|
builtins.event_system = EventSystem()
|
||||||
|
|
|
@ -18,7 +18,7 @@ from app import Application
|
||||||
|
|
||||||
|
|
||||||
def main(args, unknownargs):
|
def main(args, unknownargs):
|
||||||
setproctitle(f'{app_name}')
|
setproctitle(f'{APP_NAME}')
|
||||||
|
|
||||||
if args.debug == "true":
|
if args.debug == "true":
|
||||||
settings_manager.set_debug(True)
|
settings_manager.set_debug(True)
|
||||||
|
|
|
@ -39,7 +39,7 @@ class Application:
|
||||||
message = f"FILE|{arg}"
|
message = f"FILE|{arg}"
|
||||||
ipc_server.send_ipc_message(message)
|
ipc_server.send_ipc_message(message)
|
||||||
|
|
||||||
raise AppLaunchException(f"{app_name} IPC Server Exists: Have sent path(s) to it and closing...")
|
raise AppLaunchException(f"{APP_NAME} IPC Server Exists: Have sent path(s) to it and closing...")
|
||||||
|
|
||||||
def ipc_realization_check(self, ipc_server):
|
def ipc_realization_check(self, ipc_server):
|
||||||
try:
|
try:
|
||||||
|
@ -56,7 +56,7 @@ class Application:
|
||||||
try:
|
try:
|
||||||
# kill -SIGUSR2 <pid> from Linux/Unix or SIGBREAK signal from Windows
|
# kill -SIGUSR2 <pid> from Linux/Unix or SIGBREAK signal from Windows
|
||||||
signal.signal(
|
signal.signal(
|
||||||
vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR1"),
|
vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"),
|
||||||
debug_signal_handler
|
debug_signal_handler
|
||||||
)
|
)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class BuilderWrapper(Gtk.Builder):
|
||||||
|
"""docstring for BuilderWrapper."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(BuilderWrapper, self).__init__()
|
||||||
|
|
||||||
|
self.objects = {}
|
||||||
|
|
||||||
|
def get_object(self, id: str, use_gtk: bool = True) -> any:
|
||||||
|
if not use_gtk:
|
||||||
|
return self.objects[id]
|
||||||
|
|
||||||
|
return super(BuilderWrapper, self).get_object(id)
|
||||||
|
|
||||||
|
def expose_object(self, id: str, object: any, use_gtk: bool = True) -> None:
|
||||||
|
if not use_gtk:
|
||||||
|
self.objects[id] = object
|
||||||
|
else:
|
||||||
|
super(BuilderWrapper, self).expose_object(id, object)
|
||||||
|
|
||||||
|
def dereference_object(self, id: str) -> None:
|
||||||
|
del self.objects[id]
|
|
@ -22,7 +22,7 @@ class BaseContainer(Gtk.Box):
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
|
|
||||||
self.show_all()
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
|
@ -33,8 +33,8 @@ class BaseContainer(Gtk.Box):
|
||||||
...
|
...
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("update_transparency", self._update_transparency)
|
event_system.subscribe("update-transparency", self._update_transparency)
|
||||||
event_system.subscribe("remove_transparency", self._remove_transparency)
|
event_system.subscribe("remove-transparency", self._remove_transparency)
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
self.add(HeaderContainer())
|
self.add(HeaderContainer())
|
||||||
|
|
|
@ -23,13 +23,13 @@ class BodyContainer(Gtk.Box):
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
|
|
||||||
self.show_all()
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||||
self.ctx.add_class("body-container")
|
self.ctx.add_class("body-container")
|
||||||
self.set_homogeneous(True)
|
# self.set_homogeneous(True)
|
||||||
|
|
||||||
def _setup_signals(self):
|
def _setup_signals(self):
|
||||||
...
|
...
|
||||||
|
|
|
@ -6,7 +6,7 @@ gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from ..widgets.webkit.webkit_ui import WebkitUI
|
from ..widgets.lsp_notebook import LSPNotebook
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,6 +21,8 @@ class CenterContainer(Gtk.Box):
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
|
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||||
|
@ -31,18 +33,7 @@ class CenterContainer(Gtk.Box):
|
||||||
...
|
...
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
# event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc)
|
|
||||||
...
|
...
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
glade_box = self._builder.get_object("glade_box")
|
self.add( LSPNotebook() )
|
||||||
button = Gtk.Button(label = "Click Me!")
|
|
||||||
|
|
||||||
button.connect("clicked", self._hello_world)
|
|
||||||
|
|
||||||
self.add(button)
|
|
||||||
self.add(glade_box)
|
|
||||||
self.add( WebkitUI() )
|
|
||||||
|
|
||||||
def _hello_world(self, widget = None, eve = None):
|
|
||||||
logger.debug("Hello, World!")
|
|
|
@ -6,7 +6,8 @@ gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from ..widgets.transparency_scale import TransparencyScale
|
from ..widgets.controls.open_files_button import OpenFilesButton
|
||||||
|
from ..widgets.controls.transparency_scale import TransparencyScale
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,8 +22,6 @@ class HeaderContainer(Gtk.Box):
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
|
|
||||||
self.show_all()
|
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
self.set_orientation(Gtk.Orientation.HORIZONTAL)
|
||||||
|
@ -32,15 +31,19 @@ class HeaderContainer(Gtk.Box):
|
||||||
...
|
...
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
...
|
event_system.subscribe("tggl-top-main-menubar", self.tggl_top_main_menubar)
|
||||||
|
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
button = Gtk.Button(label = "Interactive Debug")
|
button = Gtk.Button(label = "Interactive Debug")
|
||||||
button.connect("clicked", self._interactive_debug)
|
button.connect("clicked", self._interactive_debug)
|
||||||
|
|
||||||
self.add(TransparencyScale())
|
self.add( OpenFilesButton() )
|
||||||
|
self.add( TransparencyScale() )
|
||||||
self.add(button)
|
self.add(button)
|
||||||
|
|
||||||
def _interactive_debug(self, widget = None, eve = None):
|
def _interactive_debug(self, widget = None, eve = None):
|
||||||
event_system.emit("load_interactive_debug")
|
event_system.emit("load-interactive-debug")
|
||||||
|
|
||||||
|
def tggl_top_main_menubar(self):
|
||||||
|
self.hide() if self.is_visible() else self.show_all()
|
|
@ -18,6 +18,8 @@ class LeftContainer(Gtk.Box):
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||||
|
@ -28,7 +30,6 @@ class LeftContainer(Gtk.Box):
|
||||||
...
|
...
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
# event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc)
|
|
||||||
...
|
...
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
|
|
|
@ -18,6 +18,8 @@ class RightContainer(Gtk.Box):
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_widgets()
|
self._load_widgets()
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_orientation(Gtk.Orientation.VERTICAL)
|
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||||
|
@ -28,7 +30,6 @@ class RightContainer(Gtk.Box):
|
||||||
...
|
...
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
# event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc)
|
|
||||||
...
|
...
|
||||||
|
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# Python imports
|
# Python imports
|
||||||
import os
|
|
||||||
|
|
||||||
# Lib imports
|
# Lib imports
|
||||||
import gi
|
import gi
|
||||||
|
@ -19,6 +18,8 @@ from .bridge_controller import BridgeController
|
||||||
|
|
||||||
class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
|
class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
|
||||||
def __init__(self, args, unknownargs):
|
def __init__(self, args, unknownargs):
|
||||||
|
self.collect_files_dirs(args, unknownargs)
|
||||||
|
|
||||||
self.setup_controller_data()
|
self.setup_controller_data()
|
||||||
|
|
||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
|
@ -27,16 +28,13 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
|
||||||
self._load_controllers()
|
self._load_controllers()
|
||||||
|
|
||||||
if args.no_plugins == "false":
|
if args.no_plugins == "false":
|
||||||
self.plugins.launch_plugins()
|
self.plugins_controller.pre_launch_plugins()
|
||||||
|
|
||||||
for arg in unknownargs + [args.new_tab,]:
|
if args.no_plugins == "false":
|
||||||
if os.path.isfile(arg):
|
self.plugins_controller.post_launch_plugins()
|
||||||
message = f"FILE|{arg}"
|
|
||||||
event_system.emit("post_file_to_ipc", message)
|
|
||||||
|
|
||||||
if os.path.isdir(arg):
|
for file in settings_manager.get_starting_files():
|
||||||
message = f"DIR|{arg}"
|
event_system.emit("post-file-to-ipc", file)
|
||||||
event_system.emit("post_file_to_ipc", message)
|
|
||||||
|
|
||||||
logger.info(f"Made it past {self.__class__} loading...")
|
logger.info(f"Made it past {self.__class__} loading...")
|
||||||
|
|
||||||
|
@ -50,10 +48,10 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
|
||||||
self.window.connect("key-release-event", self.on_global_key_release_controller)
|
self.window.connect("key-release-event", self.on_global_key_release_controller)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("shutting_down", lambda: print("Shutting down..."))
|
event_system.subscribe("shutting-down", lambda: print("Shutting down..."))
|
||||||
event_system.subscribe("handle_file_from_ipc", self.handle_file_from_ipc)
|
event_system.subscribe("handle-file-from-ipc", self.handle_file_from_ipc)
|
||||||
event_system.subscribe("handle_dir_from_ipc", self.handle_dir_from_ipc)
|
event_system.subscribe("handle-dir-from-ipc", self.handle_dir_from_ipc)
|
||||||
event_system.subscribe("tggl_top_main_menubar", self._tggl_top_main_menubar)
|
event_system.subscribe("tggl-top-main-menubar", self._tggl_top_main_menubar)
|
||||||
|
|
||||||
def _load_controllers(self):
|
def _load_controllers(self):
|
||||||
BridgeController()
|
BridgeController()
|
||||||
|
@ -61,8 +59,7 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
|
||||||
def _tggl_top_main_menubar(self):
|
def _tggl_top_main_menubar(self):
|
||||||
logger.debug("_tggl_top_main_menubar > stub...")
|
logger.debug("_tggl_top_main_menubar > stub...")
|
||||||
|
|
||||||
def setup_builder_and_container(self):
|
def _load_glade_file(self):
|
||||||
self.builder = Gtk.Builder()
|
|
||||||
self.builder.add_from_file(settings_manager.get_glade_file())
|
self.builder.add_from_file(settings_manager.get_glade_file())
|
||||||
self.builder.expose_object("main_window", self.window)
|
self.builder.expose_object("main_window", self.window)
|
||||||
|
|
||||||
|
@ -70,3 +67,4 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
|
||||||
self.base_container = BaseContainer()
|
self.base_container = BaseContainer()
|
||||||
|
|
||||||
settings_manager.register_signals_to_builder([self, self.base_container])
|
settings_manager.register_signals_to_builder([self, self.base_container])
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ from shutil import which
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from plugins.plugins_controller import PluginsController
|
from plugins.plugins_controller import PluginsController
|
||||||
|
from ..builder_wrapper import BuilderWrapper
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,15 +16,31 @@ class BaseControllerData:
|
||||||
|
|
||||||
def setup_controller_data(self) -> None:
|
def setup_controller_data(self) -> None:
|
||||||
self.window = settings_manager.get_main_window()
|
self.window = settings_manager.get_main_window()
|
||||||
self.builder = None
|
self.builder = BuilderWrapper()
|
||||||
|
self.plugins_controller = PluginsController()
|
||||||
|
|
||||||
self.base_container = None
|
self.base_container = None
|
||||||
self.was_midified_key = False
|
self.was_midified_key = False
|
||||||
self.ctrl_down = False
|
self.ctrl_down = False
|
||||||
self.shift_down = False
|
self.shift_down = False
|
||||||
self.alt_down = False
|
self.alt_down = False
|
||||||
|
|
||||||
self.setup_builder_and_container()
|
self._load_glade_file()
|
||||||
self.plugins = PluginsController()
|
|
||||||
|
|
||||||
|
def collect_files_dirs(self, args, unknownargs):
|
||||||
|
files = []
|
||||||
|
for arg in unknownargs + [args.new_tab,]:
|
||||||
|
if os.path.isdir( arg.replace("file://", "") ):
|
||||||
|
files.append( f"DIR|{arg.replace('file://', '')}" )
|
||||||
|
|
||||||
|
# NOTE: If passing line number with file split against :
|
||||||
|
if os.path.isfile( arg.replace("file://", "").split(":")[0] ):
|
||||||
|
files.append( f"FILE|{arg.replace('file://', '')}" )
|
||||||
|
|
||||||
|
if len(files) > 0:
|
||||||
|
settings_manager.set_is_starting_with_file(True)
|
||||||
|
settings_manager.set_starting_files(files)
|
||||||
|
|
||||||
def get_base_container(self):
|
def get_base_container(self):
|
||||||
return self.base_container
|
return self.base_container
|
||||||
|
|
|
@ -20,19 +20,19 @@ class BridgeController:
|
||||||
...
|
...
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("handle_bridge_event", self.handle_bridge_event)
|
event_system.subscribe("handle-bridge-event", self.handle_bridge_event)
|
||||||
|
|
||||||
|
|
||||||
def handle_bridge_event(self, event):
|
def handle_bridge_event(self, event):
|
||||||
match event.topic:
|
match event.topic:
|
||||||
case "save":
|
case "save":
|
||||||
event_system.emit(f"handle_file_event_{event.originator}", (event,))
|
event_system.emit(f"handle-file-event-{event.originator}", (event,))
|
||||||
case "close":
|
case "close":
|
||||||
event_system.emit(f"handle_file_event_{event.originator}", (event,))
|
event_system.emit(f"handle-file-event-{event.originator}", (event,))
|
||||||
case "load_buffer":
|
case "load_buffer":
|
||||||
event_system.emit(f"handle_file_event_{event.originator}", (event,))
|
event_system.emit(f"handle-file-event-{event.originator}", (event,))
|
||||||
case "load_file":
|
case "load_file":
|
||||||
event_system.emit(f"handle_file_event_{event.originator}", (event,))
|
event_system.emit(f"handle-file-event-{event.originator}", (event,))
|
||||||
case "alert":
|
case "alert":
|
||||||
content = base64.b64decode( event.content.encode() ).decode("utf-8")
|
content = base64.b64decode( event.content.encode() ).decode("utf-8")
|
||||||
logger.info(f"\nMessage Topic: {event.topic}\nMessage Content: {content}")
|
logger.info(f"\nMessage Topic: {event.topic}\nMessage Content: {content}")
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
"""
|
||||||
|
Widgets.Controls Module
|
||||||
|
"""
|
|
@ -0,0 +1,86 @@
|
||||||
|
# Python imports
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
gi.require_version('Gdk', '3.0')
|
||||||
|
from gi.repository import Gtk
|
||||||
|
from gi.repository import Gdk
|
||||||
|
from gi.repository import Gio
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class OpenFilesButton(Gtk.Button):
|
||||||
|
"""docstring for OpenFilesButton."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(OpenFilesButton, self).__init__()
|
||||||
|
|
||||||
|
self._setup_styling()
|
||||||
|
self._setup_signals()
|
||||||
|
self._subscribe_to_events()
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
|
|
||||||
|
def _setup_styling(self):
|
||||||
|
self.set_label("Open File(s)...")
|
||||||
|
self.set_image( Gtk.Image.new_from_icon_name("gtk-open", 4) )
|
||||||
|
self.set_always_show_image(True)
|
||||||
|
self.set_image_position(1) # Left - 0, Right = 1
|
||||||
|
self.set_hexpand(False)
|
||||||
|
|
||||||
|
def _setup_signals(self):
|
||||||
|
self.connect("button-release-event", self._open_files)
|
||||||
|
|
||||||
|
def _subscribe_to_events(self):
|
||||||
|
event_system.subscribe("open_files", self._open_files)
|
||||||
|
|
||||||
|
def _load_widgets(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _open_files(self, widget = None, eve = None, gfile = None):
|
||||||
|
start_dir = None
|
||||||
|
_gfiles = []
|
||||||
|
|
||||||
|
if gfile and gfile.query_exists():
|
||||||
|
start_dir = gfile.get_parent()
|
||||||
|
|
||||||
|
chooser = Gtk.FileChooserDialog("Open File(s)...", None,
|
||||||
|
Gtk.FileChooserAction.OPEN,
|
||||||
|
(
|
||||||
|
Gtk.STOCK_CANCEL,
|
||||||
|
Gtk.ResponseType.CANCEL,
|
||||||
|
Gtk.STOCK_OPEN,
|
||||||
|
Gtk.ResponseType.OK
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
chooser.set_select_multiple(True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
folder = widget.get_current_file().get_parent() if not start_dir else start_dir
|
||||||
|
chooser.set_current_folder( folder.get_path() )
|
||||||
|
except Exception as e:
|
||||||
|
...
|
||||||
|
|
||||||
|
response = chooser.run()
|
||||||
|
if not response == Gtk.ResponseType.OK:
|
||||||
|
chooser.destroy()
|
||||||
|
return _gfiles
|
||||||
|
|
||||||
|
filenames = chooser.get_filenames()
|
||||||
|
if not filenames:
|
||||||
|
chooser.destroy()
|
||||||
|
return _gfiles
|
||||||
|
|
||||||
|
for file in filenames:
|
||||||
|
path = file if os.path.isabs(file) else os.path.abspath(file)
|
||||||
|
_gfiles.append( Gio.File.new_for_path(path) )
|
||||||
|
|
||||||
|
chooser.destroy()
|
||||||
|
|
||||||
|
logger.debug(_gfiles)
|
||||||
|
return _gfiles
|
|
@ -37,12 +37,12 @@ class TransparencyScale(Gtk.Scale):
|
||||||
def _load_widgets(self):
|
def _load_widgets(self):
|
||||||
adjust = self.get_adjustment()
|
adjust = self.get_adjustment()
|
||||||
adjust.set_lower(0)
|
adjust.set_lower(0)
|
||||||
adjust.set_upper(99)
|
adjust.set_upper(100)
|
||||||
adjust.set_value(settings.theming.transparency)
|
adjust.set_value(settings.theming.transparency)
|
||||||
adjust.set_step_increment(1.0)
|
adjust.set_step_increment(1.0)
|
||||||
|
|
||||||
def _update_transparency(self, range):
|
def _update_transparency(self, range):
|
||||||
event_system.emit("remove_transparency")
|
event_system.emit("remove-transparency")
|
||||||
tp = int(range.get_value())
|
tp = int(range.get_value())
|
||||||
settings.theming.transparency = tp
|
settings.theming.transparency = tp
|
||||||
event_system.emit("update_transparency")
|
event_system.emit("update-transparency")
|
|
@ -0,0 +1,380 @@
|
||||||
|
# Python imports
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Request type formatting
|
||||||
|
# https://github.com/microsoft/multilspy/blob/main/src/multilspy/language_server.py#L417
|
||||||
|
|
||||||
|
content_part = """{
|
||||||
|
"method": "textDocument/definition",
|
||||||
|
"params": {
|
||||||
|
"textDocument": {
|
||||||
|
"uri": "file:///home/abaddon/Coding/Projects/Active/Python_Projects/testing/lsp_manager/src/core/widgets/lsp_message_box.py",
|
||||||
|
"languageId": "python3",
|
||||||
|
"version": 1,
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"line": 5,
|
||||||
|
"character": 12,
|
||||||
|
"offset": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
references_query = """{
|
||||||
|
|
||||||
|
"method": "textDocument/references",
|
||||||
|
"params": {
|
||||||
|
"context": {
|
||||||
|
"includeDeclaration": false
|
||||||
|
},
|
||||||
|
"textDocument": {
|
||||||
|
"uri": "file:///home/abaddon/Coding/Projects/Active/Python_Projects/testing/lsp_manager/src/core/widgets/lsp_message_box.py",
|
||||||
|
"languageId": "python3",
|
||||||
|
"version": 1,
|
||||||
|
"text": ""
|
||||||
|
},
|
||||||
|
"position": {
|
||||||
|
"line": 43,
|
||||||
|
"character": 13,
|
||||||
|
"offset": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
symbols_query = """{
|
||||||
|
"method": "textDocument/documentSymbol",
|
||||||
|
"params": {
|
||||||
|
"textDocument": {
|
||||||
|
"uri": "file:///home/abaddon/Coding/Projects/Active/Python_Projects/testing/lsp_manager/src/core/widgets/lsp_message_box.py",
|
||||||
|
"languageId": "python3",
|
||||||
|
"version": 1,
|
||||||
|
"text": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
LEN_HEADER = "Content-Length: "
|
||||||
|
TYPE_HEADER = "Content-Type: "
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LSPMessageBox(Gtk.Box):
|
||||||
|
def __init__(self):
|
||||||
|
super(LSPMessageBox, self).__init__()
|
||||||
|
|
||||||
|
self._lsp_pid = -1
|
||||||
|
self._message_id = 0
|
||||||
|
|
||||||
|
# https://github.com/microsoft/multilspy/tree/main/src/multilspy/language_servers
|
||||||
|
# initialize-params-slim.json was created off of jedi_language_server one
|
||||||
|
self._lsp_init_data = settings_manager.get_lsp_init_data()
|
||||||
|
|
||||||
|
self.read_lock = threading.Lock()
|
||||||
|
self.write_lock = threading.Lock()
|
||||||
|
|
||||||
|
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("lsp-message-box")
|
||||||
|
|
||||||
|
self.set_orientation(Gtk.Orientation.VERTICAL)
|
||||||
|
self.set_hexpand(True)
|
||||||
|
self.set_vexpand(True)
|
||||||
|
|
||||||
|
def _setup_signals(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _subscribe_to_events(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _load_widgets(self):
|
||||||
|
scrolled_win = Gtk.ScrolledWindow()
|
||||||
|
self.top_buttons = Gtk.ButtonBox()
|
||||||
|
self.buttons = Gtk.ButtonBox()
|
||||||
|
|
||||||
|
file_choser_lbl = Gtk.Label(label="Workspace Folder:")
|
||||||
|
self.file_choser_btn = Gtk.FileChooserButton()
|
||||||
|
|
||||||
|
initialize_btn = Gtk.Button(label="Send Initialize Message")
|
||||||
|
notification_btn = Gtk.Button(label="Send Notification Message")
|
||||||
|
message_btn = Gtk.Button(label="Send Message")
|
||||||
|
start_stop_lsp_btn = Gtk.Button(label="Start LSP")
|
||||||
|
|
||||||
|
source_view = GtkSource.View()
|
||||||
|
language_manager = GtkSource.LanguageManager()
|
||||||
|
style_scheme_manager = GtkSource.StyleSchemeManager()
|
||||||
|
style_scheme = style_scheme_manager.get_scheme("peacocks-in-space")
|
||||||
|
style_scheme = style_scheme if style_scheme else style_scheme_manager.get_scheme("solarized-dark")
|
||||||
|
self.buffer = source_view.get_buffer()
|
||||||
|
|
||||||
|
self.file_choser_btn.set_title("Chose Workspace")
|
||||||
|
self.file_choser_btn.set_action( Gtk.FileChooserAction.SELECT_FOLDER )
|
||||||
|
self.file_choser_btn.set_uri("file:///home/abaddon/Coding/Projects/Active/Python_Projects/testing/lsp_manager")
|
||||||
|
|
||||||
|
self.buffer.set_language( language_manager.get_language("json") )
|
||||||
|
self.buffer.set_style_scheme(style_scheme)
|
||||||
|
self.buffer.set_text(content_part)
|
||||||
|
|
||||||
|
source_view.set_indent_width(4)
|
||||||
|
source_view.set_tab_width(4)
|
||||||
|
source_view.set_insert_spaces_instead_of_tabs(True)
|
||||||
|
source_view.set_hexpand(True)
|
||||||
|
source_view.set_vexpand(True)
|
||||||
|
|
||||||
|
initialize_btn.connect("clicked", self.send_initialize_message)
|
||||||
|
notification_btn.connect("clicked", self.send_notification_message)
|
||||||
|
message_btn.connect("clicked", self.send_message_message)
|
||||||
|
start_stop_lsp_btn.connect("clicked", self.start_stop_lsp)
|
||||||
|
|
||||||
|
scrolled_win.add(source_view)
|
||||||
|
|
||||||
|
self.top_buttons.add(Gtk.Label(label=f"Message ID: {self._message_id}"))
|
||||||
|
self.top_buttons.add(file_choser_lbl)
|
||||||
|
self.top_buttons.add(self.file_choser_btn)
|
||||||
|
|
||||||
|
self.buttons.add(initialize_btn)
|
||||||
|
self.buttons.add(notification_btn)
|
||||||
|
self.buttons.add(message_btn)
|
||||||
|
self.buttons.add(start_stop_lsp_btn)
|
||||||
|
|
||||||
|
self.add(self.top_buttons)
|
||||||
|
self.add(scrolled_win)
|
||||||
|
self.add(self.buttons)
|
||||||
|
|
||||||
|
self._disable_buttons()
|
||||||
|
start_stop_lsp_btn.set_sensitive(True)
|
||||||
|
|
||||||
|
def update_message_id_label(self):
|
||||||
|
self.top_buttons.get_children()[0].set_label(f"Message ID: {self._message_id}")
|
||||||
|
|
||||||
|
def post_int_run(self):
|
||||||
|
lsp_ui = self.get_parent()
|
||||||
|
self.alt_command_entry = lsp_ui.alt_command_entry
|
||||||
|
self.command_entry = lsp_ui.command_entry
|
||||||
|
self.socket_entry = lsp_ui.socket_entry
|
||||||
|
self.init_options_buffer = lsp_ui.init_options_text_vw.get_buffer()
|
||||||
|
del lsp_ui
|
||||||
|
|
||||||
|
def send_initialize_message(self, button, eve = None):
|
||||||
|
workspace_file = self.file_choser_btn.get_file().get_path()
|
||||||
|
workspace_uri = self.file_choser_btn.get_uri()
|
||||||
|
folder_name = os.path.basename(workspace_file)
|
||||||
|
|
||||||
|
self._lsp_init_data["processId"] = settings_manager.get_app_pid()
|
||||||
|
self._lsp_init_data["rootPath"] = workspace_file
|
||||||
|
self._lsp_init_data["rootUri"] = workspace_uri
|
||||||
|
self._lsp_init_data["workspaceFolders"] = [
|
||||||
|
{
|
||||||
|
"name": folder_name,
|
||||||
|
"uri": workspace_uri
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
start, end = self.init_options_buffer.get_bounds()
|
||||||
|
init_ops = self.init_options_buffer.get_text(start, end, True)
|
||||||
|
self._lsp_init_data["initializationOptions"] = json.loads(init_ops)
|
||||||
|
|
||||||
|
self.make_request("initialize", self._lsp_init_data)
|
||||||
|
button.set_sensitive(False)
|
||||||
|
|
||||||
|
def send_initialized_message():
|
||||||
|
self.make_request("initialized")
|
||||||
|
|
||||||
|
def make_notification(self, method: str, params: {} = {}):
|
||||||
|
data = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": method,
|
||||||
|
"params": params
|
||||||
|
}
|
||||||
|
message_str = json.dumps(data)
|
||||||
|
message_size = len(message_str)
|
||||||
|
message = f"Content-Length: {message_size}\r\n\r\n{message_str}"
|
||||||
|
|
||||||
|
self.lsp_process.stdin.write( message.encode("utf-8") )
|
||||||
|
self.lsp_process.stdin.flush()
|
||||||
|
|
||||||
|
def make_request(self, method: str, params: {} = {}):
|
||||||
|
self._monitor_lsp_response()
|
||||||
|
|
||||||
|
data = {
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": self._message_id,
|
||||||
|
"method": method,
|
||||||
|
"params": params
|
||||||
|
}
|
||||||
|
message_str = json.dumps(data)
|
||||||
|
message_size = len(message_str)
|
||||||
|
message = f"Content-Length: {message_size}\r\n\r\n{message_str}"
|
||||||
|
|
||||||
|
with self.write_lock:
|
||||||
|
self.lsp_process.stdin.write( message.encode("utf-8") )
|
||||||
|
self.lsp_process.stdin.flush()
|
||||||
|
|
||||||
|
self._message_id += 1
|
||||||
|
self.update_message_id_label()
|
||||||
|
|
||||||
|
|
||||||
|
def send_notification_message(self, button, eve = None):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def send_message_message(self, button, eve = None):
|
||||||
|
start, end = self.buffer.get_bounds()
|
||||||
|
data = self.buffer.get_text(start, end, True)
|
||||||
|
message = json.loads(data)
|
||||||
|
|
||||||
|
self.make_request(message["method"], message["params"])
|
||||||
|
|
||||||
|
def start_stop_lsp(self, button, eve = None):
|
||||||
|
if self._lsp_pid == -1:
|
||||||
|
pid = self.start_lsp()
|
||||||
|
if not pid: return
|
||||||
|
|
||||||
|
button.set_label("Stop LSP")
|
||||||
|
self._lsp_pid = pid
|
||||||
|
self._monitor_lsp_response()
|
||||||
|
self._enable_buttons()
|
||||||
|
else:
|
||||||
|
button.set_label("Start LSP")
|
||||||
|
self.stop_lsp()
|
||||||
|
self._disable_buttons()
|
||||||
|
button.set_sensitive(True)
|
||||||
|
|
||||||
|
def start_lsp(self):
|
||||||
|
_command: str = self.alt_command_entry.get_text()
|
||||||
|
# _command: str = self.command_entry.get_text()
|
||||||
|
# _command: str = self.socket_entry.get_text()
|
||||||
|
command: [] = _command.split() if len( _command.split() ) > 0 else [ _command ]
|
||||||
|
self.lsp_process = subprocess.Popen(
|
||||||
|
command,
|
||||||
|
stdout = subprocess.PIPE,
|
||||||
|
stdin = subprocess.PIPE
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.lsp_process.pid
|
||||||
|
|
||||||
|
def stop_lsp(self):
|
||||||
|
if self._lsp_pid == -1: return
|
||||||
|
|
||||||
|
self._lsp_pid = -1
|
||||||
|
self._message_id = 0
|
||||||
|
self.lsp_process.terminate()
|
||||||
|
self.update_message_id_label()
|
||||||
|
|
||||||
|
# https://github.com/sr-lab/coqpyt/blob/master/coqpyt/lsp/json_rpc_endpoint.py#L65
|
||||||
|
# Virtually this whole method unabashedly taken from ^ ...
|
||||||
|
@daemon_threaded
|
||||||
|
def _monitor_lsp_response(self):
|
||||||
|
with self.read_lock:
|
||||||
|
message_size = None
|
||||||
|
while True:
|
||||||
|
line = self.lsp_process.stdout.readline()
|
||||||
|
if not line: return None # Quit listener...
|
||||||
|
|
||||||
|
line = line.decode("utf-8")
|
||||||
|
if not line.endswith("\r\n"):
|
||||||
|
raise Exception(
|
||||||
|
"Bad header: missing newline"
|
||||||
|
)
|
||||||
|
line = line[:-2] # Strip the "\r\n"
|
||||||
|
if line == "": # We're done with the headers...
|
||||||
|
break
|
||||||
|
elif line.startswith(LEN_HEADER):
|
||||||
|
line = line[len(LEN_HEADER) :]
|
||||||
|
if not line.isdigit():
|
||||||
|
raise Exception(
|
||||||
|
"Bad header: size is not int",
|
||||||
|
)
|
||||||
|
message_size = int(line)
|
||||||
|
elif line.startswith(TYPE_HEADER):
|
||||||
|
# Not doing anything with type header, currently...
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
line = line.split(LEN_HEADER)
|
||||||
|
if len(line) == 2:
|
||||||
|
message_size = line[1]
|
||||||
|
raise Exception(
|
||||||
|
"Bad header: unknown header"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not message_size: return
|
||||||
|
|
||||||
|
data = self.lsp_process.stdout.read(message_size)
|
||||||
|
jsonrpc_res = data.decode("utf-8")
|
||||||
|
lsp_result = json.loads( jsonrpc_res )
|
||||||
|
response_id = -1
|
||||||
|
|
||||||
|
if not lsp_result: return
|
||||||
|
if "id" in lsp_result.keys(): response_id = lsp_result["id"]
|
||||||
|
|
||||||
|
GLib.idle_add(self.handle_lsp_response, response_id, lsp_result)
|
||||||
|
|
||||||
|
def handle_lsp_response(self, id: int, lsp_result: {}):
|
||||||
|
keys = lsp_result.keys()
|
||||||
|
if "error" in keys:
|
||||||
|
lsp_result = lsp_result["error"]
|
||||||
|
logger.debug(f"LSP Error Code: {lsp_result['code']}")
|
||||||
|
logger.debug(f"LSP Error Message:\n{lsp_result['message']}")
|
||||||
|
return
|
||||||
|
|
||||||
|
if "result" in keys:
|
||||||
|
lsp_result = lsp_result["result"]
|
||||||
|
|
||||||
|
if isinstance(lsp_result, dict):
|
||||||
|
keys = lsp_result.keys()
|
||||||
|
if "capabilities" in keys:
|
||||||
|
logger.debug(f"LSP Capabilities Response:\n{lsp_result}")
|
||||||
|
self.send_initialized_message()
|
||||||
|
|
||||||
|
|
||||||
|
if isinstance(lsp_result, list):
|
||||||
|
print()
|
||||||
|
print( str(id) )
|
||||||
|
print(lsp_result)
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
|
||||||
|
if isinstance(lsp_result, tuple):
|
||||||
|
print()
|
||||||
|
print( str(id) )
|
||||||
|
print(lsp_result)
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
|
||||||
|
def _enable_buttons(self):
|
||||||
|
for button in self.buttons.get_children():
|
||||||
|
button.set_sensitive(True)
|
||||||
|
|
||||||
|
def _disable_buttons(self):
|
||||||
|
for button in self.buttons.get_children():
|
||||||
|
button.set_sensitive(False)
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
# 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 .lsp_window import LSPWindow
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LSPNotebook(Gtk.Notebook):
|
||||||
|
def __init__(self):
|
||||||
|
super(LSPNotebook, self).__init__()
|
||||||
|
|
||||||
|
self._builder = settings_manager.get_builder()
|
||||||
|
self.lsp_config_data = settings_manager.get_lsp_config_data()
|
||||||
|
|
||||||
|
self._setup_styling()
|
||||||
|
self._setup_signals()
|
||||||
|
self._subscribe_to_events()
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
|
|
||||||
|
def _setup_styling(self):
|
||||||
|
self.set_tab_pos(Gtk.PositionType.LEFT)
|
||||||
|
|
||||||
|
self.set_hexpand(True)
|
||||||
|
self.set_vexpand(True)
|
||||||
|
|
||||||
|
ctx = self.get_style_context()
|
||||||
|
ctx.add_class("lsp-notebook")
|
||||||
|
|
||||||
|
def _setup_signals(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _subscribe_to_events(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _load_widgets(self):
|
||||||
|
for language, data in self.lsp_config_data.items():
|
||||||
|
tab_widget = Gtk.Label(label=language)
|
||||||
|
lsp_window = LSPWindow(language, data)
|
||||||
|
|
||||||
|
self.append_page(lsp_window, tab_widget)
|
||||||
|
self.set_tab_detachable(lsp_window, False)
|
||||||
|
self.set_tab_reorderable(lsp_window, False)
|
|
@ -0,0 +1,124 @@
|
||||||
|
# Python imports
|
||||||
|
import json
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .lsp_message_box import LSPMessageBox
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LSPUI(Gtk.Grid):
|
||||||
|
def __init__(self, language, data):
|
||||||
|
super(LSPUI, self).__init__()
|
||||||
|
|
||||||
|
self._data = data
|
||||||
|
self._language = language
|
||||||
|
self._no_init_ops_text = "{\n \n}"
|
||||||
|
|
||||||
|
self.alt_command_entry = Gtk.Entry()
|
||||||
|
self.command_entry = Gtk.Entry()
|
||||||
|
self.socket_entry = Gtk.Entry()
|
||||||
|
self.init_options_text_vw = GtkSource.View()
|
||||||
|
self.message_box = LSPMessageBox()
|
||||||
|
|
||||||
|
self._setup_styling()
|
||||||
|
self._setup_signals()
|
||||||
|
self._subscribe_to_events()
|
||||||
|
self._load_widgets()
|
||||||
|
|
||||||
|
self.message_box.post_int_run()
|
||||||
|
|
||||||
|
self.show_all()
|
||||||
|
|
||||||
|
|
||||||
|
def _setup_styling(self):
|
||||||
|
ctx = self.get_style_context()
|
||||||
|
ctx.add_class("lsp-ui")
|
||||||
|
|
||||||
|
self.set_hexpand(True)
|
||||||
|
self.set_vexpand(True)
|
||||||
|
self.set_margin_top(5)
|
||||||
|
self.set_margin_bottom(5)
|
||||||
|
self.set_margin_left(10)
|
||||||
|
self.set_margin_right(10)
|
||||||
|
|
||||||
|
self.alt_command_entry.set_hexpand(True)
|
||||||
|
self.command_entry.set_hexpand(True)
|
||||||
|
self.socket_entry.set_hexpand(True)
|
||||||
|
self.init_options_text_vw.set_vexpand(True)
|
||||||
|
self.init_options_text_vw.set_hexpand(True)
|
||||||
|
|
||||||
|
self.alt_command_entry.set_placeholder_text("Alt Command:")
|
||||||
|
self.command_entry.set_placeholder_text("Command:")
|
||||||
|
self.socket_entry.set_placeholder_text("Socket")
|
||||||
|
|
||||||
|
def _setup_signals(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _subscribe_to_events(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _load_widgets(self):
|
||||||
|
_language_manager = GtkSource.LanguageManager()
|
||||||
|
_style_scheme_manager = GtkSource.StyleSchemeManager()
|
||||||
|
style_scheme = _style_scheme_manager.get_scheme("peacocks-in-space")
|
||||||
|
style_scheme = style_scheme if style_scheme else _style_scheme_manager.get_scheme("solarized-dark")
|
||||||
|
buffer = self.init_options_text_vw.get_buffer()
|
||||||
|
scrolled_win1 = Gtk.ScrolledWindow()
|
||||||
|
|
||||||
|
buffer.set_language( _language_manager.get_language("json") )
|
||||||
|
buffer.set_style_scheme(style_scheme)
|
||||||
|
|
||||||
|
info_link = self._data["info"]
|
||||||
|
info_link_title = self._language.title() + " LSP Info" if info_link else "Generic LSP Info"
|
||||||
|
info_link = info_link if info_link else "https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#contentPart"
|
||||||
|
link_btn = Gtk.LinkButton(info_link)
|
||||||
|
|
||||||
|
alt_command_lbl = Gtk.Label(label="Alt Command:")
|
||||||
|
command_lbl = Gtk.Label(label="Command:")
|
||||||
|
socket_lbl = Gtk.Label(label="Socket:")
|
||||||
|
init_options_lbl = Gtk.Label(label="Initialization Options:")
|
||||||
|
message_box_lbl = Gtk.Label(label="Message Box:")
|
||||||
|
|
||||||
|
self.alt_command_entry.set_text(self._data["alt-command"])
|
||||||
|
self.command_entry.set_text(self._data["command"])
|
||||||
|
self.socket_entry.set_text(self._data["socket"])
|
||||||
|
|
||||||
|
init_ops_txt = json.dumps( self._data["initialization-options"], separators=(',', ':'), indent=4 )
|
||||||
|
init_ops_txt = init_ops_txt if not init_ops_txt in ["", "{}"] else self._no_init_ops_text
|
||||||
|
buffer.set_text(init_ops_txt)
|
||||||
|
|
||||||
|
link_btn.set_label(info_link_title)
|
||||||
|
init_options_lbl.set_margin_top(10)
|
||||||
|
message_box_lbl.set_margin_top(10)
|
||||||
|
self.init_options_text_vw.set_indent_width(4)
|
||||||
|
self.init_options_text_vw.set_tab_width(4)
|
||||||
|
self.init_options_text_vw.set_insert_spaces_instead_of_tabs(True)
|
||||||
|
self.init_options_text_vw.set_hexpand(True)
|
||||||
|
self.init_options_text_vw.set_vexpand(True)
|
||||||
|
|
||||||
|
scrolled_win1.add(self.init_options_text_vw)
|
||||||
|
|
||||||
|
# child, left, top, width, height
|
||||||
|
self.attach(link_btn, 0, 0, 3, 1)
|
||||||
|
|
||||||
|
self.attach(alt_command_lbl, 0, 1, 1, 1)
|
||||||
|
self.attach(command_lbl, 0, 2, 1, 1)
|
||||||
|
self.attach(socket_lbl, 0, 3, 1, 1)
|
||||||
|
|
||||||
|
self.attach(self.alt_command_entry, 1, 1, 2, 1)
|
||||||
|
self.attach(self.command_entry, 1, 2, 2, 1)
|
||||||
|
self.attach(self.socket_entry, 1, 3, 2, 1)
|
||||||
|
|
||||||
|
self.attach(init_options_lbl, 0, 4, 3, 1)
|
||||||
|
self.attach(scrolled_win1, 0, 5, 3, 1)
|
||||||
|
|
||||||
|
self.attach(message_box_lbl, 0, 6, 3, 1)
|
||||||
|
self.attach(self.message_box, 0, 7, 3, 1)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
from gi.repository import Gtk
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
from .lsp_ui import LSPUI
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class LSPWindow(Gtk.ScrolledWindow):
|
||||||
|
def __init__(self, language, data):
|
||||||
|
super(LSPWindow, self).__init__()
|
||||||
|
|
||||||
|
self._builder = settings_manager.get_builder()
|
||||||
|
|
||||||
|
self._setup_styling()
|
||||||
|
self._setup_signals()
|
||||||
|
self._subscribe_to_events()
|
||||||
|
self._load_widgets(language, data)
|
||||||
|
|
||||||
|
|
||||||
|
def _setup_styling(self):
|
||||||
|
ctx = self.get_style_context()
|
||||||
|
ctx.add_class("lsp-window")
|
||||||
|
|
||||||
|
def _setup_signals(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _subscribe_to_events(self):
|
||||||
|
...
|
||||||
|
|
||||||
|
def _load_widgets(self, language, data):
|
||||||
|
viewport = Gtk.Viewport()
|
||||||
|
viewport.add( LSPUI(language, data) )
|
||||||
|
self.add(viewport)
|
|
@ -9,17 +9,14 @@ from gi.repository import Gdk
|
||||||
from gi.repository import WebKit2
|
from gi.repository import WebKit2
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
from libs.data_types import Event
|
from libs.settings.other.webkit_ui_settings import WebkitUISettings
|
||||||
|
from libs.dto.event import Event
|
||||||
|
|
||||||
|
|
||||||
class WebkitUI(WebKit2.WebView):
|
class WebkitUI(WebKit2.WebView):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(WebkitUI, self).__init__()
|
super(WebkitUI, self).__init__()
|
||||||
|
|
||||||
# self.get_context().set_sandbox_enabled(False)
|
|
||||||
|
|
||||||
self._load_settings()
|
|
||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
self._load_view()
|
self._load_view()
|
||||||
|
@ -27,10 +24,6 @@ class WebkitUI(WebKit2.WebView):
|
||||||
|
|
||||||
self.show_all()
|
self.show_all()
|
||||||
|
|
||||||
if settings_manager.is_debug():
|
|
||||||
inspector = self.get_inspector()
|
|
||||||
inspector.show()
|
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_vexpand(True)
|
self.set_vexpand(True)
|
||||||
|
@ -38,7 +31,7 @@ class WebkitUI(WebKit2.WebView):
|
||||||
self.set_background_color( Gdk.RGBA(0, 0, 0, 0.0) )
|
self.set_background_color( Gdk.RGBA(0, 0, 0, 0.0) )
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe(f"ui_message", self.ui_message)
|
event_system.subscribe(f"ui-message", self.ui_message)
|
||||||
|
|
||||||
def _load_settings(self):
|
def _load_settings(self):
|
||||||
self.set_settings( WebkitUISettings() )
|
self.set_settings( WebkitUISettings() )
|
||||||
|
@ -54,7 +47,6 @@ class WebkitUI(WebKit2.WebView):
|
||||||
|
|
||||||
def _setup_content_manager(self):
|
def _setup_content_manager(self):
|
||||||
content_manager = self.get_user_content_manager()
|
content_manager = self.get_user_content_manager()
|
||||||
|
|
||||||
content_manager.connect("script-message-received", self._process_js_message)
|
content_manager.connect("script-message-received", self._process_js_message)
|
||||||
content_manager.register_script_message_handler("backend")
|
content_manager.register_script_message_handler("backend")
|
||||||
|
|
||||||
|
@ -64,45 +56,14 @@ class WebkitUI(WebKit2.WebView):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
event = Event( **json.loads(message) )
|
event = Event( **json.loads(message) )
|
||||||
event_system.emit("handle_bridge_event", (event,))
|
event_system.emit("handle-bridge-event", (event,))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info(e)
|
logger.info(e)
|
||||||
|
|
||||||
def ui_message(self, mtype, message):
|
def ui_message(self, message, mtype):
|
||||||
command = f"displayMessage('{message}', '{mtype}', '3')"
|
command = f"displayMessage('{message}', '{mtype}', '3')"
|
||||||
self.run_javascript(command, None, None)
|
self.run_javascript(command, None, None)
|
||||||
|
|
||||||
|
def run_javascript(self, script, cancellable, callback):
|
||||||
class WebkitUISettings(WebKit2.Settings):
|
logger.debug(script)
|
||||||
def __init__(self):
|
super().run_javascript(script, cancellable, callback)
|
||||||
super(WebkitUISettings, self).__init__()
|
|
||||||
|
|
||||||
self._set_default_settings()
|
|
||||||
|
|
||||||
|
|
||||||
# Note: Highly insecure setup but most "app" like setup I could think of.
|
|
||||||
# Audit heavily any scripts/links ran/clicked under this setup!
|
|
||||||
def _set_default_settings(self):
|
|
||||||
# self.set_enable_xss_auditor(True)
|
|
||||||
# self.set_enable_hyperlink_auditing(True)
|
|
||||||
self.set_enable_xss_auditor(False)
|
|
||||||
self.set_enable_hyperlink_auditing(False)
|
|
||||||
self.set_enable_dns_prefetching(False)
|
|
||||||
self.set_allow_file_access_from_file_urls(True)
|
|
||||||
self.set_allow_universal_access_from_file_urls(True)
|
|
||||||
# self.set_enable_java(True)
|
|
||||||
|
|
||||||
self.set_enable_page_cache(False)
|
|
||||||
self.set_enable_offline_web_application_cache(False)
|
|
||||||
self.set_enable_html5_local_storage(False)
|
|
||||||
self.set_enable_html5_database(False)
|
|
||||||
|
|
||||||
self.set_print_backgrounds(False)
|
|
||||||
self.set_enable_tabs_to_links(False)
|
|
||||||
self.set_enable_fullscreen(True)
|
|
||||||
self.set_enable_developer_extras(True)
|
|
||||||
self.set_enable_webrtc(True)
|
|
||||||
self.set_enable_webaudio(True)
|
|
||||||
self.set_enable_accelerated_2d_canvas(True)
|
|
||||||
|
|
||||||
self.set_user_agent(f"Mozilla/5.0 {app_name}")
|
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
# Python imports
|
|
||||||
|
|
||||||
# Lib imports
|
|
||||||
import gi
|
|
||||||
gi.require_version('Gdk', '3.0')
|
|
||||||
gi.require_version('WebKit2', '4.0')
|
|
||||||
from gi.repository import Gdk
|
|
||||||
from gi.repository import WebKit2
|
|
||||||
|
|
||||||
# Application imports
|
|
||||||
from libs.settings_manager.other.webkit_ui_settings import WebkitUISettings
|
|
||||||
|
|
||||||
|
|
||||||
class WebkitUI(WebKit2.WebView):
|
|
||||||
def __init__(self):
|
|
||||||
super(WebkitUI, self).__init__()
|
|
||||||
|
|
||||||
self._setup_styling()
|
|
||||||
self._subscribe_to_events()
|
|
||||||
self._load_view()
|
|
||||||
self._setup_content_manager()
|
|
||||||
|
|
||||||
self.show_all()
|
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
|
||||||
self.set_vexpand(True)
|
|
||||||
self.set_hexpand(True)
|
|
||||||
self.set_background_color( Gdk.RGBA(0, 0, 0, 0.0) )
|
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
|
||||||
event_system.subscribe(f"ui_message", self.ui_message)
|
|
||||||
|
|
||||||
def _load_settings(self):
|
|
||||||
self.set_settings( WebkitUISettings() )
|
|
||||||
|
|
||||||
def _load_view(self):
|
|
||||||
path = settings_manager.get_context_path()
|
|
||||||
data = None
|
|
||||||
|
|
||||||
with open(f"{path}/index.html", "r") as f:
|
|
||||||
data = f.read()
|
|
||||||
|
|
||||||
self.load_html(content = data, base_uri = f"file://{path}/")
|
|
||||||
|
|
||||||
def _setup_content_manager(self):
|
|
||||||
content_manager = self.get_user_content_manager()
|
|
||||||
content_manager.connect("script-message-received", self._process_js_message)
|
|
||||||
content_manager.register_script_message_handler("backend")
|
|
||||||
|
|
||||||
def _process_js_message(self, user_content_manager, js_result):
|
|
||||||
js_value = js_result.get_js_value()
|
|
||||||
message = js_value.to_string()
|
|
||||||
|
|
||||||
try:
|
|
||||||
event = Event( **json.loads(message) )
|
|
||||||
event_system.emit("handle_bridge_event", (event,))
|
|
||||||
except Exception as e:
|
|
||||||
logger.info(e)
|
|
||||||
|
|
||||||
def ui_message(self, message, mtype):
|
|
||||||
command = f"displayMessage('{message}', '{mtype}', '3')"
|
|
||||||
self.run_javascript(command, None, None)
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from gi.repository import Gdk
|
||||||
from gi.repository import GLib
|
from gi.repository import GLib
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
|
from libs.status_icon import StatusIcon
|
||||||
from core.controllers.base_controller import BaseController
|
from core.controllers.base_controller import BaseController
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@ class Window(Gtk.ApplicationWindow):
|
||||||
super(Window, self).__init__()
|
super(Window, self).__init__()
|
||||||
settings_manager.set_main_window(self)
|
settings_manager.set_main_window(self)
|
||||||
|
|
||||||
|
self._status_icon = None
|
||||||
self._controller = None
|
self._controller = None
|
||||||
|
|
||||||
self._setup_styling()
|
self._setup_styling()
|
||||||
|
@ -41,7 +43,7 @@ class Window(Gtk.ApplicationWindow):
|
||||||
|
|
||||||
|
|
||||||
def _setup_styling(self):
|
def _setup_styling(self):
|
||||||
self.set_title(f"{app_name}")
|
self.set_title(f"{APP_NAME}")
|
||||||
self.set_icon_from_file( settings_manager.get_window_icon() )
|
self.set_icon_from_file( settings_manager.get_window_icon() )
|
||||||
self.set_gravity(5) # 5 = CENTER
|
self.set_gravity(5) # 5 = CENTER
|
||||||
self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS
|
self.set_position(1) # 1 = CENTER, 4 = CENTER_ALWAYS
|
||||||
|
@ -58,14 +60,15 @@ class Window(Gtk.ApplicationWindow):
|
||||||
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self._tear_down)
|
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, self._tear_down)
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("tear_down", self._tear_down)
|
event_system.subscribe("tear-down", self._tear_down)
|
||||||
event_system.subscribe("load_interactive_debug", self._load_interactive_debug)
|
event_system.subscribe("load-interactive-debug", self._load_interactive_debug)
|
||||||
|
|
||||||
def _load_widgets(self, args, unknownargs):
|
def _load_widgets(self, args, unknownargs):
|
||||||
if settings_manager.is_debug():
|
if settings_manager.is_debug():
|
||||||
self.set_interactive_debugging(True)
|
self.set_interactive_debugging(True)
|
||||||
|
|
||||||
self._controller = BaseController(args, unknownargs)
|
self._controller = BaseController(args, unknownargs)
|
||||||
|
self._status_icon = StatusIcon()
|
||||||
if not self._controller:
|
if not self._controller:
|
||||||
raise ControllerStartException("BaseController exited and doesn't exist...")
|
raise ControllerStartException("BaseController exited and doesn't exist...")
|
||||||
|
|
||||||
|
@ -90,7 +93,7 @@ class Window(Gtk.ApplicationWindow):
|
||||||
if visual and screen.is_composited() and settings.config.make_transparent == 0:
|
if visual and screen.is_composited() and settings.config.make_transparent == 0:
|
||||||
self.set_visual(visual)
|
self.set_visual(visual)
|
||||||
self.set_app_paintable(True)
|
self.set_app_paintable(True)
|
||||||
self.connect("draw", self._area_draw)
|
# self.connect("draw", self._area_draw)
|
||||||
|
|
||||||
# bind css file
|
# bind css file
|
||||||
cssProvider = Gtk.CssProvider()
|
cssProvider = Gtk.CssProvider()
|
||||||
|
@ -107,17 +110,17 @@ class Window(Gtk.ApplicationWindow):
|
||||||
|
|
||||||
|
|
||||||
def _on_focus_in_event(self, widget, event):
|
def _on_focus_in_event(self, widget, event):
|
||||||
event_system.emit("pause_dnd_signals")
|
event_system.emit("pause-dnd-signals")
|
||||||
|
|
||||||
def _on_focus_out_event(self, widget, event):
|
def _on_focus_out_event(self, widget, event):
|
||||||
event_system.emit("listen_dnd_signals")
|
event_system.emit("listen-dnd-signals")
|
||||||
|
|
||||||
def _load_interactive_debug(self):
|
def _load_interactive_debug(self):
|
||||||
self.set_interactive_debugging(True)
|
self.set_interactive_debugging(True)
|
||||||
|
|
||||||
|
|
||||||
def _tear_down(self, widget = None, eve = None):
|
def _tear_down(self, widget = None, eve = None):
|
||||||
event_system.emit("shutting_down")
|
event_system.emit("shutting-down")
|
||||||
|
|
||||||
size = self.get_size()
|
size = self.get_size()
|
||||||
pos = self.get_position()
|
pos = self.get_position()
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
"""
|
||||||
|
DB module
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .models import User
|
||||||
|
from .db import DB
|
|
@ -18,7 +18,7 @@ def debug_signal_handler(signal, frame):
|
||||||
rpdb2.start_embedded_debugger("foobar", True, True)
|
rpdb2.start_embedded_debugger("foobar", True, True)
|
||||||
rpdb2.setbreak(depth=1)
|
rpdb2.setbreak(depth=1)
|
||||||
return
|
return
|
||||||
except StandardError:
|
except Exception:
|
||||||
...
|
...
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -26,7 +26,7 @@ def debug_signal_handler(signal, frame):
|
||||||
logger.debug("\n\nStarting embedded rconsole debugger...\n\n")
|
logger.debug("\n\nStarting embedded rconsole debugger...\n\n")
|
||||||
rconsole.spawn_server()
|
rconsole.spawn_server()
|
||||||
return
|
return
|
||||||
except StandardError as ex:
|
except Exception as ex:
|
||||||
...
|
...
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -34,7 +34,15 @@ def debug_signal_handler(signal, frame):
|
||||||
logger.debug("\n\nStarting PuDB debugger...\n\n")
|
logger.debug("\n\nStarting PuDB debugger...\n\n")
|
||||||
set_trace(paused = True)
|
set_trace(paused = True)
|
||||||
return
|
return
|
||||||
except StandardError as ex:
|
except Exception as ex:
|
||||||
|
...
|
||||||
|
|
||||||
|
try:
|
||||||
|
import ipdb
|
||||||
|
logger.debug("\n\nStarting IPDB debugger...\n\n")
|
||||||
|
ipdb.set_trace()
|
||||||
|
return
|
||||||
|
except Exception as ex:
|
||||||
...
|
...
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -42,11 +50,11 @@ def debug_signal_handler(signal, frame):
|
||||||
logger.debug("\n\nStarting embedded PDB debugger...\n\n")
|
logger.debug("\n\nStarting embedded PDB debugger...\n\n")
|
||||||
pdb.Pdb(skip=['gi.*']).set_trace()
|
pdb.Pdb(skip=['gi.*']).set_trace()
|
||||||
return
|
return
|
||||||
except StandardError as ex:
|
except Exception as ex:
|
||||||
...
|
...
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import code
|
import code
|
||||||
code.interact()
|
code.interact()
|
||||||
except StandardError as ex:
|
except Exception as ex:
|
||||||
logger.debug(f"{ex}, returning to normal program flow...")
|
logger.debug(f"{ex}, returning to normal program flow...")
|
|
@ -13,17 +13,17 @@ from .singleton import Singleton
|
||||||
|
|
||||||
|
|
||||||
class IPCServer(Singleton):
|
class IPCServer(Singleton):
|
||||||
""" Create a listener so that other {app_name} instances send requests back to existing instance. """
|
""" Create a listener so that other {APP_NAME} instances send requests back to existing instance. """
|
||||||
def __init__(self, ipc_address: str = '127.0.0.1', conn_type: str = "socket"):
|
def __init__(self, ipc_address: str = '127.0.0.1', conn_type: str = "socket"):
|
||||||
self.is_ipc_alive = False
|
self.is_ipc_alive = False
|
||||||
self._ipc_port = 4848
|
self._ipc_port = 4848
|
||||||
self._ipc_address = ipc_address
|
self._ipc_address = ipc_address
|
||||||
self._conn_type = conn_type
|
self._conn_type = conn_type
|
||||||
self._ipc_authkey = b'' + bytes(f'{app_name}-ipc', 'utf-8')
|
self._ipc_authkey = b'' + bytes(f'{APP_NAME}-ipc', 'utf-8')
|
||||||
self._ipc_timeout = 15.0
|
self._ipc_timeout = 15.0
|
||||||
|
|
||||||
if conn_type == "socket":
|
if conn_type == "socket":
|
||||||
self._ipc_address = f'/tmp/{app_name}-ipc.sock'
|
self._ipc_address = f'/tmp/{APP_NAME}-ipc.sock'
|
||||||
elif conn_type == "full_network":
|
elif conn_type == "full_network":
|
||||||
self._ipc_address = '0.0.0.0'
|
self._ipc_address = '0.0.0.0'
|
||||||
elif conn_type == "full_network_unsecured":
|
elif conn_type == "full_network_unsecured":
|
||||||
|
@ -35,7 +35,7 @@ class IPCServer(Singleton):
|
||||||
self._subscribe_to_events()
|
self._subscribe_to_events()
|
||||||
|
|
||||||
def _subscribe_to_events(self):
|
def _subscribe_to_events(self):
|
||||||
event_system.subscribe("post_file_to_ipc", self.send_ipc_message)
|
event_system.subscribe("post-file-to-ipc", self.send_ipc_message)
|
||||||
|
|
||||||
|
|
||||||
def create_ipc_listener(self) -> None:
|
def create_ipc_listener(self) -> None:
|
||||||
|
@ -74,12 +74,12 @@ class IPCServer(Singleton):
|
||||||
if "FILE|" in msg:
|
if "FILE|" in msg:
|
||||||
file = msg.split("FILE|")[1].strip()
|
file = msg.split("FILE|")[1].strip()
|
||||||
if file:
|
if file:
|
||||||
event_system.emit("handle_file_from_ipc", file)
|
event_system.emit("handle-file-from-ipc", file)
|
||||||
|
|
||||||
if "DIR|" in msg:
|
if "DIR|" in msg:
|
||||||
file = msg.split("DIR|")[1].strip()
|
file = msg.split("DIR|")[1].strip()
|
||||||
if file:
|
if file:
|
||||||
event_system.emit("handle_dir_from_ipc", file)
|
event_system.emit("handle-dir-from-ipc", file)
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
break
|
break
|
||||||
|
|
|
@ -67,4 +67,4 @@ class DnDMixin:
|
||||||
|
|
||||||
files.append(gfile)
|
files.append(gfile)
|
||||||
|
|
||||||
event_system.emit('set_pre_drop_dnd', (files,))
|
event_system.emit('set-pre-drop-dnd', (files,))
|
|
@ -68,11 +68,11 @@ class KeyboardSignalsMixin:
|
||||||
if mapping:
|
if mapping:
|
||||||
self.handle_mapped_key_event(mapping)
|
self.handle_mapped_key_event(mapping)
|
||||||
else:
|
else:
|
||||||
self.handle_as_key_event_scope(mapping)
|
self.handle_as_key_event_scope(keyname)
|
||||||
|
|
||||||
def handle_mapped_key_event(self, mapping):
|
def handle_mapped_key_event(self, mapping):
|
||||||
try:
|
try:
|
||||||
self.handle_as_controller_scope()
|
self.handle_as_controller_scope(mapping)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.handle_as_plugin_scope(mapping)
|
self.handle_as_plugin_scope(mapping)
|
||||||
|
|
||||||
|
@ -86,13 +86,11 @@ class KeyboardSignalsMixin:
|
||||||
sender = ""
|
sender = ""
|
||||||
eve_type = mapping
|
eve_type = mapping
|
||||||
|
|
||||||
self.handle_as_key_event_system(sender, eve_type)
|
self.handle_key_event_system(sender, eve_type)
|
||||||
|
|
||||||
def handle_as_key_event_scope(self, mapping):
|
|
||||||
logger.debug(f"on_global_key_release_controller > key > {keyname}")
|
|
||||||
|
|
||||||
|
def handle_as_key_event_scope(self, keyname):
|
||||||
if self.ctrl_down and not keyname in ["1", "kp_1", "2", "kp_2", "3", "kp_3", "4", "kp_4"]:
|
if self.ctrl_down and not keyname in ["1", "kp_1", "2", "kp_2", "3", "kp_3", "4", "kp_4"]:
|
||||||
self.handle_key_event_system(None, mapping)
|
self.handle_key_event_system(None, keyname)
|
||||||
|
|
||||||
def handle_key_event_system(self, sender, eve_type):
|
def handle_key_event_system(self, sender, eve_type):
|
||||||
event_system.emit(eve_type)
|
event_system.emit(eve_type)
|
|
@ -24,8 +24,8 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._SCRIPT_PTH = path.dirname(path.realpath(__file__))
|
self._SCRIPT_PTH = path.dirname(path.realpath(__file__))
|
||||||
self._USER_HOME = path.expanduser('~')
|
self._USER_HOME = path.expanduser('~')
|
||||||
self._HOME_CONFIG_PATH = f"{self._USER_HOME}/.config/{app_name.lower()}"
|
self._HOME_CONFIG_PATH = f"{self._USER_HOME}/.config/{APP_NAME.lower()}"
|
||||||
self._USR_PATH = f"/usr/share/{app_name.lower()}"
|
self._USR_PATH = f"/usr/share/{APP_NAME.lower()}"
|
||||||
self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json"
|
self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json"
|
||||||
|
|
||||||
self._CONTEXT_PATH = f"{self._HOME_CONFIG_PATH}/context_path"
|
self._CONTEXT_PATH = f"{self._HOME_CONFIG_PATH}/context_path"
|
||||||
|
@ -35,10 +35,14 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
self._GLADE_FILE = f"{self._HOME_CONFIG_PATH}/Main_Window.glade"
|
self._GLADE_FILE = f"{self._HOME_CONFIG_PATH}/Main_Window.glade"
|
||||||
self._CSS_FILE = f"{self._HOME_CONFIG_PATH}/stylesheet.css"
|
self._CSS_FILE = f"{self._HOME_CONFIG_PATH}/stylesheet.css"
|
||||||
self._KEY_BINDINGS_FILE = f"{self._HOME_CONFIG_PATH}/key-bindings.json"
|
self._KEY_BINDINGS_FILE = f"{self._HOME_CONFIG_PATH}/key-bindings.json"
|
||||||
self._PID_FILE = f"{self._HOME_CONFIG_PATH}/{app_name.lower()}.pid"
|
self._PID_FILE = f"{self._HOME_CONFIG_PATH}/{APP_NAME.lower()}.pid"
|
||||||
self._UI_WIDEGTS_PATH = f"{self._HOME_CONFIG_PATH}/ui_widgets"
|
self._UI_WIDEGTS_PATH = f"{self._HOME_CONFIG_PATH}/ui_widgets"
|
||||||
self._CONTEXT_MENU = f"{self._HOME_CONFIG_PATH}/contexct_menu.json"
|
self._CONTEXT_MENU = f"{self._HOME_CONFIG_PATH}/contexct_menu.json"
|
||||||
self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{app_name.lower()}.png"
|
self._LSP_CONFIG = f"{self._HOME_CONFIG_PATH}/lsp-servers-config.json"
|
||||||
|
# https://github.com/microsoft/multilspy/tree/main/src/multilspy/language_servers
|
||||||
|
# initialize-params-slim.json was created off of jedi_language_server one
|
||||||
|
self._LSP_INIT_CONFIG = f"{self._HOME_CONFIG_PATH}/initialize-params-slim.json"
|
||||||
|
self._WINDOW_ICON = f"{self._DEFAULT_ICONS}/{APP_NAME.lower()}.png"
|
||||||
|
|
||||||
# self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json"
|
# self._USR_CONFIG_FILE = f"{self._USR_PATH}/settings.json"
|
||||||
# self._PLUGINS_PATH = f"plugins"
|
# self._PLUGINS_PATH = f"plugins"
|
||||||
|
@ -46,8 +50,8 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
# self._GLADE_FILE = f"Main_Window.glade"
|
# self._GLADE_FILE = f"Main_Window.glade"
|
||||||
# self._CSS_FILE = f"stylesheet.css"
|
# self._CSS_FILE = f"stylesheet.css"
|
||||||
# self._KEY_BINDINGS_FILE = f"key-bindings.json"
|
# self._KEY_BINDINGS_FILE = f"key-bindings.json"
|
||||||
# self._PID_FILE = f"{app_name.lower()}.pid"
|
# self._PID_FILE = f"{APP_NAME.lower()}.pid"
|
||||||
# self._WINDOW_ICON = f"{app_name.lower()}.png"
|
# self._WINDOW_ICON = f"{APP_NAME.lower()}.png"
|
||||||
# self._UI_WIDEGTS_PATH = f"ui_widgets"
|
# self._UI_WIDEGTS_PATH = f"ui_widgets"
|
||||||
# self._CONTEXT_MENU = f"contexct_menu.json"
|
# self._CONTEXT_MENU = f"contexct_menu.json"
|
||||||
# self._DEFAULT_ICONS = f"icons"
|
# self._DEFAULT_ICONS = f"icons"
|
||||||
|
@ -79,7 +83,7 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
if not path.exists(self._CSS_FILE):
|
if not path.exists(self._CSS_FILE):
|
||||||
raise MissingConfigError("Unable to find the application Stylesheet file.")
|
raise MissingConfigError("Unable to find the application Stylesheet file.")
|
||||||
if not path.exists(self._WINDOW_ICON):
|
if not path.exists(self._WINDOW_ICON):
|
||||||
self._WINDOW_ICON = f"{self._USR_PATH}/icons/{app_name.lower()}.png"
|
self._WINDOW_ICON = f"{self._USR_PATH}/icons/{APP_NAME.lower()}.png"
|
||||||
if not path.exists(self._WINDOW_ICON):
|
if not path.exists(self._WINDOW_ICON):
|
||||||
raise MissingConfigError("Unable to find the application icon.")
|
raise MissingConfigError("Unable to find the application icon.")
|
||||||
if not path.exists(self._UI_WIDEGTS_PATH):
|
if not path.exists(self._UI_WIDEGTS_PATH):
|
||||||
|
@ -101,6 +105,18 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print( f"Settings Manager: {self._CONTEXT_MENU}\n\t\t{repr(e)}" )
|
print( f"Settings Manager: {self._CONTEXT_MENU}\n\t\t{repr(e)}" )
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self._LSP_CONFIG) as file:
|
||||||
|
self._lsp_config_data = json.load(file)
|
||||||
|
except Exception as e:
|
||||||
|
print( f"Settings Manager: {self._LSP_CONFIG}\n\t\t{repr(e)}" )
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(self._LSP_INIT_CONFIG) as file:
|
||||||
|
self._lsp_init_data = json.load(file)
|
||||||
|
except Exception as e:
|
||||||
|
print( f"Settings Manager: {self._LSP_INIT_CONFIG}\n\t\t{repr(e)}" )
|
||||||
|
|
||||||
|
|
||||||
self.settings: Settings = None
|
self.settings: Settings = None
|
||||||
self._main_window = None
|
self._main_window = None
|
||||||
|
@ -110,6 +126,8 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
self._trace_debug = False
|
self._trace_debug = False
|
||||||
self._debug = False
|
self._debug = False
|
||||||
self._dirty_start = False
|
self._dirty_start = False
|
||||||
|
self._passed_in_file = False
|
||||||
|
self._starting_files = []
|
||||||
|
|
||||||
|
|
||||||
def register_signals_to_builder(self, classes=None):
|
def register_signals_to_builder(self, classes=None):
|
||||||
|
@ -128,7 +146,6 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
def set_main_window(self, window): self._main_window = window
|
def set_main_window(self, window): self._main_window = window
|
||||||
def set_builder(self, builder) -> any: self._builder = builder
|
def set_builder(self, builder) -> any: self._builder = builder
|
||||||
|
|
||||||
|
|
||||||
def get_monitor_data(self) -> list:
|
def get_monitor_data(self) -> list:
|
||||||
screen = self._main_window.get_screen()
|
screen = self._main_window.get_screen()
|
||||||
monitors = []
|
monitors = []
|
||||||
|
@ -144,6 +161,9 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
def get_glade_file(self) -> str: return self._GLADE_FILE
|
def get_glade_file(self) -> str: return self._GLADE_FILE
|
||||||
def get_ui_widgets_path(self) -> str: return self._UI_WIDEGTS_PATH
|
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_menu_data(self) -> str: return self._context_menu_data
|
||||||
|
def get_lsp_config_data(self) -> str: return self._lsp_config_data
|
||||||
|
def get_lsp_init_data(self) -> {}: return self._lsp_init_data
|
||||||
|
def get_app_pid(self) -> int: return self.pid
|
||||||
|
|
||||||
def get_context_path(self) -> str: return self._CONTEXT_PATH
|
def get_context_path(self) -> str: return self._CONTEXT_PATH
|
||||||
def get_plugins_path(self) -> str: return self._PLUGINS_PATH
|
def get_plugins_path(self) -> str: return self._PLUGINS_PATH
|
||||||
|
@ -152,9 +172,11 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
def get_home_config_path(self) -> str: return self._HOME_CONFIG_PATH
|
def get_home_config_path(self) -> str: return self._HOME_CONFIG_PATH
|
||||||
def get_window_icon(self) -> str: return self._WINDOW_ICON
|
def get_window_icon(self) -> str: return self._WINDOW_ICON
|
||||||
def get_home_path(self) -> str: return self._USER_HOME
|
def get_home_path(self) -> str: return self._USER_HOME
|
||||||
|
def get_starting_files(self) -> []: return self._starting_files
|
||||||
|
|
||||||
def is_trace_debug(self) -> str: return self._trace_debug
|
def is_trace_debug(self) -> str: return self._trace_debug
|
||||||
def is_debug(self) -> str: return self._debug
|
def is_debug(self) -> str: return self._debug
|
||||||
|
def is_starting_with_file(self) -> bool: return self._passed_in_file
|
||||||
|
|
||||||
def call_method(self, target_class = None, _method_name = None, data = None):
|
def call_method(self, target_class = None, _method_name = None, data = None):
|
||||||
method_name = str(_method_name)
|
method_name = str(_method_name)
|
||||||
|
@ -167,6 +189,7 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
def set_main_window_height(self, height = 600): self.settings.config.main_window_height = height
|
def set_main_window_height(self, height = 600): self.settings.config.main_window_height = height
|
||||||
def set_main_window_min_width(self, width = 720): self.settings.config.main_window_min_width = width
|
def set_main_window_min_width(self, width = 720): self.settings.config.main_window_min_width = width
|
||||||
def set_main_window_min_height(self, height = 480): self.settings.config.main_window_min_height = height
|
def set_main_window_min_height(self, height = 480): self.settings.config.main_window_min_height = height
|
||||||
|
def set_starting_files(self, files: []) -> None: self._starting_files = files
|
||||||
|
|
||||||
def set_trace_debug(self, trace_debug):
|
def set_trace_debug(self, trace_debug):
|
||||||
self._trace_debug = trace_debug
|
self._trace_debug = trace_debug
|
||||||
|
@ -174,6 +197,8 @@ class SettingsManager(StartCheckMixin, Singleton):
|
||||||
def set_debug(self, debug):
|
def set_debug(self, debug):
|
||||||
self._debug = debug
|
self._debug = debug
|
||||||
|
|
||||||
|
def set_is_starting_with_file(self, is_passed_in_file: False):
|
||||||
|
self._passed_in_file = is_passed_in_file
|
||||||
|
|
||||||
def load_settings(self):
|
def load_settings(self):
|
||||||
if not path.exists(self._CONFIG_FILE):
|
if not path.exists(self._CONFIG_FILE):
|
|
@ -39,4 +39,4 @@ class WebkitUISettings(WebKit2.Settings):
|
||||||
self.set_enable_webaudio(True)
|
self.set_enable_webaudio(True)
|
||||||
self.set_enable_accelerated_2d_canvas(True)
|
self.set_enable_accelerated_2d_canvas(True)
|
||||||
|
|
||||||
self.set_user_agent(f"{app_name}")
|
self.set_user_agent(f"{APP_NAME}")
|
|
@ -41,7 +41,7 @@ class StartCheckMixin:
|
||||||
try:
|
try:
|
||||||
os.kill(pid, 0)
|
os.kill(pid, 0)
|
||||||
except OSError:
|
except OSError:
|
||||||
print(f"{app_name} PID file exists but PID is irrelevant; starting dirty...")
|
print(f"{APP_NAME} PID file exists but PID is irrelevant; starting dirty...")
|
||||||
self._dirty_start = True
|
self._dirty_start = True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -49,11 +49,12 @@ class StartCheckMixin:
|
||||||
|
|
||||||
def _write_new_pid(self):
|
def _write_new_pid(self):
|
||||||
pid = os.getpid()
|
pid = os.getpid()
|
||||||
|
self.pid = pid
|
||||||
self._write_pid(pid)
|
self._write_pid(pid)
|
||||||
self._print_pid(pid)
|
self._print_pid(pid)
|
||||||
|
|
||||||
def _print_pid(self, pid):
|
def _print_pid(self, pid):
|
||||||
print(f"{app_name} PID: {pid}")
|
print(f"{APP_NAME} PID: {pid}")
|
||||||
|
|
||||||
def _clean_pid(self):
|
def _clean_pid(self):
|
||||||
os.unlink(self._PID_FILE)
|
os.unlink(self._PID_FILE)
|
|
@ -0,0 +1,67 @@
|
||||||
|
# Python imports
|
||||||
|
|
||||||
|
# Lib imports
|
||||||
|
import gi
|
||||||
|
gi.require_version('Gtk', '3.0')
|
||||||
|
gi.require_version('AppIndicator3', '0.1')
|
||||||
|
from gi.repository import Gtk
|
||||||
|
from gi.repository import GLib
|
||||||
|
from gi.repository import AppIndicator3
|
||||||
|
|
||||||
|
# Application imports
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class StatusIcon():
|
||||||
|
""" StatusIcon for Application to go to Status Tray. """
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
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):
|
||||||
|
status_menu = Gtk.Menu()
|
||||||
|
icon_theme = Gtk.IconTheme.get_default()
|
||||||
|
check_menu_item = Gtk.CheckMenuItem.new_with_label("Update icon")
|
||||||
|
quit_menu_item = Gtk.MenuItem.new_with_label("Quit")
|
||||||
|
|
||||||
|
# Create StatusNotifierItem
|
||||||
|
self.indicator = AppIndicator3.Indicator.new(
|
||||||
|
f"{APP_NAME}-statusicon",
|
||||||
|
"gtk-info",
|
||||||
|
AppIndicator3.IndicatorCategory.APPLICATION_STATUS)
|
||||||
|
self.indicator.set_status(AppIndicator3.IndicatorStatus.ACTIVE)
|
||||||
|
|
||||||
|
check_menu_item.connect("activate", self.check_menu_item_cb)
|
||||||
|
quit_menu_item.connect("activate", self.quit_menu_item_cb)
|
||||||
|
icon_theme.connect('changed', self.icon_theme_changed_cb)
|
||||||
|
|
||||||
|
self.indicator.set_menu(status_menu)
|
||||||
|
status_menu.append(check_menu_item)
|
||||||
|
status_menu.append(quit_menu_item)
|
||||||
|
status_menu.show_all()
|
||||||
|
|
||||||
|
def update_icon(self, icon_name):
|
||||||
|
self.indicator.set_icon(icon_name)
|
||||||
|
|
||||||
|
def check_menu_item_cb(self, widget, data = None):
|
||||||
|
icon_name = "parole" if widget.get_active() else "gtk-info"
|
||||||
|
self.update_icon(icon_name)
|
||||||
|
|
||||||
|
def icon_theme_changed_cb(self, theme):
|
||||||
|
self.update_icon("gtk-info")
|
||||||
|
|
||||||
|
def quit_menu_item_cb(self, widget, data = None):
|
||||||
|
event_system.emit("tear-down")
|
|
@ -22,6 +22,7 @@ class Plugin:
|
||||||
support: str = None
|
support: str = None
|
||||||
requests:{} = None
|
requests:{} = None
|
||||||
reference: type = None
|
reference: type = None
|
||||||
|
pre_launch: bool = False
|
||||||
|
|
||||||
|
|
||||||
class ManifestProcessor:
|
class ManifestProcessor:
|
||||||
|
@ -46,23 +47,25 @@ class ManifestProcessor:
|
||||||
plugin.support = self._manifest["support"]
|
plugin.support = self._manifest["support"]
|
||||||
plugin.requests = self._manifest["requests"]
|
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
|
return plugin
|
||||||
|
|
||||||
def get_loading_data(self):
|
def get_loading_data(self):
|
||||||
loading_data = {}
|
loading_data = {}
|
||||||
requests = self._plugin.requests
|
requests = self._plugin.requests
|
||||||
keys = requests.keys()
|
|
||||||
|
|
||||||
if "pass_events" in keys:
|
if "pass_events" in requests:
|
||||||
if requests["pass_events"] in ["true"]:
|
if requests["pass_events"] in ["true"]:
|
||||||
loading_data["pass_events"] = True
|
loading_data["pass_events"] = True
|
||||||
|
|
||||||
if "bind_keys" in keys:
|
if "pass_ui_objects" in requests:
|
||||||
if isinstance(requests["bind_keys"], list):
|
|
||||||
loading_data["bind_keys"] = requests["bind_keys"]
|
|
||||||
|
|
||||||
if "pass_ui_objects" in keys:
|
|
||||||
if isinstance(requests["pass_ui_objects"], list):
|
if isinstance(requests["pass_ui_objects"], list):
|
||||||
loading_data["pass_ui_objects"] = [ self._builder.get_object(obj) for obj in requests["pass_ui_objects"] ]
|
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
|
return self._plugin, loading_data
|
||||||
|
|
|
@ -10,6 +10,7 @@ from os.path import isdir
|
||||||
import gi
|
import gi
|
||||||
gi.require_version('Gtk', '3.0')
|
gi.require_version('Gtk', '3.0')
|
||||||
from gi.repository import Gtk
|
from gi.repository import Gtk
|
||||||
|
from gi.repository import GLib
|
||||||
from gi.repository import Gio
|
from gi.repository import Gio
|
||||||
|
|
||||||
# Application imports
|
# Application imports
|
||||||
|
@ -35,11 +36,23 @@ class PluginsController:
|
||||||
|
|
||||||
self._plugins_dir_watcher = None
|
self._plugins_dir_watcher = None
|
||||||
self._plugin_collection = []
|
self._plugin_collection = []
|
||||||
|
self._plugin_manifests = {}
|
||||||
|
|
||||||
|
self._load_manifests()
|
||||||
|
|
||||||
|
|
||||||
def launch_plugins(self) -> None:
|
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()
|
self._set_plugins_watcher()
|
||||||
self.load_plugins()
|
|
||||||
|
|
||||||
def _set_plugins_watcher(self) -> None:
|
def _set_plugins_watcher(self) -> None:
|
||||||
self._plugins_dir_watcher = Gio.File.new_for_path(self._plugins_path) \
|
self._plugins_dir_watcher = Gio.File.new_for_path(self._plugins_path) \
|
||||||
|
@ -52,21 +65,47 @@ class PluginsController:
|
||||||
Gio.FileMonitorEvent.MOVED_OUT]:
|
Gio.FileMonitorEvent.MOVED_OUT]:
|
||||||
self.reload_plugins(file)
|
self.reload_plugins(file)
|
||||||
|
|
||||||
def load_plugins(self, file: str = None) -> None:
|
def pre_launch_plugins(self) -> None:
|
||||||
logger.info(f"Loading plugins...")
|
logger.info(f"Loading pre-launch plugins...")
|
||||||
|
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...")
|
||||||
|
plugin_manifests: {} = {}
|
||||||
|
|
||||||
|
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()
|
parent_path = os.getcwd()
|
||||||
|
|
||||||
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)]:
|
for key in plugin_manifests:
|
||||||
|
target_manifest = plugin_manifests[key]
|
||||||
|
path, folder, manifest = target_manifest["path"], target_manifest["folder"], target_manifest["manifest"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
target = join(path, "plugin.py")
|
target = join(path, "plugin.py")
|
||||||
manifest = ManifestProcessor(path, self._builder)
|
|
||||||
|
|
||||||
if not os.path.exists(target):
|
if not os.path.exists(target):
|
||||||
raise InvalidPluginException("Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load...")
|
raise InvalidPluginException("Invalid Plugin Structure: Plugin doesn't have 'plugin.py'. Aboarting load...")
|
||||||
|
|
||||||
plugin, loading_data = manifest.get_loading_data()
|
plugin, loading_data = manifest.get_loading_data()
|
||||||
module = self.load_plugin_module(path, folder, target)
|
module = self.load_plugin_module(path, folder, target)
|
||||||
|
|
||||||
|
if is_pre_launch:
|
||||||
self.execute_plugin(module, plugin, loading_data)
|
self.execute_plugin(module, plugin, loading_data)
|
||||||
|
else:
|
||||||
|
GLib.idle_add(self.execute_plugin, *(module, plugin, loading_data))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info(f"Malformed Plugin: Not loading -->: '{folder}' !")
|
logger.info(f"Malformed Plugin: Not loading -->: '{folder}' !")
|
||||||
logger.debug("Trace: ", traceback.print_exc())
|
logger.debug("Trace: ", traceback.print_exc())
|
||||||
|
|
|
@ -11,19 +11,6 @@ function main() {
|
||||||
call_path=`pwd`
|
call_path=`pwd`
|
||||||
path=""
|
path=""
|
||||||
|
|
||||||
# NOTE: Remove if you want to pass file(s) besides directories...
|
|
||||||
if [[ ! "${1::1}" == /* ]]; then
|
|
||||||
path="${call_path}/${1}"
|
|
||||||
else
|
|
||||||
path="${1}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d "${path}" ]; then
|
|
||||||
echo "<change_me>: Path given not a directory..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# End NOTE: Remove if you want to pass file(s) besides directories...
|
|
||||||
|
|
||||||
# Collect abs paths and stuff in 'files' array
|
# Collect abs paths and stuff in 'files' array
|
||||||
files=()
|
files=()
|
||||||
for f in "$@"; do
|
for f in "$@"; do
|
||||||
|
@ -34,6 +21,6 @@ function main() {
|
||||||
done
|
done
|
||||||
|
|
||||||
cd "/opt/"
|
cd "/opt/"
|
||||||
python /opt/<change_me>.zip "$@"
|
python /opt/lsp-manager.zip "$@"
|
||||||
}
|
}
|
||||||
main "$@";
|
main "$@";
|
|
@ -1,11 +0,0 @@
|
||||||
[Desktop Entry]
|
|
||||||
Name=<change_me>
|
|
||||||
GenericName=<change_me>
|
|
||||||
Comment=<change_me>
|
|
||||||
Exec=/bin/<change_me> %F
|
|
||||||
Icon=/usr/share/<change_me>/icons/<change_me>.png
|
|
||||||
Type=Application
|
|
||||||
StartupNotify=true
|
|
||||||
Categories=System;FileTools;Utility;Core;GTK;FileManager;
|
|
||||||
MimeType=
|
|
||||||
Terminal=false
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Name=LSP Manager
|
||||||
|
GenericName=A Python + Gtk app to handle interacting LSP Client and Servers.
|
||||||
|
Comment=UI for LSP Client and Server Management
|
||||||
|
Exec=/bin/lsp-manager %F
|
||||||
|
Icon=/usr/share/lsp_manager/icons/lsp_manager.png
|
||||||
|
Type=Application
|
||||||
|
StartupNotify=true
|
||||||
|
Categories=System;FileTools;Utility;Core;GTK;
|
||||||
|
MimeType=
|
||||||
|
Terminal=false
|
|
@ -1,23 +0,0 @@
|
||||||
{
|
|
||||||
"keybindings": {
|
|
||||||
"help" : "F1",
|
|
||||||
"rename_files" : ["F2", "<Control>e"],
|
|
||||||
"open_terminal" : "F4",
|
|
||||||
"refresh_tab" : ["F5", "<Control>r"],
|
|
||||||
"delete_files" : "Delete",
|
|
||||||
"tggl_top_main_menubar" : "Alt_L",
|
|
||||||
"trash_files" : "<Shift><Control>t",
|
|
||||||
"tear_down" : "<Control>q",
|
|
||||||
"go_up" : "<Control>Up",
|
|
||||||
"go_home" : "<Control>slash",
|
|
||||||
"grab_focus_path_entry" : "<Control>l",
|
|
||||||
"open_files" : "<Control>o",
|
|
||||||
"show_hide_hidden_files" : "<Control>h",
|
|
||||||
"keyboard_create_tab" : "<Control>t",
|
|
||||||
"keyboard_close_tab" : "<Control>w",
|
|
||||||
"keyboard_copy_files" : "<Control>c",
|
|
||||||
"keyboard_cut_files" : "<Control>x",
|
|
||||||
"paste_files" : "<Control>v",
|
|
||||||
"show_new_file_menu" : "<Control>n"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 870 B After Width: | Height: | Size: 870 B |
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 367 B |
Before Width: | Height: | Size: 626 B After Width: | Height: | Size: 626 B |
Before Width: | Height: | Size: 711 B After Width: | Height: | Size: 711 B |
Before Width: | Height: | Size: 271 B After Width: | Height: | Size: 271 B |
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 318 B After Width: | Height: | Size: 318 B |
Before Width: | Height: | Size: 316 B After Width: | Height: | Size: 316 B |
Before Width: | Height: | Size: 318 B After Width: | Height: | Size: 318 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
Before Width: | Height: | Size: 387 B After Width: | Height: | Size: 387 B |
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 282 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 401 B After Width: | Height: | Size: 401 B |
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 349 B |
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 349 B |
Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 375 B After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 376 B After Width: | Height: | Size: 376 B |
Before Width: | Height: | Size: 352 B After Width: | Height: | Size: 352 B |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 321 B After Width: | Height: | Size: 321 B |
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 370 B |
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 363 B |
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 451 B |
Before Width: | Height: | Size: 286 B After Width: | Height: | Size: 286 B |
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
Before Width: | Height: | Size: 379 B After Width: | Height: | Size: 379 B |
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 365 B |
Before Width: | Height: | Size: 453 B After Width: | Height: | Size: 453 B |
Before Width: | Height: | Size: 289 B After Width: | Height: | Size: 289 B |
Before Width: | Height: | Size: 314 B After Width: | Height: | Size: 314 B |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 444 B After Width: | Height: | Size: 444 B |
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 457 B |
Before Width: | Height: | Size: 309 B After Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 320 B After Width: | Height: | Size: 320 B |
Before Width: | Height: | Size: 370 B After Width: | Height: | Size: 370 B |