57 lines
1.3 KiB
Go
57 lines
1.3 KiB
Go
package terminal
|
|
|
|
import "time"
|
|
|
|
// sendLocked queues what the operation in progress rendered and wakes the writer.
|
|
// Caller MUST hold mu.
|
|
func (t *termImpl) sendLocked() {
|
|
buf := &t.output.buf
|
|
if buf.Len() == 0 {
|
|
return
|
|
}
|
|
t.queued = append(t.queued, buf.Bytes()...)
|
|
buf.Reset()
|
|
select {
|
|
case t.wake <- struct{}{}:
|
|
default:
|
|
}
|
|
}
|
|
|
|
// writeLoop is the only writer of terminal output after Init. It returns once Fini
|
|
// has queued the restoring sequences and they are written; a terminal that never
|
|
// takes them leaves it in its write, and Fini stops waiting.
|
|
func (t *termImpl) writeLoop() {
|
|
defer close(t.writerDone)
|
|
for {
|
|
select {
|
|
case <-t.wake:
|
|
t.drain()
|
|
case <-t.quit:
|
|
t.drain()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// drain writes what is queued until nothing is, and draws a frame held while a
|
|
// write was out once that write returns. The write runs without mu, so whoever
|
|
// draws meanwhile finds writeSince set and holds its frame instead of waiting.
|
|
func (t *termImpl) drain() {
|
|
t.mu.Lock()
|
|
for {
|
|
if len(t.queued) == 0 {
|
|
t.releaseLocked()
|
|
}
|
|
if len(t.queued) == 0 {
|
|
break
|
|
}
|
|
t.writing, t.queued = t.queued, t.writing[:0]
|
|
t.writeSince.Store(time.Now().UnixNano())
|
|
t.mu.Unlock()
|
|
_ = t.backend.Write(t.writing) // a failed write is lost, as one through a buffered writer was
|
|
t.writeSince.Store(0)
|
|
t.mu.Lock()
|
|
}
|
|
t.mu.Unlock()
|
|
}
|