Remove custom LSP manager plugins and add new language server clients
- Delete old lsp_manager plugin (custom websocket-based LSP client implementation) - Delete java_lsp_client plugin - Delete python_lsp_client plugin - Remove unused LSP DTO files in src/libs/dto/code/lsp/ - Add new language_server_clients plugin directory - Improve event_factory with register_events method - Add PYTHONDONTWRITEBYTECODE to user config - Update events init.py docstring
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
{
|
||||
"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:9999/java",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=jdtls",
|
||||
"alt-socket": "ws://127.0.0.1:9999/?name=java-language-server",
|
||||
"initialization-options": {
|
||||
"bundles": [
|
||||
"intellicode-core.jar"
|
||||
],
|
||||
"workspaceFolders": [
|
||||
"file://{workspace.folder}"
|
||||
],
|
||||
"extendedClientCapabilities": {
|
||||
"classFileContentsSupport": true,
|
||||
"executeClientCommandSupport": false
|
||||
},
|
||||
"settings": {
|
||||
"java": {
|
||||
"autobuild": {
|
||||
"enabled": true
|
||||
},
|
||||
"jdt": {
|
||||
"ls": {
|
||||
"javac": {
|
||||
"enabled": true
|
||||
},
|
||||
"java": {
|
||||
"home": "{user.home}/Portable_Apps/sdks/javasdk/jdk-22.0.2"
|
||||
},
|
||||
"lombokSupport": {
|
||||
"enabled": true
|
||||
},
|
||||
"protobufSupport":{
|
||||
"enabled": true
|
||||
},
|
||||
"androidSupport": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"configuration": {
|
||||
"updateBuildConfiguration": "automatic",
|
||||
"maven": {
|
||||
"userSettings": "{user.home}/.config/jdtls/settings.xml",
|
||||
"globalSettings": "{user.home}/.config/jdtls/settings.xml"
|
||||
},
|
||||
"runtimes": [
|
||||
{
|
||||
"name": "JavaSE-17",
|
||||
"path": "/usr/lib/jvm/java-17-openjdk",
|
||||
"javadoc": "https://docs.oracle.com/en/java/javase/17/docs/api/",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "JavaSE-22",
|
||||
"path": "{user.home}/Portable_Apps/sdks/javasdk/jdk-22.0.2",
|
||||
"javadoc": "https://docs.oracle.com/en/java/javase/22/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"
|
||||
],
|
||||
"project": {
|
||||
"encoding": "ignore",
|
||||
"outputPath": "bin",
|
||||
"referencedLibraries": [
|
||||
"{user.home}/.config/jdtls/m2/repository/**/*.jar",
|
||||
"lib/**/*.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": false,
|
||||
"wrapper": {
|
||||
"enabled": true
|
||||
},
|
||||
"version": "",
|
||||
"home": "abs(static/gradle-7.3.3)",
|
||||
"java": {
|
||||
"home": "abs(static/launch_jres/17.0.6-linux-x86_64)"
|
||||
},
|
||||
"offline": {
|
||||
"enabled": false
|
||||
},
|
||||
"arguments": [],
|
||||
"jvmArguments": [],
|
||||
"user": {
|
||||
"home": ""
|
||||
},
|
||||
"annotationProcessing": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"exclusions": [
|
||||
"**/node_modules/**",
|
||||
"**/.metadata/**",
|
||||
"**/archetype-resources/**",
|
||||
"**/META-INF/maven/**"
|
||||
],
|
||||
"generatesMetadataFilesAtProjectRoot": false
|
||||
},
|
||||
"maven": {
|
||||
"downloadSources": true,
|
||||
"updateSnapshots": true
|
||||
},
|
||||
"silentNotification": true,
|
||||
"contentProvider": {
|
||||
"preferred": "fernflower"
|
||||
},
|
||||
"signatureHelp": {
|
||||
"enabled": true,
|
||||
"description": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
"completion": {
|
||||
"enabled": true,
|
||||
"engine": "ecj",
|
||||
"matchCase": "firstletter",
|
||||
"maxResults": 25,
|
||||
"guessMethodArguments": true,
|
||||
"lazyResolveTextEdit": {
|
||||
"enabled": true
|
||||
},
|
||||
"postfix": {
|
||||
"enabled": true
|
||||
},
|
||||
"favoriteStaticMembers": [
|
||||
"org.junit.Assert.*",
|
||||
"org.junit.Assume.*",
|
||||
"org.junit.jupiter.api.Assertions.*",
|
||||
"org.junit.jupiter.api.Assumptions.*",
|
||||
"org.junit.jupiter.api.DynamicContainer.*",
|
||||
"org.junit.jupiter.api.DynamicTest.*"
|
||||
],
|
||||
"importOrder": [
|
||||
"#",
|
||||
"java",
|
||||
"javax",
|
||||
"org",
|
||||
"com"
|
||||
]
|
||||
},
|
||||
"references": {
|
||||
"includeAccessors": true,
|
||||
"includeDecompiledSources": true
|
||||
},
|
||||
"codeGeneration": {
|
||||
"toString": {
|
||||
"template": "${object.className}{${member.name()}=${member.value}, ${otherMembers}}"
|
||||
},
|
||||
"insertionLocation": "afterCursor",
|
||||
"useBlocks": true
|
||||
},
|
||||
"implementationsCodeLens": {
|
||||
"enabled": true
|
||||
},
|
||||
"referencesCodeLens": {
|
||||
"enabled": true
|
||||
},
|
||||
"progressReports": {
|
||||
"enabled": false
|
||||
},
|
||||
"saveActions": {
|
||||
"organizeImports": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Java LSP Client",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Python imports
|
||||
from os import path
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
from .response_handler import JavaHandler
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
dirPth = path.dirname( path.realpath(__file__) )
|
||||
with open(f"{dirPth}/config/lsp-server-config.json", "r") as f:
|
||||
config = f.read()
|
||||
event = Event_Factory.create_event("register_lsp_client",
|
||||
lang_id = "java",
|
||||
lang_config = config,
|
||||
handler = JavaHandler
|
||||
)
|
||||
self.emit_to("lsp_manager", event)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
@@ -0,0 +1 @@
|
||||
from .java import JavaHandler
|
||||
@@ -9,7 +9,7 @@ from gi.repository import GtkSource
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from .default import DefaultHandler
|
||||
from lsp_manager.response_handlers.default import DefaultHandler
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
@@ -8,8 +8,9 @@ import gi
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from libs.dto.code.lsp.lsp_messages import get_message_str
|
||||
from libs.dto.code.lsp.lsp_message_structs import LSPResponseTypes, ClientRequest, ClientNotification
|
||||
from ..dto.code.lsp.lsp_messages import get_message_str
|
||||
from ..dto.code.lsp.lsp_message_structs import \
|
||||
LSPResponseTypes, ClientRequest, ClientNotification
|
||||
from .lsp_client_websocket import LSPClientWebsocket
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from ..dto.code.lsp.lsp_message_structs import ClientRequest, ClientNotification
|
||||
|
||||
from .lsp_client_events import LSPClientEvents
|
||||
from libs.dto.code.lsp.lsp_message_structs import ClientRequest, ClientNotification
|
||||
|
||||
|
||||
|
||||
@@ -4,15 +4,15 @@ import os
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.dto.code.lsp.lsp_messages import get_message_obj
|
||||
from libs.dto.code.lsp.lsp_messages import didopen_notification
|
||||
from libs.dto.code.lsp.lsp_messages import didsave_notification
|
||||
from libs.dto.code.lsp.lsp_messages import didclose_notification
|
||||
from libs.dto.code.lsp.lsp_messages import didchange_notification
|
||||
from libs.dto.code.lsp.lsp_messages import completion_request
|
||||
from libs.dto.code.lsp.lsp_messages import definition_request
|
||||
from libs.dto.code.lsp.lsp_messages import references_request
|
||||
from libs.dto.code.lsp.lsp_messages import symbols_request
|
||||
from ..dto.code.lsp.lsp_messages import get_message_obj
|
||||
from ..dto.code.lsp.lsp_messages import didopen_notification
|
||||
from ..dto.code.lsp.lsp_messages import didsave_notification
|
||||
from ..dto.code.lsp.lsp_messages import didclose_notification
|
||||
from ..dto.code.lsp.lsp_messages import didchange_notification
|
||||
from ..dto.code.lsp.lsp_messages import completion_request
|
||||
from ..dto.code.lsp.lsp_messages import definition_request
|
||||
from ..dto.code.lsp.lsp_messages import references_request
|
||||
from ..dto.code.lsp.lsp_messages import symbols_request
|
||||
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
# from libs import websockets
|
||||
from libs.dto.code.lsp.lsp_messages import get_message_str, get_message_obj
|
||||
from libs.dto.code.lsp.lsp_message_structs import \
|
||||
from ..dto.code.lsp.lsp_messages import get_message_str, get_message_obj
|
||||
from ..dto.code.lsp.lsp_message_structs import \
|
||||
LSPResponseTypes, ClientRequest, ClientNotification, \
|
||||
LSPResponseRequest, LSPResponseNotification, LSPIDResponseNotification
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
Libs Code DTO(s) Events Package
|
||||
"""
|
||||
|
||||
from .lsp_event import LspEvent
|
||||
|
||||
from .register_lsp_client_event import RegisterLspClientEvent
|
||||
from .unregister_lsp_client_event import UnregisterLspClientEvent
|
||||
@@ -0,0 +1,13 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.dto.code.events import CodeEvent
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class LspEvent(CodeEvent):
|
||||
...
|
||||
@@ -0,0 +1,17 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from ....response_handlers.base_handler import BaseHandler
|
||||
|
||||
from .lsp_event import LspEvent
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class RegisterLspClientEvent(LspEvent):
|
||||
lang_id: str = ""
|
||||
lang_config: str = "{}"
|
||||
handler: BaseHandler = None
|
||||
@@ -0,0 +1,13 @@
|
||||
# Python imports
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .lsp_event import LspEvent
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class UnregisterLspClientEvent(LspEvent):
|
||||
lang_id: str = ""
|
||||
@@ -0,0 +1,95 @@
|
||||
# Python imports
|
||||
import json
|
||||
import enum
|
||||
from dataclasses import dataclass
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .lsp_structs import TextDocumentItem
|
||||
|
||||
|
||||
|
||||
class MessageEncoder(json.JSONEncoder):
|
||||
"""
|
||||
Encodes an object in JSON
|
||||
"""
|
||||
|
||||
def default(self, o): # pylint: disable=E0202
|
||||
return o.__dict__
|
||||
|
||||
|
||||
@dataclass
|
||||
class ClientRequest(object):
|
||||
def __init__(self, id: int, method: str, params: dict):
|
||||
"""
|
||||
Constructs a new Client Request instance.
|
||||
|
||||
:param int id: Message id to track instance.
|
||||
:param str method: The type of lsp request being made.
|
||||
:param dict params: The arguments of the given method.
|
||||
"""
|
||||
self.jsonrpc = "2.0"
|
||||
self.id = id
|
||||
self.method = method
|
||||
self.params = params
|
||||
|
||||
@dataclass
|
||||
class ClientNotification(object):
|
||||
def __init__(self, method: str, params: dict):
|
||||
"""
|
||||
Constructs a new Client Notification instance.
|
||||
|
||||
:param str method: The type of lsp notification being made.
|
||||
:param dict params: The arguments of the given method.
|
||||
"""
|
||||
self.jsonrpc = "2.0"
|
||||
self.method = method
|
||||
self.params = params
|
||||
|
||||
@dataclass
|
||||
class LSPResponseRequest(object):
|
||||
"""
|
||||
Constructs a new LSP Response Request instance.
|
||||
|
||||
:param id result: The id of the given message.
|
||||
:param dict result: The arguments of the given method.
|
||||
"""
|
||||
jsonrpc: str
|
||||
id: int
|
||||
result: dict
|
||||
|
||||
@dataclass
|
||||
class LSPResponseNotification(object):
|
||||
"""
|
||||
Constructs a new LSP Response Notification instance.
|
||||
|
||||
:param str method: The type of lsp notification being made.
|
||||
:params dict result: The arguments of the given method.
|
||||
"""
|
||||
jsonrpc: str
|
||||
method: str
|
||||
params: dict
|
||||
|
||||
@dataclass
|
||||
class LSPIDResponseNotification(object):
|
||||
"""
|
||||
Constructs a new LSP Response Notification instance.
|
||||
|
||||
: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):
|
||||
...
|
||||
@@ -0,0 +1,193 @@
|
||||
# Python imports
|
||||
import json
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .lsp_message_structs import MessageEncoder
|
||||
|
||||
|
||||
|
||||
LEN_HEADER = "Content-Length: "
|
||||
TYPE_HEADER = "Content-Type: "
|
||||
|
||||
|
||||
|
||||
def get_message_str(data: dict) -> str:
|
||||
return json.dumps(data, separators = (',', ':'), indent = 4, cls = MessageEncoder)
|
||||
|
||||
def get_message_obj(data: str):
|
||||
return json.loads(data)
|
||||
|
||||
|
||||
|
||||
# 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://",
|
||||
"languageId": "python",
|
||||
"version": 1,
|
||||
"text": ""
|
||||
},
|
||||
"position": {
|
||||
"line": 5,
|
||||
"character": 12,
|
||||
"offset": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
didopen_notification = {
|
||||
"method": "textDocument/didOpen",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file://",
|
||||
"languageId": "python",
|
||||
"version": 1,
|
||||
"text": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
didsave_notification = {
|
||||
"method": "textDocument/didSave",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file://"
|
||||
},
|
||||
"text": ""
|
||||
}
|
||||
}
|
||||
|
||||
didclose_notification = {
|
||||
"method": "textDocument/didClose",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file://"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
didchange_notification = {
|
||||
"method": "textDocument/didChange",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file://",
|
||||
"languageId": "python",
|
||||
"version": 1,
|
||||
},
|
||||
"contentChanges": [
|
||||
{
|
||||
"text": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
didchange_notification_range = {
|
||||
"method": "textDocument/didChange",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file://",
|
||||
"languageId": "python",
|
||||
"version": 1,
|
||||
"text": ""
|
||||
},
|
||||
"contentChanges": [
|
||||
{
|
||||
"range": {
|
||||
"start": {
|
||||
"line": 1,
|
||||
"character": 1,
|
||||
},
|
||||
"end": {
|
||||
"line": 1,
|
||||
"character": 1,
|
||||
},
|
||||
"rangeLength": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# CompletionTriggerKind = 1 | 2 | 3;
|
||||
# export const Invoked: 1 = 1;
|
||||
# export const TriggerCharacter: 2 = 2;
|
||||
# export const TriggerForIncompleteCompletions: 3 = 3;
|
||||
completion_request = {
|
||||
"method": "textDocument/completion",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file://",
|
||||
"languageId": "python",
|
||||
"version": 1,
|
||||
"text": ""
|
||||
},
|
||||
"position": {
|
||||
"line": 5,
|
||||
"character": 12,
|
||||
"offset": 0
|
||||
},
|
||||
"contet": {
|
||||
"triggerKind": 3,
|
||||
"triggerCharacter": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
definition_request = {
|
||||
"method": "textDocument/definition",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file://",
|
||||
"languageId": "python",
|
||||
"version": 1,
|
||||
"text": ""
|
||||
},
|
||||
"position": {
|
||||
"line": 5,
|
||||
"character": 12,
|
||||
"offset": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
references_request = {
|
||||
"method": "textDocument/references",
|
||||
"params": {
|
||||
"context": {
|
||||
"includeDeclaration": False
|
||||
},
|
||||
"textDocument": {
|
||||
"uri": "file://",
|
||||
"languageId": "python",
|
||||
"version": 1,
|
||||
"text": ""
|
||||
},
|
||||
"position": {
|
||||
"line": 30,
|
||||
"character": 13,
|
||||
"offset": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
symbols_request = {
|
||||
"method": "textDocument/documentSymbol",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file://",
|
||||
"languageId": "python",
|
||||
"version": 1,
|
||||
"text": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,571 @@
|
||||
# Python imports
|
||||
import enum
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
|
||||
|
||||
def to_type(o, new_type):
|
||||
'''
|
||||
Helper funciton that receives an object or a dict and convert it to a new
|
||||
given type.
|
||||
|
||||
:param object|dict o: The object to convert
|
||||
:param Type new_type: The type to convert to.
|
||||
'''
|
||||
|
||||
return o if new_type == type(o) else new_type(**o)
|
||||
|
||||
|
||||
class Position(object):
|
||||
def __init__(self, line, character):
|
||||
"""
|
||||
Constructs a new Position instance.
|
||||
|
||||
:param int line: Line position in a document (zero-based).
|
||||
:param int character: Character offset on a line in a document
|
||||
(zero-based).
|
||||
"""
|
||||
self.line = line
|
||||
self.character = character
|
||||
|
||||
|
||||
class Range(object):
|
||||
def __init__(self, start, end):
|
||||
"""
|
||||
Constructs a new Range instance.
|
||||
|
||||
:param Position start: The range's start position.
|
||||
:param Position end: The range's end position.
|
||||
"""
|
||||
self.start = to_type(start, Position)
|
||||
self.end = to_type(end, Position)
|
||||
|
||||
|
||||
class Location(object):
|
||||
"""
|
||||
Represents a location inside a resource, such as a line inside a text file.
|
||||
"""
|
||||
|
||||
def __init__(self, uri, range):
|
||||
"""
|
||||
Constructs a new Location instance.
|
||||
|
||||
:param str uri: Resource file.
|
||||
:param Range range: The range inside the file
|
||||
"""
|
||||
self.uri = uri
|
||||
self.range = to_type(range, Range)
|
||||
|
||||
|
||||
class LocationLink(object):
|
||||
"""
|
||||
Represents a link between a source and a target location.
|
||||
"""
|
||||
|
||||
def __init__(self, originSelectionRange, targetUri, targetRange, targetSelectionRange):
|
||||
"""
|
||||
Constructs a new LocationLink instance.
|
||||
|
||||
:param Range originSelectionRange: Span of the origin of this link.
|
||||
Used as the underlined span for mouse interaction. Defaults to the word range at the mouse position.
|
||||
:param str targetUri: The target resource identifier of this link.
|
||||
:param Range targetRange: The full target range of this link. If the target for example is a symbol then target
|
||||
range is the range enclosing this symbol not including leading/trailing whitespace but everything else
|
||||
like comments. This information is typically used to highlight the range in the editor.
|
||||
:param Range targetSelectionRange: The range that should be selected and revealed when this link is being followed,
|
||||
e.g the name of a function. Must be contained by the the `targetRange`. See also `DocumentSymbol#range`
|
||||
"""
|
||||
self.originSelectionRange = to_type(originSelectionRange, Range)
|
||||
self.targetUri = targetUri
|
||||
self.targetRange = to_type(targetRange, Range)
|
||||
self.targetSelectionRange = to_type(targetSelectionRange, Range)
|
||||
|
||||
|
||||
class Diagnostic(object):
|
||||
def __init__(self, range, severity, code, source, message, relatedInformation):
|
||||
"""
|
||||
Constructs a new Diagnostic instance.
|
||||
:param Range range: The range at which the message applies.Resource file.
|
||||
:param int severity: The diagnostic's severity. Can be omitted. If omitted it is up to the
|
||||
client to interpret diagnostics as error, warning, info or hint.
|
||||
:param str code: The diagnostic's code, which might appear in the user interface.
|
||||
:param str source: A human-readable string describing the source of this
|
||||
diagnostic, e.g. 'typescript' or 'super lint'.
|
||||
:param str message: The diagnostic's message.
|
||||
:param list relatedInformation: An array of related diagnostic information, e.g. when symbol-names within
|
||||
a scope collide all definitions can be marked via this property.
|
||||
"""
|
||||
self.range = range
|
||||
self.severity = severity
|
||||
self.code = code
|
||||
self.source = source
|
||||
self.message = message
|
||||
self.relatedInformation = relatedInformation
|
||||
|
||||
|
||||
class DiagnosticSeverity(object):
|
||||
Error = 1
|
||||
Warning = 2 # TODO: warning is known in python
|
||||
Information = 3
|
||||
Hint = 4
|
||||
|
||||
|
||||
class DiagnosticRelatedInformation(object):
|
||||
def __init__(self, location, message):
|
||||
"""
|
||||
Constructs a new Diagnostic instance.
|
||||
:param Location location: The location of this related diagnostic information.
|
||||
:param str message: The message of this related diagnostic information.
|
||||
"""
|
||||
self.location = location
|
||||
self.message = message
|
||||
|
||||
|
||||
class Command(object):
|
||||
def __init__(self, title, command, arguments):
|
||||
"""
|
||||
Constructs a new Diagnostic instance.
|
||||
:param str title: Title of the command, like `save`.
|
||||
:param str command: The identifier of the actual command handler.
|
||||
:param list argusments: Arguments that the command handler should be invoked with.
|
||||
"""
|
||||
self.title = title
|
||||
self.command = command
|
||||
self.arguments = arguments
|
||||
|
||||
|
||||
class TextDocumentItem(object):
|
||||
"""
|
||||
An item to transfer a text document from the client to the server.
|
||||
"""
|
||||
def __init__(self, uri, languageId, version, text):
|
||||
"""
|
||||
Constructs a new Diagnostic instance.
|
||||
|
||||
:param DocumentUri uri: uri file path.
|
||||
:param str languageId: The identifier of the actual command handler.
|
||||
:param int version: Arguments that the command handler should be invoked with.
|
||||
:param str text: Arguments that the command handler should be invoked with.
|
||||
"""
|
||||
self.uri = uri
|
||||
self.languageId = languageId
|
||||
self.version = version
|
||||
self.text = text
|
||||
|
||||
|
||||
class TextDocumentIdentifier(object):
|
||||
"""
|
||||
Text documents are identified using a URI. On the protocol level, URIs are passed as strings.
|
||||
"""
|
||||
def __init__(self, uri):
|
||||
"""
|
||||
Constructs a new TextDocumentIdentifier instance.
|
||||
|
||||
:param DocumentUri uri: The text document's URI.
|
||||
"""
|
||||
self.uri = uri
|
||||
|
||||
|
||||
class VersionedTextDocumentIdentifier(TextDocumentIdentifier):
|
||||
"""
|
||||
An identifier to denote a specific version of a text document.
|
||||
"""
|
||||
def __init__(self, uri, version):
|
||||
"""
|
||||
Constructs a new TextDocumentIdentifier instance.
|
||||
|
||||
:param DocumentUri uri: The text document's URI.
|
||||
:param int version: The version number of this document. If a versioned
|
||||
text document identifier is sent from the server to the client and
|
||||
the file is not open in the editor (the server has not received an
|
||||
open notification before) the server can send `null` to indicate
|
||||
that the version is known and the content on disk is the truth (as
|
||||
speced with document content ownership).
|
||||
The version number of a document will increase after each change, including
|
||||
undo/redo. The number doesn't need to be consecutive.
|
||||
"""
|
||||
super(VersionedTextDocumentIdentifier, self).__init__(uri)
|
||||
self.version = version
|
||||
|
||||
|
||||
class TextDocumentContentChangeEvent(object):
|
||||
"""
|
||||
An event describing a change to a text document. If range and rangeLength are omitted
|
||||
the new text is considered to be the full content of the document.
|
||||
"""
|
||||
def __init__(self, range, rangeLength, text):
|
||||
"""
|
||||
Constructs a new TextDocumentContentChangeEvent instance.
|
||||
|
||||
:param Range range: The range of the document that changed.
|
||||
:param int rangeLength: The length of the range that got replaced.
|
||||
:param str text: The new text of the range/document.
|
||||
"""
|
||||
self.range = range
|
||||
self.rangeLength = rangeLength
|
||||
self.text = text
|
||||
|
||||
|
||||
class TextDocumentPositionParams(object):
|
||||
"""
|
||||
A parameter literal used in requests to pass a text document and a position inside that document.
|
||||
"""
|
||||
def __init__(self, textDocument, position):
|
||||
"""
|
||||
Constructs a new TextDocumentPositionParams instance.
|
||||
|
||||
:param TextDocumentIdentifier textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
"""
|
||||
self.textDocument = textDocument
|
||||
self.position = position
|
||||
|
||||
|
||||
class LANGUAGE_IDENTIFIER(object):
|
||||
BAT = "bat"
|
||||
BIBTEX = "bibtex"
|
||||
CLOJURE = "clojure"
|
||||
COFFESCRIPT = "coffeescript"
|
||||
C = "c"
|
||||
CPP = "cpp"
|
||||
CSHARP = "csharp"
|
||||
CSS = "css"
|
||||
DIFF = "diff"
|
||||
DOCKERFILE = "dockerfile"
|
||||
FSHARP = "fsharp"
|
||||
GIT_COMMIT = "git-commit"
|
||||
GIT_REBASE = "git-rebase"
|
||||
GO = "go"
|
||||
GROOVY = "groovy"
|
||||
HANDLEBARS = "handlebars"
|
||||
HTML = "html"
|
||||
INI = "ini"
|
||||
JAVA = "java"
|
||||
JAVASCRIPT = "javascript"
|
||||
JSON = "json"
|
||||
LATEX = "latex"
|
||||
LESS = "less"
|
||||
LUA = "lua"
|
||||
MAKEFILE = "makefile"
|
||||
MARKDOWN = "markdown"
|
||||
OBJECTIVE_C = "objective-c"
|
||||
OBJECTIVE_CPP = "objective-cpp"
|
||||
Perl = "perl"
|
||||
PHP = "php"
|
||||
POWERSHELL = "powershell"
|
||||
PUG = "jade"
|
||||
PYTHON = "python"
|
||||
R = "r"
|
||||
RAZOR = "razor"
|
||||
RUBY = "ruby"
|
||||
RUST = "rust"
|
||||
SASS = "sass"
|
||||
SCSS = "scss"
|
||||
ShaderLab = "shaderlab"
|
||||
SHELL_SCRIPT = "shellscript"
|
||||
SQL = "sql"
|
||||
SWIFT = "swift"
|
||||
TYPE_SCRIPT = "typescript"
|
||||
TEX = "tex"
|
||||
VB = "vb"
|
||||
XML = "xml"
|
||||
XSL = "xsl"
|
||||
YAML = "yaml"
|
||||
|
||||
|
||||
class SymbolKind(enum.Enum):
|
||||
File = 1
|
||||
Module = 2
|
||||
Namespace = 3
|
||||
Package = 4
|
||||
Class = 5
|
||||
Method = 6
|
||||
Property = 7
|
||||
Field = 8
|
||||
Constructor = 9
|
||||
Enum = 10
|
||||
Interface = 11
|
||||
Function = 12
|
||||
Variable = 13
|
||||
Constant = 14
|
||||
String = 15
|
||||
Number = 16
|
||||
Boolean = 17
|
||||
Array = 18
|
||||
Object = 19
|
||||
Key = 20
|
||||
Null = 21
|
||||
EnumMember = 22
|
||||
Struct = 23
|
||||
Event = 24
|
||||
Operator = 25
|
||||
TypeParameter = 26
|
||||
|
||||
|
||||
class SymbolInformation(object):
|
||||
"""
|
||||
Represents information about programming constructs like variables, classes, interfaces etc.
|
||||
"""
|
||||
def __init__(self, name, kind, location, containerName = None, deprecated = False):
|
||||
"""
|
||||
Constructs a new SymbolInformation instance.
|
||||
|
||||
:param str name: The name of this symbol.
|
||||
:param int kind: The kind of this symbol.
|
||||
:param bool Location: The location of this symbol. The location's range is used by a tool
|
||||
to reveal the location in the editor. If the symbol is selected in the
|
||||
tool the range's start information is used to position the cursor. So
|
||||
the range usually spans more then the actual symbol's name and does
|
||||
normally include things like visibility modifiers.
|
||||
|
||||
The range doesn't have to denote a node range in the sense of a abstract
|
||||
syntax tree. It can therefore not be used to re-construct a hierarchy of
|
||||
the symbols.
|
||||
:param str containerName: The name of the symbol containing this symbol. This information is for
|
||||
user interface purposes (e.g. to render a qualifier in the user interface
|
||||
if necessary). It can't be used to re-infer a hierarchy for the document
|
||||
symbols.
|
||||
:param bool deprecated: Indicates if this symbol is deprecated.
|
||||
"""
|
||||
self.name = name
|
||||
self.kind = SymbolKind(kind)
|
||||
self.deprecated = deprecated
|
||||
self.location = to_type(location, Location)
|
||||
self.containerName = containerName
|
||||
|
||||
|
||||
class ParameterInformation(object):
|
||||
"""
|
||||
Represents a parameter of a callable-signature. A parameter can
|
||||
have a label and a doc-comment.
|
||||
"""
|
||||
def __init__(self, label, documentation = ""):
|
||||
"""
|
||||
Constructs a new ParameterInformation instance.
|
||||
|
||||
:param str label: The label of this parameter. Will be shown in the UI.
|
||||
:param str documentation: The human-readable doc-comment of this parameter. Will be shown in the UI but can be omitted.
|
||||
"""
|
||||
self.label = label
|
||||
self.documentation = documentation
|
||||
|
||||
|
||||
class SignatureInformation(object):
|
||||
"""
|
||||
Represents the signature of something callable. A signature
|
||||
can have a label, like a function-name, a doc-comment, and
|
||||
a set of parameters.
|
||||
"""
|
||||
def __init__(self, label, documentation = "", parameters = []):
|
||||
"""
|
||||
Constructs a new SignatureInformation instance.
|
||||
|
||||
:param str label: The label of this signature. Will be shown in the UI.
|
||||
:param str documentation: The human-readable doc-comment of this signature. Will be shown in the UI but can be omitted.
|
||||
:param ParameterInformation[] parameters: The parameters of this signature.
|
||||
"""
|
||||
self.label = label
|
||||
self.documentation = documentation
|
||||
self.parameters = [to_type(parameter, ParameterInformation) for parameter in parameters]
|
||||
|
||||
|
||||
class SignatureHelp(object):
|
||||
"""
|
||||
Signature help represents the signature of something
|
||||
callable. There can be multiple signature but only one
|
||||
active and only one active parameter.
|
||||
"""
|
||||
def __init__(self, signatures, activeSignature = 0, activeParameter = 0):
|
||||
"""
|
||||
Constructs a new SignatureHelp instance.
|
||||
|
||||
:param SignatureInformation[] signatures: One or more signatures.
|
||||
:param int activeSignature:
|
||||
:param int activeParameter:
|
||||
"""
|
||||
self.signatures = [to_type(signature, SignatureInformation) for signature in signatures]
|
||||
self.activeSignature = activeSignature
|
||||
self.activeParameter = activeParameter
|
||||
|
||||
|
||||
class CompletionTriggerKind(object):
|
||||
Invoked = 1
|
||||
TriggerCharacter = 2
|
||||
TriggerForIncompleteCompletions = 3
|
||||
|
||||
|
||||
class CompletionContext(object):
|
||||
"""
|
||||
Contains additional information about the context in which a completion request is triggered.
|
||||
"""
|
||||
def __init__(self, triggerKind, triggerCharacter = None):
|
||||
"""
|
||||
Constructs a new CompletionContext instance.
|
||||
|
||||
:param CompletionTriggerKind triggerKind: How the completion was triggered.
|
||||
:param str triggerCharacter: The trigger character (a single character) that has trigger code complete.
|
||||
Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
|
||||
"""
|
||||
self.triggerKind = triggerKind
|
||||
if triggerCharacter:
|
||||
self.triggerCharacter = triggerCharacter
|
||||
|
||||
|
||||
class TextEdit(object):
|
||||
"""
|
||||
A textual edit applicable to a text document.
|
||||
"""
|
||||
def __init__(self, range, newText):
|
||||
"""
|
||||
:param Range range: The range of the text document to be manipulated. To insert
|
||||
text into a document create a range where start === end.
|
||||
:param str newText: The string to be inserted. For delete operations use an empty string.
|
||||
"""
|
||||
self.range = range
|
||||
self.newText = newText
|
||||
|
||||
|
||||
class InsertTextFormat(object):
|
||||
PlainText = 1
|
||||
Snippet = 2
|
||||
|
||||
|
||||
class CompletionItem(object):
|
||||
"""
|
||||
"""
|
||||
def __init__(self, label, \
|
||||
kind = None, \
|
||||
detail = None, \
|
||||
documentation = None, \
|
||||
deprecated = None, \
|
||||
preselect = None, \
|
||||
sortText = None, \
|
||||
filterText = None, \
|
||||
insertText = None, \
|
||||
insertTextFormat = None, \
|
||||
textEdit = None, \
|
||||
additionalTextEdits = None, \
|
||||
commitCharacters = None, \
|
||||
command = None, \
|
||||
data = None, \
|
||||
score = 0.0
|
||||
):
|
||||
"""
|
||||
:param str label: The label of this completion item. By default also the text that is inserted when selecting
|
||||
this completion.
|
||||
:param int kind: The kind of this completion item. Based of the kind an icon is chosen by the editor.
|
||||
:param str detail: A human-readable string with additional information about this item, like type or symbol information.
|
||||
:param tr ocumentation: A human-readable string that represents a doc-comment.
|
||||
:param bool deprecated: Indicates if this item is deprecated.
|
||||
:param bool preselect: Select this item when showing. Note: that only one completion item can be selected and that the
|
||||
tool / client decides which item that is. The rule is that the first item of those that match best is selected.
|
||||
:param str sortText: A string that should be used when comparing this item with other items. When `falsy` the label is used.
|
||||
:param str filterText: A string that should be used when filtering a set of completion items. When `falsy` the label is used.
|
||||
:param str insertText: A string that should be inserted into a document when selecting this completion. When `falsy` the label is used.
|
||||
The `insertText` is subject to interpretation by the client side. Some tools might not take the string literally. For example
|
||||
VS Code when code complete is requested in this example `con<cursor position>` and a completion item with an `insertText` of `console` is provided it
|
||||
will only insert `sole`. Therefore it is recommended to use `textEdit` instead since it avoids additional client side interpretation.
|
||||
@deprecated Use textEdit instead.
|
||||
:param InsertTextFormat insertTextFormat: The format of the insert text. The format applies to both the `insertText` property
|
||||
and the `newText` property of a provided `textEdit`.
|
||||
:param TextEdit textEdit: An edit which is applied to a document when selecting this completion. When an edit is provided the value of `insertText` is ignored.
|
||||
Note:* The range of the edit must be a single line range and it must contain the position at which completion
|
||||
has been requested.
|
||||
:param TextEdit additionalTextEdits: An optional array of additional text edits that are applied when selecting this completion.
|
||||
Edits must not overlap (including the same insert position) with the main edit nor with themselves.
|
||||
Additional text edits should be used to change text unrelated to the current cursor position
|
||||
(for example adding an import statement at the top of the file if the completion item will
|
||||
insert an unqualified type).
|
||||
:param str commitCharacters: An optional set of characters that when pressed while this completion is active will accept it first and
|
||||
then type that character. *Note* that all commit characters should have `length=1` and that superfluous
|
||||
characters will be ignored.
|
||||
:param Command command: An optional command that is executed *after* inserting this completion. Note: that
|
||||
additional modifications to the current document should be described with the additionalTextEdits-property.
|
||||
:param data: An data entry field that is preserved on a completion item between a completion and a completion resolve request.
|
||||
:param float score: Score of the code completion item.
|
||||
"""
|
||||
self.label = label
|
||||
self.kind = kind
|
||||
self.detail = detail
|
||||
self.documentation = documentation
|
||||
self.deprecated = deprecated
|
||||
self.preselect = preselect
|
||||
self.sortText = sortText
|
||||
self.filterText = filterText
|
||||
self.insertText = insertText
|
||||
self.insertTextFormat = insertTextFormat
|
||||
self.textEdit = textEdit
|
||||
self.additionalTextEdits = additionalTextEdits
|
||||
self.commitCharacters = commitCharacters
|
||||
self.command = command
|
||||
self.data = data
|
||||
self.score = score
|
||||
|
||||
|
||||
class CompletionItemKind(enum.Enum):
|
||||
Text = 1
|
||||
Method = 2
|
||||
Function = 3
|
||||
Constructor = 4
|
||||
Field = 5
|
||||
Variable = 6
|
||||
Class = 7
|
||||
Interface = 8
|
||||
Module = 9
|
||||
Property = 10
|
||||
Unit = 11
|
||||
Value = 12
|
||||
Enum = 13
|
||||
Keyword = 14
|
||||
Snippet = 15
|
||||
Color = 16
|
||||
File = 17
|
||||
Reference = 18
|
||||
Folder = 19
|
||||
EnumMember = 20
|
||||
Constant = 21
|
||||
Struct = 22
|
||||
Event = 23
|
||||
Operator = 24
|
||||
TypeParameter = 25
|
||||
|
||||
|
||||
class CompletionList(object):
|
||||
"""
|
||||
Represents a collection of [completion items](#CompletionItem) to be preselect in the editor.
|
||||
"""
|
||||
def __init__(self, isIncomplete, items):
|
||||
"""
|
||||
Constructs a new CompletionContext instance.
|
||||
|
||||
:param bool isIncomplete: This list it not complete. Further typing should result in recomputing this list.
|
||||
:param CompletionItem items: The completion items.
|
||||
"""
|
||||
self.isIncomplete = isIncomplete
|
||||
self.items = [to_type(i, CompletionItem) for i in items]
|
||||
|
||||
class ErrorCodes(enum.Enum):
|
||||
# Defined by JSON RPC
|
||||
ParseError = -32700
|
||||
InvalidRequest = -32600
|
||||
MethodNotFound = -32601
|
||||
InvalidParams = -32602
|
||||
InternalError = -32603
|
||||
serverErrorStart = -32099
|
||||
serverErrorEnd = -32000
|
||||
ServerNotInitialized = -32002
|
||||
UnknownErrorCode = -32001
|
||||
|
||||
# Defined by the protocol.
|
||||
RequestCancelled = -32800
|
||||
ContentModified = -32801
|
||||
|
||||
class ResponseError(Exception):
|
||||
def __init__(self, code, message, data = None):
|
||||
self.code = code
|
||||
self.message = message
|
||||
if data:
|
||||
self.data = data
|
||||
@@ -3,7 +3,13 @@
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from libs.dto.code.lsp.lsp_message_structs import LSPResponseTypes, LSPResponseRequest, LSPResponseNotification
|
||||
from libs.controllers.controller_base import ControllerBase
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from .dto.code.events import \
|
||||
RegisterLspClientEvent, UnregisterLspClientEvent
|
||||
from .dto.code.lsp.lsp_message_structs import \
|
||||
LSPResponseTypes, LSPResponseRequest, LSPResponseNotification
|
||||
|
||||
from .provider import Provider
|
||||
from .provider_response_cache import ProviderResponseCache
|
||||
@@ -13,7 +19,7 @@ from .response_handlers.response_registry import ResponseRegistry
|
||||
|
||||
|
||||
|
||||
class LSPManager:
|
||||
class LSPManager(ControllerBase):
|
||||
def __init__(self):
|
||||
super(LSPManager, self).__init__()
|
||||
|
||||
@@ -37,6 +43,20 @@ class LSPManager:
|
||||
self.response_cache.set_lsp_client(self.lsp_manager_client)
|
||||
self.provider.response_cache = self.response_cache
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
if isinstance(event, RegisterLspClientEvent):
|
||||
self.response_registry.register_handler(event.lang_id, event.handler)
|
||||
self.lsp_manager_ui.add_client_listing(event.lang_id, event.lang_config)
|
||||
elif isinstance(event, UnregisterLspClientEvent):
|
||||
self.response_registry.unregister_handler(event.lang_id)
|
||||
|
||||
# if isinstance(event, Code_Event_Types.RegisterLspClientEvent):
|
||||
# self.response_registry.register_handler(event.lang_id, event.handler)
|
||||
# self.lsp_manager_ui.add_client_listing(event.lang_id, event.lang_config)
|
||||
# elif isinstance(event, Code_Event_Types.UnregisterLspClientEvent):
|
||||
# self.response_registry.unregister_handler(event.lang_id)
|
||||
|
||||
|
||||
def _on_create_client(self, ui, lang_id: str, workspace_uri: str) -> bool:
|
||||
init_opts = ui.get_init_opts(lang_id)
|
||||
result = self.create_client(lang_id, workspace_uri, init_opts)
|
||||
@@ -1,5 +1,4 @@
|
||||
# Python imports
|
||||
from os import path
|
||||
import json
|
||||
|
||||
# Lib imports
|
||||
@@ -25,12 +24,8 @@ class LSPManagerUI(Gtk.Dialog):
|
||||
def __init__(self):
|
||||
super(LSPManagerUI, self).__init__()
|
||||
|
||||
self._SCRIPT_PTH: str = path.dirname( path.realpath(__file__) )
|
||||
self._USER_HOME: str = path.expanduser('~')
|
||||
self._LSP_SERVERS_CONFIG: str = ""
|
||||
self.servers_config: dict = {}
|
||||
self.client_configs: dict[str, str] = {}
|
||||
|
||||
self.parent = None
|
||||
self.source_view = None
|
||||
|
||||
self._setup_styling()
|
||||
@@ -69,9 +64,10 @@ class LSPManagerUI(Gtk.Dialog):
|
||||
self.path_entry.set_can_focus(False)
|
||||
self.path_entry.set_placeholder_text("Workspace Folder...")
|
||||
self.path_entry.connect("changed", self._path_changed, bttn_box)
|
||||
self.path_bttn.set_halign(Gtk.Align.FILL)
|
||||
|
||||
self.path_bttn.connect("file-set", self._file_set)
|
||||
self.path_bttn.set_halign(Gtk.Align.FILL)
|
||||
self.combo_box.connect("changed", self._on_combo_changed)
|
||||
self.hide_bttn.connect("clicked", lambda widget: self.hide())
|
||||
self.create_client_bttn.connect("clicked", self._create_client, self.close_client_bttn)
|
||||
self.close_client_bttn.connect("clicked", self._close_client, self.create_client_bttn)
|
||||
@@ -115,16 +111,56 @@ class LSPManagerUI(Gtk.Dialog):
|
||||
|
||||
def _path_changed(self, widget, buttons_widget):
|
||||
if not widget.get_text():
|
||||
self.path_bttn.unselect_all()
|
||||
self.path_bttn.emit("file-set")
|
||||
buttons_widget.hide()
|
||||
return
|
||||
|
||||
self.set_source_view_text( self.path_entry.get_text() )
|
||||
buttons_widget.show()
|
||||
|
||||
def _file_set(self, widget):
|
||||
self.path_entry.set_text(
|
||||
widget.get_filename()
|
||||
fname = widget.get_filename()
|
||||
fname = "" if not fname else fname
|
||||
self.path_entry.set_text(fname)
|
||||
|
||||
lang_id = self.combo_box.get_active_text()
|
||||
if not lang_id or lang_id not in self.client_configs: return
|
||||
|
||||
self.set_source_view_text(
|
||||
"{workspace.folder}" if not fname else fname
|
||||
)
|
||||
self.load_lsp_servers_config_placeholders()
|
||||
|
||||
def _create_client(self, widget, sibling):
|
||||
if not self.source_view: return
|
||||
|
||||
buffer = self.source_view.get_buffer()
|
||||
lang_id = self.combo_box.get_active_text()
|
||||
|
||||
if not lang_id: return
|
||||
|
||||
workspace_dir = self.path_entry.get_text()
|
||||
self.emit('create-client', lang_id, workspace_dir)
|
||||
|
||||
def _close_client(self, widget, sibling):
|
||||
lang_id = self.combo_box.get_active_text()
|
||||
|
||||
if not lang_id: return
|
||||
self.emit('close-client', lang_id)
|
||||
|
||||
def _on_combo_changed(self, combo: Gtk.ComboBoxText):
|
||||
lang_id = combo.get_active_text()
|
||||
self.set_source_view_text( self.path_entry.get_text() )
|
||||
|
||||
|
||||
def set_source_view_text(self, workspace_dir: str):
|
||||
lang_id = self.combo_box.get_active_text()
|
||||
if not lang_id: return
|
||||
|
||||
json_str = self.client_configs[lang_id].replace("{workspace.folder}", workspace_dir)
|
||||
buffer = self.source_view.get_buffer()
|
||||
|
||||
buffer.set_text(json_str, -1)
|
||||
|
||||
def map_parent_resize_event(self, parent):
|
||||
parent.connect("size-allocate", lambda w, r: self._map_resize(self, parent))
|
||||
@@ -147,68 +183,20 @@ class LSPManagerUI(Gtk.Dialog):
|
||||
|
||||
scrolled_win.show_all()
|
||||
|
||||
def load_lsp_servers_config(self):
|
||||
try:
|
||||
with open(f"{self._SCRIPT_PTH}/configs/lsp-servers-config.json") as file:
|
||||
self._LSP_SERVERS_CONFIG = file.read()
|
||||
except FileNotFoundError:
|
||||
logger.error(f"Config file not found: {self._SCRIPT_PTH}/configs/lsp-servers-config.json")
|
||||
|
||||
def load_lsp_servers_config_placeholders(self):
|
||||
if not self._LSP_SERVERS_CONFIG: return
|
||||
if not self.source_view: return
|
||||
|
||||
data = self._LSP_SERVERS_CONFIG \
|
||||
.replace("{user.home}", self._USER_HOME) \
|
||||
.replace("{workspace.folder}", self.path_entry.get_text())
|
||||
|
||||
self.servers_config = json.loads(data)
|
||||
|
||||
buffer = self.source_view.get_buffer()
|
||||
start_itr, \
|
||||
end_itr = buffer.get_bounds()
|
||||
|
||||
buffer.delete(start_itr, end_itr)
|
||||
buffer.insert(start_itr, data, -1)
|
||||
|
||||
self.set_language_combo_box( list(self.servers_config.keys()) )
|
||||
|
||||
def set_language_combo_box(self, lang_ids: list[str]):
|
||||
self.combo_box.remove_all()
|
||||
|
||||
for lang_id in lang_ids:
|
||||
self.combo_box.append_text(lang_id)
|
||||
def add_client_listing(self, lang_id: str, lang_config: str):
|
||||
self.combo_box.append_text(lang_id)
|
||||
self.client_configs[lang_id] = lang_config
|
||||
|
||||
def get_init_opts(self, lang_id: str) -> dict:
|
||||
buffer = self.source_view.get_buffer()
|
||||
if not lang_id or lang_id not in self.client_configs: return {}
|
||||
|
||||
try:
|
||||
self.servers_config = json.loads(
|
||||
buffer.get_text( *buffer.get_bounds() )
|
||||
)
|
||||
lang_config = json.loads(self.client_configs[lang_id])
|
||||
except json.JSONDecodeError as e:
|
||||
logger.error(f"Invalid JSON: {e}")
|
||||
logger.error(f"Invalid JSON for {lang_id}: {e}")
|
||||
return {}
|
||||
|
||||
if not lang_id or not lang_id in self.servers_config: return {}
|
||||
|
||||
return self.servers_config[lang_id].get("initialization-options", {})
|
||||
|
||||
def _create_client(self, widget, sibling):
|
||||
if not self.source_view: return
|
||||
|
||||
buffer = self.source_view.get_buffer()
|
||||
lang_id = self.combo_box.get_active_text()
|
||||
|
||||
if not lang_id: return
|
||||
|
||||
workspace_dir = self.path_entry.get_text()
|
||||
self.emit('create-client', lang_id, workspace_dir)
|
||||
|
||||
def _close_client(self, widget, sibling):
|
||||
lang_id = self.combo_box.get_active_text()
|
||||
|
||||
if not lang_id: return
|
||||
self.emit('close-client', lang_id)
|
||||
return lang_config.get("initialization-options", {})
|
||||
|
||||
def toggle_client_buttons(self, show_close: bool):
|
||||
self.create_client_bttn.set_visible(not show_close)
|
||||
@@ -3,5 +3,6 @@
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"pre_launch": true,
|
||||
"requests": {}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ from libs.dto.states import SourceViewStates
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
from .dto.code import events as lsp_events
|
||||
from .lsp_manager import LSPManager
|
||||
|
||||
|
||||
@@ -28,6 +29,10 @@ class Plugin(PluginCode):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
Event_Factory.register_events( lsp_events.__dict__.items() )
|
||||
|
||||
self.register_controller("lsp_manager", lsp_manager)
|
||||
|
||||
window = self.request_ui_element("main-window")
|
||||
|
||||
lsp_manager.lsp_manager_ui.map_parent_resize_event(window)
|
||||
@@ -55,11 +60,11 @@ class Plugin(PluginCode):
|
||||
self.emit_to("source_views", event)
|
||||
|
||||
source_view = event.response
|
||||
lsp_manager.lsp_manager_ui.load_lsp_servers_config()
|
||||
lsp_manager.lsp_manager_ui.set_source_view(source_view)
|
||||
lsp_manager.lsp_manager_ui.load_lsp_servers_config_placeholders()
|
||||
|
||||
lsp_manager.response_registry.set_event_hub(self.emit, self.emit_to, lsp_manager.provider)
|
||||
lsp_manager.response_registry.set_event_hub(
|
||||
self.emit, self.emit_to, lsp_manager.provider
|
||||
)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
@@ -0,0 +1,3 @@
|
||||
from .base_handler import BaseHandler
|
||||
from .default import DefaultHandler
|
||||
from .response_registry import ResponseRegistry
|
||||
@@ -8,7 +8,7 @@ from gi.repository import GLib
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from .base import BaseHandler
|
||||
from .base_handler import BaseHandler
|
||||
|
||||
|
||||
|
||||
@@ -3,10 +3,8 @@
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .base import BaseHandler
|
||||
from .base_handler import BaseHandler
|
||||
from .default import DefaultHandler
|
||||
from .python import PythonHandler
|
||||
from .java import JavaHandler
|
||||
|
||||
|
||||
|
||||
@@ -15,12 +13,11 @@ class ResponseRegistry:
|
||||
|
||||
self._instances: dict = {}
|
||||
self._lang_handlers: dict = {
|
||||
"default": DefaultHandler,
|
||||
"python": PythonHandler,
|
||||
"java": JavaHandler,
|
||||
"default": DefaultHandler
|
||||
}
|
||||
|
||||
def set_event_hub(self, emit, emit_to, provider=None):
|
||||
|
||||
def set_event_hub(self, emit, emit_to, provider = None):
|
||||
self.emit = emit
|
||||
self.emit_to = emit_to
|
||||
self._provider = provider
|
||||
@@ -36,6 +33,9 @@ class ResponseRegistry:
|
||||
def register_handler(self, lang_id: str, handler_cls: type[BaseHandler]):
|
||||
self._lang_handlers[lang_id] = handler_cls
|
||||
|
||||
def unregister_handler(self, lang_id: str, handler_cls: type[BaseHandler]):
|
||||
del self._lang_handlers[lang_id]
|
||||
|
||||
def get_handler(self, lang_id: str = "", method: str = ""):
|
||||
handler_cls = self._lang_handlers.get(
|
||||
lang_id, self._lang_handlers.get("default", DefaultHandler)
|
||||
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Module
|
||||
"""
|
||||
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Pligin Package
|
||||
"""
|
||||
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"info": "https://github.com/python-lsp/python-lsp-server",
|
||||
"command": "lsp-ws-proxy -- pylsp",
|
||||
"alt-command": "pylsp",
|
||||
"alt-command2": "lsp-ws-proxy --listen 4114 -- pylsp",
|
||||
"alt-command3": "pylsp --ws --port 4114",
|
||||
"socket": "ws://127.0.0.1:9999/python",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=pylsp",
|
||||
"initialization-options": {
|
||||
"pylsp": {
|
||||
"rope": {
|
||||
"ropeFolder": "{user.home}/.config/newton/lsps/ropeproject"
|
||||
},
|
||||
"plugins": {
|
||||
"ruff": {
|
||||
"enabled": true,
|
||||
"extendSelect": ["I"],
|
||||
"lineLength": 80
|
||||
},
|
||||
"pycodestyle": {
|
||||
"enabled": false
|
||||
},
|
||||
"pyflakes": {
|
||||
"enabled": false
|
||||
},
|
||||
"pylint": {
|
||||
"enabled": true
|
||||
},
|
||||
"mccabe": {
|
||||
"enabled": false
|
||||
},
|
||||
"pylsp_rope": {
|
||||
"rename": false
|
||||
},
|
||||
"rope_rename": {
|
||||
"enabled": false
|
||||
},
|
||||
"rope_autoimport": {
|
||||
"enabled": true
|
||||
},
|
||||
"rope_completion": {
|
||||
"enabled": false,
|
||||
"eager": false
|
||||
},
|
||||
"jedi_rename": {
|
||||
"enabled": true
|
||||
},
|
||||
"jedi_completion": {
|
||||
"enabled": true,
|
||||
"include_class_objects": true,
|
||||
"include_function_objects": true,
|
||||
"fuzzy": false
|
||||
},
|
||||
"jedi": {
|
||||
"root_dir": "file://{workspace.folder}",
|
||||
"extra_paths": [
|
||||
"{user.home}/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"python - jedi-language-server": {
|
||||
"hidden": true,
|
||||
"info": "https://pypi.org/project/jedi-language-server/",
|
||||
"command": "jedi-language-server",
|
||||
"alt-command": "lsp-ws-proxy --listen 3030 -- jedi-language-server",
|
||||
"socket": "ws://127.0.0.1:9999/python",
|
||||
"socket-two": "ws://127.0.0.1:9999/?name=jedi-language-server",
|
||||
"initialization-options": {
|
||||
"jediSettings": {
|
||||
"autoImportModules": [],
|
||||
"caseInsensitiveCompletion": true,
|
||||
"debug": false
|
||||
},
|
||||
"completion": {
|
||||
"disableSnippets": false,
|
||||
"resolveEagerly": false,
|
||||
"ignorePatterns": []
|
||||
},
|
||||
"markupKindPreferred": "markdown",
|
||||
"workspace": {
|
||||
"extraPaths": [
|
||||
"{user.home}/Portable_Apps/py-venvs/pylsp-venv/venv/lib/python3.10/site-packages"
|
||||
],
|
||||
"environmentPath": "{user.home}/Portable_Apps/py-venvs/gtk-apps-venv/venv/bin/python",
|
||||
"symbols": {
|
||||
"ignoreFolders": [
|
||||
".nox",
|
||||
".tox",
|
||||
".venv",
|
||||
"__pycache__",
|
||||
"venv"
|
||||
],
|
||||
"maxSymbols": 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "Python LSP Client",
|
||||
"author": "ITDominator",
|
||||
"version": "0.0.1",
|
||||
"support": "",
|
||||
"requests": {}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
# Python imports
|
||||
from os import path
|
||||
|
||||
# Lib imports
|
||||
import gi
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
# Application imports
|
||||
from libs.event_factory import Event_Factory, Code_Event_Types
|
||||
|
||||
from plugins.plugin_types import PluginCode
|
||||
|
||||
from .response_handler import PythonHandler
|
||||
|
||||
|
||||
class Plugin(PluginCode):
|
||||
def __init__(self):
|
||||
super(Plugin, self).__init__()
|
||||
|
||||
|
||||
def _controller_message(self, event: Code_Event_Types.CodeEvent):
|
||||
...
|
||||
|
||||
def load(self):
|
||||
dirPth = path.dirname( path.realpath(__file__) )
|
||||
with open(f"{dirPth}/config/lsp-server-config.json", "r") as f:
|
||||
config = f.read()
|
||||
event = Event_Factory.create_event("register_lsp_client",
|
||||
lang_id = "python",
|
||||
lang_config = config,
|
||||
handler = PythonHandler
|
||||
)
|
||||
self.emit_to("lsp_manager", event)
|
||||
|
||||
def run(self):
|
||||
...
|
||||
@@ -0,0 +1 @@
|
||||
from .python import PythonHandler
|
||||
@@ -3,7 +3,7 @@
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from .default import DefaultHandler
|
||||
from lsp_manager.response_handlers.default import DefaultHandler
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
from .base import BaseHandler
|
||||
from .default import DefaultHandler
|
||||
from .python import PythonHandler
|
||||
from .java import JavaHandler
|
||||
from .response_registry import ResponseRegistry
|
||||
Reference in New Issue
Block a user