Compare commits

...

10 Commits

13 changed files with 309 additions and 111 deletions

View File

@ -52,6 +52,7 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
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("tggl-top-main-menubar", self._tggl_top_main_menubar)
event_system.subscribe("copy-to-clipboard", self.set_clipboard_data)
def _load_controllers(self):
BridgeController()
@ -66,4 +67,4 @@ class BaseController(IPCSignalsMixin, KeyboardSignalsMixin, BaseControllerData):
settings_manager.set_builder(self.builder)
self.base_container = BaseContainer()
settings_manager.register_signals_to_builder([self, self.base_container])
settings_manager.register_signals_to_builder([self, self.base_container])

View File

@ -32,6 +32,7 @@ class LSPController(LSPControllerWebsocket):
self._init_params = settings_manager.get_lsp_init_data()
self._start_command = None
self._socket = None
self._lsp_pid = -1
self._message_id = 0
@ -64,6 +65,12 @@ class LSPController(LSPControllerWebsocket):
def unset_start_command(self):
self._start_command = None
def set_socket(self, socket: str):
self._socket = socket
def unset_socket(self):
self._socket = None
def send_notification(self, method: str, params: {} = {}):
self._send_message( ClientNotification(method, params) )

View File

@ -1,4 +1,5 @@
# Python imports
import traceback
import subprocess
# Lib imports
@ -8,7 +9,7 @@ from gi.repository import GLib
from libs.dto.lsp_messages import LEN_HEADER, TYPE_HEADER, get_message_str, get_message_obj
from .lsp_controller_base import LSPControllerBase
from libs.dto.lsp_message_structs import \
LSPResponseTypes, ClientRequest, ClientNotification, LSPResponseRequest, LSPResponseNotification
LSPResponseTypes, ClientRequest, ClientNotification, LSPResponseRequest, LSPResponseNotification, LSPResponseNotification
@ -42,7 +43,7 @@ class LSPControllerSTDInSTDOut(LSPControllerBase):
"2.0",
None,
{
"error": repr(e)
"error": traceback.format_exc()
}
)
)
@ -108,10 +109,9 @@ class LSPControllerSTDInSTDOut(LSPControllerBase):
lsp_response = LSPResponseRequest(**get_message_obj(data))
if "method" in keys:
lsp_response = LSPResponseNotification(**get_message_obj(data))
lsp_response = LSPResponseNotification(**get_message_obj(data)) if not "id" in keys else LSPIDResponseNotification( **get_message_obj(data) )
response_id = -1
if not lsp_response: return
GLib.idle_add(self.handle_lsp_response, lsp_response)
GLib.idle_add(self.handle_lsp_response, lsp_response)

View File

@ -1,4 +1,5 @@
# Python imports
import traceback
import subprocess
# Lib imports
@ -9,7 +10,7 @@ from gi.repository import GLib
from libs.websocket_client import WebsocketClient
from libs.dto.lsp_messages import LEN_HEADER, TYPE_HEADER, get_message_str, get_message_obj
from libs.dto.lsp_message_structs import \
LSPResponseTypes, ClientRequest, ClientNotification, LSPResponseRequest, LSPResponseNotification
LSPResponseTypes, ClientRequest, ClientNotification, LSPResponseRequest, LSPResponseNotification, LSPIDResponseNotification
from .lsp_controller_base import LSPControllerBase
@ -29,10 +30,13 @@ class LSPControllerWebsocket(LSPControllerBase):
if not self._start_command: return
try:
self.lsp_process = subprocess.Popen(
["pylsp", "--ws", "--port", "4114"],
self._start_command,
stdout = subprocess.PIPE,
stdin = subprocess.PIPE
)
if not self.lsp_process.poll() == None:
raise Exception("LSP thread not started!")
except Exception as e:
self.log_list.add_log_entry(
"LSP Client Error",
@ -40,7 +44,7 @@ class LSPControllerWebsocket(LSPControllerBase):
"2.0",
None,
{
"error": repr(e)
"error": traceback.format_exc()
}
)
)
@ -48,6 +52,7 @@ class LSPControllerWebsocket(LSPControllerBase):
return
self.ws_client = WebsocketClient()
self.ws_client.set_socket(self._socket)
self.ws_client.set_callback(self._monitor_lsp_response)
self.ws_client.start_client()
return self.lsp_process.pid
@ -72,7 +77,7 @@ class LSPControllerWebsocket(LSPControllerBase):
lsp_response = LSPResponseRequest(**get_message_obj(data))
if "method" in keys:
lsp_response = LSPResponseNotification(**get_message_obj(data))
lsp_response = LSPResponseNotification(**get_message_obj(data)) if not "id" in keys else LSPIDResponseNotification( **get_message_obj(data) )
response_id = -1

View File

@ -16,6 +16,8 @@ class LogList(Gtk.ListBox):
def __init__(self):
super(LogList, self).__init__()
self.display_logging = False
self._setup_styling()
self._setup_signals()
self._subscribe_to_events()
@ -35,6 +37,7 @@ class LogList(Gtk.ListBox):
def tggl_row_view(lb, row):
frame = row.get_child()
revealer = frame.get_children()[0]
self._active_label = revealer.get_children()[0]
revealer.set_reveal_child( not revealer.get_reveal_child() )
del frame
@ -45,6 +48,7 @@ class LogList(Gtk.ListBox):
self.connect("row-activated", tggl_row_view)
self.connect("size-allocate", scroll_down)
self.connect("button-release-event", self._label_button_release_event)
def _subscribe_to_events(self):
...
@ -52,7 +56,12 @@ class LogList(Gtk.ListBox):
def _load_widgets(self):
...
def toggle_logging(self, state: bool):
self.display_logging = state
def add_log_entry(self, m_type: str, data: MessageTypes):
if not self.display_logging: return
message = get_message_str(data)
frame = Gtk.Frame()
@ -80,4 +89,9 @@ class LogList(Gtk.ListBox):
def scroll_down(self):
vadjustment = self.get_parent().get_vadjustment()
vadjustment.set_value( vadjustment.get_upper())
vadjustment.set_value( vadjustment.get_upper())
def _label_button_release_event(self, log_list, eve):
if eve.button == 3:
event_system.emit("copy-to-clipboard", self._active_label.get_label())
return True

View File

@ -86,13 +86,15 @@ class LSPMessageBox(Gtk.Box):
self.update_message_id_label()
def start_stop_lsp(self):
parent = self.get_parent()
_command: str = parent.alt_command_entry.get_text()
# _command: str = parent.command_entry.get_text()
# _command: str = parent.socket_entry.get_text()
command: [] = _command.split() if len( _command.split() ) > 0 else [ _command ]
parent = self.get_parent()
data: str = parent.command_entry.get_text()
# data: str = parent.alt_command_entry.get_text()
socket: str = parent.socket_entry.get_text()
command: [] = data.split() if len( data.split() ) > 0 else [ data ]
self.lsp_controller.set_start_command(command)
self.lsp_controller.set_socket(socket)
self.lsp_controller.start_stop_lsp()
self.lsp_controller.unset_start_command()
self.lsp_controller.unset_socket()
self.update_message_id_label()

View File

@ -51,14 +51,15 @@ class LSPUI(Gtk.Grid):
def _load_widgets(self):
scrolled_win1 = Gtk.ScrolledWindow()
scrolled_win2 = Gtk.ScrolledWindow()
log_chk_btn = Gtk.CheckButton(label = "Log to UI")
self.log_list = LogList()
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")
log_list_lbl = Gtk.Label(label="Logs")
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")
log_list_lbl = Gtk.Label(label = "Logs")
self.link_btn = InfoLinkButton(self._language.title(), self._data["info"])
self.alt_command_entry = AltCommandEntry( self._data["alt-command"] )
@ -67,6 +68,8 @@ class LSPUI(Gtk.Grid):
self.init_ops_src_vw = InitOptionsSourceView( self._data["initialization-options"] )
message_box = LSPMessageBox()
log_chk_btn.connect("toggled", lambda button: self.log_list.toggle_logging( button.get_active() ) )
init_options_lbl.set_margin_top(10)
message_box_lbl.set_margin_top(10)
log_list_lbl.set_margin_top(10)
@ -81,12 +84,12 @@ class LSPUI(Gtk.Grid):
# child, left, top, width, height
self.attach(self.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(command_lbl, 0, 1, 1, 1)
self.attach(alt_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.command_entry, 1, 1, 2, 1)
self.attach(self.alt_command_entry, 1, 2, 2, 1)
self.attach(self.socket_entry, 1, 3, 2, 1)
self.attach(init_options_lbl, 0, 4, 3, 1)
@ -96,7 +99,8 @@ class LSPUI(Gtk.Grid):
self.attach(message_box, 0, 7, 3, 1)
self.attach(log_list_lbl, 3, 0, 3, 1)
self.attach(scrolled_win2, 3, 1, 3, 11)
self.attach(log_chk_btn, 3, 1, 3, 1)
self.attach(scrolled_win2, 3, 2, 3, 10)
for child in self.get_children():
child.show()

View File

@ -71,12 +71,25 @@ class LSPResponseNotification(object):
method: str
params: dict
@dataclass
class LSPIDResponseNotification(object):
"""
Constructs a new LSP Response Notification instance.
class MessageTypes(ClientRequest, ClientNotification, LSPResponseRequest, LSPResponseNotification):
:param str method: The type of lsp notification being made.
:params dict result: The arguments of the given method.
"""
jsonrpc: str
id: int
method: str
params: dict
class MessageTypes(ClientRequest, ClientNotification, LSPResponseRequest, LSPResponseNotification, LSPIDResponseNotification):
...
class ClientMessageTypes(ClientRequest, ClientNotification):
...
class LSPResponseTypes(LSPResponseRequest, LSPResponseNotification):
...
...

View File

@ -69,7 +69,6 @@ class LSPEndpointServer(Singleton):
start_time = time.perf_counter()
self._handle_ipc_message(conn, start_time)
except Exception as e:
# logger.debug( repr(e) )
logger.debug( traceback.print_exc() )
listener.close()
@ -120,7 +119,7 @@ class LSPEndpointServer(Singleton):
except ConnectionRefusedError as e:
logger.error("Connection refused...")
except Exception as e:
logger.error( repr(e) )
logger.debug( traceback.print_exc() )
def send_ipc_message(self, message: str = "Empty Data...") -> None:
@ -137,7 +136,7 @@ class LSPEndpointServer(Singleton):
except ConnectionRefusedError as e:
logger.error("Connection refused...")
except Exception as e:
logger.error( repr(e) )
logger.debug( traceback.print_exc() )
def send_test_ipc_message(self, message: str = "Empty Data...") -> None:
try:
@ -155,4 +154,4 @@ class LSPEndpointServer(Singleton):
logger.error("LSP Socket no longer valid.... Removing.")
os.unlink(self._ipc_address)
except Exception as e:
logger.error( repr(e) )
logger.debug( traceback.print_exc() )

View File

@ -107,13 +107,15 @@ class SettingsManager(StartCheckMixin, Singleton):
try:
with open(self._LSP_CONFIG) as file:
self._lsp_config_data = json.load(file)
data = file.read().replace("{user.home}", self.get_home_path())
self._lsp_config_data = json.loads(data)
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)
data = file.read().replace("{user.home}", self.get_home_path())
self._lsp_init_data = json.loads(data)
except Exception as e:
print( f"Settings Manager: {self._LSP_INIT_CONFIG}\n\t\t{repr(e)}" )
@ -212,4 +214,4 @@ class SettingsManager(StartCheckMixin, Singleton):
def save_settings(self):
with open(self._CONFIG_FILE, 'w') as outfile:
json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4)
json.dump(self.settings.as_dict(), outfile, separators=(',', ':'), indent=4)

View File

@ -13,8 +13,14 @@ from . import websocket
class WebsocketClient:
def __init__(self):
self.ws = None
self.ws = None
self._socket = None
def set_socket(self, socket: str):
self._socket = socket
def unset_socket(self):
self._socket = None
def send(self, message: str):
self.ws.send(message)
@ -39,16 +45,14 @@ class WebsocketClient:
@daemon_threaded
def start_client(self):
if not self._socket:
raise Exception("Socket address isn't set so cannot start WebsocketClient listener...")
# websocket.enableTrace(True)
self.ws = websocket.WebSocketApp("ws://localhost:4114",
on_open = self.on_open,
self.ws = websocket.WebSocketApp(self._socket,
on_open = self.on_open,
on_message = self.on_message,
on_error = self.on_error,
on_close = self.on_close)
on_error = self.on_error,
on_close = self.on_close)
# Set dispatcher to automatic reconnection, 5 second reconnect delay
# self.ws.run_forever(dispatcher = rel, reconnect = 5)
# rel.signal(2, rel.abort) # Keyboard Interrupt
# rel.dispatch()
self.ws.run_forever(reconnect = 0.5)
self.ws.run_forever(reconnect = 0.5)

View File

@ -148,4 +148,4 @@
},
"trace": "verbose",
"workspaceFolders": "[\n {\n \"uri\": pathlib.Path(repository_absolute_path).as_uri(),\n \"name\": os.path.basename(repository_absolute_path),\n }\n ]"
}
}

View File

@ -1,64 +1,209 @@
{
"sh": {
"info": "",
"alt-command": "",
"command": "",
"socket": "ws://127.0.0.1:3030/?name=shell",
"initialization-options": {}
},
"python - pylsp": {
"hidden": true,
"info": "https://github.com/python-lsp/python-lsp-server",
"alt-command": "pylsp --ws --port 3030",
"command": "lsp-ws-proxy --listen 3030 -- pylsp",
"socket": "ws://127.0.0.1:3030/?name=pylsp",
"java": {
"info": "https://download.eclipse.org/jdtls/",
"info-init-options": "https://github.com/eclipse-jdtls/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line",
"info-import-build": "https://www.javahotchocolate.com/tutorials/build-path.html",
"info-external-class-paths": "https://github.com/eclipse-jdtls/eclipse.jdt.ls/issues/3291",
"link": "https://download.eclipse.org/jdtls/milestones/?d",
"command": "lsp-ws-proxy --listen 4114 -- jdtls",
"alt-command": "lsp-ws-proxy -- jdtls",
"alt-command2": "java-language-server",
"socket": "ws://127.0.0.1:4114/?name=jdtls",
"alt-socket": "ws://127.0.0.1:3030/?name=java-language-server",
"initialization-options": {
"pylsp": {
"plugins": {
"rope_autoimport": {
"enabled": true
"bundles": [
"intellicode-core.jar"
],
"workspaceFolders": [
"file://"
],
"extendedClientCapabilities": {
"classFileContentsSupport": true,
"executeClientCommandSupport": true
},
"settings": {
"java": {
"autobuild": {
"enabled": false
},
"rope_completion": {
"enabled": false,
"eager": false
},
"jedi_completion": {
"fuzzy": true
},
"jedi":{
"extra_paths": [
"/home/abaddon/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
"completion": {
"enabled": true,
"importOrder": [
"java",
"javax",
"org",
"com"
]
},
"configuration": {
"maven": {
"userSettings": "{user.home}/.config/jdtls/settings.xml",
"globalSettings": "{user.home}/.config/jdtls/settings.xml"
},
"runtimes": [
{
"name": "JavaSE-17",
"path": "/usr/lib/jvm/default-runtime",
"javadoc": "https://docs.oracle.com/en/java/javase/17/docs/api/",
"default": true
}
]
},
"classPath": [
"{user.home}/.config/jdtls/m2/repository/**/*-sources.jar",
"lib/**/*-sources.jar"
],
"docPath": [
"{user.home}/.config/jdtls/m2/repository/**/*-javadoc.jar",
"lib/**/*-javadoc.jar"
],
"silentNotification": true,
"project": {
"encoding": "ignore",
"outputPath": "bin",
"referencedLibraries": [
"lib/**/*.jar",
"{user.home}/.config/jdtls/m2/repository/**/*.jar"
],
"importOnFirstTimeStartup": "automatic",
"importHint": true,
"resourceFilters": [
"node_modules",
"\\.git"
],
"sourcePaths": [
"src",
"{user.home}/.config/jdtls/m2/repository/**/*.jar"
]
},
"sources": {
"organizeImports": {
"starThreshold": 99,
"staticStarThreshold": 99
}
},
"imports": {
"gradle": {
"wrapper": {
"checksums": []
}
}
},
"import": {
"maven": {
"enabled": true,
"offline": {
"enabled": false
},
"disableTestClasspathFlag": false
},
"gradle": {
"enabled": true,
"wrapper": {
"enabled": true
},
"version": null,
"home": "abs(static/gradle-7.3.3)",
"java": {
"home": "abs(static/launch_jres/17.0.6-linux-x86_64)"
},
"offline": {
"enabled": false
},
"arguments": null,
"jvmArguments": null,
"user": {
"home": null
},
"annotationProcessing": {
"enabled": true
}
},
"exclusions": [
"**/node_modules/**",
"**/.metadata/**",
"**/archetype-resources/**",
"**/META-INF/maven/**"
],
"generatesMetadataFilesAtProjectRoot": false
},
"maven": {
"downloadSources": true,
"updateSnapshots": true
},
"signatureHelp": {
"enabled": true,
"description": {
"enabled": true
}
},
"implementationsCodeLens": {
"enabled": true
}
}
}
}
},
"python3 - pylsp": {
"python": {
"info": "https://github.com/python-lsp/python-lsp-server",
"command": "lsp-ws-proxy -- pylsp",
"alt-command": "pylsp",
"alt-command2": "pylsp --ws --port 3030",
"command": "lsp-ws-proxy --listen 3030 -- pylsp",
"socket": "ws://127.0.0.1:3030/?name=pylsp",
"alt-command2": "lsp-ws-proxy --listen 4114 -- pylsp",
"alt-command3": "pylsp --ws --port 4114",
"socket": "ws://127.0.0.1:9999/?name=pylsp",
"initialization-options": {
"pyls": {
"plugins": {
"pycodestyle": {
"enabled": false
},
"pydocstyle": {
"enabled": false
},
"pyflakes": {
"enabled": false
},
"pylint": {
"enabled": false
},
"mccabe": {
"enabled": false
}
}
},
"pylsp": {
"plugins": {
"pycodestyle": {
"enabled": false
},
"pydocstyle": {
"enabled": false
},
"pyflakes": {
"enabled": false
},
"pylint": {
"enabled": false
},
"mccabe": {
"enabled": false
},
"ruff": true,
"pylsp_rope": {
"rename": true
},
"rope_rename": {
"enabled": false
"enabled": true
},
"rope_autoimport": {
"enabled": true
},
"rope_completion": {
"enabled": false,
"eager": false
"enabled": true,
"eager": true
},
"jedi_rename": {
"enabled": false
"enabled": true
},
"jedi_completion": {
"enabled": true,
@ -68,18 +213,19 @@
},
"jedi":{
"extra_paths": [
"/home/abaddon/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
]
"{user.home}/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
],
"root_dir": ""
}
}
}
}
},
"python3 - jedi-language-server": {
"python - jedi-language-server": {
"hidden": true,
"info": "https://pypi.org/project/jedi-language-server/",
"alt-command": "jedi-language-server",
"command": "lsp-ws-proxy --listen 3030 -- jedi-language-server",
"command": "jedi-language-server",
"alt-command": "lsp-ws-proxy --listen 3030 -- jedi-language-server",
"socket": "ws://127.0.0.1:3030/?name=jedi-language-server",
"initialization-options": {
"jediSettings": {
@ -95,9 +241,9 @@
"markupKindPreferred": "markdown",
"workspace": {
"extraPaths": [
"/home/abaddon/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
"{user.home}/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
],
"environmentPath": "/home/abaddon/Portable_Apps/py-venvs/gtk-apps-venv/venv/bin/python",
"environmentPath": "{user.home}/Portable_Apps/py-venvs/gtk-apps-venv/venv/bin/python",
"symbols": {
"ignoreFolders": [".nox", ".tox", ".venv", "__pycache__", "venv"],
"maxSymbols": 20
@ -105,39 +251,40 @@
}
}
},
"c": {
"info": "https://clangd.llvm.org/",
"alt-command": "clangd",
"command": "lsp-ws-proxy --listen 3030 -- clangd",
"socket": "ws://127.0.0.1:3030/?name=clangd",
"initialization-options": {}
},
"cpp": {
"info": "https://clangd.llvm.org/",
"command": "lsp-ws-proxy -- clangd",
"alt-command": "clangd",
"command": "lsp-ws-proxy --listen 3030 -- clangd",
"socket": "ws://127.0.0.1:3030/?name=clangd",
"initialization-options": {}
},
"java": {
"info": "https://download.eclipse.org/jdtls/",
"alt-command": "java-language-server",
"command": "lsp-ws-proxy --listen 3030 -- java-language-server",
"socket": "ws://127.0.0.1:3030/?name=java-language-server",
"initialization-options": {}
},
"lua": {
"info": "https://github.com/LuaLS/lua-language-server",
"alt-command": "lua-language-server",
"command": "lsp-ws-proxy --listen 3030 -- lua-language-server",
"socket": "ws://127.0.0.1:3030/?name=gopls",
"sh": {
"info": "",
"command": "",
"alt-command": "",
"socket": "ws://127.0.0.1:3030/?name=shell",
"initialization-options": {}
},
"go": {
"info": "https://pkg.go.dev/golang.org/x/tools/gopls#section-readme",
"command": "lsp-ws-proxy -- gopls",
"alt-command": "gopls",
"command": "lsp-ws-proxy --listen 3030 -- gopls",
"socket": "ws://127.0.0.1:3030/?name=gopls",
"initialization-options": {}
},
"lua": {
"info": "https://github.com/LuaLS/lua-language-server",
"command": "lsp-ws-proxy -- lua-language-server",
"alt-command": "lua-language-server",
"socket": "ws://127.0.0.1:3030/?name=gopls",
"initialization-options": {}
},
"c": {
"hidden": true,
"info": "https://clangd.llvm.org/",
"command": "lsp-ws-proxy -- clangd",
"alt-command": "clangd",
"socket": "ws://127.0.0.1:3030/?name=clangd",
"initialization-options": {}
}
}