From 9977a3e9fcdc2d2feda2f8cd2990a89c21804e56 Mon Sep 17 00:00:00 2001 From: Junegunn Choi <junegunn.c@gmail.com> Date: Wed, 11 Jan 2017 22:13:40 +0900 Subject: [PATCH] Make preview renderer suspend early on line wrap --- src/terminal.go | 72 ++++++++++++++++++++++++++-------------------- src/tui/light.go | 16 +++++++---- src/tui/ncurses.go | 9 ++++-- src/tui/tcell.go | 10 +++---- src/tui/tui.go | 12 ++++++-- 5 files changed, 73 insertions(+), 46 deletions(-) diff --git a/src/terminal.go b/src/terminal.go index ce63adf1..0353157e 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1,8 +1,10 @@ package fzf import ( + "bufio" "bytes" "fmt" + "io" "os" "os/signal" "regexp" @@ -852,41 +854,49 @@ func (t *Terminal) printPreview() { return } t.pwindow.Erase() - skip := t.previewer.offset - extractColor(t.previewer.text, nil, func(str string, ansi *ansiState) bool { - if skip > 0 { - newlines := numLinesMax(str, skip) - if skip <= newlines { - for i := 0; i < skip; i++ { - str = str[strings.Index(str, "\n")+1:] - } - skip = 0 - } else { - skip -= newlines - return true - } + + maxWidth := t.pwindow.Width() + if t.tui.DoesAutoWrap() { + maxWidth -= 1 + } + reader := bufio.NewReader(strings.NewReader(t.previewer.text)) + lineNo := -t.previewer.offset + for { + line, err := reader.ReadString('\n') + eof := err == io.EOF + if !eof { + line = line[:len(line)-1] } - lines := strings.Split(str, "\n") - for i, line := range lines { - limit := t.pwindow.Width() - if t.tui.DoesAutoWrap() { - limit -= 1 - } - if i == 0 { - limit -= t.pwindow.X() - } - trimmed := []rune(line) - if !t.preview.wrap { - trimmed, _ = t.trimRight(trimmed, limit) + lineNo++ + if lineNo > t.pwindow.Height() { + break + } else if lineNo > 0 { + var fillRet tui.FillReturn + extractColor(line, nil, func(str string, ansi *ansiState) bool { + trimmed := []rune(str) + if !t.preview.wrap { + trimmed, _ = t.trimRight(trimmed, maxWidth-t.pwindow.X()) + } + str, _ = t.processTabs(trimmed, 0) + if ansi != nil && ansi.colored() { + fillRet = t.pwindow.CFill(ansi.fg, ansi.bg, ansi.attr, str) + } else { + fillRet = t.pwindow.Fill(str) + } + return fillRet == tui.FillContinue + }) + switch fillRet { + case tui.FillNextLine: + continue + case tui.FillSuspend: + break } - lines[i], _ = t.processTabs(trimmed, 0) - str = strings.Join(lines, "\n") + t.pwindow.Fill("\n") } - if ansi != nil && ansi.colored() { - return t.pwindow.CFill(ansi.fg, ansi.bg, ansi.attr, str) + if eof { + break } - return t.pwindow.Fill(str) - }) + } t.pwindow.FinishFill() if t.previewer.lines > t.pwindow.Height() { offset := fmt.Sprintf("%d/%d", t.previewer.offset+1, t.previewer.lines) diff --git a/src/tui/light.go b/src/tui/light.go index 4725ef56..248477c7 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -730,23 +730,29 @@ func wrapLine(input string, prefixLength int, max int, tabstop int) []wrappedLin return lines } -func (w *LightWindow) fill(str string, onMove func()) bool { +func (w *LightWindow) fill(str string, onMove func()) FillReturn { allLines := strings.Split(str, "\n") for i, line := range allLines { lines := wrapLine(line, w.posx, w.width, w.tabstop) for j, wl := range lines { + if w.posx >= w.Width()-1 && wl.displayWidth == 0 { + if w.posy < w.height-1 { + w.MoveAndClear(w.posy+1, 0) + } + return FillNextLine + } w.stderr(wl.text) w.posx += wl.displayWidth if j < len(lines)-1 || i < len(allLines)-1 { if w.posy+1 >= w.height { - return false + return FillSuspend } w.MoveAndClear(w.posy+1, 0) onMove() } } } - return true + return FillContinue } func (w *LightWindow) setBg() { @@ -755,13 +761,13 @@ func (w *LightWindow) setBg() { } } -func (w *LightWindow) Fill(text string) bool { +func (w *LightWindow) Fill(text string) FillReturn { w.MoveAndClear(w.posy, w.posx) w.setBg() return w.fill(text, w.setBg) } -func (w *LightWindow) CFill(fg Color, bg Color, attr Attr, text string) bool { +func (w *LightWindow) CFill(fg Color, bg Color, attr Attr, text string) FillReturn { w.MoveAndClear(w.posy, w.posx) if bg == colDefault { bg = w.bg diff --git a/src/tui/ncurses.go b/src/tui/ncurses.go index f6feefc6..3e636ba2 100644 --- a/src/tui/ncurses.go +++ b/src/tui/ncurses.go @@ -282,11 +282,14 @@ func (r *FullscreenRenderer) DoesAutoWrap() bool { return true } -func (w *CursesWindow) Fill(str string) bool { - return C.waddstr(w.impl, C.CString(str)) == C.OK +func (w *CursesWindow) Fill(str string) FillReturn { + if C.waddstr(w.impl, C.CString(str)) == C.OK { + return FillContinue + } + return FillSuspend } -func (w *CursesWindow) CFill(fg Color, bg Color, attr Attr, str string) bool { +func (w *CursesWindow) CFill(fg Color, bg Color, attr Attr, str string) FillReturn { index := ColorPair{fg, bg, -1}.index() C.wcolor_set(w.impl, C.short(index), nil) C.wattron(w.impl, C.int(attr)) diff --git a/src/tui/tcell.go b/src/tui/tcell.go index b6f08192..3399d32b 100644 --- a/src/tui/tcell.go +++ b/src/tui/tcell.go @@ -477,7 +477,7 @@ func (w *TcellWindow) CPrint(pair ColorPair, attr Attr, text string) { w.printString(text, pair, attr) } -func (w *TcellWindow) fillString(text string, pair ColorPair, a Attr) bool { +func (w *TcellWindow) fillString(text string, pair ColorPair, a Attr) FillReturn { lx := 0 var style tcell.Style @@ -511,7 +511,7 @@ func (w *TcellWindow) fillString(text string, pair ColorPair, a Attr) bool { var yPos = w.top + w.lastY if yPos >= (w.top + w.height) { - return false + return FillSuspend } _screen.SetContent(xPos, yPos, r, nil, style) @@ -520,14 +520,14 @@ func (w *TcellWindow) fillString(text string, pair ColorPair, a Attr) bool { } w.lastX += lx - return true + return FillContinue } -func (w *TcellWindow) Fill(str string) bool { +func (w *TcellWindow) Fill(str string) FillReturn { return w.fillString(str, ColDefault, 0) } -func (w *TcellWindow) CFill(fg Color, bg Color, a Attr, str string) bool { +func (w *TcellWindow) CFill(fg Color, bg Color, a Attr, str string) FillReturn { return w.fillString(str, ColorPair{fg, bg, -1}, a) } diff --git a/src/tui/tui.go b/src/tui/tui.go index eb504f8c..33358e85 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -117,6 +117,14 @@ const ( colWhite ) +type FillReturn int + +const ( + FillContinue FillReturn = iota + FillNextLine + FillSuspend +) + type ColorPair struct { fg Color bg Color @@ -216,8 +224,8 @@ type Window interface { MoveAndClear(y int, x int) Print(text string) CPrint(color ColorPair, attr Attr, text string) - Fill(text string) bool - CFill(fg Color, bg Color, attr Attr, text string) bool + Fill(text string) FillReturn + CFill(fg Color, bg Color, attr Attr, text string) FillReturn Erase() } -- GitLab