settings/scanner.go

62 lines
1.4 KiB
Go
Raw Normal View History

2025-11-25 21:10:31 -05:00
package settings
import (
"bufio"
"fmt"
"io"
"strings"
)
var (
KeyValueDelimiterChars = []byte{':', '='}
ErrNoValidDelimiter = fmt.Errorf("no valid delimiter found (use %s)", KeyValueDelimiterCharsToString())
)
func KeyValueDelimiterCharsToString() string {
var builder strings.Builder
for i, char := range KeyValueDelimiterChars {
builder.WriteString(fmt.Sprintf("'%c'", char))
if i < len(KeyValueDelimiterChars)-1 {
builder.WriteString(" or ")
}
}
return builder.String()
}
func LineIsComment(line string) bool {
return strings.HasPrefix(line, "//") || strings.HasPrefix(line, "#")
}
type Scanner struct {
lineNumber int
scanner *bufio.Scanner
}
// returns errors without any key/value.
// does not clone the strings it extracted.
func (s *Scanner) ReadNextLine() (key, value string, err error) {
for s.scanner.Scan() {
s.lineNumber++
line := strings.TrimSpace(s.scanner.Text())
if len(line) == 0 || LineIsComment(line) {
continue
}
splitIndex := strings.IndexAny(line, string(KeyValueDelimiterChars))
if splitIndex == -1 {
return "", "", fmt.Errorf("line %d: %w", s.lineNumber, ErrNoValidDelimiter)
}
key = strings.TrimSpace(line[:splitIndex])
value = strings.TrimSpace(line[splitIndex+1:])
return
}
return "", "", io.EOF
}
func NewScanner(r io.Reader) *Scanner {
return &Scanner{
lineNumber: 0,
scanner: bufio.NewScanner(r),
}
}