summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2021-11-03 21:19:22 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2021-11-03 21:19:22 +0900
commit7bff4661f6961fa9a7aad83f8cabc1bc6eb5c787 (patch)
tree7858e97bb3924e97747532afea8c83649c14d067
parentffd8bef8085cceedb1c3398cd478a78f5582cafd (diff)
Add --header-first option to display header before prompt line
Close #2422
-rw-r--r--CHANGELOG.md6
-rw-r--r--man/man1/fzf.15
-rw-r--r--src/options.go7
-rw-r--r--src/terminal.go43
-rwxr-xr-xtest/test_go.rb33
5 files changed, 83 insertions, 11 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 13f0615a..2b2d20ce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,8 +1,12 @@
CHANGELOG
=========
-0.27.4
+0.28.0
------
+- Added `--header-first` option to print header before the prompt line
+ ```sh
+ fzf --header $'Welcome to fzf\n▔▔▔▔▔▔▔▔▔▔▔▔▔▔' --reverse --height 30% --border --header-first
+ ```
- Added `--scroll-off=LINES` option (similar to `scrolloff` option of Vim)
- You can set it to a very large number so that the cursor stays in the
middle of the screen while scrolling
diff --git a/man/man1/fzf.1 b/man/man1/fzf.1
index 975018b3..b4721d04 100644
--- a/man/man1/fzf.1
+++ b/man/man1/fzf.1
@@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
..
-.TH fzf 1 "Nov 2021" "fzf 0.27.4" "fzf - a command-line fuzzy finder"
+.TH fzf 1 "Nov 2021" "fzf 0.28.0" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
@@ -299,6 +299,9 @@ are not affected by \fB--with-nth\fR. ANSI color codes are processed even when
The first N lines of the input are treated as the sticky header. When
\fB--with-nth\fR is set, the lines are transformed just like the other
lines that follow.
+.TP
+.B "--header-first"
+Print header before the prompt line
.SS Display
.TP
.B "--ansi"
diff --git a/src/options.go b/src/options.go
index daa4fe07..e2c03dd9 100644
--- a/src/options.go
+++ b/src/options.go
@@ -69,6 +69,7 @@ const usage = `usage: fzf [options]
--marker=STR Multi-select marker (default: '>')
--header=STR String to print as header
--header-lines=N The first N lines of the input are treated as header
+ --header-first Print header before the prompt line
Display
--ansi Enable processing of ANSI color codes
@@ -225,6 +226,7 @@ type Options struct {
History *History
Header []string
HeaderLines int
+ HeaderFirst bool
Margin [4]sizeSpec
Padding [4]sizeSpec
BorderShape tui.BorderShape
@@ -287,6 +289,7 @@ func defaultOptions() *Options {
History: nil,
Header: make([]string, 0),
HeaderLines: 0,
+ HeaderFirst: false,
Margin: defaultMargin(),
Padding: defaultMargin(),
Unicode: true,
@@ -1427,6 +1430,10 @@ func parseOptions(opts *Options, allArgs []string) {
case "--header-lines":
opts.HeaderLines = atoi(
nextString(allArgs, &i, "number of header lines required"))
+ case "--header-first":
+ opts.HeaderFirst = true
+ case "--no-header-first":
+ opts.HeaderFirst = false
case "--preview":
opts.Preview.command = nextString(allArgs, &i, "preview command required")
case "--no-preview":
diff --git a/src/terminal.go b/src/terminal.go
index 1af399a0..2bad5d75 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -140,6 +140,8 @@ type Terminal struct {
printQuery bool
history *History
cycle bool
+ headerFirst bool
+ headerLines int
header []string
header0 []string
ansi bool
@@ -529,6 +531,8 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
paused: opts.Phony,
strong: strongAttr,
cycle: opts.Cycle,
+ headerFirst: opts.HeaderFirst,
+ headerLines: opts.HeaderLines,
header: header,
header0: header,
ansi: opts.Ansi,
@@ -976,12 +980,23 @@ func (t *Terminal) updatePromptOffset() ([]rune, []rune) {
return before, after
}
+func (t *Terminal) promptLine() int {
+ if t.headerFirst {
+ max := t.window.Height() - 1
+ if !t.noInfoLine() {
+ max--
+ }
+ return util.Min(len(t.header0)+t.headerLines, max)
+ }
+ return 0
+}
+
func (t *Terminal) placeCursor() {
- t.move(0, t.promptLen+t.queryLen[0], false)
+ t.move(t.promptLine(), t.promptLen+t.queryLen[0], false)
}
func (t *Terminal) printPrompt() {
- t.move(0, 0, true)
+ t.move(t.promptLine(), 0, true)
t.prompt()
before, after := t.updatePromptOffset()
@@ -1003,22 +1018,23 @@ func (t *Terminal) trimMessage(message string, maxWidth int) string {
func (t *Terminal) printInfo() {
pos := 0
+ line := t.promptLine()
switch t.infoStyle {
case infoDefault:
- t.move(1, 0, true)
+ t.move(line+1, 0, true)
if t.reading {
duration := int64(spinnerDuration)
idx := (time.Now().UnixNano() % (duration * int64(len(t.spinner)))) / duration
t.window.CPrint(tui.ColSpinner, t.spinner[idx])
}
- t.move(1, 2, false)
+ t.move(line+1, 2, false)
pos = 2
case infoInline:
pos = t.promptLen + t.queryLen[0] + t.queryLen[1] + 1
if pos+len(" < ") > t.window.Width() {
return
}
- t.move(0, pos, true)
+ t.move(line, pos, true)
if t.reading {
t.window.CPrint(tui.ColSpinner, " < ")
} else {
@@ -1061,11 +1077,20 @@ func (t *Terminal) printHeader() {
return
}
max := t.window.Height()
+ if t.headerFirst {
+ max--
+ if !t.noInfoLine() {
+ max--
+ }
+ }
var state *ansiState
for idx, lineStr := range t.header {
- line := idx + 2
- if t.noInfoLine() {
- line--
+ line := idx
+ if !t.headerFirst {
+ line++
+ if !t.noInfoLine() {
+ line++
+ }
}
if line >= max {
continue
@@ -2644,7 +2669,7 @@ func (t *Terminal) Loop() {
}
}
} else if me.Down {
- if my == 0 && mx >= 0 {
+ if my == t.promptLine() && mx >= 0 {
// Prompt
t.cx = mx + t.xoffset
} else if my >= min {
diff --git a/test/test_go.rb b/test/test_go.rb
index e82a85c1..20a4c923 100755
--- a/test/test_go.rb
+++ b/test/test_go.rb
@@ -2109,6 +2109,39 @@ class TestGoFZF < TestBase
tmux.send_keys :Down
tmux.until { |lines| assert_equal "> #{height + 1}", lines[height / 2].strip }
end
+
+ def test_header_first
+ tmux.send_keys "seq 1000 | #{FZF} --header foobar --header-lines 3 --header-first", :Enter
+ tmux.until do |lines|
+ expected = <<~OUTPUT
+ > 4
+ 997/997
+ >
+ 3
+ 2
+ 1
+ foobar
+ OUTPUT
+
+ assert_equal expected.chomp, lines.reverse.take(7).reverse.join("\n")
+ end
+ end
+
+ def test_header_first_reverse
+ tmux.send_keys "seq 1000 | #{FZF} --header foobar --header-lines 3 --header-first --reverse --inline-info", :Enter
+ tmux.until do |lines|
+ expected = <<~OUTPUT
+ foobar
+ 1
+ 2
+ 3
+ > < 997/997
+ > 4
+ OUTPUT
+
+ assert_equal expected.chomp, lines.take(6).join("\n")
+ end
+ end
end
module TestShell