aboutsummaryrefslogtreecommitdiff
path: root/nomnom/pretty_errors.nom
blob: db4be5a770e001ad118e18f8620bfe7ef353eeb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#!/usr/bin/env nomsu -V4.8.10
# This file has code for converting errors to user-friendly format, with colors,
    line numbers, code excerpts, and so on.
(visible size of %text) means:
    return (size of (%text::with "\027%[[0-9;]*m" -> ""))

(%text boxed) means:
    %max_line = (max of ((visible size of %line) for %line in (%text::lines)))
    %ret = (..)
        "\n\%text"::with "\n([^\n]*)" -> (..)
            [%] -> (..)
                "\n\%\(" "::* (%max_line - (visible size of %))) \027[0m"
    return %ret.[2,-1]

%CONTEXT = 2
externally (pretty %title error at %tree %err hint %hint) means:
    %source_code = (%tree::get source code)
    %start = %tree.source.start
    %stop = %tree.source.stop
    %filename = (%tree.source.filename or "???")
    %err_line = (%source_code::line at %start)
    %err_linenum = (%source_code::line number at %start)
    %err_linepos = (%source_code::line position at %start)
    
    # TODO: better handle multi-line errors
    %err_size = (min of [%stop - %start, (size of %err_line) - %err_linepos + 1])
    %nl_indicator = (" " if (%err_linepos > (size of %err_line)) else "")
    %fmt_str = " %\(size of "\(%err_linenum + %CONTEXT)")d|"
    (num %i) means (%fmt_str::formatted with %i)
    %linenum_size = (size of (num 0))
    %pointer = "\(" "::* (%err_linepos + %linenum_size - 1))"
    if (%err_size >= 2):
        %pointer += "╚\("═"::* (%err_size - 2))╝"
    ..else: %pointer += "⬆"
    
    %err_msg = "\
        ..\027[33;41;1m\(%title or "Error") at \%filename:\%err_linenum\027[0m"
    for %i in (%err_linenum - %CONTEXT) to (%err_linenum - 1):
        %line = (%source_code::line %i)
        if %line:
            %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m"
    
    if %err_line:
        %before = %err_line.[1, %err_linepos - 1]
        %during = %err_line.[%err_linepos, %err_linepos + %err_size - 1]
        %after = %err_line.[%err_linepos + %err_size, -1]
        %err_line = "\027[0m\(%before)\027[41;30m\%during\(%nl_indicator)\027[0m\%after"
        %err_msg += "\n\027[2m\(num %err_linenum)\(%err_line)\027[0m"
    
    %err_linenum_end = (%source_code::line number at %stop)
    %err_linepos_end = (%source_code::line position at %stop)
    %err_linenum_end or= %err_linenum
    if (%err_linenum_end == %err_linenum):
        %err_msg += "\n\%pointer"
    ..else:
        for %i in (%err_linenum + 1) to %err_linenum_end:
            %line = (%source_code::line %i)
            if %line:
                if (%i == %err_linenum_end):
                    %during = %line.[1, %err_linepos_end - 1]
                    %after = %line.[%err_linepos_end, -1]
                    %err_msg += "\n\027[2m\(num %i)\027[0;41;30m\(%during)\027[0m\%after"
                ..else:
                    %err_msg += "\n\027[2m\(num %i)\027[0;41;30m\(%line)\027[0m"
    
    %box_width = 70
    %err_text = "\
        ..\027[47;31;1m\((" \%err"::wrapped to %box_width)::with "\n" -> "\n\027[47;31;1m ")"
    if %hint:
        %err_text += "\n\027[47;30m\((" Suggestion: \(%hint)"::wrapped to %box_width)::with "\n" -> "\n\027[47;30m ")"
    %err_msg += "\n\027[33;1m \((%err_text boxed)::with "\n" -> "\n ")"
    
    %err_msg += "\n\027[33;1m \((%err_text boxed)::with "\n" -> "\n ")"
    for %i in (%err_linenum_end + 1) to (%err_linenum_end + %CONTEXT):
        %line = (%source_code::line %i)
        if %line:
            %err_msg += "\n\027[2m\(num %i)\027[0m\(%line)\027[0m"
    
    return %err_msg

externally (pretty %title error at %tree %err) means (..)
    pretty %title error at %tree %err (nil)

externally (%err_tree as a pretty error) means (..)
    pretty %err_tree.title error at %err_tree %err_tree.error hint %err_tree.hint