feat(cli): improve diagnostic printing
This commit is contained in:
@@ -19,7 +19,8 @@ class Diagnostic:
|
|||||||
type: DiagnosticType
|
type: DiagnosticType
|
||||||
message: str
|
message: str
|
||||||
|
|
||||||
def __str__(self) -> str:
|
@property
|
||||||
|
def location_str(self) -> str:
|
||||||
start_loc: str = f"L{self.location.lineno}:{self.location.col_offset+1}"
|
start_loc: str = f"L{self.location.lineno}:{self.location.col_offset+1}"
|
||||||
end_loc: Optional[str] = ""
|
end_loc: Optional[str] = ""
|
||||||
if (
|
if (
|
||||||
@@ -30,4 +31,7 @@ class Diagnostic:
|
|||||||
loc: str = (
|
loc: str = (
|
||||||
f"at {start_loc}" if end_loc is None else f"from {start_loc} to {end_loc}"
|
f"at {start_loc}" if end_loc is None else f"from {start_loc} to {end_loc}"
|
||||||
)
|
)
|
||||||
return f"{self.type} in {self.file_path} {loc}: {self.message}"
|
return f"{self.type} in {self.file_path} {loc}"
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"{self.location_str}: {self.message}"
|
||||||
|
|||||||
41
midas/cli/ansi.py
Normal file
41
midas/cli/ansi.py
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
class Ansi:
|
||||||
|
CTRL = "\x1b["
|
||||||
|
RESET = CTRL + "0m"
|
||||||
|
BOLD = CTRL + "1m"
|
||||||
|
DIM = CTRL + "2m"
|
||||||
|
ITALIC = CTRL + "3m"
|
||||||
|
UNDERLINE = CTRL + "4m"
|
||||||
|
|
||||||
|
BLACK = 0
|
||||||
|
RED = 1
|
||||||
|
GREEN = 2
|
||||||
|
YELLOW = 3
|
||||||
|
BLUE = 4
|
||||||
|
MAGENTA = 5
|
||||||
|
CYAN = 6
|
||||||
|
WHITE = 7
|
||||||
|
|
||||||
|
BRIGHT_BLACK = 60
|
||||||
|
BRIGHT_RED = 61
|
||||||
|
BRIGHT_GREEN = 62
|
||||||
|
BRIGHT_YELLOW = 63
|
||||||
|
BRIGHT_BLUE = 64
|
||||||
|
BRIGHT_MAGENTA = 65
|
||||||
|
BRIGHT_CYAN = 66
|
||||||
|
BRIGHT_WHITE = 67
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def FG(cls, col: int) -> str:
|
||||||
|
return f"{cls.CTRL}{30 + col}m"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def BG(cls, col: int) -> str:
|
||||||
|
return f"{cls.CTRL}{40 + col}m"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def FG_RGB(cls, r: int, g: int, b: int) -> str:
|
||||||
|
return f"{cls.CTRL}38;2;{r};{g};{b}m"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def BG_RGB(cls, r: int, g: int, b: int) -> str:
|
||||||
|
return f"{cls.CTRL}48;2;{r};{g};{b}m"
|
||||||
@@ -8,10 +8,12 @@ import click
|
|||||||
|
|
||||||
import midas.ast.midas as m
|
import midas.ast.midas as m
|
||||||
import midas.ast.python as p
|
import midas.ast.python as p
|
||||||
|
from midas.ast.location import Location
|
||||||
from midas.ast.printer import MidasAstPrinter, MidasPrinter, PythonAstPrinter
|
from midas.ast.printer import MidasAstPrinter, MidasPrinter, PythonAstPrinter
|
||||||
from midas.checker.checker import Checker
|
from midas.checker.checker import Checker
|
||||||
from midas.checker.diagnostic import Diagnostic
|
from midas.checker.diagnostic import Diagnostic, DiagnosticType
|
||||||
from midas.checker.types import Type
|
from midas.checker.types import Type
|
||||||
|
from midas.cli.ansi import Ansi
|
||||||
from midas.cli.highlighter import (
|
from midas.cli.highlighter import (
|
||||||
DiagnosticsHighlighter,
|
DiagnosticsHighlighter,
|
||||||
Highlighter,
|
Highlighter,
|
||||||
@@ -32,6 +34,57 @@ def midas():
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def print_diagnostic(lines: list[str], diagnostic: Diagnostic, indent: int = 4):
|
||||||
|
"""Pretty-print a diagnostic, showing some context if possible
|
||||||
|
|
||||||
|
If the diagnostic concerns a specific part of one line, the line is shown
|
||||||
|
with the affected part highlighted. The message is clearly printed under the
|
||||||
|
line with an underline further indicating the target expression.
|
||||||
|
|
||||||
|
If multiple lines are concerned, no context is shown, only the
|
||||||
|
diagnostic type, location and message
|
||||||
|
|
||||||
|
Args:
|
||||||
|
lines (list[str]): source code lines
|
||||||
|
diagnostic (Diagnostic): the diagnostic to print
|
||||||
|
indent (int, optional): the number of spaces added before the target line to indent if from the location header. Defaults to 4.
|
||||||
|
"""
|
||||||
|
|
||||||
|
loc: Location = diagnostic.location
|
||||||
|
if loc.lineno != loc.end_lineno:
|
||||||
|
print(diagnostic)
|
||||||
|
return
|
||||||
|
|
||||||
|
start_offset: int = loc.col_offset
|
||||||
|
end_offset: int = loc.end_col_offset or (start_offset + 1)
|
||||||
|
|
||||||
|
line: str = lines[loc.lineno - 1]
|
||||||
|
before: str = line[:start_offset]
|
||||||
|
after: str = line[end_offset:]
|
||||||
|
|
||||||
|
color: int = {
|
||||||
|
DiagnosticType.ERROR: Ansi.RED,
|
||||||
|
DiagnosticType.WARNING: Ansi.YELLOW,
|
||||||
|
DiagnosticType.INFO: Ansi.CYAN,
|
||||||
|
}.get(diagnostic.type, Ansi.WHITE)
|
||||||
|
|
||||||
|
subject: str = Ansi.FG(color) + line[start_offset:end_offset] + Ansi.RESET
|
||||||
|
cursor: str = (
|
||||||
|
" " * start_offset
|
||||||
|
+ Ansi.FG(color)
|
||||||
|
+ "~" * (end_offset - start_offset)
|
||||||
|
+ "> "
|
||||||
|
+ diagnostic.message
|
||||||
|
+ Ansi.RESET
|
||||||
|
)
|
||||||
|
|
||||||
|
indent_str: str = " " * indent
|
||||||
|
print(diagnostic.location_str + ":")
|
||||||
|
print(indent_str + before + subject + after)
|
||||||
|
print(indent_str + cursor)
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
@midas.command()
|
@midas.command()
|
||||||
@click.option("-l", "--highlight", type=click.File("w"))
|
@click.option("-l", "--highlight", type=click.File("w"))
|
||||||
@click.option("-t", "--types", type=click.File("r"), multiple=True)
|
@click.option("-t", "--types", type=click.File("r"), multiple=True)
|
||||||
@@ -57,8 +110,9 @@ def compile(
|
|||||||
types_paths=types_paths,
|
types_paths=types_paths,
|
||||||
)
|
)
|
||||||
diagnostics: list[Diagnostic] = checker.check(stmts)
|
diagnostics: list[Diagnostic] = checker.check(stmts)
|
||||||
|
lines: list[str] = source.split("\n")
|
||||||
for diagnostic in diagnostics:
|
for diagnostic in diagnostics:
|
||||||
print(diagnostic)
|
print_diagnostic(lines, diagnostic)
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
print(
|
print(
|
||||||
|
|||||||
Reference in New Issue
Block a user