Skip to content

Commit d364d53

Browse files
authored
Merge pull request #20 from liamg/liamg-fix-output-race-condition
Fix output race condition
2 parents 1744307 + d547e19 commit d364d53

File tree

5 files changed

+29
-14
lines changed

5 files changed

+29
-14
lines changed

pkg/decorators/decorator.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ const (
1212

1313
// Decorator is an entity which modifies the terminal output in a desirable way
1414
type Decorator interface {
15-
Draw(rows uint16, cols uint16) // Draw renders the decorator to StdOut
16-
GetAnchor() Anchor // GetAnchor returns the anchor e.g. Top/Bottom
17-
GetHeight() (rows uint16) // GetHeight returns the height of the decorator in terminal character rows
15+
Draw(rows uint16, cols uint16, output func(data []byte)) // Draw renders the decorator to StdOut
16+
GetAnchor() Anchor // GetAnchor returns the anchor e.g. Top/Bottom
17+
GetHeight() (rows uint16) // GetHeight returns the height of the decorator in terminal character rows
1818
IsVisible() bool
1919
}

pkg/decorators/statusbar.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,19 +59,22 @@ func (b *StatusBar) SetFg(colour ansi.Colour) {
5959
}
6060

6161
// Draw renders the decorator to StdOut
62-
func (b *StatusBar) Draw(rows uint16, cols uint16) {
62+
func (b *StatusBar) Draw(rows uint16, cols uint16, writeFunc func(data []byte)) {
6363

6464
var row, col uint16
6565
switch b.anchor {
6666
case AnchorBottom:
6767
row = rows - 1
6868
}
69-
ansi.SaveCursorPosition()
70-
ansi.MoveCursorTo(row+1, col+1)
71-
ansi.ClearLine()
69+
70+
// move cursor to status bar location
71+
writeFunc([]byte(fmt.Sprintf("\033[%d;%dH", row+1, col+1)))
72+
73+
// clear line
74+
writeFunc([]byte("\x1b[K"))
7275

7376
// set colours
74-
fmt.Printf("\r\033[%dm\033[%dm", b.bg, b.fg)
77+
writeFunc([]byte(fmt.Sprintf("\r\033[%dm\033[%dm", b.bg, b.fg)))
7578

7679
segments := strings.SplitN(b.format, "|", 3)
7780
colSize := int(cols) / len(segments)
@@ -93,15 +96,14 @@ func (b *StatusBar) Draw(rows uint16, cols uint16) {
9396
output = padLeft(output, colSize)
9497
}
9598

96-
fmt.Printf("%s", output)
99+
writeFunc([]byte(output))
97100

98101
}
99102

100103
for i := uint16(0); i < b.padding; i++ {
101-
fmt.Printf("\n")
104+
writeFunc([]byte{0x0a})
102105
}
103106

104-
ansi.RestoreCursorPosition()
105107
}
106108

107109
// SetPadding sets a vertical padding on the status bar

pkg/proxy/ansi.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func (p *Proxy) proxyANSICommand(input chan byte) (output []byte, original []byt
1717
switch b {
1818
case 'c': //RIS
1919
row, col := p.HandleCoordinates(0, 0)
20-
output := []byte(fmt.Sprintf("\033[%d;%dH", row, col))
20+
output := []byte(fmt.Sprintf("\033[%d;%dH", row+1, col+1))
2121
return output, original, true
2222
case '[': // CSI
2323
output, original2, redraw, err := p.handleCSI(input)

pkg/proxy/csi.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func (p *Proxy) handleCSI(pty chan byte) (output []byte, original []byte, redraw
1919
'h': p.csiSetModeHandler,
2020
'l': p.csiResetModeHandler,
2121
'J': p.csiEraseInDisplayHandler,
22+
'r': p.csiSetMarginHandler,
2223
}
2324

2425
var final byte
@@ -136,6 +137,13 @@ func (p *Proxy) csiLinePositionAbsolute(params []string, intermediate string) (o
136137
return []byte(fmt.Sprintf("\033[%dd", newRow)), false, nil
137138
}
138139

140+
// CSI Pt Pb r
141+
func (p *Proxy) csiSetMarginHandler(params []string, intermediate string) (output []byte, redraw bool, err error) {
142+
// pass through command, and inject reset position afterwards
143+
row, col := p.HandleCoordinates(0, 0)
144+
return []byte(fmt.Sprintf("\033[%d;%dH", row+1, col+1)), true, ErrorCommandNotSupported
145+
}
146+
139147
// CSI Ps J
140148
func (p *Proxy) csiEraseInDisplayHandler(params []string, intermediate string) (output []byte, redraw bool, err error) {
141149

@@ -151,7 +159,7 @@ func (p *Proxy) csiEraseInDisplayHandler(params []string, intermediate string) (
151159
switch n {
152160
case "2", "3":
153161
row, col := p.HandleCoordinates(0, 0)
154-
return []byte(fmt.Sprintf("\033[%d;%dH", row, col)), true, ErrorCommandNotSupported
162+
return []byte(fmt.Sprintf("\033[%d;%dH", row+1, col+1)), true, ErrorCommandNotSupported
155163
}
156164

157165
return nil, false, ErrorCommandNotSupported

pkg/proxy/proxy.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ func (p *Proxy) process() {
164164
for {
165165
select {
166166
case b := <-p.workChan:
167+
167168
if b == 0x1b {
168169
output, original, redraw := p.proxyANSICommand(p.workChan)
169170
if original != nil {
@@ -222,12 +223,16 @@ func (p *Proxy) redraw() {
222223
if !p.canRender {
223224
return
224225
}
226+
//save cursor pos
227+
p.writeOutput([]byte("\x1b[s"))
225228
for _, decorator := range p.decorators {
226229
if !decorator.IsVisible() {
227230
continue
228231
}
229-
decorator.Draw(p.realRows, p.realCols)
232+
decorator.Draw(p.realRows, p.realCols, p.writeOutput)
230233
}
234+
// restore cursor position
235+
p.writeOutput([]byte(fmt.Sprintf("\x1b[u")))
231236
}
232237

233238
func (p *Proxy) writeOutput(data []byte) {

0 commit comments

Comments
 (0)