Skip to content

Commit 4844011

Browse files
authored
output: hide the cursor when updating (#456)
1 parent c47c349 commit 4844011

File tree

5 files changed

+89
-70
lines changed

5 files changed

+89
-70
lines changed

internal/output/block.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ func newBlock(indent int, o *Output) *Block {
3434
}
3535

3636
func (b *Block) Close() {
37-
b.unwrapped.lock.Lock()
38-
defer b.unwrapped.lock.Unlock()
37+
b.unwrapped.Lock()
38+
defer b.unwrapped.Unlock()
3939

4040
// This is a little tricky: output from Writer methods includes a trailing
4141
// newline, so we need to trim that so we don't output extra blank lines.

internal/output/output.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ type Output struct {
4747
lock sync.Mutex
4848
}
4949

50+
var _ sync.Locker = &Output{}
51+
5052
type OutputOpts struct {
5153
// ForceColor ignores all terminal detection and enabled coloured output.
5254
ForceColor bool
@@ -90,6 +92,23 @@ func NewOutput(w io.Writer, opts OutputOpts) *Output {
9092
return o
9193
}
9294

95+
func (o *Output) Lock() {
96+
o.lock.Lock()
97+
98+
// Hide the cursor while we update: this reduces the jitteriness of the
99+
// whole thing, and some terminals are smart enough to make the update we're
100+
// about to render atomic if the cursor is hidden for a short length of
101+
// time.
102+
o.w.Write([]byte("\033[?25l"))
103+
}
104+
105+
func (o *Output) Unlock() {
106+
// Show the cursor once more.
107+
o.w.Write([]byte("\033[?25h"))
108+
109+
o.lock.Unlock()
110+
}
111+
93112
func (o *Output) Verbose(s string) {
94113
if o.opts.Verbose {
95114
o.Write(s)
@@ -109,21 +128,21 @@ func (o *Output) VerboseLine(line FancyLine) {
109128
}
110129

111130
func (o *Output) Write(s string) {
112-
o.lock.Lock()
113-
defer o.lock.Unlock()
131+
o.Lock()
132+
defer o.Unlock()
114133
fmt.Fprintln(o.w, s)
115134
}
116135

117136
func (o *Output) Writef(format string, args ...interface{}) {
118-
o.lock.Lock()
119-
defer o.lock.Unlock()
137+
o.Lock()
138+
defer o.Unlock()
120139
fmt.Fprintf(o.w, format, o.caps.formatArgs(args)...)
121140
fmt.Fprint(o.w, "\n")
122141
}
123142

124143
func (o *Output) WriteLine(line FancyLine) {
125-
o.lock.Lock()
126-
defer o.lock.Unlock()
144+
o.Lock()
145+
defer o.Unlock()
127146
line.write(o.w, o.caps)
128147
}
129148

internal/output/pending_tty.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ func (p *pendingTTY) VerboseLine(line FancyLine) {
3333
}
3434

3535
func (p *pendingTTY) Write(s string) {
36-
p.o.lock.Lock()
37-
defer p.o.lock.Unlock()
36+
p.o.Lock()
37+
defer p.o.Unlock()
3838

3939
p.o.moveUp(1)
4040
p.o.clearCurrentLine()
@@ -43,8 +43,8 @@ func (p *pendingTTY) Write(s string) {
4343
}
4444

4545
func (p *pendingTTY) Writef(format string, args ...interface{}) {
46-
p.o.lock.Lock()
47-
defer p.o.lock.Unlock()
46+
p.o.Lock()
47+
defer p.o.Unlock()
4848

4949
p.o.moveUp(1)
5050
p.o.clearCurrentLine()
@@ -54,8 +54,8 @@ func (p *pendingTTY) Writef(format string, args ...interface{}) {
5454
}
5555

5656
func (p *pendingTTY) WriteLine(line FancyLine) {
57-
p.o.lock.Lock()
58-
defer p.o.lock.Unlock()
57+
p.o.Lock()
58+
defer p.o.Unlock()
5959

6060
p.o.moveUp(1)
6161
p.o.clearCurrentLine()
@@ -64,8 +64,8 @@ func (p *pendingTTY) WriteLine(line FancyLine) {
6464
}
6565

6666
func (p *pendingTTY) Update(s string) {
67-
p.o.lock.Lock()
68-
defer p.o.lock.Unlock()
67+
p.o.Lock()
68+
defer p.o.Unlock()
6969

7070
p.line.format = "%s"
7171
p.line.args = []interface{}{s}
@@ -76,8 +76,8 @@ func (p *pendingTTY) Update(s string) {
7676
}
7777

7878
func (p *pendingTTY) Updatef(format string, args ...interface{}) {
79-
p.o.lock.Lock()
80-
defer p.o.lock.Unlock()
79+
p.o.Lock()
80+
defer p.o.Unlock()
8181

8282
p.line.format = format
8383
p.line.args = args
@@ -90,8 +90,8 @@ func (p *pendingTTY) Updatef(format string, args ...interface{}) {
9090
func (p *pendingTTY) Complete(message FancyLine) {
9191
p.spinner.stop()
9292

93-
p.o.lock.Lock()
94-
defer p.o.lock.Unlock()
93+
p.o.Lock()
94+
defer p.o.Unlock()
9595

9696
p.o.moveUp(1)
9797
p.o.clearCurrentLine()
@@ -103,8 +103,8 @@ func (p *pendingTTY) Close() { p.Destroy() }
103103
func (p *pendingTTY) Destroy() {
104104
p.spinner.stop()
105105

106-
p.o.lock.Lock()
107-
defer p.o.lock.Unlock()
106+
p.o.Lock()
107+
defer p.o.Unlock()
108108

109109
p.o.moveUp(1)
110110
p.o.clearCurrentLine()
@@ -122,8 +122,8 @@ func newPendingTTY(message FancyLine, o *Output) *pendingTTY {
122122
go func() {
123123
for s := range p.spinner.C {
124124
func() {
125-
p.o.lock.Lock()
126-
defer p.o.lock.Unlock()
125+
p.o.Lock()
126+
defer p.o.Unlock()
127127

128128
p.updateEmoji(s)
129129

internal/output/progress_tty.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ type progressTTY struct {
3030
func (p *progressTTY) Complete() {
3131
p.spinner.stop()
3232

33-
p.o.lock.Lock()
34-
defer p.o.lock.Unlock()
33+
p.o.Lock()
34+
defer p.o.Unlock()
3535

3636
for _, bar := range p.bars {
3737
bar.Value = bar.Max
@@ -44,8 +44,8 @@ func (p *progressTTY) Close() { p.Destroy() }
4444
func (p *progressTTY) Destroy() {
4545
p.spinner.stop()
4646

47-
p.o.lock.Lock()
48-
defer p.o.lock.Unlock()
47+
p.o.Lock()
48+
defer p.o.Unlock()
4949

5050
p.moveToOrigin()
5151
for i := 0; i < len(p.bars); i += 1 {
@@ -57,17 +57,17 @@ func (p *progressTTY) Destroy() {
5757
}
5858

5959
func (p *progressTTY) SetLabel(i int, label string) {
60-
p.o.lock.Lock()
61-
defer p.o.lock.Unlock()
60+
p.o.Lock()
61+
defer p.o.Unlock()
6262

6363
p.bars[i].Label = label
6464
p.bars[i].labelWidth = runewidth.StringWidth(label)
6565
p.drawInSitu()
6666
}
6767

6868
func (p *progressTTY) SetLabelAndRecalc(i int, label string) {
69-
p.o.lock.Lock()
70-
defer p.o.lock.Unlock()
69+
p.o.Lock()
70+
defer p.o.Unlock()
7171

7272
p.bars[i].Label = label
7373
p.bars[i].labelWidth = runewidth.StringWidth(label)
@@ -77,8 +77,8 @@ func (p *progressTTY) SetLabelAndRecalc(i int, label string) {
7777
}
7878

7979
func (p *progressTTY) SetValue(i int, v float64) {
80-
p.o.lock.Lock()
81-
defer p.o.lock.Unlock()
80+
p.o.Lock()
81+
defer p.o.Unlock()
8282

8383
p.bars[i].Value = v
8484
p.drawInSitu()
@@ -103,8 +103,8 @@ func (p *progressTTY) VerboseLine(line FancyLine) {
103103
}
104104

105105
func (p *progressTTY) Write(s string) {
106-
p.o.lock.Lock()
107-
defer p.o.lock.Unlock()
106+
p.o.Lock()
107+
defer p.o.Unlock()
108108

109109
p.moveToOrigin()
110110
p.o.clearCurrentLine()
@@ -113,8 +113,8 @@ func (p *progressTTY) Write(s string) {
113113
}
114114

115115
func (p *progressTTY) Writef(format string, args ...interface{}) {
116-
p.o.lock.Lock()
117-
defer p.o.lock.Unlock()
116+
p.o.Lock()
117+
defer p.o.Unlock()
118118

119119
p.moveToOrigin()
120120
p.o.clearCurrentLine()
@@ -124,8 +124,8 @@ func (p *progressTTY) Writef(format string, args ...interface{}) {
124124
}
125125

126126
func (p *progressTTY) WriteLine(line FancyLine) {
127-
p.o.lock.Lock()
128-
defer p.o.lock.Unlock()
127+
p.o.Lock()
128+
defer p.o.Unlock()
129129

130130
p.moveToOrigin()
131131
p.o.clearCurrentLine()
@@ -151,8 +151,8 @@ func newProgressTTY(bars []*ProgressBar, o *Output, opts *ProgressOpts) *progres
151151
p.determineEmojiWidth()
152152
p.determineLabelWidth()
153153

154-
p.o.lock.Lock()
155-
defer p.o.lock.Unlock()
154+
p.o.Lock()
155+
defer p.o.Unlock()
156156

157157
p.draw()
158158

@@ -165,8 +165,8 @@ func newProgressTTY(bars []*ProgressBar, o *Output, opts *ProgressOpts) *progres
165165
func() {
166166
p.pendingEmoji = s
167167

168-
p.o.lock.Lock()
169-
defer p.o.lock.Unlock()
168+
p.o.Lock()
169+
defer p.o.Unlock()
170170

171171
p.moveToOrigin()
172172
p.draw()

0 commit comments

Comments
 (0)