forked from krisnova/lolgopher
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwriter.go
134 lines (120 loc) · 2.83 KB
/
writer.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
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
130
131
132
133
134
package lol
import (
"fmt"
"io"
"os"
"strings"
isatty "github.com/mattn/go-isatty"
)
const (
DEFAULT_SPREAD = float64(3.0)
DEFAULT_FREQ = float64(0.1)
DEFAULT_ORIGIN = 0
)
const (
ColorModeTrueColor = iota
ColorMode256
ColorMode0
)
// LolWriter writes a little lol-er.
type Writer struct {
Output io.Writer
ColorMode int
Freq float64
Spread float64
lineIdx int
Origin int
}
var noColor = os.Getenv("TERM") == "dumb" || (!isatty.IsTerminal(os.Stdout.Fd()) && !isatty.IsCygwinTerminal(os.Stdout.Fd()))
// writeRaw will write a lol'd s to the underlying writer. It does no line
// detection.
func (w *Writer) writeRaw(s string) (int, error) {
c, err := w.getColorer()
if err != nil {
return -1, err
}
nWritten := 0
for _, r := range s {
c.rainbow(w.Freq, float64(w.Origin)+float64(w.lineIdx)/w.Spread)
_, err := w.Output.Write(c.format())
if err != nil {
return nWritten, err
}
n, err := w.Output.Write([]byte(string(r)))
if err != nil {
return nWritten, err
}
_, err = w.Output.Write(c.reset())
if err != nil {
return nWritten, err
}
nWritten += n
w.lineIdx++
}
return nWritten, nil
}
// getColorer will attempt to map the defined color mode, to a colorer{}
func (w *Writer) getColorer() (colorer, error) {
switch w.ColorMode {
case ColorModeTrueColor:
return newTruecolorColorer(), nil
case ColorMode256:
return New256Colorer(), nil
case ColorMode0:
return New0Colorer(), nil
default:
return nil, fmt.Errorf("Invalid colorer: [%d]", w.ColorMode)
}
}
// Write will write a byte slice to the Writer
func (w *Writer) Write(p []byte) (int, error) {
nWritten := 0
ss := strings.Split(string(p), "\n")
for i, s := range ss {
// TODO: strip out pre-existing ANSI codes and expand tabs. Would be
// great to expand tabs in a context aware way (line linux expand
// command).
n, err := w.writeRaw(s)
if err != nil {
return nWritten, err
}
nWritten += n
// Increment the Origin (line count) for each newline. There is a
// newline for every item in this array except the last one.
if i != len(ss)-1 {
n, err := w.Output.Write([]byte("\n"))
if err != nil {
return nWritten, err
}
nWritten += n
w.Origin++
w.lineIdx = 0
}
}
return nWritten, nil
}
// NewLolWriter will return a new io.Writer with a default ColorMode of 256
func NewLolWriter() io.Writer {
colorMode := ColorMode256
if noColor {
colorMode = ColorMode0
}
return &Writer{
Output: stdout,
ColorMode: colorMode,
Freq: DEFAULT_FREQ,
Spread: DEFAULT_SPREAD,
Origin: DEFAULT_ORIGIN,
}
}
// NewTruecolorLolWriter will return a new io.Writer with a default ColorMode of truecolor
func NewTruecolorLolWriter() io.Writer {
colorMode := ColorModeTrueColor
if noColor {
colorMode = ColorMode0
}
return &Writer{
Output: stdout,
ColorMode: colorMode,
}
}