diff --git a/CHANGELOG.md b/CHANGELOG.md index 9cc1af55..4e92620c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ CHANGELOG # Separator shown; no border separates the input section from the list section fzf --style full --input-border none --header foo --no-header-border + + # Conversely, separator is now shown when the input border does not draw + # a line facing the list section + fzf --input-border bottom ``` - Rendering improvements - Each frame is now wrapped in synchronized update mode (mode 2026) to reduce flickering on supported terminals diff --git a/src/options.go b/src/options.go index f67583c9..39bda044 100644 --- a/src/options.go +++ b/src/options.go @@ -3699,7 +3699,14 @@ func (opts *Options) noSeparatorLine() bool { // NOTE: This does not know that the default separator can be suppressed at // runtime (see Terminal.separatorLength), so the minimum heights derived // from it can be one line taller than strictly necessary. - sep := opts.Separator == nil && !opts.InputBorderShape.Visible() || opts.Separator != nil && len(*opts.Separator) > 0 + // + // Whether the input border draws a line on the side facing the list + // section; BorderLine always resolves to that side (see NewTerminal) + shape := opts.InputBorderShape + facingLine := shape == tui.BorderLine || + opts.Layout == layoutReverse && shape.HasBottom() || + opts.Layout != layoutReverse && shape.HasTop() + sep := opts.Separator == nil && !facingLine || opts.Separator != nil && len(*opts.Separator) > 0 return noSeparatorLine(opts.InfoStyle, sep) } diff --git a/src/terminal.go b/src/terminal.go index a4815472..4425c48a 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1714,7 +1714,9 @@ func (t *Terminal) separatorLength() int { // The default horizontal separator is redundant if the input section is // already visually separated from the list section by a border line func (t *Terminal) separatedByBorder() bool { - if t.inputBorderShape.Visible() { + // The input border itself draws a line on the side facing the list section + if t.layout == layoutReverse && t.inputBorderShape.HasBottom() || + t.layout != layoutReverse && t.inputBorderShape.HasTop() { return true } for po := &t.previewOpts; po != nil; po = po.alternative { @@ -1727,7 +1729,7 @@ func (t *Terminal) separatedByBorder() bool { } hasHeaderLinesWindow, headerLinesShape := t.determineHeaderLinesShape() hasHeaderWindow := t.hasHeaderWindow() - if !hasHeaderWindow && !hasHeaderLinesWindow { + if !t.inputBorderShape.Visible() && !hasHeaderWindow && !hasHeaderLinesWindow { // No separate window is created for the input section in this case // (see hasInputWindow in resizeWindows), i.e. the input section is // embedded in the list window and no border separates the two @@ -1736,7 +1738,11 @@ func (t *Terminal) separatedByBorder() bool { // The input section has its own window. Determine which section it is // facing, and check if the border of that section draws a line toward it. - if hasHeaderWindow && !t.headerFirst && t.headerBorderShape != tui.BorderInline { + // NOTE: hasHeaderWindow can be true with no header content when the input + // border is visible (see Terminal.hasHeaderWindow). An empty header window + // takes no space, so it cannot be the facing section. + hasHeaderSection := hasHeaderWindow && len(t.header0)+t.headerLines > 0 + if hasHeaderSection && !t.headerFirst && t.headerBorderShape != tui.BorderInline { // Header section; an inline header is not a separate section, it is // drawn inside the list border, so it falls through to the branches // below