mirror of
https://github.com/Llewellynvdm/fzf.git
synced 2025-02-08 15:08:30 +00:00
Add --header-lines-border to separate two headers
Examples: # Border only around the header from --header-lines seq 10 | fzf --header 'hello' --header-lines 2 --header-lines-border # Both headers with borders seq 10 | fzf --header 'hello' --header-lines 2 --header-border --header-lines-border # Use 'none' to still separate two headers but without a border seq 10 | fzf --header 'hello' --header-lines 2 --header-border --header-lines-border none --list-border
This commit is contained in:
parent
578108280e
commit
06547d0cbe
@ -929,6 +929,12 @@ Label to print on the header border
|
|||||||
.BI "\-\-header\-label\-pos" [=N[:top|bottom]]
|
.BI "\-\-header\-label\-pos" [=N[:top|bottom]]
|
||||||
Position of the header label
|
Position of the header label
|
||||||
|
|
||||||
|
.TP
|
||||||
|
.BI "\-\-header\-lines\-border" [=STYLE]
|
||||||
|
Display header from \fB--header-lines\fR with a separate border. Pass
|
||||||
|
\fBnone\fR to still separate the header lines but without a border. To combine
|
||||||
|
two headers, use \fB\-\-no\-header\-lines\-border\fR.
|
||||||
|
|
||||||
.SS SCRIPTING
|
.SS SCRIPTING
|
||||||
.TP
|
.TP
|
||||||
.BI "\-q, \-\-query=" "STR"
|
.BI "\-q, \-\-query=" "STR"
|
||||||
|
@ -164,6 +164,9 @@ Usage: fzf [options]
|
|||||||
--header-border[=STYLE] Draw border around the header section
|
--header-border[=STYLE] Draw border around the header section
|
||||||
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical|
|
[rounded|sharp|bold|block|thinblock|double|horizontal|vertical|
|
||||||
top|bottom|left|right|none] (default: rounded)
|
top|bottom|left|right|none] (default: rounded)
|
||||||
|
--header-lines-border[=STYLE]
|
||||||
|
Display header from --header-lines with a separate border.
|
||||||
|
Pass 'none' to still separate it but without a border.
|
||||||
--header-label=LABEL Label to print on the header border
|
--header-label=LABEL Label to print on the header border
|
||||||
--header-label-pos=COL Position of the header label
|
--header-label-pos=COL Position of the header label
|
||||||
[POSITIVE_INTEGER: columns from left|
|
[POSITIVE_INTEGER: columns from left|
|
||||||
@ -597,6 +600,7 @@ type Options struct {
|
|||||||
ListBorderShape tui.BorderShape
|
ListBorderShape tui.BorderShape
|
||||||
InputBorderShape tui.BorderShape
|
InputBorderShape tui.BorderShape
|
||||||
HeaderBorderShape tui.BorderShape
|
HeaderBorderShape tui.BorderShape
|
||||||
|
HeaderLinesShape tui.BorderShape
|
||||||
InputLabel labelOpts
|
InputLabel labelOpts
|
||||||
HeaderLabel labelOpts
|
HeaderLabel labelOpts
|
||||||
BorderLabel labelOpts
|
BorderLabel labelOpts
|
||||||
@ -2669,6 +2673,13 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
|
|||||||
if opts.HeaderBorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
|
if opts.HeaderBorderShape, err = parseBorder(arg, !hasArg, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
case "--no-header-lines-border":
|
||||||
|
opts.HeaderLinesShape = tui.BorderNone
|
||||||
|
case "--header-lines-border":
|
||||||
|
hasArg, arg := optionalNextString()
|
||||||
|
if opts.HeaderLinesShape, err = parseBorder(arg, !hasArg, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case "--no-header-label":
|
case "--no-header-label":
|
||||||
opts.HeaderLabel.label = ""
|
opts.HeaderLabel.label = ""
|
||||||
case "--header-label":
|
case "--header-label":
|
||||||
@ -3016,6 +3027,12 @@ func postProcessOptions(opts *Options) error {
|
|||||||
opts.HeaderBorderShape = tui.BorderNone
|
opts.HeaderBorderShape = tui.BorderNone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.HeaderLinesShape == tui.BorderNone {
|
||||||
|
opts.HeaderLinesShape = tui.BorderPhantom
|
||||||
|
} else if opts.HeaderLinesShape == tui.BorderUndefined {
|
||||||
|
opts.HeaderLinesShape = tui.BorderNone
|
||||||
|
}
|
||||||
|
|
||||||
if opts.Pointer == nil {
|
if opts.Pointer == nil {
|
||||||
defaultPointer := "▌"
|
defaultPointer := "▌"
|
||||||
if !opts.Unicode {
|
if !opts.Unicode {
|
||||||
|
207
src/terminal.go
207
src/terminal.go
@ -316,6 +316,7 @@ type Terminal struct {
|
|||||||
listBorderShape tui.BorderShape
|
listBorderShape tui.BorderShape
|
||||||
inputBorderShape tui.BorderShape
|
inputBorderShape tui.BorderShape
|
||||||
headerBorderShape tui.BorderShape
|
headerBorderShape tui.BorderShape
|
||||||
|
headerLinesShape tui.BorderShape
|
||||||
listLabel labelPrinter
|
listLabel labelPrinter
|
||||||
listLabelLen int
|
listLabelLen int
|
||||||
listLabelOpts labelOpts
|
listLabelOpts labelOpts
|
||||||
@ -328,6 +329,8 @@ type Terminal struct {
|
|||||||
inputBorder tui.Window
|
inputBorder tui.Window
|
||||||
headerWindow tui.Window
|
headerWindow tui.Window
|
||||||
headerBorder tui.Window
|
headerBorder tui.Window
|
||||||
|
headerLinesWindow tui.Window
|
||||||
|
headerLinesBorder tui.Window
|
||||||
wborder tui.Window
|
wborder tui.Window
|
||||||
pborder tui.Window
|
pborder tui.Window
|
||||||
pwindow tui.Window
|
pwindow tui.Window
|
||||||
@ -864,6 +867,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
|
|||||||
listBorderShape: opts.ListBorderShape,
|
listBorderShape: opts.ListBorderShape,
|
||||||
inputBorderShape: opts.InputBorderShape,
|
inputBorderShape: opts.InputBorderShape,
|
||||||
headerBorderShape: opts.HeaderBorderShape,
|
headerBorderShape: opts.HeaderBorderShape,
|
||||||
|
headerLinesShape: opts.HeaderLinesShape,
|
||||||
borderWidth: 1,
|
borderWidth: 1,
|
||||||
listLabel: nil,
|
listLabel: nil,
|
||||||
listLabelOpts: opts.ListLabel,
|
listLabelOpts: opts.ListLabel,
|
||||||
@ -1106,7 +1110,7 @@ func (t *Terminal) visibleHeaderLines() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) visibleHeaderLinesInList() int {
|
func (t *Terminal) visibleHeaderLinesInList() int {
|
||||||
if t.headerWindow != nil {
|
if t.headerWindow != nil || t.headerLinesWindow != nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return t.visibleHeaderLines()
|
return t.visibleHeaderLines()
|
||||||
@ -1114,15 +1118,22 @@ func (t *Terminal) visibleHeaderLinesInList() int {
|
|||||||
|
|
||||||
// Extra number of lines needed to display fzf
|
// Extra number of lines needed to display fzf
|
||||||
func (t *Terminal) extraLines() int {
|
func (t *Terminal) extraLines() int {
|
||||||
extra := t.visibleHeaderLines() + 1
|
extra := 1
|
||||||
if t.inputBorderShape.Visible() {
|
if t.inputBorderShape.Visible() {
|
||||||
extra += borderLines(t.inputBorderShape)
|
extra += borderLines(t.inputBorderShape)
|
||||||
}
|
}
|
||||||
if t.listBorderShape.Visible() {
|
if t.listBorderShape.Visible() {
|
||||||
extra += borderLines(t.listBorderShape)
|
extra += borderLines(t.listBorderShape)
|
||||||
}
|
}
|
||||||
if t.headerBorderShape.Visible() {
|
if t.headerVisible {
|
||||||
extra += borderLines(t.headerBorderShape)
|
if t.hasHeaderWindow() {
|
||||||
|
extra += borderLines(t.headerBorderShape)
|
||||||
|
}
|
||||||
|
extra += len(t.header0)
|
||||||
|
if t.hasHeaderLinesWindow() {
|
||||||
|
extra += borderLines(t.headerLinesShape)
|
||||||
|
}
|
||||||
|
extra += t.headerLines
|
||||||
}
|
}
|
||||||
if !t.noSeparatorLine() {
|
if !t.noSeparatorLine() {
|
||||||
extra++
|
extra++
|
||||||
@ -1644,6 +1655,23 @@ func (t *Terminal) forceRerenderList() {
|
|||||||
t.prevLines = make([]itemLine, len(t.prevLines))
|
t.prevLines = make([]itemLine, len(t.prevLines))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) hasHeaderWindow() bool {
|
||||||
|
if !t.headerVisible {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if t.hasHeaderLinesWindow() {
|
||||||
|
return len(t.header0) > 0
|
||||||
|
}
|
||||||
|
if t.headerBorderShape.Visible() {
|
||||||
|
return len(t.header0)+t.headerLines > 0
|
||||||
|
}
|
||||||
|
return t.inputBorderShape.Visible()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) hasHeaderLinesWindow() bool {
|
||||||
|
return t.headerVisible && t.headerLines > 0 && t.headerLinesShape.Visible()
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
||||||
t.forcePreview = forcePreview
|
t.forcePreview = forcePreview
|
||||||
screenWidth, screenHeight, marginInt, paddingInt := t.adjustMarginAndPadding()
|
screenWidth, screenHeight, marginInt, paddingInt := t.adjustMarginAndPadding()
|
||||||
@ -1666,6 +1694,12 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
if t.headerBorder != nil {
|
if t.headerBorder != nil {
|
||||||
t.headerBorder = nil
|
t.headerBorder = nil
|
||||||
}
|
}
|
||||||
|
if t.headerLinesWindow != nil {
|
||||||
|
t.headerLinesWindow = nil
|
||||||
|
}
|
||||||
|
if t.headerLinesBorder != nil {
|
||||||
|
t.headerLinesBorder = nil
|
||||||
|
}
|
||||||
if t.inputWindow != nil {
|
if t.inputWindow != nil {
|
||||||
t.inputWindow = nil
|
t.inputWindow = nil
|
||||||
}
|
}
|
||||||
@ -1716,7 +1750,9 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
availableLines := height
|
availableLines := height
|
||||||
shift := 0
|
shift := 0
|
||||||
shrink := 0
|
shrink := 0
|
||||||
hasInputWindow := t.inputBorderShape.Visible() || t.headerBorderShape.Visible()
|
hasHeaderWindow := t.hasHeaderWindow()
|
||||||
|
hasHeaderLinesWindow := t.hasHeaderLinesWindow()
|
||||||
|
hasInputWindow := t.inputBorderShape.Visible() || hasHeaderWindow || hasHeaderLinesWindow
|
||||||
if hasInputWindow {
|
if hasInputWindow {
|
||||||
inputWindowHeight := 2
|
inputWindowHeight := 2
|
||||||
if t.noSeparatorLine() {
|
if t.noSeparatorLine() {
|
||||||
@ -1733,10 +1769,12 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Adjust position and size of the list window if header border is set
|
// Adjust position and size of the list window if header border is set
|
||||||
hasHeaderWindow := t.visibleHeaderLines() > 0 && (t.headerBorderShape.Visible() || t.inputBorderShape.Visible())
|
|
||||||
headerBorderHeight := 0
|
headerBorderHeight := 0
|
||||||
if hasHeaderWindow {
|
if hasHeaderWindow {
|
||||||
headerWindowHeight := t.visibleHeaderLines()
|
headerWindowHeight := t.visibleHeaderLines()
|
||||||
|
if hasHeaderLinesWindow {
|
||||||
|
headerWindowHeight -= t.headerLines
|
||||||
|
}
|
||||||
headerBorderHeight = util.Min(availableLines, borderLines(t.headerBorderShape)+headerWindowHeight)
|
headerBorderHeight = util.Min(availableLines, borderLines(t.headerBorderShape)+headerWindowHeight)
|
||||||
if t.layout == layoutReverse {
|
if t.layout == layoutReverse {
|
||||||
shift += headerBorderHeight
|
shift += headerBorderHeight
|
||||||
@ -1747,6 +1785,18 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
availableLines -= headerBorderHeight
|
availableLines -= headerBorderHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
headerLinesHeight := 0
|
||||||
|
if hasHeaderLinesWindow {
|
||||||
|
headerLinesHeight = util.Min(availableLines, borderLines(t.headerLinesShape)+t.headerLines)
|
||||||
|
if t.layout == layoutReverse {
|
||||||
|
shift += headerLinesHeight
|
||||||
|
shrink += headerLinesHeight
|
||||||
|
} else {
|
||||||
|
shrink += headerLinesHeight
|
||||||
|
}
|
||||||
|
availableLines -= headerLinesHeight
|
||||||
|
}
|
||||||
|
|
||||||
// Set up list border
|
// Set up list border
|
||||||
hasListBorder := t.listBorderShape.Visible()
|
hasListBorder := t.listBorderShape.Visible()
|
||||||
innerWidth := width
|
innerWidth := width
|
||||||
@ -1995,22 +2045,36 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
var btop int
|
var btop int
|
||||||
if hasHeaderWindow && t.headerFirst {
|
if hasHeaderWindow && t.headerFirst {
|
||||||
if t.layout == layoutReverse {
|
if t.layout == layoutReverse {
|
||||||
btop = w.Top() - inputBorderHeight
|
btop = w.Top() - inputBorderHeight - headerLinesHeight
|
||||||
} else {
|
} else {
|
||||||
btop = w.Top() + w.Height()
|
btop = w.Top() + w.Height() + headerLinesHeight
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if t.layout == layoutReverse {
|
if t.layout == layoutReverse {
|
||||||
btop = w.Top() - shrink
|
btop = w.Top() - shrink
|
||||||
} else {
|
} else {
|
||||||
btop = w.Top() + w.Height() + headerBorderHeight
|
btop = w.Top() + w.Height() + headerBorderHeight + headerLinesHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
left := w.Left()
|
||||||
|
if !t.inputBorderShape.HasLeft() && t.listBorderShape.HasLeft() {
|
||||||
|
left += t.borderWidth + 1
|
||||||
|
}
|
||||||
|
width := w.Width()
|
||||||
|
if t.listBorderShape.HasRight() && !t.inputBorderShape.HasRight() {
|
||||||
|
width -= t.borderWidth + 1
|
||||||
|
}
|
||||||
t.inputBorder = t.tui.NewWindow(
|
t.inputBorder = t.tui.NewWindow(
|
||||||
btop,
|
btop,
|
||||||
w.Left(),
|
left,
|
||||||
w.Width(),
|
width,
|
||||||
inputBorderHeight, tui.WindowInput, tui.MakeBorderStyle(t.inputBorderShape, t.unicode), true)
|
inputBorderHeight, tui.WindowInput, tui.MakeBorderStyle(t.inputBorderShape, t.unicode), true)
|
||||||
|
if left > w.Left() {
|
||||||
|
// Small box on the left to erase the residue
|
||||||
|
// e.g.
|
||||||
|
// fzf --list-border --header-border --bind 'space:change-header(hello),enter:change-header()'
|
||||||
|
t.tui.NewWindow(btop, w.Left(), left-w.Left(), inputBorderHeight, tui.WindowInput, noBorder, false).Erase()
|
||||||
|
}
|
||||||
t.inputWindow = createInnerWindow(t.inputBorder, t.inputBorderShape, tui.WindowInput)
|
t.inputWindow = createInnerWindow(t.inputBorder, t.inputBorderShape, tui.WindowInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2021,23 +2085,48 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
|
|||||||
if t.layout == layoutReverse {
|
if t.layout == layoutReverse {
|
||||||
btop = w.Top() - shrink
|
btop = w.Top() - shrink
|
||||||
} else {
|
} else {
|
||||||
btop = w.Top() + w.Height() + inputBorderHeight
|
btop = w.Top() + w.Height() + inputBorderHeight + headerLinesHeight
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if t.layout == layoutReverse {
|
if t.layout == layoutReverse {
|
||||||
btop = w.Top() - headerBorderHeight
|
btop = w.Top() - headerBorderHeight - headerLinesHeight
|
||||||
} else {
|
} else {
|
||||||
btop = w.Top() + w.Height()
|
btop = w.Top() + w.Height() + headerLinesHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
width := w.Width()
|
||||||
|
if t.listBorderShape.HasRight() && !t.headerBorderShape.HasRight() {
|
||||||
|
width -= t.borderWidth + 1
|
||||||
|
}
|
||||||
|
|
||||||
t.headerBorder = t.tui.NewWindow(
|
t.headerBorder = t.tui.NewWindow(
|
||||||
btop,
|
btop,
|
||||||
w.Left(),
|
w.Left(),
|
||||||
w.Width(),
|
width,
|
||||||
headerBorderHeight, tui.WindowHeader, tui.MakeBorderStyle(t.headerBorderShape, t.unicode), true)
|
headerBorderHeight, tui.WindowHeader, tui.MakeBorderStyle(t.headerBorderShape, t.unicode), true)
|
||||||
t.headerWindow = createInnerWindow(t.headerBorder, t.headerBorderShape, tui.WindowHeader)
|
t.headerWindow = createInnerWindow(t.headerBorder, t.headerBorderShape, tui.WindowHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up header lines border
|
||||||
|
if hasHeaderLinesWindow {
|
||||||
|
var btop int
|
||||||
|
if t.layout == layoutReverse {
|
||||||
|
btop = w.Top() - headerLinesHeight
|
||||||
|
} else {
|
||||||
|
btop = w.Top() + w.Height()
|
||||||
|
}
|
||||||
|
width := w.Width()
|
||||||
|
if t.listBorderShape.HasRight() && !t.headerLinesShape.HasRight() {
|
||||||
|
width -= t.borderWidth + 1
|
||||||
|
}
|
||||||
|
t.headerLinesBorder = t.tui.NewWindow(
|
||||||
|
btop,
|
||||||
|
w.Left(),
|
||||||
|
width,
|
||||||
|
headerLinesHeight, tui.WindowHeader, tui.MakeBorderStyle(t.headerLinesShape, t.unicode), true)
|
||||||
|
t.headerLinesWindow = createInnerWindow(t.headerLinesBorder, t.headerLinesShape, tui.WindowHeader)
|
||||||
|
}
|
||||||
|
|
||||||
// Print border label
|
// Print border label
|
||||||
t.printLabel(t.wborder, t.listLabel, t.listLabelOpts, t.listLabelLen, t.listBorderShape, false)
|
t.printLabel(t.wborder, t.listLabel, t.listLabelOpts, t.listLabelLen, t.listBorderShape, false)
|
||||||
t.printLabel(t.border, t.borderLabel, t.borderLabelOpts, t.borderLabelLen, t.borderShape, false)
|
t.printLabel(t.border, t.borderLabel, t.borderLabelOpts, t.borderLabelLen, t.borderShape, false)
|
||||||
@ -2383,23 +2472,53 @@ func (t *Terminal) printInfoImpl() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Terminal) printHeader() {
|
func (t *Terminal) printHeader() {
|
||||||
headerLines := t.visibleHeaderLines()
|
allHeaderLines := t.visibleHeaderLines()
|
||||||
if t.headerBorderShape.Visible() && (t.headerWindow == nil && headerLines > 0 || t.headerWindow != nil && headerLines != t.headerWindow.Height()) {
|
primaryHeaderLines := allHeaderLines
|
||||||
|
if t.headerLinesShape.Visible() {
|
||||||
|
primaryHeaderLines -= t.headerLines
|
||||||
|
}
|
||||||
|
// We may need to resize header windows
|
||||||
|
if (t.headerBorderShape.Visible() || t.headerLinesShape.Visible()) &&
|
||||||
|
(t.headerWindow == nil && primaryHeaderLines > 0 || t.headerWindow != nil && primaryHeaderLines != t.headerWindow.Height()) ||
|
||||||
|
t.headerLinesShape.Visible() && (t.headerLinesWindow == nil && t.headerLines > 0 || t.headerLinesWindow != nil && t.headerLines != t.headerLinesWindow.Height()) {
|
||||||
t.resizeWindows(false, true)
|
t.resizeWindows(false, true)
|
||||||
t.printList()
|
t.printList()
|
||||||
t.printPrompt()
|
t.printPrompt()
|
||||||
t.printInfo()
|
t.printInfo()
|
||||||
t.printPreview()
|
t.printPreview()
|
||||||
}
|
}
|
||||||
t.withWindow(t.headerWindow, func() { t.printHeaderImpl() })
|
if !t.headerVisible {
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Terminal) printHeaderImpl() {
|
|
||||||
if t.visibleHeaderLines() == 0 {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.withWindow(t.headerWindow, func() {
|
||||||
|
var lines []string
|
||||||
|
if !t.headerLinesShape.Visible() {
|
||||||
|
lines = t.header
|
||||||
|
}
|
||||||
|
t.printHeaderImpl(t.headerWindow, t.headerBorderShape, t.header0, lines)
|
||||||
|
})
|
||||||
|
if t.headerLinesShape.Visible() {
|
||||||
|
t.withWindow(t.headerLinesWindow, func() {
|
||||||
|
t.printHeaderImpl(t.headerLinesWindow, t.headerLinesShape, nil, t.header)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) headerIndent(borderShape tui.BorderShape) int {
|
||||||
|
indentSize := t.pointerLen + t.markerLen
|
||||||
|
if t.listBorderShape.HasLeft() {
|
||||||
|
indentSize += 1 + t.borderWidth
|
||||||
|
}
|
||||||
|
if borderShape.HasLeft() {
|
||||||
|
indentSize -= 1 + t.borderWidth
|
||||||
|
}
|
||||||
|
return indentSize
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Terminal) printHeaderImpl(window tui.Window, borderShape tui.BorderShape, lines1 []string, lines2 []string) {
|
||||||
max := t.window.Height()
|
max := t.window.Height()
|
||||||
if t.inputWindow == nil && t.headerWindow == nil && t.headerFirst {
|
if t.inputWindow == nil && window == nil && t.headerFirst {
|
||||||
max--
|
max--
|
||||||
if !t.noSeparatorLine() {
|
if !t.noSeparatorLine() {
|
||||||
max--
|
max--
|
||||||
@ -2419,22 +2538,17 @@ func (t *Terminal) printHeaderImpl() {
|
|||||||
// fzf --header-lines 3 --style full --no-header-border
|
// fzf --header-lines 3 --style full --no-header-border
|
||||||
// fzf --header-lines 3 --style full --no-header-border --no-input-border
|
// fzf --header-lines 3 --style full --no-header-border --no-input-border
|
||||||
indentSize := t.pointerLen + t.markerLen
|
indentSize := t.pointerLen + t.markerLen
|
||||||
if t.headerWindow != nil {
|
if window != nil {
|
||||||
if t.listBorderShape.HasLeft() {
|
indentSize = t.headerIndent(borderShape)
|
||||||
indentSize += 1 + t.borderWidth
|
|
||||||
}
|
|
||||||
if t.headerBorderShape.HasLeft() {
|
|
||||||
indentSize -= 1 + t.borderWidth
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
indent := strings.Repeat(" ", indentSize)
|
indent := strings.Repeat(" ", indentSize)
|
||||||
t.wrap = false
|
t.wrap = false
|
||||||
for idx, lineStr := range append(append([]string{}, t.header0...), t.header...) {
|
for idx, lineStr := range append(append([]string{}, lines1...), lines2...) {
|
||||||
line := idx
|
line := idx
|
||||||
if needReverse && idx < len(t.header0) {
|
if needReverse && idx < len(lines1) {
|
||||||
line = len(t.header0) - idx - 1
|
line = len(lines1) - idx - 1
|
||||||
}
|
}
|
||||||
if t.inputWindow == nil && t.headerWindow == nil && !t.headerFirst {
|
if t.inputWindow == nil && window == nil && !t.headerFirst {
|
||||||
line++
|
line++
|
||||||
if !t.noSeparatorLine() {
|
if !t.noSeparatorLine() {
|
||||||
line++
|
line++
|
||||||
@ -3416,6 +3530,12 @@ func (t *Terminal) flush() {
|
|||||||
if t.headerWindow != nil {
|
if t.headerWindow != nil {
|
||||||
windows = append(windows, t.headerWindow)
|
windows = append(windows, t.headerWindow)
|
||||||
}
|
}
|
||||||
|
if t.headerLinesBorder != nil {
|
||||||
|
windows = append(windows, t.headerLinesBorder)
|
||||||
|
}
|
||||||
|
if t.headerLinesWindow != nil {
|
||||||
|
windows = append(windows, t.headerLinesWindow)
|
||||||
|
}
|
||||||
if t.inputBorder != nil {
|
if t.inputBorder != nil {
|
||||||
windows = append(windows, t.inputBorder)
|
windows = append(windows, t.inputBorder)
|
||||||
}
|
}
|
||||||
@ -5354,12 +5474,29 @@ func (t *Terminal) Loop() error {
|
|||||||
// TODO: Should we trigger this on mouse up instead?
|
// TODO: Should we trigger this on mouse up instead?
|
||||||
// Should we still trigger it when the position has changed from the down event?
|
// Should we still trigger it when the position has changed from the down event?
|
||||||
if t.headerVisible && t.headerWindow != nil && t.headerWindow.Enclose(my, mx) {
|
if t.headerVisible && t.headerWindow != nil && t.headerWindow.Enclose(my, mx) {
|
||||||
mx -= t.headerWindow.Left() + t.pointerLen + t.markerLen
|
mx -= t.headerWindow.Left() + t.headerIndent(t.headerBorderShape)
|
||||||
my -= t.headerWindow.Top()
|
my -= t.headerWindow.Top()
|
||||||
if mx < 0 {
|
if mx < 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
t.clickHeaderLine = my + 1
|
t.clickHeaderLine = my + 1
|
||||||
|
if t.layout != layoutReverse && t.headerLinesWindow != nil {
|
||||||
|
t.clickHeaderLine += t.headerLines
|
||||||
|
}
|
||||||
|
t.clickHeaderColumn = mx + 1
|
||||||
|
return doActions(actionsFor(tui.ClickHeader))
|
||||||
|
}
|
||||||
|
|
||||||
|
if t.headerVisible && t.headerLinesWindow != nil && t.headerLinesWindow.Enclose(my, mx) {
|
||||||
|
mx -= t.headerLinesWindow.Left() + t.headerIndent(t.headerLinesShape)
|
||||||
|
my -= t.headerLinesWindow.Top()
|
||||||
|
if mx < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
t.clickHeaderLine = my + 1
|
||||||
|
if t.layout == layoutReverse {
|
||||||
|
t.clickHeaderLine += len(t.header0)
|
||||||
|
}
|
||||||
t.clickHeaderColumn = mx + 1
|
t.clickHeaderColumn = mx + 1
|
||||||
return doActions(actionsFor(tui.ClickHeader))
|
return doActions(actionsFor(tui.ClickHeader))
|
||||||
}
|
}
|
||||||
|
@ -376,6 +376,7 @@ const (
|
|||||||
BorderUndefined BorderShape = iota
|
BorderUndefined BorderShape = iota
|
||||||
BorderLine
|
BorderLine
|
||||||
BorderNone
|
BorderNone
|
||||||
|
BorderPhantom
|
||||||
BorderRounded
|
BorderRounded
|
||||||
BorderSharp
|
BorderSharp
|
||||||
BorderBold
|
BorderBold
|
||||||
@ -392,7 +393,7 @@ const (
|
|||||||
|
|
||||||
func (s BorderShape) HasLeft() bool {
|
func (s BorderShape) HasLeft() bool {
|
||||||
switch s {
|
switch s {
|
||||||
case BorderNone, BorderLine, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
|
case BorderNone, BorderPhantom, BorderLine, BorderRight, BorderTop, BorderBottom, BorderHorizontal: // No Left
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -400,7 +401,7 @@ func (s BorderShape) HasLeft() bool {
|
|||||||
|
|
||||||
func (s BorderShape) HasRight() bool {
|
func (s BorderShape) HasRight() bool {
|
||||||
switch s {
|
switch s {
|
||||||
case BorderNone, BorderLine, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
|
case BorderNone, BorderPhantom, BorderLine, BorderLeft, BorderTop, BorderBottom, BorderHorizontal: // No right
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -408,7 +409,7 @@ func (s BorderShape) HasRight() bool {
|
|||||||
|
|
||||||
func (s BorderShape) HasTop() bool {
|
func (s BorderShape) HasTop() bool {
|
||||||
switch s {
|
switch s {
|
||||||
case BorderNone, BorderLine, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
|
case BorderNone, BorderPhantom, BorderLine, BorderLeft, BorderRight, BorderBottom, BorderVertical: // No top
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -416,7 +417,7 @@ func (s BorderShape) HasTop() bool {
|
|||||||
|
|
||||||
func (s BorderShape) HasBottom() bool {
|
func (s BorderShape) HasBottom() bool {
|
||||||
switch s {
|
switch s {
|
||||||
case BorderNone, BorderLine, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
|
case BorderNone, BorderPhantom, BorderLine, BorderLeft, BorderRight, BorderTop, BorderVertical: // No bottom
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@ -441,7 +442,7 @@ type BorderStyle struct {
|
|||||||
type BorderCharacter int
|
type BorderCharacter int
|
||||||
|
|
||||||
func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
func MakeBorderStyle(shape BorderShape, unicode bool) BorderStyle {
|
||||||
if shape == BorderNone {
|
if shape == BorderNone || shape == BorderPhantom {
|
||||||
return BorderStyle{
|
return BorderStyle{
|
||||||
shape: shape,
|
shape: shape,
|
||||||
top: ' ',
|
top: ' ',
|
||||||
|
198
test/test_go.rb
198
test/test_go.rb
@ -3600,6 +3600,180 @@ class TestGoFZF < TestBase
|
|||||||
tmux.until { assert_block(block, _1) }
|
tmux.until { assert_block(block, _1) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_header_border_toggle
|
||||||
|
tmux.send_keys %(seq 100 | #{FZF} --list-border rounded --header-border rounded --bind 'space:change-header(hello),enter:change-header()'), :Enter
|
||||||
|
block1 = <<~BLOCK
|
||||||
|
│ 5
|
||||||
|
│ 4
|
||||||
|
│ 3
|
||||||
|
│ 2
|
||||||
|
│ > 1
|
||||||
|
│ 100/100 ─
|
||||||
|
│ >
|
||||||
|
╰────────────
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Space
|
||||||
|
block2 = <<~BLOCK
|
||||||
|
│ 3
|
||||||
|
│ 2
|
||||||
|
│ > 1
|
||||||
|
╰────────────
|
||||||
|
╭────────────
|
||||||
|
│ hello
|
||||||
|
╰────────────
|
||||||
|
100/100 ─
|
||||||
|
>
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block2, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Enter
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_header_border_toggle_with_header_lines
|
||||||
|
tmux.send_keys %(seq 100 | #{FZF} --list-border rounded --header-border rounded --bind 'space:change-header(hello),enter:change-header()' --header-lines 2), :Enter
|
||||||
|
block1 = <<~BLOCK
|
||||||
|
│ 5
|
||||||
|
│ 4
|
||||||
|
│ > 3
|
||||||
|
╰──────────
|
||||||
|
╭──────────
|
||||||
|
│ 2
|
||||||
|
│ 1
|
||||||
|
╰──────────
|
||||||
|
98/98 ─
|
||||||
|
>
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Space
|
||||||
|
block2 = <<~BLOCK
|
||||||
|
│ 4
|
||||||
|
│ > 3
|
||||||
|
╰──────────
|
||||||
|
╭──────────
|
||||||
|
│ 2
|
||||||
|
│ 1
|
||||||
|
│ hello
|
||||||
|
╰──────────
|
||||||
|
98/98 ─
|
||||||
|
>
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block2, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Enter
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_header_border_toggle_with_header_lines_header_first
|
||||||
|
tmux.send_keys %(seq 100 | #{FZF} --list-border rounded --header-border rounded --bind 'space:change-header(hello),enter:change-header()' --header-lines 2 --header-first), :Enter
|
||||||
|
block1 = <<~BLOCK
|
||||||
|
│ 5
|
||||||
|
│ 4
|
||||||
|
│ > 3
|
||||||
|
╰──────────
|
||||||
|
98/98 ─
|
||||||
|
>
|
||||||
|
╭──────────
|
||||||
|
│ 2
|
||||||
|
│ 1
|
||||||
|
╰──────────
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Space
|
||||||
|
block2 = <<~BLOCK
|
||||||
|
│ 4
|
||||||
|
│ > 3
|
||||||
|
╰──────────
|
||||||
|
98/98 ─
|
||||||
|
>
|
||||||
|
╭──────────
|
||||||
|
│ 2
|
||||||
|
│ 1
|
||||||
|
│ hello
|
||||||
|
╰──────────
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block2, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Enter
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_header_border_toggle_with_header_lines_header_lines_border
|
||||||
|
tmux.send_keys %(seq 100 | #{FZF} --list-border rounded --header-border rounded --bind 'space:change-header(hello),enter:change-header()' --header-lines 2 --header-lines-border double), :Enter
|
||||||
|
block1 = <<~BLOCK
|
||||||
|
│ 5
|
||||||
|
│ 4
|
||||||
|
│ > 3
|
||||||
|
╰──────────
|
||||||
|
╔══════════
|
||||||
|
║ 2
|
||||||
|
║ 1
|
||||||
|
╚══════════
|
||||||
|
98/98 ─
|
||||||
|
>
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Space
|
||||||
|
block2 = <<~BLOCK
|
||||||
|
│ > 3
|
||||||
|
╰──────────
|
||||||
|
╔══════════
|
||||||
|
║ 2
|
||||||
|
║ 1
|
||||||
|
╚══════════
|
||||||
|
╭──────────
|
||||||
|
│ hello
|
||||||
|
╰──────────
|
||||||
|
98/98 ─
|
||||||
|
>
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block2, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Enter
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_header_border_toggle_with_header_lines_header_first_header_lines_border
|
||||||
|
tmux.send_keys %(seq 100 | #{FZF} --list-border rounded --header-border rounded --bind 'space:change-header(hello),enter:change-header()' --header-lines 2 --header-first --header-lines-border double), :Enter
|
||||||
|
block1 = <<~BLOCK
|
||||||
|
│ 5
|
||||||
|
│ 4
|
||||||
|
│ > 3
|
||||||
|
╰──────────
|
||||||
|
╔══════════
|
||||||
|
║ 2
|
||||||
|
║ 1
|
||||||
|
╚══════════
|
||||||
|
98/98 ─
|
||||||
|
>
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Space
|
||||||
|
block2 = <<~BLOCK
|
||||||
|
│ > 3
|
||||||
|
╰──────────
|
||||||
|
╔══════════
|
||||||
|
║ 2
|
||||||
|
║ 1
|
||||||
|
╚══════════
|
||||||
|
98/98 ─
|
||||||
|
>
|
||||||
|
╭──────────
|
||||||
|
│ hello
|
||||||
|
╰──────────
|
||||||
|
BLOCK
|
||||||
|
tmux.until { assert_block(block2, _1) }
|
||||||
|
|
||||||
|
tmux.send_keys :Enter
|
||||||
|
tmux.until { assert_block(block1, _1) }
|
||||||
|
end
|
||||||
|
|
||||||
def test_header_border_and_label_header_first
|
def test_header_border_and_label_header_first
|
||||||
tmux.send_keys %(seq 100 | #{FZF} --border rounded --header-lines 3 --header-border sharp --header-label header --header-label-pos 2:bottom --query 1 --padding 1,2 --header-first), :Enter
|
tmux.send_keys %(seq 100 | #{FZF} --border rounded --header-lines 3 --header-border sharp --header-label header --header-label-pos 2:bottom --query 1 --padding 1,2 --header-first), :Enter
|
||||||
block = <<~BLOCK
|
block = <<~BLOCK
|
||||||
@ -3625,16 +3799,16 @@ class TestGoFZF < TestBase
|
|||||||
│ ║ 12
|
│ ║ 12
|
||||||
│ ║ 11
|
│ ║ 11
|
||||||
│ ║ > 10
|
│ ║ > 10
|
||||||
│ ╚list════
|
│ ╚list══════
|
||||||
│ ┌────────
|
│ ┌──────────
|
||||||
│ │ 3
|
│ │ 3
|
||||||
│ │ 2
|
│ │ 2
|
||||||
│ │ 1
|
│ │ 1
|
||||||
│ └header──
|
│ └header────
|
||||||
│ 19/97 ─
|
│ 19/97 ─
|
||||||
│ > 1
|
│ > 1
|
||||||
│
|
│
|
||||||
╰────────────
|
╰──────────────
|
||||||
BLOCK
|
BLOCK
|
||||||
tmux.until { assert_block(block, _1) }
|
tmux.until { assert_block(block, _1) }
|
||||||
end
|
end
|
||||||
@ -3645,16 +3819,16 @@ class TestGoFZF < TestBase
|
|||||||
│ ║ 12
|
│ ║ 12
|
||||||
│ ║ 11
|
│ ║ 11
|
||||||
│ ║ > 10
|
│ ║ > 10
|
||||||
│ ╚list════
|
│ ╚list══════
|
||||||
│ 19/97 ─
|
│ 19/97 ─
|
||||||
│ > 1
|
│ > 1
|
||||||
│ ┌────────
|
│ ┌──────────
|
||||||
│ │ 3
|
│ │ 3
|
||||||
│ │ 2
|
│ │ 2
|
||||||
│ │ 1
|
│ │ 1
|
||||||
│ └header──
|
│ └header────
|
||||||
│
|
│
|
||||||
╰────────────
|
╰──────────────
|
||||||
BLOCK
|
BLOCK
|
||||||
tmux.until { assert_block(block, _1) }
|
tmux.until { assert_block(block, _1) }
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user