Merge pull request #652 from SamWhited/tview_writer

Add batch writer for TextView's
This commit is contained in:
rivo 2021-10-29 07:15:55 +02:00 committed by GitHub
commit d710b0beff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 88 additions and 7 deletions

21
example_textview_test.go Normal file
View File

@ -0,0 +1,21 @@
package tview_test
import (
"fmt"
"github.com/rivo/tview"
)
func ExampleTextView_BatchWriter() {
tv := tview.NewTextView()
w := tv.BatchWriter()
defer w.Close()
w.Clear()
fmt.Fprintln(w, "To sit in solemn silence")
fmt.Fprintln(w, "on a dull, dark, dock")
fmt.Println(tv.GetText(false))
// Output:
// To sit in solemn silence
// on a dull, dark, dock
}

View File

@ -281,7 +281,10 @@ func (t *TextView) SetTextColor(color tcell.Color) *TextView {
// SetText sets the text of this text view to the provided string. Previously
// contained text will be removed.
func (t *TextView) SetText(text string) *TextView {
t.Clear()
t.Lock()
defer t.Unlock()
t.clear()
fmt.Fprint(t, text)
return t
}
@ -419,10 +422,20 @@ func (t *TextView) GetScrollOffset() (row, column int) {
// Clear removes all text from the buffer.
func (t *TextView) Clear() *TextView {
t.Lock()
defer t.Unlock()
t.clear()
return t
}
// clear is the internal implementaton of clear.
// It is used by TextViewWriter and anywhere that we need to perform a write
// without locking the buffer.
func (t *TextView) clear() {
t.buffer = nil
t.recentBytes = nil
t.index = nil
return t
}
// Highlight specifies which regions should be highlighted. If highlight
@ -622,10 +635,18 @@ func (t *TextView) HasFocus() bool {
// replaced with TabSize space characters. A "\n" or "\r\n" will be interpreted
// as a new line.
func (t *TextView) Write(p []byte) (n int, err error) {
// Notify at the end.
t.Lock()
defer t.Unlock()
return t.write(p)
}
// write is the internal implementation of Write.
// It is used by TextViewWriter and anywhere that we need to perform a write
// without locking the buffer.
func (t *TextView) write(p []byte) (n int, err error) {
// Notify at the end.
changed := t.changed
t.Unlock()
if changed != nil {
defer func() {
// We always call the "changed" function in a separate goroutine to avoid
@ -634,9 +655,6 @@ func (t *TextView) Write(p []byte) (n int, err error) {
}()
}
t.Lock()
defer t.Unlock()
// Copy data over.
newBytes := append(t.recentBytes, p...)
t.recentBytes = nil
@ -1259,3 +1277,45 @@ func (t *TextView) MouseHandler() func(action MouseAction, event *tcell.EventMou
return
})
}
// TextViewWriter is a writer that can be used to write and clear a TextView in
// batches (ie. multiple writes with the lock only being aquired once).
// It should not be instantiated directly and should instead only be created by
// TextView's BatchWriter method.
type TextViewWriter struct {
t *TextView
}
// Close implements io.Closer for the writer by unlocking the original TextView.
func (w TextViewWriter) Close() error {
w.t.Unlock()
return nil
}
// Clear removes all text from the buffer.
func (w TextViewWriter) Clear() {
w.t.clear()
}
// Write implements the io.Writer interface.
// It behaves like the TextView's Write method except that it does not aquire
// the lock.
func (w TextViewWriter) Write(p []byte) (n int, err error) {
return w.t.write(p)
}
// HasFocus returns whether the underlying TextView has focus.
func (w TextViewWriter) HasFocus() bool {
return w.t.hasFocus
}
// BatchWriter returns a new writer that can be used to write into the buffer
// but without Locking/Unlocking the buffer on every write.
// The lock will only be aquired once when BatchWriter is called, and will be
// released when the returned writer is Closed.
func (t *TextView) BatchWriter() TextViewWriter {
t.Lock()
return TextViewWriter{
t: t,
}
}