Did personalizxed formatting; example cleanup; added some client commands
This commit is contained in:
parent
fc6e645261
commit
248771d57e
@ -1,8 +1,12 @@
|
||||
#from __future__ import absolute_import
|
||||
|
||||
__all__ = []
|
||||
|
||||
from pylspclient.json_rpc_endpoint import JsonRpcEndpoint
|
||||
from pylspclient.lsp_client import LspClient
|
||||
from pylspclient.lsp_endpoint import LspEndpoint
|
||||
from pylspclient import lsp_structs
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
|
||||
from .json_rpc_endpoint import JsonRpcEndpoint
|
||||
from .lsp_client import LspClient
|
||||
from .lsp_endpoint import LspEndpoint
|
||||
from . import lsp_structs
|
||||
|
@ -1,17 +1,25 @@
|
||||
# Python imports
|
||||
from __future__ import print_function
|
||||
|
||||
import json
|
||||
import re
|
||||
from pylspclient import lsp_structs
|
||||
import threading
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from . import lsp_structs
|
||||
|
||||
|
||||
|
||||
JSON_RPC_REQ_FORMAT = "Content-Length: {json_string_len}\r\n\r\n{json_string}"
|
||||
LEN_HEADER = "Content-Length: "
|
||||
TYPE_HEADER = "Content-Type: "
|
||||
|
||||
|
||||
# TODO: add content-type
|
||||
|
||||
|
||||
|
||||
class MyEncoder(json.JSONEncoder):
|
||||
"""
|
||||
Encodes an object in JSON
|
||||
@ -64,18 +72,16 @@ class JsonRpcEndpoint(object):
|
||||
with self.read_lock:
|
||||
message_size = None
|
||||
while True:
|
||||
#read header
|
||||
line = self.stdout.readline()
|
||||
if not line:
|
||||
# server quit
|
||||
return None
|
||||
|
||||
line = line.decode("utf-8")
|
||||
if not line.endswith("\r\n"):
|
||||
raise lsp_structs.ResponseError(lsp_structs.ErrorCodes.ParseError, "Bad header: missing newline")
|
||||
#remove the "\r\n"
|
||||
line = line[:-2]
|
||||
|
||||
line = line[:-2] #remove the "\r\n"
|
||||
if line == "":
|
||||
# done with the headers
|
||||
break
|
||||
elif line.startswith(LEN_HEADER):
|
||||
line = line[len(LEN_HEADER):]
|
||||
@ -83,10 +89,10 @@ class JsonRpcEndpoint(object):
|
||||
raise lsp_structs.ResponseError(lsp_structs.ErrorCodes.ParseError, "Bad header: size is not int")
|
||||
message_size = int(line)
|
||||
elif line.startswith(TYPE_HEADER):
|
||||
# nothing todo with type for now.
|
||||
pass
|
||||
...
|
||||
else:
|
||||
raise lsp_structs.ResponseError(lsp_structs.ErrorCodes.ParseError, "Bad header: unkown header")
|
||||
|
||||
if not message_size:
|
||||
raise lsp_structs.ResponseError(lsp_structs.ErrorCodes.ParseError, "Bad header: missing size")
|
||||
|
||||
|
@ -1,4 +1,11 @@
|
||||
from pylspclient import lsp_structs
|
||||
# Python imports
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from . import lsp_structs
|
||||
|
||||
|
||||
|
||||
class LspClient(object):
|
||||
def __init__(self, lsp_endpoint):
|
||||
@ -7,8 +14,8 @@ class LspClient(object):
|
||||
|
||||
:param lsp_endpoint: TODO
|
||||
"""
|
||||
self.lsp_endpoint = lsp_endpoint
|
||||
|
||||
self.lsp_endpoint = lsp_endpoint
|
||||
|
||||
def initialize(self, processId, rootPath, rootUri, initializationOptions, capabilities, trace, workspaceFolders):
|
||||
"""
|
||||
@ -36,9 +43,17 @@ class LspClient(object):
|
||||
:param list workspaceFolders: The workspace folders configured in the client when the server starts. This property is only available if the client supports workspace folders.
|
||||
It can be `null` if the client supports workspace folders but none are configured.
|
||||
"""
|
||||
self.lsp_endpoint.start()
|
||||
return self.lsp_endpoint.call_method("initialize", processId=processId, rootPath=rootPath, rootUri=rootUri, initializationOptions=initializationOptions, capabilities=capabilities, trace=trace, workspaceFolders=workspaceFolders)
|
||||
|
||||
self.lsp_endpoint.start()
|
||||
return self.lsp_endpoint.call_method("initialize",
|
||||
processId = processId,
|
||||
rootPath = rootPath,
|
||||
rootUri = rootUri,
|
||||
initializationOptions = initializationOptions,
|
||||
capabilities = capabilities,
|
||||
trace = trace,
|
||||
workspaceFolders = workspaceFolders
|
||||
)
|
||||
|
||||
def initialized(self):
|
||||
"""
|
||||
@ -46,26 +61,21 @@ class LspClient(object):
|
||||
but before the client is sending any other request or notification to the server. The server can use the initialized notification
|
||||
for example to dynamically register capabilities. The initialized notification may only be sent once.
|
||||
"""
|
||||
self.lsp_endpoint.send_notification("initialized")
|
||||
|
||||
self.lsp_endpoint.send_notification("initialized")
|
||||
|
||||
def shutdown(self):
|
||||
"""
|
||||
The initialized notification is sent from the client to the server after the client received the result of the initialize request
|
||||
but before the client is sending any other request or notification to the server. The server can use the initialized notification
|
||||
for example to dynamically register capabilities. The initialized notification may only be sent once.
|
||||
"""
|
||||
self.lsp_endpoint.stop()
|
||||
return self.lsp_endpoint.call_method("shutdown")
|
||||
|
||||
return self.lsp_endpoint.call_method("shutdown")
|
||||
|
||||
def exit(self):
|
||||
"""
|
||||
The initialized notification is sent from the client to the server after the client received the result of the initialize request
|
||||
but before the client is sending any other request or notification to the server. The server can use the initialized notification
|
||||
for example to dynamically register capabilities. The initialized notification may only be sent once.
|
||||
"""
|
||||
|
||||
self.lsp_endpoint.send_notification("exit")
|
||||
self.lsp_endpoint.stop()
|
||||
|
||||
|
||||
def didOpen(self, textDocument):
|
||||
@ -83,8 +93,21 @@ class LspClient(object):
|
||||
|
||||
:param TextDocumentItem textDocument: The document that was opened.
|
||||
"""
|
||||
|
||||
return self.lsp_endpoint.send_notification("textDocument/didOpen", textDocument = textDocument)
|
||||
|
||||
def didSave(self, textDocument):
|
||||
"""
|
||||
:param TextDocumentIdentifier textDocument: The document that was saved.
|
||||
"""
|
||||
|
||||
return self.lsp_endpoint.send_notification("textDocument/didSave", textDocument = textDocument)
|
||||
|
||||
def didClose(self, textDocument):
|
||||
"""
|
||||
:param TextDocumentIdentifier textDocument: The document that was closed.
|
||||
"""
|
||||
return self.lsp_endpoint.send_notification("textDocument/didClose", textDocument = textDocument)
|
||||
|
||||
def didChange(self, textDocument, contentChanges):
|
||||
"""
|
||||
@ -96,100 +119,139 @@ class LspClient(object):
|
||||
to the document. So if there are two content changes c1 and c2 for a document in state S then c1 move the document
|
||||
to S' and c2 to S''.
|
||||
"""
|
||||
return self.lsp_endpoint.send_notification("textDocument/didChange", textDocument=textDocument, contentChanges=contentChanges)
|
||||
|
||||
return self.lsp_endpoint.send_notification("textDocument/didChange", textDocument = textDocument, contentChanges = contentChanges)
|
||||
|
||||
def documentSymbol(self, textDocument):
|
||||
"""
|
||||
The document symbol request is sent from the client to the server to return a flat list of all symbols found in a given text document.
|
||||
Neither the symbol's location range nor the symbol's container name should be used to infer a hierarchy.
|
||||
The document symbol request is sent from the client to the server to
|
||||
return a flat list of all symbols found in a given text document.
|
||||
Neither the symbol's location range nor the symbol's container name
|
||||
should be used to infer a hierarchy.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
"""
|
||||
result_dict = self.lsp_endpoint.call_method( "textDocument/documentSymbol", textDocument=textDocument )
|
||||
|
||||
if not result_dict: return []
|
||||
return [lsp_structs.SymbolInformation(**sym) for sym in result_dict]
|
||||
|
||||
|
||||
def definition(self, textDocument, position):
|
||||
"""
|
||||
The goto definition request is sent from the client to the server to resolve the definition location of a symbol at a given text document position.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
"""
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/definition", textDocument=textDocument, position=position)
|
||||
return [lsp_structs.Location(**l) for l in result_dict]
|
||||
|
||||
|
||||
def typeDefinition(self, textDocument, position):
|
||||
"""
|
||||
The goto type definition request is sent from the client to the server to resolve the type definition location of a symbol at a given text document position.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
"""
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/definition", textDocument=textDocument, position=position)
|
||||
return [lsp_structs.Location(**l) for l in result_dict]
|
||||
|
||||
|
||||
def signatureHelp(self, textDocument, position):
|
||||
"""
|
||||
The signature help request is sent from the client to the server to request signature information at a given cursor position.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
"""
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/signatureHelp", textDocument=textDocument, position=position)
|
||||
return lsp_structs.SignatureHelp(**result_dict)
|
||||
|
||||
|
||||
def completion(self, textDocument, position, context):
|
||||
"""
|
||||
The signature help request is sent from the client to the server to request signature information at a given cursor position.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
:param CompletionContext context: The completion context. This is only available if the client specifies
|
||||
to send this using `ClientCapabilities.textDocument.completion.contextSupport === true`
|
||||
"""
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/completion", textDocument=textDocument, position=position, context=context)
|
||||
if "isIncomplete" in result_dict:
|
||||
return lsp_structs.CompletionList(**result_dict)
|
||||
|
||||
return [lsp_structs.CompletionItem(**l) for l in result_dict]
|
||||
|
||||
|
||||
def declaration(self, textDocument, position):
|
||||
"""
|
||||
The go to declaration request is sent from the client to the server to resolve the declaration location of a
|
||||
symbol at a given text document position.
|
||||
The go to declaration request is sent from the client to the server to
|
||||
resolve the declaration location of a symbol at a given text document
|
||||
position.
|
||||
|
||||
The result type LocationLink[] got introduce with version 3.14.0 and depends in the corresponding client
|
||||
capability `clientCapabilities.textDocument.declaration.linkSupport`.
|
||||
The result type LocationLink[] got introduce with version 3.14.0 and
|
||||
depends in the corresponding client capability
|
||||
`clientCapabilities.textDocument.declaration.linkSupport`.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
"""
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/declaration", textDocument=textDocument, position=position)
|
||||
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/declaration",
|
||||
textDocument = textDocument,
|
||||
position = position
|
||||
)
|
||||
|
||||
if not result_dict: return []
|
||||
|
||||
if "uri" in result_dict:
|
||||
return lsp_structs.Location(**result_dict)
|
||||
|
||||
return [lsp_structs.Location(**l) if "uri" in l else lsp_structs.LinkLocation(**l) for l in result_dict]
|
||||
|
||||
return [lsp_structs.Location(**loc) if "uri" in loc else lsp_structs.LinkLocation(**loc) for loc in result_dict]
|
||||
|
||||
def definition(self, textDocument, position):
|
||||
"""
|
||||
The go to definition request is sent from the client to the server to resolve the declaration location of a
|
||||
symbol at a given text document position.
|
||||
|
||||
The result type LocationLink[] got introduce with version 3.14.0 and depends in the corresponding client
|
||||
capability `clientCapabilities.textDocument.declaration.linkSupport`.
|
||||
The goto definition request is sent from the client to the server to
|
||||
resolve the definition location of a symbol at a given text document
|
||||
position.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
"""
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/definition", textDocument=textDocument, position=position)
|
||||
if "uri" in result_dict:
|
||||
return lsp_structs.Location(**result_dict)
|
||||
|
||||
return [lsp_structs.Location(**l) if "uri" in l else lsp_structs.LinkLocation(**l) for l in result_dict]
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/definition",
|
||||
textDocument = textDocument,
|
||||
position = position
|
||||
)
|
||||
|
||||
if not result_dict: return []
|
||||
return [lsp_structs.Location(**loc) for loc in result_dict]
|
||||
|
||||
def typeDefinition(self, textDocument, position):
|
||||
"""
|
||||
The goto type definition request is sent from the client to the server
|
||||
to resolve the type definition location of a symbol at a given text
|
||||
document position.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
"""
|
||||
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/typeDefinition",
|
||||
textDocument = textDocument,
|
||||
position = position
|
||||
)
|
||||
|
||||
if not result_dict: return []
|
||||
return [lsp_structs.Location(**loc) for loc in result_dict]
|
||||
|
||||
def signatureHelp(self, textDocument, position):
|
||||
"""
|
||||
The signature help request is sent from the client to the server to
|
||||
request signature information at a given cursor position.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
"""
|
||||
|
||||
result_dict = self.lsp_endpoint.call_method( "textDocument/signatureHelp",
|
||||
textDocument = textDocument,
|
||||
position = position
|
||||
)
|
||||
|
||||
if not result_dict: return []
|
||||
return lsp_structs.SignatureHelp(**result_dict)
|
||||
|
||||
def completion(self, textDocument, position, context):
|
||||
"""
|
||||
The signature help request is sent from the client to the server to
|
||||
request signature information at a given cursor position.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
:param CompletionContext context: The completion context. This is only
|
||||
available if the client specifies
|
||||
to send this using `ClientCapabilities.textDocument.completion.contextSupport === true`
|
||||
"""
|
||||
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/completion",
|
||||
textDocument = textDocument,
|
||||
position = position,
|
||||
context = context
|
||||
)
|
||||
if not result_dict: return []
|
||||
|
||||
if "isIncomplete" in result_dict:
|
||||
return lsp_structs.CompletionList(**result_dict)
|
||||
|
||||
return [lsp_structs.CompletionItem(**loc) for loc in result_dict]
|
||||
|
||||
def references(self, textDocument, position):
|
||||
"""
|
||||
The references request is sent from the client to the server to resolve
|
||||
project-wide references for the symbol denoted by the given text
|
||||
document position.
|
||||
|
||||
:param TextDocumentItem textDocument: The text document.
|
||||
:param Position position: The position inside the text document.
|
||||
"""
|
||||
|
||||
result_dict = self.lsp_endpoint.call_method("textDocument/references",
|
||||
textDocument = textDocument,
|
||||
position = position)
|
||||
|
||||
if not result_dict: return []
|
||||
return [lsp_structs.Location(**loc) for loc in result_dict]
|
@ -1,7 +1,14 @@
|
||||
# Python imports
|
||||
from __future__ import print_function
|
||||
|
||||
import threading
|
||||
import collections
|
||||
from pylspclient import lsp_structs
|
||||
|
||||
# Lib imports
|
||||
|
||||
# Application imports
|
||||
from . import lsp_structs
|
||||
|
||||
|
||||
|
||||
class LspEndpoint(threading.Thread):
|
||||
@ -34,8 +41,9 @@ class LspEndpoint(threading.Thread):
|
||||
try:
|
||||
jsonrpc_message = self.json_rpc_endpoint.recv_response()
|
||||
if jsonrpc_message is None:
|
||||
print("server quit")
|
||||
print("Server Quit...")
|
||||
break
|
||||
|
||||
method = jsonrpc_message.get("method")
|
||||
result = jsonrpc_message.get("result")
|
||||
error = jsonrpc_message.get("error")
|
||||
@ -44,15 +52,12 @@ class LspEndpoint(threading.Thread):
|
||||
|
||||
if method:
|
||||
if rpc_id:
|
||||
# a call for method
|
||||
if method not in self.method_callbacks:
|
||||
raise lsp_structs.ResponseError(lsp_structs.ErrorCodes.MethodNotFound, "Method not found: {method}".format(method=method))
|
||||
result = self.method_callbacks[method](params)
|
||||
self.send_response(rpc_id, result, None)
|
||||
else:
|
||||
# a call for notify
|
||||
if method not in self.notify_callbacks:
|
||||
# Have nothing to do with this.
|
||||
print("Notify method not found: {method}.".format(method=method))
|
||||
else:
|
||||
self.notify_callbacks[method](params)
|
||||
@ -101,7 +106,9 @@ class LspEndpoint(threading.Thread):
|
||||
self.event_dict.pop(current_id)
|
||||
result, error = self.response_dict.pop(current_id)
|
||||
if error:
|
||||
raise lsp_structs.ResponseError(error.get("code"), error.get("message"), error.get("data"))
|
||||
raise lsp_structs.ResponseError(error.get("code"),
|
||||
error.get("message"),
|
||||
error.get("data"))
|
||||
return result
|
||||
|
||||
|
||||
|
@ -1,17 +1,22 @@
|
||||
# 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.
|
||||
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.
|
||||
'''
|
||||
if new_type == type(o):
|
||||
return o
|
||||
else:
|
||||
return new_type(**o)
|
||||
|
||||
return o if new_type == type(o) else new_type(**o)
|
||||
|
||||
|
||||
class Position(object):
|
||||
@ -20,7 +25,8 @@ class Position(object):
|
||||
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).
|
||||
:param int character: Character offset on a line in a document
|
||||
(zero-based).
|
||||
"""
|
||||
self.line = line
|
||||
self.character = character
|
||||
@ -42,6 +48,7 @@ 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.
|
||||
@ -57,6 +64,7 @@ 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.
|
||||
@ -428,7 +436,23 @@ class InsertTextFormat(object):
|
||||
class CompletionItem(object):
|
||||
"""
|
||||
"""
|
||||
def __init__(self, label, kind=None, detail=None, documentation=None, deprecated=None, presented=None, sortText=None, filterText=None, insertText=None, insertTextFormat=None, textEdit=None, additionalTextEdits=None, commitCharacters=None, command=None, data=None, score=0.0):
|
||||
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.
|
||||
@ -436,7 +460,7 @@ class CompletionItem(object):
|
||||
: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 presented: Select this item when showing. Note: that only one completion item can be selected and that the
|
||||
: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.
|
||||
@ -468,7 +492,7 @@ class CompletionItem(object):
|
||||
self.detail = detail
|
||||
self.documentation = documentation
|
||||
self.deprecated = deprecated
|
||||
self.presented = presented
|
||||
self.preselect = preselect
|
||||
self.sortText = sortText
|
||||
self.filterText = filterText
|
||||
self.insertText = insertText
|
||||
@ -511,7 +535,7 @@ class CompletionItemKind(enum.Enum):
|
||||
|
||||
class CompletionList(object):
|
||||
"""
|
||||
Represents a collection of [completion items](#CompletionItem) to be presented in the editor.
|
||||
Represents a collection of [completion items](#CompletionItem) to be preselect in the editor.
|
||||
"""
|
||||
def __init__(self, isIncomplete, items):
|
||||
"""
|
||||
|
Loading…
Reference in New Issue
Block a user