gitstack

grindlemire/go-tui code browser

3.4 KB Go 129 lines 2026-03-14 · 9a7d97c raw
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package tuigen

import (
	"fmt"
	"strings"
)

// Error represents a compilation error with source location and optional hint.
type Error struct {
	Pos     Position
	EndPos  Position // optional end position for range-based highlighting
	Message string
	Hint    string // optional suggestion for fixing the error
}

// Error implements the error interface.
func (e *Error) Error() string {
	var sb strings.Builder
	sb.WriteString(e.Pos.String())
	sb.WriteString(": error: ")
	sb.WriteString(e.Message)
	if e.Hint != "" {
		sb.WriteString(" (")
		sb.WriteString(e.Hint)
		sb.WriteString(")")
	}
	return sb.String()
}

// NewError creates a new Error with the given position and message.
func NewError(pos Position, message string) *Error {
	return &Error{Pos: pos, Message: message}
}

// NewErrorf creates a new Error with a formatted message.
func NewErrorf(pos Position, format string, args ...any) *Error {
	return &Error{Pos: pos, Message: fmt.Sprintf(format, args...)}
}

// NewErrorWithHint creates a new Error with a hint for fixing the error.
func NewErrorWithHint(pos Position, message, hint string) *Error {
	return &Error{Pos: pos, Message: message, Hint: hint}
}

// NewErrorWithRange creates a new Error with start and end positions for range highlighting.
func NewErrorWithRange(pos, endPos Position, message string) *Error {
	return &Error{Pos: pos, EndPos: endPos, Message: message}
}

// NewErrorWithRangeAndHint creates a new Error with range and hint.
func NewErrorWithRangeAndHint(pos, endPos Position, message, hint string) *Error {
	return &Error{Pos: pos, EndPos: endPos, Message: message, Hint: hint}
}

// ErrorList collects multiple errors during compilation.
type ErrorList struct {
	errors []*Error
}

// NewErrorList creates an empty error list.
func NewErrorList() *ErrorList {
	return &ErrorList{}
}

// Add appends an error to the list.
func (el *ErrorList) Add(err *Error) {
	el.errors = append(el.errors, err)
}

// AddError creates and adds an error with the given position and message.
func (el *ErrorList) AddError(pos Position, message string) {
	el.errors = append(el.errors, NewError(pos, message))
}

// AddErrorf creates and adds an error with a formatted message.
func (el *ErrorList) AddErrorf(pos Position, format string, args ...any) {
	el.errors = append(el.errors, NewErrorf(pos, format, args...))
}

// Len returns the number of errors.
func (el *ErrorList) Len() int {
	return len(el.errors)
}

// Truncate removes all errors after position n, restoring the list to a prior length.
func (el *ErrorList) Truncate(n int) {
	if n < len(el.errors) {
		el.errors = el.errors[:n]
	}
}

// HasErrors returns true if there are any errors.
func (el *ErrorList) HasErrors() bool {
	return len(el.errors) > 0
}

// Errors returns a copy of the error slice.
func (el *ErrorList) Errors() []*Error {
	result := make([]*Error, len(el.errors))
	copy(result, el.errors)
	return result
}

// Error implements the error interface, returning all errors joined by newlines.
func (el *ErrorList) Error() string {
	if len(el.errors) == 0 {
		return ""
	}
	if len(el.errors) == 1 {
		return el.errors[0].Error()
	}

	var sb strings.Builder
	for i, err := range el.errors {
		if i > 0 {
			sb.WriteByte('\n')
		}
		sb.WriteString(err.Error())
	}
	return sb.String()
}

// Err returns nil if there are no errors, otherwise returns the ErrorList as an error.
func (el *ErrorList) Err() error {
	if len(el.errors) == 0 {
		return nil
	}
	return el
}