Optimize LightRenderer for slow terminals
This commit is contained in:
parent
44d3faa048
commit
ede7bfb901
@ -46,6 +46,7 @@ type itemLine struct {
|
|||||||
current bool
|
current bool
|
||||||
selected bool
|
selected bool
|
||||||
label string
|
label string
|
||||||
|
width int
|
||||||
result Result
|
result Result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,13 +679,17 @@ func (t *Terminal) printItem(result *Result, line int, i int, current bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Avoid unnecessary redraw
|
// Avoid unnecessary redraw
|
||||||
newLine := itemLine{current, selected, label, *result}
|
newLine := itemLine{current: current, selected: selected, label: label, result: *result, width: 0}
|
||||||
if t.prevLines[i] == newLine {
|
prevLine := t.prevLines[i]
|
||||||
|
if prevLine.current == newLine.current &&
|
||||||
|
prevLine.selected == newLine.selected &&
|
||||||
|
prevLine.label == newLine.label &&
|
||||||
|
prevLine.result == newLine.result {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.prevLines[i] = newLine
|
|
||||||
|
|
||||||
t.move(line, 0, true)
|
// Optimized renderer can simply erase to the end of the window
|
||||||
|
t.move(line, 0, t.tui.IsOptimized())
|
||||||
t.window.CPrint(tui.ColCursor, t.strong, label)
|
t.window.CPrint(tui.ColCursor, t.strong, label)
|
||||||
if current {
|
if current {
|
||||||
if selected {
|
if selected {
|
||||||
@ -692,15 +697,22 @@ func (t *Terminal) printItem(result *Result, line int, i int, current bool) {
|
|||||||
} else {
|
} else {
|
||||||
t.window.CPrint(tui.ColCurrent, t.strong, " ")
|
t.window.CPrint(tui.ColCurrent, t.strong, " ")
|
||||||
}
|
}
|
||||||
t.printHighlighted(result, t.strong, tui.ColCurrent, tui.ColCurrentMatch, true, true)
|
newLine.width = t.printHighlighted(result, t.strong, tui.ColCurrent, tui.ColCurrentMatch, true, true)
|
||||||
} else {
|
} else {
|
||||||
if selected {
|
if selected {
|
||||||
t.window.CPrint(tui.ColSelected, t.strong, ">")
|
t.window.CPrint(tui.ColSelected, t.strong, ">")
|
||||||
} else {
|
} else {
|
||||||
t.window.Print(" ")
|
t.window.Print(" ")
|
||||||
}
|
}
|
||||||
t.printHighlighted(result, 0, tui.ColNormal, tui.ColMatch, false, true)
|
newLine.width = t.printHighlighted(result, 0, tui.ColNormal, tui.ColMatch, false, true)
|
||||||
}
|
}
|
||||||
|
if !t.tui.IsOptimized() {
|
||||||
|
fillSpaces := prevLine.width - newLine.width
|
||||||
|
if fillSpaces > 0 {
|
||||||
|
t.window.Print(strings.Repeat(" ", fillSpaces))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.prevLines[i] = newLine
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) trimRight(runes []rune, width int) ([]rune, int) {
|
func (t *Terminal) trimRight(runes []rune, width int) ([]rune, int) {
|
||||||
@ -745,17 +757,10 @@ func (t *Terminal) trimLeft(runes []rune, width int) ([]rune, int32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) overflow(runes []rune, max int) bool {
|
func (t *Terminal) overflow(runes []rune, max int) bool {
|
||||||
l := 0
|
return t.displayWidthWithLimit(runes, 0, max) > max
|
||||||
for _, r := range runes {
|
|
||||||
l += util.RuneWidth(r, l, t.tabstop)
|
|
||||||
if l > max {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) printHighlighted(result *Result, attr tui.Attr, col1 tui.ColorPair, col2 tui.ColorPair, current bool, match bool) {
|
func (t *Terminal) printHighlighted(result *Result, attr tui.Attr, col1 tui.ColorPair, col2 tui.ColorPair, current bool, match bool) int {
|
||||||
item := result.item
|
item := result.item
|
||||||
|
|
||||||
// Overflow
|
// Overflow
|
||||||
@ -783,7 +788,8 @@ func (t *Terminal) printHighlighted(result *Result, attr tui.Attr, col1 tui.Colo
|
|||||||
offsets := result.colorOffsets(charOffsets, t.theme, col2, attr, current)
|
offsets := result.colorOffsets(charOffsets, t.theme, col2, attr, current)
|
||||||
maxWidth := t.window.Width() - 3
|
maxWidth := t.window.Width() - 3
|
||||||
maxe = util.Constrain(maxe+util.Min(maxWidth/2-2, t.hscrollOff), 0, len(text))
|
maxe = util.Constrain(maxe+util.Min(maxWidth/2-2, t.hscrollOff), 0, len(text))
|
||||||
if t.overflow(text, maxWidth) {
|
displayWidth := t.displayWidthWithLimit(text, 0, maxWidth)
|
||||||
|
if displayWidth > maxWidth {
|
||||||
if t.hscroll {
|
if t.hscroll {
|
||||||
// Stri..
|
// Stri..
|
||||||
if !t.overflow(text[:maxe], maxWidth-2) {
|
if !t.overflow(text[:maxe], maxWidth-2) {
|
||||||
@ -845,6 +851,7 @@ func (t *Terminal) printHighlighted(result *Result, attr tui.Attr, col1 tui.Colo
|
|||||||
substr, _ = t.processTabs(text[index:], prefixWidth)
|
substr, _ = t.processTabs(text[index:], prefixWidth)
|
||||||
t.window.CPrint(col1, attr, substr)
|
t.window.CPrint(col1, attr, substr)
|
||||||
}
|
}
|
||||||
|
return displayWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
func numLinesMax(str string, max int) int {
|
func numLinesMax(str string, max int) int {
|
||||||
|
@ -32,13 +32,18 @@ func openTtyIn() *os.File {
|
|||||||
return in
|
return in
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Need better handling of non-displayable characters
|
|
||||||
func (r *LightRenderer) stderr(str string) {
|
func (r *LightRenderer) stderr(str string) {
|
||||||
|
r.stderrInternal(str, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Need better handling of non-displayable characters
|
||||||
|
func (r *LightRenderer) stderrInternal(str string, allowNLCR bool) {
|
||||||
bytes := []byte(str)
|
bytes := []byte(str)
|
||||||
runes := []rune{}
|
runes := []rune{}
|
||||||
for len(bytes) > 0 {
|
for len(bytes) > 0 {
|
||||||
r, sz := utf8.DecodeRune(bytes)
|
r, sz := utf8.DecodeRune(bytes)
|
||||||
if r == utf8.RuneError || r != '\x1b' && r != '\n' && r != '\r' && r < 32 {
|
if r == utf8.RuneError || r < 32 &&
|
||||||
|
r != '\x1b' && (!allowNLCR || r != '\n' && r != '\r') {
|
||||||
runes = append(runes, '?')
|
runes = append(runes, '?')
|
||||||
} else {
|
} else {
|
||||||
runes = append(runes, r)
|
runes = append(runes, r)
|
||||||
@ -553,6 +558,10 @@ func (r *LightRenderer) DoesAutoWrap() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *LightRenderer) IsOptimized() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (r *LightRenderer) NewWindow(top int, left int, width int, height int, border bool) Window {
|
func (r *LightRenderer) NewWindow(top int, left int, width int, height int, border bool) Window {
|
||||||
w := &LightWindow{
|
w := &LightWindow{
|
||||||
renderer: r,
|
renderer: r,
|
||||||
@ -594,6 +603,10 @@ func (w *LightWindow) stderr(str string) {
|
|||||||
w.renderer.stderr(str)
|
w.renderer.stderr(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *LightWindow) stderrInternal(str string, allowNLCR bool) {
|
||||||
|
w.renderer.stderrInternal(str, allowNLCR)
|
||||||
|
}
|
||||||
|
|
||||||
func (w *LightWindow) Top() int {
|
func (w *LightWindow) Top() int {
|
||||||
return w.top
|
return w.top
|
||||||
}
|
}
|
||||||
@ -703,7 +716,7 @@ func (w *LightWindow) CPrint(pair ColorPair, attr Attr, text string) {
|
|||||||
} else {
|
} else {
|
||||||
w.csiColor(pair.Fg(), pair.Bg(), attr)
|
w.csiColor(pair.Fg(), pair.Bg(), attr)
|
||||||
}
|
}
|
||||||
w.stderr(text)
|
w.stderrInternal(text, false)
|
||||||
w.csi("m")
|
w.csi("m")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,7 +724,7 @@ func (w *LightWindow) cprint2(fg Color, bg Color, attr Attr, text string) {
|
|||||||
if w.csiColor(fg, bg, attr) {
|
if w.csiColor(fg, bg, attr) {
|
||||||
defer w.csi("m")
|
defer w.csi("m")
|
||||||
}
|
}
|
||||||
w.stderr(text)
|
w.stderrInternal(text, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
type wrappedLine struct {
|
type wrappedLine struct {
|
||||||
@ -754,7 +767,7 @@ func (w *LightWindow) fill(str string, onMove func()) FillReturn {
|
|||||||
}
|
}
|
||||||
return FillNextLine
|
return FillNextLine
|
||||||
}
|
}
|
||||||
w.stderr(wl.text)
|
w.stderrInternal(wl.text, false)
|
||||||
w.posx += wl.displayWidth
|
w.posx += wl.displayWidth
|
||||||
if j < len(lines)-1 || i < len(allLines)-1 {
|
if j < len(lines)-1 || i < len(allLines)-1 {
|
||||||
if w.posy+1 >= w.height {
|
if w.posy+1 >= w.height {
|
||||||
|
@ -279,6 +279,10 @@ func (r *FullscreenRenderer) DoesAutoWrap() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *FullscreenRenderer) IsOptimized() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (w *CursesWindow) Fill(str string) FillReturn {
|
func (w *CursesWindow) Fill(str string) FillReturn {
|
||||||
if C.waddstr(w.impl, C.CString(str)) == C.OK {
|
if C.waddstr(w.impl, C.CString(str)) == C.OK {
|
||||||
return FillContinue
|
return FillContinue
|
||||||
|
@ -158,6 +158,10 @@ func (r *FullscreenRenderer) DoesAutoWrap() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *FullscreenRenderer) IsOptimized() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (r *FullscreenRenderer) Clear() {
|
func (r *FullscreenRenderer) Clear() {
|
||||||
_screen.Sync()
|
_screen.Sync()
|
||||||
_screen.Clear()
|
_screen.Clear()
|
||||||
|
@ -204,6 +204,7 @@ type Renderer interface {
|
|||||||
MaxX() int
|
MaxX() int
|
||||||
MaxY() int
|
MaxY() int
|
||||||
DoesAutoWrap() bool
|
DoesAutoWrap() bool
|
||||||
|
IsOptimized() bool
|
||||||
|
|
||||||
NewWindow(top int, left int, width int, height int, border bool) Window
|
NewWindow(top int, left int, width int, height int, border bool) Window
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user