diff --git a/src/terminal.go b/src/terminal.go index 0c3226cf..273f2650 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1936,6 +1936,7 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) { pwidth -= 1 } t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, tui.WindowPreview, noBorder, true) + t.pwindow.SetWrapSign(t.wrapSign, t.wrapSignWidth) if !hadPreviewWindow { t.pwindow.Erase() } diff --git a/src/tui/light.go b/src/tui/light.go index ab7bd87f..bf2a2fd2 100644 --- a/src/tui/light.go +++ b/src/tui/light.go @@ -44,8 +44,9 @@ func (r *LightRenderer) stderr(str string) { r.stderrInternal(str, true, "") } -const CR string = "\x1b[2m␍" -const LF string = "\x1b[2m␊" +const DIM string = "\x1b[2m" +const CR string = DIM + "␍" +const LF string = DIM + "␊" func (r *LightRenderer) stderrInternal(str string, allowNLCR bool, resetCode string) { bytes := []byte(str) @@ -127,19 +128,21 @@ type LightRenderer struct { } type LightWindow struct { - renderer *LightRenderer - colored bool - windowType WindowType - border BorderStyle - top int - left int - width int - height int - posx int - posy int - tabstop int - fg Color - bg Color + renderer *LightRenderer + colored bool + windowType WindowType + border BorderStyle + top int + left int + width int + height int + posx int + posy int + tabstop int + fg Color + bg Color + wrapSign string + wrapSignWidth int } func NewLightRenderer(ttyin *os.File, theme *ColorTheme, forceBlack bool, mouse bool, tabstop int, clearOnExit bool, fullscreen bool, maxHeightFunc func(int) int) (Renderer, error) { @@ -1105,11 +1108,12 @@ type wrappedLine struct { displayWidth int } -func wrapLine(input string, prefixLength int, max int, tabstop int) []wrappedLine { +func wrapLine(input string, prefixLength int, initialMax int, tabstop int, wrapSignWidth int) []wrappedLine { lines := []wrappedLine{} width := 0 line := "" gr := uniseg.NewGraphemes(input) + max := initialMax for gr.Next() { rs := gr.Runes() str := string(rs) @@ -1131,6 +1135,7 @@ func wrapLine(input string, prefixLength int, max int, tabstop int) []wrappedLin line = str prefixLength = 0 width = w + max = initialMax - wrapSignWidth } } lines = append(lines, wrappedLine{string(line), width}) @@ -1140,7 +1145,7 @@ func wrapLine(input string, prefixLength int, max int, tabstop int) []wrappedLin func (w *LightWindow) fill(str string, resetCode string) FillReturn { allLines := strings.Split(str, "\n") for i, line := range allLines { - lines := wrapLine(line, w.posx, w.width, w.tabstop) + lines := wrapLine(line, w.posx, w.width, w.tabstop, w.wrapSignWidth) for j, wl := range lines { w.stderrInternal(wl.text, false, resetCode) w.posx += wl.displayWidth @@ -1153,6 +1158,11 @@ func (w *LightWindow) fill(str string, resetCode string) FillReturn { w.MoveAndClear(w.posy, w.posx) w.Move(w.posy+1, 0) w.renderer.stderr(resetCode) + if len(lines) > 1 { + w.stderrInternal(DIM+w.wrapSign, false, resetCode) + w.renderer.stderr(resetCode) + w.Move(w.posy, w.wrapSignWidth) + } } } } @@ -1226,6 +1236,11 @@ func (w *LightWindow) EraseMaybe() bool { return false } +func (w *LightWindow) SetWrapSign(sign string, width int) { + w.wrapSign = sign + w.wrapSignWidth = width +} + func (r *LightRenderer) HideCursor() { r.showCursor = false r.csi("?25l") diff --git a/src/tui/tcell.go b/src/tui/tcell.go index 0009b912..b70eed48 100644 --- a/src/tui/tcell.go +++ b/src/tui/tcell.go @@ -39,20 +39,22 @@ func (p ColorPair) style() tcell.Style { type Attr int32 type TcellWindow struct { - color bool - windowType WindowType - top int - left int - width int - height int - normal ColorPair - lastX int - lastY int - moveCursor bool - borderStyle BorderStyle - uri *string - params *string - showCursor bool + color bool + windowType WindowType + top int + left int + width int + height int + normal ColorPair + lastX int + lastY int + moveCursor bool + borderStyle BorderStyle + uri *string + params *string + showCursor bool + wrapSign string + wrapSignWidth int } func (w *TcellWindow) Top() int { @@ -629,6 +631,11 @@ func (w *TcellWindow) EraseMaybe() bool { return true } +func (w *TcellWindow) SetWrapSign(sign string, width int) { + w.wrapSign = sign + w.wrapSignWidth = width +} + func (w *TcellWindow) EncloseX(x int) bool { return x >= w.left && x < (w.left+w.width) } @@ -757,11 +764,18 @@ Loop: // word wrap: xPos := w.left + w.lastX + lx - if xPos >= (w.left + w.width) { + if xPos >= w.left+w.width { w.lastY++ w.lastX = 0 lx = 0 xPos = w.left + wgr := uniseg.NewGraphemes(w.wrapSign) + for wgr.Next() { + rs := wgr.Runes() + _screen.SetContent(w.left+lx, w.top+w.lastY, rs[0], rs[1:], style.Dim(true)) + lx += uniseg.StringWidth(string(rs)) + } + xPos = w.left + lx } yPos := w.top + w.lastY diff --git a/src/tui/tui.go b/src/tui/tui.go index 265d3cff..4f2fe2c6 100644 --- a/src/tui/tui.go +++ b/src/tui/tui.go @@ -659,6 +659,8 @@ type Window interface { LinkEnd() Erase() EraseMaybe() bool + + SetWrapSign(string, int) } type FullscreenRenderer struct { diff --git a/test/test_preview.rb b/test/test_preview.rb index ee1a5672..11b3225d 100644 --- a/test/test_preview.rb +++ b/test/test_preview.rb @@ -453,7 +453,7 @@ class TestPreview < TestInteractive tmux.send_keys 'f' tmux.until do |lines| assert_equal '::', lines[0] - assert_equal ' 3', lines[1] + assert_equal '↳ 3', lines[1] end end @@ -527,7 +527,7 @@ class TestPreview < TestInteractive tmux.send_keys "seq 10 | #{FZF} --preview-border rounded --preview-window '~5,2,+0,<100000(~0,+100,wrap,noinfo)' --preview 'seq 1000'", :Enter tmux.until { |lines| assert_equal 10, lines.match_count } tmux.until do |lines| - assert_equal ['╭────╮', '│ 10 │', '│ 0 │', '│ 10 │', '│ 1 │'], lines.take(5).map(&:strip) + assert_equal ['╭────╮', '│ 10 │', '│ ↳ 0│', '│ 10 │', '│ ↳ 1│'], lines.take(5).map(&:strip) end end