diff options
Diffstat (limited to 'src/debputy/lsp/lsp_dispatch.py')
-rw-r--r-- | src/debputy/lsp/lsp_dispatch.py | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/debputy/lsp/lsp_dispatch.py b/src/debputy/lsp/lsp_dispatch.py new file mode 100644 index 0000000..41e9111 --- /dev/null +++ b/src/debputy/lsp/lsp_dispatch.py @@ -0,0 +1,131 @@ +import asyncio +from typing import Dict, Sequence, Union, Optional + +from lsprotocol.types import ( + DidOpenTextDocumentParams, + DidChangeTextDocumentParams, + TEXT_DOCUMENT_DID_CHANGE, + TEXT_DOCUMENT_DID_OPEN, + TEXT_DOCUMENT_COMPLETION, + CompletionList, + CompletionItem, + CompletionParams, + TEXT_DOCUMENT_HOVER, +) + +from debputy import __version__ +from debputy.lsp.lsp_features import ( + DIAGNOSTIC_HANDLERS, + COMPLETER_HANDLERS, + HOVER_HANDLERS, +) +from debputy.util import _info + +_DOCUMENT_VERSION_TABLE: Dict[str, int] = {} + +try: + from pygls.server import LanguageServer + + DEBPUTY_LANGUAGE_SERVER = LanguageServer("debputy", f"v{__version__}") +except ImportError: + + class Mock: + + def feature(self, *args, **kwargs): + return lambda x: x + + DEBPUTY_LANGUAGE_SERVER = Mock() + + +def is_doc_at_version(uri: str, version: int) -> bool: + dv = _DOCUMENT_VERSION_TABLE.get(uri) + return dv == version + + +@DEBPUTY_LANGUAGE_SERVER.feature(TEXT_DOCUMENT_DID_OPEN) +@DEBPUTY_LANGUAGE_SERVER.feature(TEXT_DOCUMENT_DID_CHANGE) +async def _open_or_changed_document( + ls: "LanguageServer", + params: Union[DidOpenTextDocumentParams, DidChangeTextDocumentParams], +) -> None: + version = params.text_document.version + doc_uri = params.text_document.uri + doc = ls.workspace.get_text_document(doc_uri) + + _DOCUMENT_VERSION_TABLE[doc_uri] = version + + handler = DIAGNOSTIC_HANDLERS.get(doc.language_id) + if handler is None: + _info( + f"Opened/Changed document: {doc.path} ({doc.language_id}) - no diagnostics handler" + ) + return + _info( + f"Opened/Changed document: {doc.path} ({doc.language_id}) - running diagnostics for doc version {version}" + ) + last_publish_count = -1 + + diagnostics_scanner = handler(ls, params) + async for diagnostics in diagnostics_scanner: + await asyncio.sleep(0) + if not is_doc_at_version(doc_uri, version): + # This basically happens with very edit, so lets not notify the client + # for that. + _info( + f"Cancel (obsolete) diagnostics for doc version {version}: document version changed" + ) + break + if diagnostics is None or last_publish_count != len(diagnostics): + last_publish_count = len(diagnostics) if diagnostics is not None else 0 + ls.publish_diagnostics( + doc.uri, + diagnostics, + ) + + +@DEBPUTY_LANGUAGE_SERVER.feature(TEXT_DOCUMENT_COMPLETION) +def _completions( + ls: "LanguageServer", + params: CompletionParams, +) -> Optional[Union[CompletionList, Sequence[CompletionItem]]]: + doc_uri = params.text_document.uri + doc = ls.workspace.get_text_document(doc_uri) + + handler = COMPLETER_HANDLERS.get(doc.language_id) + if handler is None: + _info( + f"Complete request for document: {doc.path} ({doc.language_id}) - no handler" + ) + return + _info( + f"Complete request for document: {doc.path} ({doc.language_id}) - delegating to handler" + ) + + return handler( + ls, + params, + ) + + +@DEBPUTY_LANGUAGE_SERVER.feature(TEXT_DOCUMENT_HOVER) +def _hover( + ls: "LanguageServer", + params: CompletionParams, +) -> Optional[Union[CompletionList, Sequence[CompletionItem]]]: + doc_uri = params.text_document.uri + doc = ls.workspace.get_text_document(doc_uri) + + handler = HOVER_HANDLERS.get(doc.language_id) + if handler is None: + _info( + f"Hover request for document: {doc.path} ({doc.language_id}) - no handler" + ) + return + _info( + f"Hover request for document: {doc.path} ({doc.language_id}) - delegating to handler" + ) + + return handler( + ls, + params, + ) |