summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2021-11-02 21:18:29 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2021-11-02 21:48:19 +0900
commit02cee2234dc85af7198f707072fd60a156fc4035 (patch)
tree27e4366b898baf6d644d9a35b00d1776d88edba6
parente0dd2be3fbf10d8125fdbaf80b62a15cc04c88b6 (diff)
Implement --scroll-off=LINES
Close #2533
-rw-r--r--man/man1/fzf.18
-rw-r--r--src/options.go14
-rw-r--r--src/terminal.go21
-rwxr-xr-xtest/test_go.rb33
4 files changed, 72 insertions, 4 deletions
diff --git a/man/man1/fzf.1 b/man/man1/fzf.1
index 1cee9d9c..975018b3 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 "Oct 2021" "fzf 0.27.3" "fzf - a command-line fuzzy finder"
+.TH fzf 1 "Nov 2021" "fzf 0.27.4" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
@@ -135,10 +135,14 @@ Enable cyclic scroll
Keep the right end of the line visible when it's too long. Effective only when
the query string is empty.
.TP
+.BI "--scroll-off=" "LINES"
+Number of screen lines to keep above or below when scrolling to the top or to
+the bottom (default: 0).
+.TP
.B "--no-hscroll"
Disable horizontal scroll
.TP
-.BI "--hscroll-off=" "COL"
+.BI "--hscroll-off=" "COLS"
Number of screen columns to keep to the right of the highlighted substring
(default: 10). Setting it to a large value will cause the text to be positioned
on the center of the screen.
diff --git a/src/options.go b/src/options.go
index 385eabc2..daa4fe07 100644
--- a/src/options.go
+++ b/src/options.go
@@ -44,8 +44,10 @@ const usage = `usage: fzf [options]
--bind=KEYBINDS Custom key bindings. Refer to the man page.
--cycle Enable cyclic scroll
--keep-right Keep the right end of the line visible on overflow
+ --scroll-off=LINES Number of screen lines to keep above or below when
+ scrolling to the top or to the bottom (default: 0)
--no-hscroll Disable horizontal scroll
- --hscroll-off=COL Number of screen columns to keep to the right of the
+ --hscroll-off=COLS Number of screen columns to keep to the right of the
highlighted substring (default: 10)
--filepath-word Make word-wise movements respect path separators
--jump-labels=CHARS Label characters for jump and jump-accept
@@ -200,6 +202,7 @@ type Options struct {
KeepRight bool
Hscroll bool
HscrollOff int
+ ScrollOff int
FileWord bool
InfoStyle infoStyle
JumpLabels string
@@ -261,6 +264,7 @@ func defaultOptions() *Options {
KeepRight: false,
Hscroll: true,
HscrollOff: 10,
+ ScrollOff: 0,
FileWord: false,
InfoStyle: infoDefault,
JumpLabels: defaultJumpLabels,
@@ -1354,6 +1358,8 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Hscroll = false
case "--hscroll-off":
opts.HscrollOff = nextInt(allArgs, &i, "hscroll offset required")
+ case "--scroll-off":
+ opts.ScrollOff = nextInt(allArgs, &i, "scroll offset required")
case "--filepath-word":
opts.FileWord = true
case "--no-filepath-word":
@@ -1530,6 +1536,8 @@ func parseOptions(opts *Options, allArgs []string) {
opts.Tabstop = atoi(value)
} else if match, value := optString(arg, "--hscroll-off="); match {
opts.HscrollOff = atoi(value)
+ } else if match, value := optString(arg, "--scroll-off="); match {
+ opts.ScrollOff = atoi(value)
} else if match, value := optString(arg, "--jump-labels="); match {
opts.JumpLabels = value
validateJumpLabels = true
@@ -1547,6 +1555,10 @@ func parseOptions(opts *Options, allArgs []string) {
errorExit("hscroll offset must be a non-negative integer")
}
+ if opts.ScrollOff < 0 {
+ errorExit("scroll offset must be a non-negative integer")
+ }
+
if opts.Tabstop < 1 {
errorExit("tab stop must be a positive integer")
}
diff --git a/src/terminal.go b/src/terminal.go
index 07fa986a..1af399a0 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -121,6 +121,7 @@ type Terminal struct {
keepRight bool
hscroll bool
hscrollOff int
+ scrollOff int
wordRubout string
wordNext string
cx int
@@ -502,6 +503,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
keepRight: opts.KeepRight,
hscroll: opts.Hscroll,
hscrollOff: opts.HscrollOff,
+ scrollOff: opts.ScrollOff,
wordRubout: wordRubout,
wordNext: wordNext,
cx: len(input),
@@ -2749,9 +2751,26 @@ func (t *Terminal) constrain() {
t.cy = util.Constrain(t.cy, 0, count-1)
- minOffset := t.cy - height + 1
+ minOffset := util.Max(t.cy-height+1, 0)
maxOffset := util.Max(util.Min(count-height, t.cy), 0)
t.offset = util.Constrain(t.offset, minOffset, maxOffset)
+ if t.scrollOff == 0 {
+ return
+ }
+
+ scrollOff := util.Min(height/2, t.scrollOff)
+ for {
+ prevOffset := t.offset
+ if t.cy-t.offset < scrollOff {
+ t.offset = util.Max(minOffset, t.offset-1)
+ }
+ if t.cy-t.offset >= height-scrollOff {
+ t.offset = util.Min(maxOffset, t.offset+1)
+ }
+ if t.offset == prevOffset {
+ break
+ }
+ }
}
func (t *Terminal) vmove(o int, allowCycle bool) {
diff --git a/test/test_go.rb b/test/test_go.rb
index 2e33185b..e82a85c1 100755
--- a/test/test_go.rb
+++ b/test/test_go.rb
@@ -2076,6 +2076,39 @@ class TestGoFZF < TestBase
tmux.send_keys 'C-t'
tmux.until { |lines| assert_includes lines[1], '4' }
end
+
+ def test_scroll_off
+ tmux.send_keys "seq 1000 | #{FZF} --scroll-off=3 --bind l:last", :Enter
+ tmux.until { |lines| assert_equal 1000, lines.item_count }
+ height = tmux.until { |lines| lines }.first.to_i
+ tmux.send_keys :PgUp
+ tmux.until do |lines|
+ assert_equal height + 3, lines.first.to_i
+ assert_equal "> #{height}", lines[3].strip
+ end
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal "> #{height + 1}", lines[3].strip }
+ tmux.send_keys 'l'
+ tmux.until { |lines| assert_equal '> 1000', lines.first.strip }
+ tmux.send_keys :PgDn
+ tmux.until { |lines| assert_equal "> #{1000 - height + 1}", lines.reverse[5].strip }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal "> #{1000 - height}", lines.reverse[5].strip }
+ end
+
+ def test_scroll_off_large
+ tmux.send_keys "seq 1000 | #{FZF} --scroll-off=9999", :Enter
+ tmux.until { |lines| assert_equal 1000, lines.item_count }
+ height = tmux.until { |lines| lines }.first.to_i
+ tmux.send_keys :PgUp
+ tmux.until { |lines| assert_equal "> #{height}", lines[height / 2].strip }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal "> #{height + 1}", lines[height / 2].strip }
+ tmux.send_keys :Up
+ tmux.until { |lines| assert_equal "> #{height + 2}", lines[height / 2].strip }
+ tmux.send_keys :Down
+ tmux.until { |lines| assert_equal "> #{height + 1}", lines[height / 2].strip }
+ end
end
module TestShell