feat(cli): add option to highlight diagnostics
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ venv
|
||||
*.pyc
|
||||
uv.lock
|
||||
.python-version
|
||||
/out
|
||||
@@ -7,6 +7,7 @@ from typing import Generic, Optional, Protocol, TextIO, TypeVar
|
||||
import midas.ast.midas as m
|
||||
import midas.ast.python as p
|
||||
from midas.ast.location import Location
|
||||
from midas.checker.diagnostic import Diagnostic
|
||||
|
||||
H = TypeVar("H", bound="Highlighter", contravariant=True)
|
||||
|
||||
@@ -71,6 +72,7 @@ class Highlighter(ABC):
|
||||
openings: list[str] = self.openings.get(pos, [])
|
||||
line_buf += "".join(closings + openings)
|
||||
line_buf += char
|
||||
line_buf += "".join(self.closings.get((lineno, len(line)), []))
|
||||
line_buf += "</div></div>"
|
||||
lines.append(" " + line_buf)
|
||||
lines.extend(
|
||||
@@ -83,7 +85,7 @@ class Highlighter(ABC):
|
||||
|
||||
buf.write("\n".join(lines))
|
||||
|
||||
def wrap(self, node: Locatable, cls: str):
|
||||
def wrap(self, node: Locatable, cls: str, message: Optional[str] = None):
|
||||
if node.location is None:
|
||||
return
|
||||
if node.location.end_lineno is None or node.location.end_col_offset is None:
|
||||
@@ -95,6 +97,10 @@ class Highlighter(ABC):
|
||||
)
|
||||
opening: str = f'<span class="{cls}" title="{cls}">'
|
||||
closing: str = "</span>"
|
||||
if message is not None:
|
||||
opening = f'<span class="with-msg">{opening}'
|
||||
closing = f'{closing}<span class="message">{message}</span></span>'
|
||||
|
||||
self.openings.setdefault(start_pos, []).append(opening)
|
||||
self.closings.setdefault(end_pos, []).insert(0, closing)
|
||||
if start_pos[0] != end_pos[0]:
|
||||
@@ -260,3 +266,11 @@ class MidasHighlighter(Highlighter, m.Stmt.Visitor[None], m.Expr.Visitor[None]):
|
||||
self.wrap(expr, "type")
|
||||
if expr.template is not None:
|
||||
expr.template.accept(self)
|
||||
|
||||
|
||||
class DiagnosticsHighlighter(Highlighter):
|
||||
EXTRA_CSS_PATH: Optional[Path] = Path(__file__).parent / "hl_diagnostic.css"
|
||||
|
||||
def highlight(self, diagnostics: list[Diagnostic]):
|
||||
for diagnostic in diagnostics:
|
||||
self.wrap(diagnostic, str(diagnostic.type).lower(), diagnostic.message)
|
||||
|
||||
32
midas/cli/hl_diagnostic.css
Normal file
32
midas/cli/hl_diagnostic.css
Normal file
@@ -0,0 +1,32 @@
|
||||
span {
|
||||
&.error {
|
||||
--col: 255, 0, 0;
|
||||
}
|
||||
&.warning {
|
||||
--col: 250, 160, 0;
|
||||
}
|
||||
&.info {
|
||||
--col: 150, 190, 250;
|
||||
}
|
||||
|
||||
&.with-msg {
|
||||
position: relative;
|
||||
&:not(:hover) {
|
||||
.message {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
position: absolute;
|
||||
top: calc(100% + 0.2em);
|
||||
left: -.2em;
|
||||
background-color: black;
|
||||
color: white;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: .2em;
|
||||
z-index: 10;
|
||||
width: 300%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ from midas.ast.location import Location
|
||||
from midas.ast.printer import MidasAstPrinter, PythonAstPrinter
|
||||
from midas.checker.checker import Checker
|
||||
from midas.checker.diagnostic import Diagnostic
|
||||
from midas.cli.highlighter import Highlighter, MidasHighlighter, PythonHighlighter
|
||||
from midas.cli.highlighter import DiagnosticsHighlighter, Highlighter, MidasHighlighter, PythonHighlighter
|
||||
from midas.lexer.midas import MidasLexer
|
||||
from midas.lexer.token import Token, TokenType
|
||||
from midas.parser.midas import MidasParser
|
||||
@@ -28,8 +28,9 @@ def midas():
|
||||
|
||||
|
||||
@midas.command()
|
||||
@click.option("-l", "--highlight", type=click.File("w"))
|
||||
@click.argument("file", type=click.File("r"))
|
||||
def compile(file: TextIO):
|
||||
def compile(highlight: Optional[TextIO], file: TextIO):
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
source: str = file.read()
|
||||
tree: ast.Module = ast.parse(source, filename=file.name)
|
||||
@@ -50,6 +51,10 @@ def compile(file: TextIO):
|
||||
indent=4,
|
||||
)
|
||||
)
|
||||
if highlight is not None:
|
||||
highlighter = DiagnosticsHighlighter(source)
|
||||
highlighter.highlight(diagnostics)
|
||||
highlighter.dump(highlight)
|
||||
|
||||
|
||||
@midas.group()
|
||||
|
||||
Reference in New Issue
Block a user