summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2025-01-15 22:23:52 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2025-01-15 22:23:52 +0900
commit9d6637c1b3b3c7c0a6eadbc73fe887e11ab14b72 (patch)
tree5965ff5a98e4dba7281a96c28474eb99df0550ea
parent56fef7c8df2713261fbdbd396aa81ed23d9a945a (diff)
downloadfzf-9d6637c1b3b3c7c0a6eadbc73fe887e11ab14b72.tar.gz
Add gap line
Close #4182
-rw-r--r--CHANGELOG.md10
-rw-r--r--src/options.go18
-rw-r--r--src/terminal.go36
-rwxr-xr-xtest/test_go.rb12
4 files changed, 66 insertions, 10 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3e30749b..75e873b2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -61,6 +61,16 @@ Also, fzf now offers "style presets" for quick customization, which can be activ
- `transform-header-label`
- Added `--preview-border[=STYLE]` as short for `--preview-window=border[-STYLE]`
- Added new preview border style `line` which draws a single separator line between the preview window and the rest of the interface
+- fzf will now render a dashed line (`┈┈`) in each `--gap` for better visual separation.
+ ```sh
+ # All bash/zsh functions, highlighted
+ declare -f |
+ perl -0 -pe 's/^}\n/}\0/gm' |
+ bat --plain --language bash --color always |
+ fzf --read0 --ansi --layout reverse --multi --highlight-line \
+ --gap
+ ```
+ * You can customize the line using `--gap-line[=STR]`.
- You can specify `border-native` to `--tmux` so that native tmux border is used instead of `--border`. This can be useful if you start a different program from inside the popup.
```sh
fzf --tmux border-native --bind 'enter:execute:less {}'
diff --git a/src/options.go b/src/options.go
index 3932cb56..470d3081 100644
--- a/src/options.go
+++ b/src/options.go
@@ -582,6 +582,7 @@ type Options struct {
HeaderLines int
HeaderFirst bool
Gap int
+ GapLine *string
Ellipsis *string
Scrollbar *string
Margin [4]sizeSpec
@@ -2567,6 +2568,15 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
}
case "--no-gap":
opts.Gap = 0
+ case "--gap-line":
+ if given, bar := optionalNextString(); given {
+ opts.GapLine = &bar
+ } else {
+ opts.GapLine = nil
+ }
+ case "--no-gap-line":
+ empty := ""
+ opts.GapLine = &empty
case "--ellipsis":
str, err := nextString("ellipsis string required")
if err != nil {
@@ -2987,6 +2997,14 @@ func postProcessOptions(opts *Options) error {
opts.Pointer = &defaultPointer
}
+ if opts.GapLine == nil {
+ defaultGapLine := "┈"
+ if !opts.Unicode {
+ defaultGapLine = "-"
+ }
+ opts.GapLine = &defaultGapLine
+ }
+
markerLen := 1
if opts.Marker == nil {
if opts.MarkerMulti != nil && opts.MarkerMulti[0] == "" {
diff --git a/src/terminal.go b/src/terminal.go
index d7ca89b6..2b86e010 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -267,6 +267,8 @@ type Terminal struct {
hscrollOff int
scrollOff int
gap int
+ gapLine labelPrinter
+ gapLineLen int
wordRubout string
wordNext string
cx int
@@ -949,6 +951,11 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
t.separator, t.separatorLen = t.ansiLabelPrinter(bar, &tui.ColSeparator, true)
}
+ // Gap line
+ if t.gap > 0 && len(*opts.GapLine) > 0 {
+ t.gapLine, t.gapLineLen = t.ansiLabelPrinter(*opts.GapLine, &tui.ColListBorder, true)
+ }
+
if opts.Ellipsis != nil {
t.ellipsis = *opts.Ellipsis
} else if t.unicode {
@@ -2446,9 +2453,7 @@ func (t *Terminal) canSpanMultiLines() bool {
return t.multiLine || t.wrap || t.gap > 0
}
-func (t *Terminal) renderEmptyLine(line int, barRange [2]int) {
- t.move(line, 0, true)
- t.markEmptyLine(line)
+func (t *Terminal) renderBar(line int, barRange [2]int) {
// If the screen is not filled with the list in non-multi-line mode,
// scrollbar is not visible at all. But in multi-line mode, we may need
// to redraw the scrollbar character at the end.
@@ -2457,6 +2462,29 @@ func (t *Terminal) renderEmptyLine(line int, barRange [2]int) {
}
}
+func (t *Terminal) renderEmptyLine(line int, barRange [2]int) {
+ t.move(line, 0, true)
+ t.markEmptyLine(line)
+ t.renderBar(line, barRange)
+}
+
+func (t *Terminal) renderGapLine(line int, barRange [2]int, drawLine bool) {
+ t.move(line, 0, false)
+ t.window.CPrint(tui.ColCursorEmpty, t.pointerEmpty)
+ t.window.Print(t.markerEmpty)
+ x := t.pointerLen + t.markerLen
+
+ width := t.window.Width() - x - 1
+ if drawLine && t.gapLine != nil {
+ t.gapLine(t.window, width)
+ } else {
+ t.move(line, x, true)
+ }
+ t.markOtherLine(line)
+ t.renderBar(line, barRange)
+ t.prevLines[line].width = width
+}
+
func (t *Terminal) printList() {
t.constrain()
barLength, barStart := t.getScrollbar()
@@ -2629,7 +2657,7 @@ func (t *Terminal) printItem(result Result, line int, maxLine int, index int, cu
}
for i := 0; i < t.gap && finalLineNum < maxLine; i++ {
finalLineNum++
- t.renderEmptyLine(finalLineNum, barRange)
+ t.renderGapLine(finalLineNum, barRange, i == t.gap-1)
}
return finalLineNum
}
diff --git a/test/test_go.rb b/test/test_go.rb
index 6a7f2ce4..2b5e0a24 100755
--- a/test/test_go.rb
+++ b/test/test_go.rb
@@ -3423,28 +3423,28 @@ class TestGoFZF < TestBase
│ >
│ 100/100 ──────
│ > 1
- │
+ │ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈
│ 2
- │
+ │ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈
│ 3
- │
+ │ ┈┈┈┈┈┈┈┈┈┈┈┈┈┈
│ 4
BLOCK
tmux.until { assert_block(block, _1) }
end
def test_gap_2
- tmux.send_keys %(seq 100 | #{FZF} --gap=2 --border --reverse), :Enter
+ tmux.send_keys %(seq 100 | #{FZF} --gap=2 --gap-line xyz --border --reverse), :Enter
block = <<~BLOCK
╭─────────────────
│ >
│ 100/100 ──────
│ > 1
- │
+ │ xyzxyzxyzxyzxy
│ 2
- │
+ │ xyzxyzxyzxyzxy
│ 3
BLOCK
tmux.until { assert_block(block, _1) }