gogcli/internal/input/readline.go
2026-01-08 20:21:43 +01:00

51 lines
963 B
Go

package input
import (
"bufio"
"errors"
"fmt"
"io"
"strings"
)
// ReadLine reads a single line from r.
//
// It supports Unix (\n) and Windows (\r\n) line endings, and treats a bare \r as
// end-of-line as well.
//
// If the input ends with EOF before a newline and there is buffered content, the
// accumulated content is returned with a nil error.
//
// If EOF is encountered without any buffered content, ReadLine returns io.EOF.
func ReadLine(r io.Reader) (string, error) {
br := bufio.NewReader(r)
var sb strings.Builder
for {
b, err := br.ReadByte()
if err != nil {
if errors.Is(err, io.EOF) {
if sb.Len() > 0 {
return sb.String(), nil
}
return "", io.EOF
}
return "", fmt.Errorf("read line: %w", err)
}
if b == '\n' || b == '\r' {
if b == '\r' {
if next, _ := br.Peek(1); len(next) == 1 && next[0] == '\n' {
_, _ = br.ReadByte()
}
}
return sb.String(), nil
}
sb.WriteByte(b)
}
}