Add --preview-wrap-sign

This commit is contained in:
Junegunn Choi committed 2026-02-19 21:30:23 +09:00
1 parent 0ecbf3f475
commit 4a195e6323
6 files changed
+74 -7

No files matched your search

+2
View File
@@ -32,6 +32,8 @@ CHANGELOG
# In the preview window
fzf --preview "printf '\e[4:3;58;2;255;0;0mRed curly underline\e[0m\n'"
```
- Added `--preview-wrap-sign` to set a different wrap indicator for the preview
window
- Added `alt-gutter` color option (#4602) (@hedgieinsocks)
- Added fish completion support (#4605) (@lalvarezt)
- zsh: Handle multi-line history selection (#4595) (@LangLangBart)
+5
View File
@@ -919,6 +919,11 @@ Should be used with one of the following \fB\-\-preview\-window\fR options.
.B * border\-bottom
.br
.TP
.BI "\-\-preview\-wrap\-sign" =INDICATOR
Indicator for wrapped lines in the preview window. If not set, the value of
\fB\-\-wrap\-sign\fR is used.
.TP
.BI "\-\-preview\-label\-pos" [=N[:top|bottom]]
Position of the border label on the border line of the preview window. Specify
+1
View File
@@ -219,6 +219,7 @@ _fzf_opts_completion() {
--with-shell
--wrap
--wrap-sign
--preview-wrap-sign
--zsh
-0 --exit-0
-1 --select-1
+8
View File
@@ -167,6 +167,7 @@ Usage: fzf [options]
--preview-label=LABEL
--preview-label-pos=N Same as --border-label and --border-label-pos,
but for preview window
--preview-wrap-sign=STR Indicator for wrapped lines in the preview window
HEADER
--header=STR String to print as header
@@ -608,6 +609,7 @@ type Options struct {
Wrap bool
WrapWord bool
WrapSign *string
PreviewWrapSign *string
MultiLine bool
CursorLine bool
KeepRight bool
@@ -3113,6 +3115,12 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
if opts.Preview.border, err = parseBorder(arg, !hasArg); err != nil {
return err
}
case "--preview-wrap-sign":
str, err := nextString("preview wrap sign required")
if err != nil {
return err
}
opts.PreviewWrapSign = &str
case "--height":
str, err := nextString("height required: [~]HEIGHT[%]")
if err != nil {
+44
View File
@@ -464,6 +464,50 @@ func TestPreviewOpts(t *testing.T) {
}
}
func TestPreviewWrapSign(t *testing.T) {
// Default: no preview wrap sign override
opts := optsFor()
if opts.PreviewWrapSign != nil {
t.Errorf("expected nil PreviewWrapSign, got %v", *opts.PreviewWrapSign)
}
// --preview-wrap-sign sets PreviewWrapSign
opts = optsFor("--preview-wrap-sign", ">> ")
if opts.PreviewWrapSign == nil || *opts.PreviewWrapSign != ">> " {
t.Errorf("expected '>> ', got %v", opts.PreviewWrapSign)
}
// --preview-wrap-sign is independent of --wrap-sign
opts = optsFor("--wrap-sign", "| ", "--preview-wrap-sign", ">> ")
if opts.WrapSign == nil || *opts.WrapSign != "| " {
t.Errorf("expected WrapSign '| ', got %v", opts.WrapSign)
}
if opts.PreviewWrapSign == nil || *opts.PreviewWrapSign != ">> " {
t.Errorf("expected PreviewWrapSign '>> ', got %v", opts.PreviewWrapSign)
}
// --preview-wrap-sign without --wrap-sign
opts = optsFor("--preview-wrap-sign", "→ ")
if opts.WrapSign != nil {
t.Errorf("expected nil WrapSign, got %v", *opts.WrapSign)
}
if opts.PreviewWrapSign == nil || *opts.PreviewWrapSign != "→ " {
t.Errorf("expected PreviewWrapSign '→ ', got %v", opts.PreviewWrapSign)
}
// Last --preview-wrap-sign wins
opts = optsFor("--preview-wrap-sign", "A ", "--preview-wrap-sign", "B ")
if opts.PreviewWrapSign == nil || *opts.PreviewWrapSign != "B " {
t.Errorf("expected PreviewWrapSign 'B ', got %v", opts.PreviewWrapSign)
}
// Empty string is allowed
opts = optsFor("--preview-wrap-sign", "")
if opts.PreviewWrapSign == nil || *opts.PreviewWrapSign != "" {
t.Errorf("expected empty PreviewWrapSign, got %v", opts.PreviewWrapSign)
}
}
func TestAdditiveExpect(t *testing.T) {
opts := optsFor("--expect=a", "--expect", "b", "--expect=c")
if len(opts.Expect) != 3 {
+14 -7
View File
@@ -253,6 +253,8 @@ type Terminal struct {
wrapWord bool
wrapSign string
wrapSignWidth int
previewWrapSign string
previewWrapSignWidth int
ghost string
separator labelPrinter
separatorLen int
@@ -1251,6 +1253,11 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
t.wrapSign = *opts.WrapSign
}
t.wrapSign, t.wrapSignWidth = t.processTabsStr(t.wrapSign, 0)
t.previewWrapSign = t.wrapSign
t.previewWrapSignWidth = t.wrapSignWidth
if opts.PreviewWrapSign != nil {
t.previewWrapSign, t.previewWrapSignWidth = t.processTabsStr(*opts.PreviewWrapSign, 0)
}
if opts.Scrollbar == nil {
if t.unicode && t.borderWidth == 1 {
t.scrollbar = "│"
@@ -2312,7 +2319,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)
t.pwindow.SetWrapSign(t.previewWrapSign, t.previewWrapSignWidth)
if !hadPreviewWindow {
t.pwindow.Erase()
}
@@ -4130,14 +4137,14 @@ func (t *Terminal) previewLineHeight(line string, maxWidth int) int {
// For word-wrap mode, count the sub-lines produced by word wrapping.
// Each sub-line may still char-wrap if it contains a word longer than the width.
if t.activePreviewOpts.wrapWord {
subLines := t.wordWrapAnsiLine(line, maxWidth, t.wrapSignWidth)
subLines := t.wordWrapAnsiLine(line, maxWidth, t.previewWrapSignWidth)
total := 0
for i, sub := range subLines {
prefixWidth := 0
cols := maxWidth
if i > 0 {
prefixWidth = t.wrapSignWidth
cols -= t.wrapSignWidth
prefixWidth = t.previewWrapSignWidth
cols -= t.previewWrapSignWidth
}
w := t.ansiLineWidth(sub, prefixWidth)
if cols <= 0 {
@@ -4154,7 +4161,7 @@ func (t *Terminal) previewLineHeight(line string, maxWidth int) int {
return 1
}
remaining := w - maxWidth
contWidth := max(1, maxWidth-t.wrapSignWidth)
contWidth := max(1, maxWidth-t.previewWrapSignWidth)
return 1 + (remaining+contWidth-1)/contWidth
}
@@ -4333,7 +4340,7 @@ Loop:
// Pre-split line into sub-lines for word wrapping
var subLines []string
if t.activePreviewOpts.wrapWord {
subLines = t.wordWrapAnsiLine(line, maxWidth, t.wrapSignWidth)
subLines = t.wordWrapAnsiLine(line, maxWidth, t.previewWrapSignWidth)
} else {
subLines = []string{line}
}
@@ -4341,7 +4348,7 @@ Loop:
var fillRet tui.FillReturn
wrap := t.activePreviewOpts.wrap
printWrapSign := func() {
if t.pwindow.CFill(tui.ColPreview.Fg(), tui.ColPreview.Bg(), -1, tui.Dim, t.wrapSign) == tui.FillNextLine {
if t.pwindow.CFill(tui.ColPreview.Fg(), tui.ColPreview.Bg(), -1, tui.Dim, t.previewWrapSign) == tui.FillNextLine {
t.pwindow.Move(t.pwindow.Y()-1, t.pwindow.Width())
}
fillRet = tui.FillContinue