Last active
May 16, 2023 17:03
-
-
Save assyrianic/33a857f59c1cc3d1762c35f1360fe540 to your computer and use it in GitHub Desktop.
Recreates Rust's Compiler Error reporting style in Golang.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// colorful strings for printing. | |
const ( | |
COLOR_RED = "\x1B[31m" // used for errors. | |
COLOR_GREEN = "\x1B[32m" | |
COLOR_YELLOW = "\x1B[33m" | |
COLOR_BLUE = "\x1B[34m" | |
COLOR_MAGENTA = "\x1B[35m" // used for warnings. | |
COLOR_CYAN = "\x1B[36m" | |
COLOR_WHITE = "\x1B[37m" | |
COLOR_RESET = "\033[0m" // used to reset the color. | |
) | |
/* Example: | |
* {error | warning} [{ErrCode}]: {Msg} | |
* --> {file, line, col} | |
* Line1 | Code1 | |
* Span1 | ^^^^^ note1 | |
* Line2 | Code2 | |
* Span1 | ----- note2 | |
* ... | |
* LineN | CodeN | |
* SpanN | ~~~~~ noteN | |
*/ | |
type MsgSpan struct { | |
note_line, note_col []uint32 | |
notes, snippets []string | |
code *[]string | |
} | |
func (m *MsgSpan) AddNote(line, col uint32, snippet, note_fmt string, args ...any) { | |
m.note_line = append(m.note_line, line) | |
m.note_col = append(m.note_col, col) | |
m.snippets = append(m.snippets, snippet) | |
m.notes = append(m.notes, fmt.Sprintf(note_fmt, args...)) | |
} | |
func (m *MsgSpan) Report(msgtype, errcode, color, msg_fmt, filename string, line, col *uint32, args ...any) string { | |
var sb strings.Builder | |
sb.WriteString(color) | |
sb.WriteString(msgtype) | |
if errcode != "" { | |
sb.WriteRune('[') | |
sb.WriteString(errcode) | |
sb.WriteRune(']') | |
} | |
sb.WriteString(COLOR_RESET) | |
sb.WriteString(": " + fmt.Sprintf(msg_fmt, args...)) | |
if filename != "" { | |
sb.WriteRune('\n') | |
sb.WriteString("--> ") | |
sb.WriteString(filename) | |
if line != nil { | |
sb.WriteString(fmt.Sprintf(":%d", *line)) | |
} | |
if col != nil { | |
sb.WriteString(fmt.Sprintf(":%d", *col)) | |
} | |
} | |
if len(m.note_line) > 0 { | |
sb.WriteRune('\n') | |
largest := 0 | |
for _, l := range m.note_line { | |
if largest < int(l) { | |
largest = int(l) | |
} | |
} | |
big_line_str := fmt.Sprintf("%d", largest) | |
largest_span := len(big_line_str) + 1 | |
span_write := func (sb *strings.Builder, span int, c rune) { | |
for i := 0; i < span; i++ { | |
sb.WriteRune(c) | |
} | |
} | |
span_write(&sb, largest_span, ' ') | |
sb.WriteRune('|') | |
sb.WriteRune('\n') | |
for i := range m.note_line { | |
line := m.note_line[i] | |
line_num_str := fmt.Sprintf("%d", line) | |
sb.WriteString(line_num_str) | |
span_write(&sb, largest_span - len(line_num_str), ' ') | |
sb.WriteRune('|') | |
note_col := m.note_col[i] | |
snippet := m.snippets[i] | |
snippet_len := len(snippet) | |
note := m.notes[i] | |
code_line := (*m.code)[line] | |
sb.WriteString(code_line) | |
sb.WriteRune('\n') | |
span_write(&sb, largest_span, ' ') | |
sb.WriteRune('|') | |
span_write(&sb, int(note_col), ' ') | |
span_write(&sb, snippet_len, '^') | |
sb.WriteRune(' ') | |
sb.WriteString(COLOR_CYAN); | |
sb.WriteString(note); | |
sb.WriteString(COLOR_RESET) | |
} | |
} | |
return sb.String() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Was able to reduce it into one single function.