diff options
Diffstat (limited to 'src/debputy/lsp/lsp_debian_debputy_manifest.py')
-rw-r--r-- | src/debputy/lsp/lsp_debian_debputy_manifest.py | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/src/debputy/lsp/lsp_debian_debputy_manifest.py b/src/debputy/lsp/lsp_debian_debputy_manifest.py new file mode 100644 index 0000000..2f9920e --- /dev/null +++ b/src/debputy/lsp/lsp_debian_debputy_manifest.py @@ -0,0 +1,111 @@ +import re +from typing import ( + Optional, + List, +) + +from lsprotocol.types import ( + Diagnostic, + TEXT_DOCUMENT_WILL_SAVE_WAIT_UNTIL, + Position, + Range, + DiagnosticSeverity, +) +from ruamel.yaml.error import MarkedYAMLError, YAMLError + +from debputy.highlevel_manifest import MANIFEST_YAML +from debputy.lsp.lsp_features import ( + lint_diagnostics, + lsp_standard_handler, +) +from debputy.lsp.text_util import ( + LintCapablePositionCodec, +) + +try: + from pygls.server import LanguageServer +except ImportError: + pass + + +_CONTAINS_TAB_OR_COLON = re.compile(r"[\t:]") +_WORDS_RE = re.compile("([a-zA-Z0-9_-]+)") +_MAKE_ERROR_RE = re.compile(r"^[^:]+:(\d+):\s*(\S.+)") + + +_LANGUAGE_IDS = [ + "debian/debputy.manifest", + "debputy.manifest", + # LSP's official language ID for YAML files + "yaml", +] + + +# lsp_standard_handler(_LANGUAGE_IDS, TEXT_DOCUMENT_CODE_ACTION) +lsp_standard_handler(_LANGUAGE_IDS, TEXT_DOCUMENT_WILL_SAVE_WAIT_UNTIL) + + +def _word_range_at_position( + lines: List[str], + line_no: int, + char_offset: int, +) -> Range: + line = lines[line_no] + line_len = len(line) + start_idx = char_offset + end_idx = char_offset + while end_idx + 1 < line_len and not line[end_idx + 1].isspace(): + end_idx += 1 + + while start_idx - 1 >= 0 and not line[start_idx - 1].isspace(): + start_idx -= 1 + + return Range( + Position(line_no, start_idx), + Position(line_no, end_idx), + ) + + +@lint_diagnostics(_LANGUAGE_IDS) +def _lint_debian_debputy_manifest( + _doc_reference: str, + _path: str, + lines: List[str], + position_codec: LintCapablePositionCodec, +) -> Optional[List[Diagnostic]]: + diagnostics = [] + try: + MANIFEST_YAML.load("".join(lines)) + except MarkedYAMLError as e: + error_range = position_codec.range_to_client_units( + lines, + _word_range_at_position( + lines, + e.problem_mark.line, + e.problem_mark.column, + ), + ) + diagnostics.append( + Diagnostic( + error_range, + f"YAML parse error: {e}", + DiagnosticSeverity.Error, + ), + ) + except YAMLError as e: + error_range = position_codec.range_to_client_units( + lines, + Range( + Position(0, 0), + Position(0, len(lines[0])), + ), + ) + diagnostics.append( + Diagnostic( + error_range, + f"Unknown YAML parse error: {e} [{e!r}]", + DiagnosticSeverity.Error, + ), + ) + + return diagnostics |