diff --git a/examples/example.il b/examples/example.il index 6fb57eb..c76df28 100644 --- a/examples/example.il +++ b/examples/example.il @@ -5,11 +5,11 @@ example2 = example ( (let (some vars (default 0)) ; ... some wall of text - "))" - + "))\"" wqdqwf = '(doqwf) var = 1.3 var = 231 qqvwv + cfunc() ) ) diff --git a/skillls/main.py b/skillls/main.py index c98c77e..d7cc287 100644 --- a/skillls/main.py +++ b/skillls/main.py @@ -1,17 +1,34 @@ +from collections.abc import Generator from logging import INFO, basicConfig, getLogger +from re import fullmatch +import re from time import time from lsprotocol.types import ( + TEXT_DOCUMENT_DID_CHANGE, TEXT_DOCUMENT_DID_OPEN, TEXT_DOCUMENT_DID_SAVE, TEXT_DOCUMENT_DOCUMENT_SYMBOL, + TEXT_DOCUMENT_HOVER, + TEXT_DOCUMENT_INLAY_HINT, CompletionItem, + Diagnostic, + DiagnosticSeverity, + DidChangeTextDocumentParams, DidOpenTextDocumentParams, DidSaveTextDocumentParams, DocumentSymbol, DocumentSymbolParams, + Hover, + HoverParams, + InlayHint, + InlayHintParams, + MessageType, + Position, + Range, ) from pygls.server import LanguageServer +from pygls.workspace import TextDocument from skillls.parsing.iterative import IterativeParser, TokenParser @@ -24,35 +41,97 @@ basicConfig(filename="skillls.log", level=INFO) cache: Cache[str, CompletionItem] = Cache() logger = getLogger(__name__) -server = LanguageServer("skillls", "v0.1") -@server.feature(TEXT_DOCUMENT_DOCUMENT_SYMBOL) -def on_hover(params: DocumentSymbolParams) -> list[DocumentSymbol]: - server.workspace.remove_text_document(params.text_document.uri) - doc = server.workspace.get_text_document(params.text_document.uri) - t = TokenParser() - t.prepare_content(doc.source) +class SkillLanguageServer(LanguageServer): + def _diagnose_parens(self, doc: TextDocument) -> Generator[Diagnostic, None, None]: + open: list[tuple[int, int]] = [] + in_str: bool = False + last = "" + for row, line in enumerate(doc.lines): + for col, char in enumerate(line): + match char: + case "(": + if not in_str: + open.append((row, col)) + case ")": + if not in_str: + if len(open) > 0: + open.pop() + else: + yield ( + Diagnostic( + Range( + Position(row, col), + Position(row, col), + ), + "unopened ) encountered", + ) + ) + case '"': + if not (in_str and last == "\\"): + in_str = not in_str + case _: + last = char - return t._token_tree + last = char + + if len(open) > 0: + for row, col in open: + yield ( + Diagnostic( + Range(Position(row, col), Position(row, col)), + "unclosed ) encountered", + ) + ) + + def _diagnose_cisms(self, doc: TextDocument) -> Generator[Diagnostic, None, None]: + for row, line in enumerate(doc.lines): + for col, char in enumerate(line): + if col > 0: + if fullmatch("\\w", line[col - 1]) and char == "(": + if m := re.match(r"\W+(\w+)$", line[:col]): + tok = m.group(1) + else: + tok = line[col - 1] + yield Diagnostic( + Range( + Position(row, col - len(tok)), + Position(row, col + 1), + ), + f"c-ism detected: change to `( {tok}`", + DiagnosticSeverity.Warning, + ) + + def diagnose(self, doc: TextDocument) -> None: + diags: list[Diagnostic] = [] + + diags.extend(self._diagnose_parens(doc)) + diags.extend(self._diagnose_cisms(doc)) + + self.publish_diagnostics(doc.uri, diags) + + +server = SkillLanguageServer("skillls", "v0.2") @server.feature(TEXT_DOCUMENT_DID_OPEN) -def on_open(params: DidOpenTextDocumentParams) -> None: +def on_open(ls: SkillLanguageServer, params: DidOpenTextDocumentParams) -> None: doc = server.workspace.get_text_document(params.text_document.uri) - p = IterativeParser() - diags = p(doc.lines) - server.publish_diagnostics(params.text_document.uri, diags, version=int(time())) + ls.diagnose(doc) -@server.feature(TEXT_DOCUMENT_DID_SAVE) -def on_save(params: DidSaveTextDocumentParams) -> None: - server.workspace.remove_text_document(params.text_document.uri) +@server.feature(TEXT_DOCUMENT_DID_CHANGE) +def on_save(ls: SkillLanguageServer, params: DidChangeTextDocumentParams) -> None: doc = server.workspace.get_text_document(params.text_document.uri) - p = IterativeParser() - diags = p(doc.lines) - logger.warning(doc.source) - server.publish_diagnostics(params.text_document.uri, diags, version=int(time())) + ls.diagnose(doc) + + +@server.feature(TEXT_DOCUMENT_INLAY_HINT) +def inlay_hints(ls: SkillLanguageServer, params: InlayHintParams) -> list[InlayHint]: + hints: list[InlayHint] = [] + + return hints def main():