diff options
Diffstat (limited to 'src/terminal.go')
-rw-r--r-- | src/terminal.go | 58 |
1 files changed, 26 insertions, 32 deletions
diff --git a/src/terminal.go b/src/terminal.go index 54f96675..aabeb07c 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -2,7 +2,6 @@ package fzf import ( "bufio" - "bytes" "fmt" "io/ioutil" "os" @@ -15,6 +14,9 @@ import ( "syscall" "time" + "github.com/mattn/go-runewidth" + "github.com/rivo/uniseg" + "github.com/junegunn/fzf/src/tui" "github.com/junegunn/fzf/src/util" ) @@ -673,11 +675,8 @@ func (t *Terminal) sortSelected() []selectedItem { } func (t *Terminal) displayWidth(runes []rune) int { - l := 0 - for _, r := range runes { - l += util.RuneWidth(r, l, t.tabstop) - } - return l + width, _ := util.RunesWidth(runes, 0, t.tabstop, 0) + return width } const ( @@ -1141,28 +1140,18 @@ func (t *Terminal) printItem(result Result, line int, i int, current bool) { t.prevLines[i] = newLine } -func (t *Terminal) trimRight(runes []rune, width int) ([]rune, int) { +func (t *Terminal) trimRight(runes []rune, width int) ([]rune, bool) { // We start from the beginning to handle tab characters - l := 0 - for idx, r := range runes { - l += util.RuneWidth(r, l, t.tabstop) - if l > width { - return runes[:idx], len(runes) - idx - } + width, overflowIdx := util.RunesWidth(runes, 0, t.tabstop, width) + if overflowIdx >= 0 { + return runes[:overflowIdx], true } - return runes, 0 + return runes, false } func (t *Terminal) displayWidthWithLimit(runes []rune, prefixWidth int, limit int) int { - l := 0 - for _, r := range runes { - l += util.RuneWidth(r, l+prefixWidth, t.tabstop) - if l > limit { - // Early exit - return l - } - } - return l + width, _ := util.RunesWidth(runes, prefixWidth, t.tabstop, limit) + return width } func (t *Terminal) trimLeft(runes []rune, width int) ([]rune, int32) { @@ -1362,9 +1351,9 @@ func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unc prefixWidth := 0 _, _, ansi = extractColor(line, ansi, func(str string, ansi *ansiState) bool { trimmed := []rune(str) - trimmedLen := 0 + isTrimmed := false if !t.previewOpts.wrap { - trimmed, trimmedLen = t.trimRight(trimmed, maxWidth-t.pwindow.X()) + trimmed, isTrimmed = t.trimRight(trimmed, maxWidth-t.pwindow.X()) } str, width := t.processTabs(trimmed, prefixWidth) prefixWidth += width @@ -1374,7 +1363,7 @@ func (t *Terminal) renderPreviewText(height int, lines []string, lineNo int, unc } else { fillRet = t.pwindow.CFill(tui.ColPreview.Fg(), tui.ColPreview.Bg(), tui.AttrRegular, str) } - return trimmedLen == 0 && + return !isTrimmed && (fillRet == tui.FillContinue || t.previewOpts.wrap && fillRet == tui.FillNextLine) }) t.previewer.scrollable = t.previewer.scrollable || t.pwindow.Y() == height-1 && t.pwindow.X() == t.pwindow.Width() @@ -1430,16 +1419,21 @@ func (t *Terminal) printPreviewDelayed() { } func (t *Terminal) processTabs(runes []rune, prefixWidth int) (string, int) { - var strbuf bytes.Buffer + var strbuf strings.Builder l := prefixWidth - for _, r := range runes { - w := util.RuneWidth(r, l, t.tabstop) - l += w - if r == '\t' { + gr := uniseg.NewGraphemes(string(runes)) + for gr.Next() { + rs := gr.Runes() + str := string(rs) + var w int + if len(rs) == 1 && rs[0] == '\t' { + w = t.tabstop - l%t.tabstop strbuf.WriteString(strings.Repeat(" ", w)) } else { - strbuf.WriteRune(r) + w = runewidth.StringWidth(str) + strbuf.WriteString(str) } + l += w } return strbuf.String(), l } |