-
Notifications
You must be signed in to change notification settings - Fork 352
/
stdin.go
90 lines (75 loc) · 1.5 KB
/
stdin.go
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
package stdin
import (
"bufio"
"fmt"
"io"
"os"
"strings"
"github.com/charmbracelet/x/ansi"
)
type options struct {
ansiStrip bool
singleLine bool
}
// Option is a read option.
type Option func(*options)
// StripANSI optionally strips ansi sequences.
func StripANSI(b bool) Option {
return func(o *options) {
o.ansiStrip = b
}
}
// SingleLine reads a single line.
func SingleLine(b bool) Option {
return func(o *options) {
o.singleLine = b
}
}
// Read reads input from an stdin pipe.
func Read(opts ...Option) (string, error) {
if IsEmpty() {
return "", fmt.Errorf("stdin is empty")
}
options := options{}
for _, opt := range opts {
opt(&options)
}
reader := bufio.NewReader(os.Stdin)
var b strings.Builder
if options.singleLine {
line, _, err := reader.ReadLine()
if err != nil {
return "", fmt.Errorf("failed to read line: %w", err)
}
_, err = b.Write(line)
if err != nil {
return "", fmt.Errorf("failed to write: %w", err)
}
}
for !options.singleLine {
r, _, err := reader.ReadRune()
if err != nil && err == io.EOF {
break
}
_, err = b.WriteRune(r)
if err != nil {
return "", fmt.Errorf("failed to write rune: %w", err)
}
}
s := strings.TrimSpace(b.String())
if options.ansiStrip {
return ansi.Strip(s), nil
}
return s, nil
}
// IsEmpty returns whether stdin is empty.
func IsEmpty() bool {
stat, err := os.Stdin.Stat()
if err != nil {
return true
}
if stat.Mode()&os.ModeNamedPipe == 0 && stat.Size() == 0 {
return true
}
return false
}