Skip to content

Instantly share code, notes, and snippets.

@assyrianic
Last active May 16, 2023 17:03
Show Gist options
  • Save assyrianic/33a857f59c1cc3d1762c35f1360fe540 to your computer and use it in GitHub Desktop.
Save assyrianic/33a857f59c1cc3d1762c35f1360fe540 to your computer and use it in GitHub Desktop.
Recreates Rust's Compiler Error reporting style in Golang.
// 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()
}
@assyrianic
Copy link
Author

Was able to reduce it into one single function.

func MsgReport(code []string, msgtype, errcode, color, msg_fmt, snippet, note, 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...))
	sb.WriteRune('|')
	if filename != "" {
		sb.WriteRune('\n')
		sb.WriteString("--> ")
		sb.WriteString(filename)
		if line > 0 {
			sb.WriteString(fmt.Sprintf(":%d", line))
			sb.WriteString(fmt.Sprintf(":%d", col))
		}
	}
	
	if len(note) > 0 {
		sb.WriteRune('\n')
		big_line_str := fmt.Sprintf("%d", line)
		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')
		line_num_str := fmt.Sprintf("%d", line)
		sb.WriteString(line_num_str)
		span_write(&sb, largest_span - len(line_num_str), ' ')
		sb.WriteRune('|')
		snippet_len := len(snippet)
		code_line := code[line - 1]
		sb.WriteString(code_line)
		sb.WriteRune('\n')
		span_write(&sb, largest_span, ' ')
		sb.WriteRune('|')
		span_write(&sb, int(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