summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2024-01-21 02:52:28 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2024-01-21 02:54:41 +0900
commit16f647393838ea3eb0778a45178323aea21b67a0 (patch)
tree71f117d5d727b204f3e7f418ab8e68e1f5cbb437
parent66546208b2d29257b736302592f9566952e29905 (diff)
Change mattn/go-runewidth dependency to rivo/uniseg for accurate results
Related #3588 #3588 #3567
-rw-r--r--BUILD.md4
-rw-r--r--CHANGELOG.md2
-rw-r--r--go.mod4
-rw-r--r--go.sum4
-rw-r--r--man/man1/fzf.110
-rw-r--r--src/options.go42
-rw-r--r--src/terminal.go5
-rw-r--r--src/tui/light.go15
-rw-r--r--src/tui/tcell.go11
-rw-r--r--src/tui/tui.go6
-rw-r--r--src/util/util.go7
11 files changed, 59 insertions, 51 deletions
diff --git a/BUILD.md b/BUILD.md
index 71066ef0..af0a04e9 100644
--- a/BUILD.md
+++ b/BUILD.md
@@ -34,8 +34,8 @@ make release
Third-party libraries used
--------------------------
-- [mattn/go-runewidth](https://github.com/mattn/go-runewidth)
- - Licensed under [MIT](http://mattn.mit-license.org)
+- [rivo/uniseg](https://github.com/rivo/uniseg)
+ - Licensed under [MIT](https://raw.githubusercontent.com/rivo/uniseg/master/LICENSE.txt)
- [mattn/go-shellwords](https://github.com/mattn/go-shellwords)
- Licensed under [MIT](http://mattn.mit-license.org)
- [mattn/go-isatty](https://github.com/mattn/go-isatty)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 25cabe8f..fe99cc61 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,6 +31,8 @@ CHANGELOG
' --preview 'seq {} 10000' --preview-window up
```
- And we're phasing out `{fzf:prompt}` and `{fzf:action}`
+- Changed [mattn/go-runewidth](https://github.com/mattn/go-runewidth) dependency to [rivo/uniseg](https://github.com/rivo/uniseg) for accurate results
+ - Set `--ambidouble` if your terminal displays characters with East Asian Width Class Ambiguous (e.g. box-drawing characters for borders) as 2 columns
- Bug fixes
0.45.0
diff --git a/go.mod b/go.mod
index 18d4cd19..64e7e7cb 100644
--- a/go.mod
+++ b/go.mod
@@ -2,10 +2,9 @@ module github.com/junegunn/fzf
require (
github.com/gdamore/tcell/v2 v2.5.4
- github.com/junegunn/go-runewidth v0.0.15-0.20240119074001-7d2ea235ec54
+ github.com/junegunn/uniseg v0.0.0-20240120174029-b504da4f6ed2
github.com/mattn/go-isatty v0.0.17
github.com/mattn/go-shellwords v1.0.12
- github.com/rivo/uniseg v0.4.4
github.com/saracen/walker v0.1.3
golang.org/x/sys v0.16.0
golang.org/x/term v0.16.0
@@ -15,6 +14,7 @@ require (
github.com/gdamore/encoding v1.0.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
+ github.com/rivo/uniseg v0.4.4 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/text v0.5.0 // indirect
)
diff --git a/go.sum b/go.sum
index 6b920d53..9945377d 100644
--- a/go.sum
+++ b/go.sum
@@ -2,8 +2,8 @@ github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdk
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell/v2 v2.5.4 h1:TGU4tSjD3sCL788vFNeJnTdzpNKIw1H5dgLnJRQVv/k=
github.com/gdamore/tcell/v2 v2.5.4/go.mod h1:dZgRy5v4iMobMEcWNYBtREnDZAT9DYmfqIkrgEMxLyw=
-github.com/junegunn/go-runewidth v0.0.15-0.20240119074001-7d2ea235ec54 h1:eBbXiL4VPihi5C8DhESYtax8HYfgCDUkzVYigADhkzU=
-github.com/junegunn/go-runewidth v0.0.15-0.20240119074001-7d2ea235ec54/go.mod h1:Mq6NazeZhIIQPMFoInCi35AktcN/MuW2elHsDK5N52w=
+github.com/junegunn/uniseg v0.0.0-20240120174029-b504da4f6ed2 h1:oEwPBh29BPu1MaTsz2dM9bDrkOgKBoYFC0u6uY2izWo=
+github.com/junegunn/uniseg v0.0.0-20240120174029-b504da4f6ed2/go.mod h1:ywqF55XaSE3/uS2tkJqVFKiE0oIYAXRvU2N7DU4y3XQ=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
diff --git a/man/man1/fzf.1 b/man/man1/fzf.1
index 55db6d6b..6e6417c7 100644
--- a/man/man1/fzf.1
+++ b/man/man1/fzf.1
@@ -260,9 +260,8 @@ Draw border around the finder
.br
If you use a terminal emulator where each box-drawing character takes
-2 columns, try setting \fBRUNEWIDTH_EASTASIAN\fR environment variable to
-\fB0\fR or \fB1\fR. If the border is still not properly rendered, set
-\fB--no-unicode\fR.
+2 columns, try setting \fB--ambidouble\fR. If the border is still not properly
+rendered, set \fB--no-unicode\fR.
.TP
.BI "--border-label" [=LABEL]
@@ -314,6 +313,11 @@ Use ASCII characters instead of Unicode drawing characters to draw borders,
the spinner and the horizontal separator.
.TP
+.B "--ambidouble"
+Set this option if your terminal displays characters with East Asian Width
+Class Ambiguous (e.g. box-drawing characters for borders) as 2 columns.
+
+.TP
.BI "--margin=" MARGIN
Comma-separated expression for margins around the finder.
.br
diff --git a/src/options.go b/src/options.go
index b2d702d2..fc614c5b 100644
--- a/src/options.go
+++ b/src/options.go
@@ -11,8 +11,8 @@ import (
"github.com/junegunn/fzf/src/algo"
"github.com/junegunn/fzf/src/tui"
"github.com/junegunn/fzf/src/util"
+ "github.com/junegunn/uniseg"
- "github.com/junegunn/go-runewidth"
"github.com/mattn/go-shellwords"
)
@@ -337,6 +337,7 @@ type Options struct {
BorderLabel labelOpts
PreviewLabel labelOpts
Unicode bool
+ Ambidouble bool
Tabstop int
ListenAddr *listenAddress
Unsafe bool
@@ -406,6 +407,7 @@ func defaultOptions() *Options {
Margin: defaultMargin(),
Padding: defaultMargin(),
Unicode: true,
+ Ambidouble: os.Getenv("RUNEWIDTH_EASTASIAN") == "1",
Tabstop: 8,
BorderLabel: labelOpts{},
PreviewLabel: labelOpts{},
@@ -1593,8 +1595,6 @@ func parseOptions(opts *Options, allArgs []string) {
}
}
validateJumpLabels := false
- validatePointer := false
- validateMarker := false
for i := 0; i < len(allArgs); i++ {
arg := allArgs[i]
switch arg {
@@ -1774,10 +1774,8 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Prompt = nextString(allArgs, &i, "prompt string required")
case "--pointer":
opts.Pointer = firstLine(nextString(allArgs, &i, "pointer sign string required"))
- validatePointer = true
case "--marker":
opts.Marker = firstLine(nextString(allArgs, &i, "selected sign string required"))
- validateMarker = true
case "--sync":
opts.Sync = true
case "--no-sync":
@@ -1845,6 +1843,10 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Unicode = false
case "--unicode":
opts.Unicode = true
+ case "--ambidouble":
+ opts.Ambidouble = true
+ case "--no-ambidouble":
+ opts.Ambidouble = false
case "--margin":
opts.Margin = parseMargin(
"margin",
@@ -1903,10 +1905,8 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Prompt = value
} else if match, value := optString(arg, "--pointer="); match {
opts.Pointer = firstLine(value)
- validatePointer = true
} else if match, value := optString(arg, "--marker="); match {
opts.Marker = firstLine(value)
- validateMarker = true
} else if match, value := optString(arg, "-n", "--nth="); match {
opts.Nth = splitNth(value)
} else if match, value := optString(arg, "--with-nth="); match {
@@ -2013,31 +2013,31 @@ func parseOptions(opts *Options, allArgs []string) {
}
}
}
-
- if validatePointer {
- if err := validateSign(opts.Pointer, "pointer"); err != nil {
- errorExit(err.Error())
- }
- }
-
- if validateMarker {
- if err := validateSign(opts.Marker, "marker"); err != nil {
- errorExit(err.Error())
- }
- }
}
func validateSign(sign string, signOptName string) error {
if sign == "" {
return fmt.Errorf("%v cannot be empty", signOptName)
}
- if runewidth.StringWidth(sign) > 2 {
+ if uniseg.StringWidth(sign) > 2 {
return fmt.Errorf("%v display width should be up to 2", signOptName)
}
return nil
}
func postProcessOptions(opts *Options) {
+ if opts.Ambidouble {
+ uniseg.EastAsianAmbiguousWidth = 2
+ }
+
+ if err := validateSign(opts.Pointer, "pointer"); err != nil {
+ errorExit(err.Error())
+ }
+
+ if err := validateSign(opts.Marker, "marker"); err != nil {
+ errorExit(err.Error())
+ }
+
if !opts.Version && !tui.IsLightRendererSupported() && opts.Height.size > 0 {
errorExit("--height option is currently not supported on this platform")
}
@@ -2048,7 +2048,7 @@ func postProcessOptions(opts *Options) {
errorExit("--scrollbar should be given one or two characters")
}
for _, r := range runes {
- if runewidth.RuneWidth(r) != 1 {
+ if uniseg.StringWidth(string(r)) != 1 {
errorExit("scrollbar display width should be 1")
}
}
diff --git a/src/terminal.go b/src/terminal.go
index 7832cbbc..b5763aba 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -17,8 +17,7 @@ import (
"syscall"
"time"
- "github.com/junegunn/go-runewidth"
- "github.com/rivo/uniseg"
+ "github.com/junegunn/uniseg"
"github.com/junegunn/fzf/src/tui"
"github.com/junegunn/fzf/src/util"
@@ -798,7 +797,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
t.separator, t.separatorLen = t.ansiLabelPrinter(bar, &tui.ColSeparator, true)
}
if t.unicode {
- t.borderWidth = runewidth.RuneWidth('│')
+ t.borderWidth = uniseg.StringWidth("│")
}
if opts.Scrollbar == nil {
if t.unicode && t.borderWidth == 1 {
diff --git a/src/tui/light.go b/src/tui/light.go
index ae7cc0cb..5092371d 100644
--- a/src/tui/light.go
+++ b/src/tui/light.go
@@ -10,8 +10,7 @@ import (
"time"
"unicode/utf8"
- "github.com/junegunn/go-runewidth"
- "github.com/rivo/uniseg"
+ "github.com/junegunn/uniseg"
"golang.org/x/term"
)
@@ -804,7 +803,7 @@ func (w *LightWindow) drawBorderHorizontal(top, bottom bool) {
if w.preview {
color = ColPreviewBorder
}
- hw := runewidth.RuneWidth(w.border.top)
+ hw := runeWidth(w.border.top)
if top {
w.Move(0, 0)
w.CPrint(color, repeat(w.border.top, w.width/hw))
@@ -842,13 +841,13 @@ func (w *LightWindow) drawBorderAround(onlyHorizontal bool) {
if w.preview {
color = ColPreviewBorder
}
- hw := runewidth.RuneWidth(w.border.top)
- tcw := runewidth.RuneWidth(w.border.topLeft) + runewidth.RuneWidth(w.border.topRight)
- bcw := runewidth.RuneWidth(w.border.bottomLeft) + runewidth.RuneWidth(w.border.bottomRight)
+ hw := runeWidth(w.border.top)
+ tcw := runeWidth(w.border.topLeft) + runeWidth(w.border.topRight)
+ bcw := runeWidth(w.border.bottomLeft) + runeWidth(w.border.bottomRight)
rem := (w.width - tcw) % hw
w.CPrint(color, string(w.border.topLeft)+repeat(w.border.top, (w.width-tcw)/hw)+repeat(' ', rem)+string(w.border.topRight))
if !onlyHorizontal {
- vw := runewidth.RuneWidth(w.border.left)
+ vw := runeWidth(w.border.left)
for y := 1; y < w.height-1; y++ {
w.Move(y, 0)
w.CPrint(color, string(w.border.left))
@@ -1020,7 +1019,7 @@ func wrapLine(input string, prefixLength int, max int, tabstop int) []wrappedLin
} else if rs[0] == '\r' {
w++
} else {
- w = runewidth.StringWidth(str)
+ w = uniseg.StringWidth(str)
}
width += w
diff --git a/src/tui/tcell.go b/src/tui/tcell.go
index d1180ac7..917dc9cb 100644
--- a/src/tui/tcell.go
+++ b/src/tui/tcell.go
@@ -10,8 +10,7 @@ import (
"github.com/gdamore/tcell/v2/encoding"
"github.com/junegunn/fzf/src/util"
- "github.com/junegunn/go-runewidth"
- "github.com/rivo/uniseg"
+ "github.com/junegunn/uniseg"
)
func HasFullscreenRenderer() bool {
@@ -738,7 +737,7 @@ func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
style = w.normal.style()
}
- hw := runewidth.RuneWidth(w.borderStyle.top)
+ hw := runeWidth(w.borderStyle.top)
switch shape {
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderHorizontal, BorderTop:
max := right - 2*hw
@@ -773,7 +772,7 @@ func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
}
switch shape {
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble, BorderVertical, BorderRight:
- vw := runewidth.RuneWidth(w.borderStyle.right)
+ vw := runeWidth(w.borderStyle.right)
for y := top; y < bot; y++ {
_screen.SetContent(right-vw, y, w.borderStyle.right, nil, style)
}
@@ -782,8 +781,8 @@ func (w *TcellWindow) drawBorder(onlyHorizontal bool) {
switch shape {
case BorderRounded, BorderSharp, BorderBold, BorderBlock, BorderThinBlock, BorderDouble:
_screen.SetContent(left, top, w.borderStyle.topLeft, nil, style)
- _screen.SetContent(right-runewidth.RuneWidth(w.borderStyle.topRight), top, w.borderStyle.topRight, nil, style)
+ _screen.SetContent(right-runeWidth(w.borderStyle.topRight), top, w.borderStyle.topRight, nil, style)
_screen.SetContent(left, bot-1, w.borderStyle.bottomLeft, nil, style)
- _screen.SetContent(right-runewidth.RuneWidth(w.borderStyle.bottomRight), bot-1, w.borderStyle.bottomRight, nil, style)
+ _screen.SetContent(right-runeWidth(w.borderStyle.bottomRight), bot-1, w.borderStyle.bottomRight, nil, style)
}
}
diff --git a/src/tui/tui.go b/src/tui/tui.go
index 74129c16..a937e2b4 100644
--- a/src/tui/tui.go
+++ b/src/tui/tui.go
@@ -5,6 +5,8 @@ import (
"os"
"strconv"
"time"
+
+ "github.com/junegunn/uniseg"
)
// Types of user action
@@ -812,3 +814,7 @@ func initPalette(theme *ColorTheme) {
ColPreviewScrollbar = pair(theme.PreviewScrollbar, theme.PreviewBg)
ColPreviewSpinner = pair(theme.Spinner, theme.PreviewBg)
}
+
+func runeWidth(r rune) int {
+ return uniseg.StringWidth(string(r))
+}
diff --git a/src/util/util.go b/src/util/util.go
index 91884378..46950812 100644
--- a/src/util/util.go
+++ b/src/util/util.go
@@ -6,14 +6,13 @@ import (
"strings"
"time"
- "github.com/junegunn/go-runewidth"
+ "github.com/junegunn/uniseg"
"github.com/mattn/go-isatty"
- "github.com/rivo/uniseg"
)
// StringWidth returns string width where each CR/LF character takes 1 column
func StringWidth(s string) int {
- return runewidth.StringWidth(s) + strings.Count(s, "\n") + strings.Count(s, "\r")
+ return uniseg.StringWidth(s) + strings.Count(s, "\n") + strings.Count(s, "\r")
}
// RunesWidth returns runes width
@@ -165,7 +164,7 @@ func RepeatToFill(str string, length int, limit int) string {
output := strings.Repeat(str, times)
if rest > 0 {
for _, r := range str {
- rest -= runewidth.RuneWidth(r)
+ rest -= uniseg.StringWidth(string(r))
if rest < 0 {
break
}