Skip to content

Commit fb3c73e

Browse files
committed
Introduce reader based box
Add function `Box` that writes to a writer and reads from a reader instead of reading directly from a string. This enables a use case where the content is coming in piece by piece and the code can already start to print the box.
1 parent 3032b7c commit fb3c73e

File tree

2 files changed

+70
-25
lines changed

2 files changed

+70
-25
lines changed

box.go

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"bufio"
2525
"bytes"
2626
"fmt"
27+
"io"
2728
"strings"
2829

2930
"github.com/gonvenience/bunt"
@@ -60,59 +61,65 @@ func ContentColor(color colorful.Color) BoxStyle {
6061
}
6162
}
6263

63-
type buntBuffer struct {
64-
buf bytes.Buffer
65-
}
66-
67-
func (b *buntBuffer) Write(format string, a ...interface{}) {
68-
b.buf.WriteString(fmt.Sprintf(format, a...))
69-
}
70-
71-
func (b *buntBuffer) String() string {
72-
return b.buf.String()
73-
}
74-
7564
// ContentBox creates a string for the terminal where content is printed inside
7665
// a simple box shape.
7766
func ContentBox(headline string, content string, opts ...BoxStyle) string {
67+
var buf bytes.Buffer
68+
Box(&buf, headline, strings.NewReader(content), opts...)
69+
70+
return buf.String()
71+
}
72+
73+
// Box writes the provided content in a simple box shape to given writer
74+
func Box(out io.Writer, headline string, content io.Reader, opts ...BoxStyle) {
7875
var (
79-
beginning = "╭"
80-
prefix = "│"
81-
lastline = "╵"
76+
beginning = "╭"
77+
prefix = "│"
78+
lastline = "╵"
79+
linewritten = false
80+
outprint = func(format string, a ...interface{}) {
81+
out.Write([]byte(fmt.Sprintf(format, a...)))
82+
}
8283
)
8384

85+
// Process all provided box style options
8486
options := &boxOptions{}
8587
for _, f := range opts {
8688
f(options)
8789
}
8890

91+
// Apply headline color if it is set
8992
if options.headlineColor != nil {
9093
for _, pointer := range []*string{&beginning, &headline, &prefix, &lastline} {
91-
*pointer = bunt.Style(
92-
*pointer,
94+
*pointer = bunt.Style(*pointer,
9395
bunt.Foreground(*options.headlineColor),
9496
)
9597
}
9698
}
9799

100+
// Apply headline styles if they are set
98101
for _, style := range options.headlineStyles {
99102
headline = bunt.Style(headline, style)
100103
}
101104

102-
var buf buntBuffer
103-
buf.Write("%s %s\n", beginning, headline)
104-
105-
scanner := bufio.NewScanner(strings.NewReader(content))
105+
// Process each line of the content and apply styles if necessary
106+
scanner := bufio.NewScanner(content)
106107
for scanner.Scan() {
107108
text := scanner.Text()
108109
if options.contentColor != nil {
109110
text = bunt.Style(text, bunt.Foreground(*options.contentColor))
110111
}
111112

112-
buf.Write("%s %s\n", prefix, text)
113-
}
113+
if !linewritten {
114+
// Write the headline string including the corner item
115+
outprint("%s %s\n", beginning, headline)
116+
}
114117

115-
buf.Write("%s\n", lastline)
118+
outprint("%s %s\n", prefix, text)
119+
linewritten = true
120+
}
116121

117-
return buf.String()
122+
if linewritten {
123+
outprint("%s\n", lastline)
124+
}
118125
}

box_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
package neat_test
2222

2323
import (
24+
"bytes"
25+
"io"
26+
2427
. "github.com/onsi/ginkgo"
2528
. "github.com/onsi/gomega"
2629

@@ -168,4 +171,39 @@ DimGray{╵}
168171
`)))
169172
})
170173
})
174+
175+
Context("using reader directly", func() {
176+
It("should create a box using a reader", func() {
177+
r, w := io.Pipe()
178+
go func() {
179+
w.Write([]byte("multi\n"))
180+
w.Write([]byte("line\n"))
181+
w.Write([]byte("content\n"))
182+
w.Close()
183+
}()
184+
185+
var buf bytes.Buffer
186+
Box(&buf, "headline", r)
187+
188+
Expect("\n" + buf.String()).To(BeEquivalentTo(Sprintf(`
189+
╭ headline
190+
│ multi
191+
│ line
192+
│ content
193+
194+
`)))
195+
})
196+
197+
It("should create no box if no content could be obtained from the reader", func() {
198+
r, w := io.Pipe()
199+
go func() {
200+
w.Close()
201+
}()
202+
203+
var buf bytes.Buffer
204+
Box(&buf, "headline", r)
205+
206+
Expect(len(buf.String())).To(BeIdenticalTo(0))
207+
})
208+
})
171209
})

0 commit comments

Comments
 (0)