func (t *textWrapper) EraseUp() {
	t.clearLinePart(t.cursorRow, t.cursorCol, -1, -1)
	for r := t.cursorRow-1; r >= 0; r-- {
		t.clearLinePart(r, 0, t.cols, 1)
	}
}
EraseUp clears the screen from the cursor upwards, including everything on
the current line before the cursor.
package term
import (
	"unicode"
	"github.com/mattn/go-runewidth"
	"github.com/gdamore/tcell"
)
type textWrapper struct {
	rows, cols int
	buf tcell.CellBuffer
	cursorRow, cursorCol int
}
func (t *textWrapper) Resize(cols, rows int) {
	t.cols = cols
	t.rows = rows
	t.buf.Resize(cols, rows)
}
func (t *textWrapper) Reset() {
	t.buf.Fill(' ', tcell.StyleDefault)
	t.cursorRow = 0
	t.cursorCol = 0
}
func (t *textWrapper) Newline() {
	t.clearLinePart(t.cursorRow, t.cursorCol, t.cols, 1)  
	t.cursorRow++
	t.cursorCol = 0
	if t.cursorRow >= t.rows {
		t.cursorRow = t.rows-1
		t.ScrollDown()
	}
}
func (t *textWrapper) WriteString(str string, sty tcell.Style) {
	var charsBuffer []rune
	mainWidth := 0
	for _, rn := range str {
		switch {
		case rn == '\n':
			if len(charsBuffer) > 0 {
				t.writeNextCell(mainWidth, charsBuffer, sty)
				charsBuffer = charsBuffer[:0]
				mainWidth = 0
			}
			t.Newline()
			continue
		case unicode.IsControl(rn):
			continue
		}
		switch width := runewidth.RuneWidth(rn); width {
		case 0:  
			if len(charsBuffer) == 0 {
				charsBuffer = append(charsBuffer, ' ')
				mainWidth = 1
			}
			charsBuffer = append(charsBuffer, rn)
		default:  
			if len(charsBuffer) > 0 {
				t.writeNextCell(mainWidth, charsBuffer, sty)
				charsBuffer = charsBuffer[:0]
			}
			charsBuffer = append(charsBuffer, rn)
			mainWidth = width
		}
	}
	if len(charsBuffer) > 0 {
		t.writeNextCell(mainWidth, charsBuffer, sty)
	}
}
func (t *textWrapper) writeNextCell(width int, runes []rune, sty tcell.Style) {
	if remaining := t.cols - t.cursorCol; remaining < width {
		t.Newline()
	}
	t.buf.SetContent(t.cursorCol, t.cursorRow, runes[0], runes[1:], sty)
	t.cursorCol += width
}
func (t *textWrapper) FlushTo(screen tcell.Screen, startCol, startRow int) {
	for row := 0; row < t.rows; row++ {
		for col := 0; col < t.cols; col++ {
			if !t.buf.Dirty(col, row) {
				continue
			}
			mainRune, combRunes, style, _ := t.buf.GetContent(col, row)
			screen.SetContent(startCol+col, startRow+row, mainRune, combRunes, style)
		}
	}
}
func (t *textWrapper) clearLinePart(row int, startCol, endCol int, dir int) {
	if startCol > endCol && dir > 0 {
		panic("invalid start and end for forward iteration")
	} else if startCol < endCol && dir < 0 {
		panic("invalid start and end for backward iteration")
	} else if dir != 1 && dir != -1 {
		panic("dir must be 1 or -1")
	}
	for c := startCol; c != endCol; c += dir {
		t.buf.SetContent(c, row, ' ', nil, tcell.StyleDefault)
	}
}
func (t *textWrapper) ScrollDown() {
	if t.cursorRow < t.rows-1 {
		t.CursorDown(1)
		return
	}
	for r := 1; r < t.rows; r++ {
		for c := 0; c < t.cols; c++ {
			mainRune, combRunes, style, _ := t.buf.GetContent(c, r)
			t.buf.SetContent(c, r-1, mainRune, combRunes, style)
		}
	}
	t.clearLinePart(t.rows-1, 0, t.cols, 1)
}
func (t *textWrapper) ScrollUp() {
	if t.cursorRow > 0 {
		t.CursorUp(1)
		return
	}
	for r := t.rows-2; r <= 0; r-- {
		for c := 0; c < t.cols; c++ {
			mainRune, combRunes, style, _ := t.buf.GetContent(c, r)
			t.buf.SetContent(c, r+1, mainRune, combRunes, style)
		}
	}
	t.clearLinePart(0, 0, t.cols, 1)
}
func (t *textWrapper) Erase() {
	for r := 0; r < t.rows; r++ {
		t.clearLinePart(r, 0, t.cols, 1)
	}
}