diff --git a/.gitignore b/.gitignore
index b540ed8..66f4aa9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,4 +5,5 @@ venv
.venv
*.pyc
uv.lock
-.python-version
\ No newline at end of file
+.python-version
+/out
\ No newline at end of file
diff --git a/midas/cli/highlighter.py b/midas/cli/highlighter.py
index 9b24259..b297404 100644
--- a/midas/cli/highlighter.py
+++ b/midas/cli/highlighter.py
@@ -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 += ""
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''
closing: str = ""
+ if message is not None:
+ opening = f'{opening}'
+ closing = f'{closing}{message}'
+
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)
diff --git a/midas/cli/hl_diagnostic.css b/midas/cli/hl_diagnostic.css
new file mode 100644
index 0000000..f79bab5
--- /dev/null
+++ b/midas/cli/hl_diagnostic.css
@@ -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%;
+ }
+ }
+}
\ No newline at end of file
diff --git a/midas/cli/main.py b/midas/cli/main.py
index 9119a07..220cca9 100644
--- a/midas/cli/main.py
+++ b/midas/cli/main.py
@@ -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()