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