summaryrefslogtreecommitdiffstats
path: root/src/debputy/lsp/lsp_dispatch.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/debputy/lsp/lsp_dispatch.py')
-rw-r--r--src/debputy/lsp/lsp_dispatch.py131
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,
+ )