source: greatly improve location reporting for multi-line source extracts

This commit is contained in:
Antoine Viallon 2023-05-08 17:29:03 +02:00
parent fc9b6b30c6
commit 820fa1760d
Signed by: aviallon
GPG key ID: D126B13AB555E16F

View file

@ -1,8 +1,11 @@
from __future__ import annotations
import math
from dataclasses import dataclass
from beartype import beartype
from beartype.typing import Optional
from dataclasses import dataclass
@beartype
@dataclass
@ -44,21 +47,35 @@ class SourceLocation:
source_lines[-1] = source_lines[-1][:self.end.character]
return "\n".join(source_lines)
def show_in_source(self) -> str:
source = self.source.splitlines(keepends=False)
source_line = source[self.begin.line]
result = [source_line]
if self.begin.line != self.end.line:
return "\n".join(result)
line = " " * self.begin.character
line += "^" + "-" * max(0, (self.end.character - self.begin.character - 1))
line += " " * (len(source_line) - len(line))
@staticmethod
def underline(string: str, begin: int, end: int) -> str:
assert begin <= end
result = [string]
line = " " * begin
line += "^" + "~" * max(0, (end - begin - 1))
line += " " * (len(string) - len(line))
result += [line]
return "\n".join(result)
def show_in_source(self) -> str:
source = self.source.splitlines(keepends=False)
line_number_maxlen = int(math.log10(len(source)) + 1)
lines = source[self.begin.line:self.end.line + 1]
result = []
begin_char = self.begin.character
while len(lines) > 0:
line = lines.pop(0)
end_char = self.end.character if len(lines) == 0 else len(line)
result += [SourceLocation.underline(line, begin_char, end_char)]
begin_char = 0
for i, source_line in enumerate(result):
line_prefix = f"Line {self.begin.line + i:0>{line_number_maxlen}}: "
lines = source_line.splitlines(keepends=False)
lines[0] = line_prefix + lines[0]
lines[1] = " " * len(line_prefix) + lines[1]
result[i] = "\n".join(lines)
return "\n".join(result)