Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parameter or flag to scroll to certain line number #388

Closed
felipesere opened this issue Oct 29, 2018 · 15 comments
Closed

Parameter or flag to scroll to certain line number #388

felipesere opened this issue Oct 29, 2018 · 15 comments
Labels
question Further information is requested

Comments

@felipesere
Copy link

I want to use bat as part of the preview for my fzf setup in vim with ripgrep.
One of the shortcuts I am working on is search, which might get a hit somewhere in the middle of the file.

Currently, I can not find a way to tell bat which line to center on. So I might get a hit in a bunch of files, scroll through them, and then have to scroll in the preview pane to gage whether its worth opening the file. It would be awesome if I could use the line number that ripgrep finds to drive bat.

Is that a feature you would consider merging?

@sharkdp
Copy link
Owner

sharkdp commented Oct 31, 2018

"Scroll to a certain line number" is something that the pager (e.g. less) would have to do for us.

I think there are multiple ways to solve this:

  • Use bats --line-range option to select a small region around the line number you are interested in. This would probably require a little bit of scripting in your fzf-preview script that calls bat. See Print Range of Lines #159 for the original request that was also related to fzf-preview. Also see highlight individual line #175 for a follow-up request that is very related to this ticket.

  • Instruct the pager to scroll to a specific line number. With less, you could do something like this:

    bat file.cpp --pager="less +300G"
    

    (--pager is only available on master. With 0.8.0, you'd have to set the BAT_PAGER environment variable accordingly)

  • We somehow include this functionality in bat. I don't think that would be the best option, because we would still have to instruct the pager to do something, so that would probably also just work for less.

@sharkdp sharkdp added the question Further information is requested label Oct 31, 2018
@felipesere
Copy link
Author

Oh I didn't know about --line-range. That solves everything I need.

@petobens
Copy link

Hi @sharkdp! I'm trying to use less to scroll to the line returned by rg through bat as preview for fzf. However I cannot seem to make the following work:

rg --vimgrep _files | fzf --delimiter=: --preview='bat --color always --pager=\"less\ +{2}G\" {1}'

any pointers?
For the record I know I can use something like --line-range {2}:. However the latter will trim the output starting from the matched grep line whereas what I want is to have some "context" around the matching line. Thanks in advance!!

@sharkdp
Copy link
Owner

sharkdp commented Mar 17, 2019

@petobens: This could be related to #509. You could try the suggested workaround or use the latest master where the bug has already been fixed.

@petobens
Copy link

Thanks for the quick reply @sharkdp! Mmm I think I'm clearly doing something wrong since using a non-existent pager on master:

rg --vimgrep _files | fzf --delimiter=: --preview='bat --color always --pager=asdasdas {1}'

actually renders properly
image

@sharkdp
Copy link
Owner

sharkdp commented Mar 25, 2019

I think the problem is that the fzf preview window can not run an interactive application like less. The preview window is (probably) not a real terminal emulator but rather just prints the output of the command that you specify. It will call bat (and less) in non-interactive mode, just as if you would pipe the output to a file. This will cause less to just print the incoming text instead of displaying an interactive window.

If the pager in --pager=… does not exist, bat will use less.

@petobens
Copy link

So basically the suggested less +line_number doesn't seem to work with bat+fzf? Then are there plans/are you willing to consider adding a center or scrolloff parameter to the the --line-range option? I was thinking something like --line-range 1:10:20 which would scroll up/center content on line 10 while showing output between lines 1 to 20. Is that even possible? Thanks!

@sharkdp
Copy link
Owner

sharkdp commented Apr 4, 2019

So basically the suggested less +line_number doesn't seem to work with bat+fzf?

It works just fine with bat alone. As I said, the problem is the preview window.

Then are there plans/are you willing to consider adding a center or scrolloff parameter to the the --line-range option?

How would that work? We are not controlling scrolling in bat itself. That is done by the pager. And the pager does not run properly in your example (due to fzfs preview window).

@petobens
Copy link

petobens commented Apr 4, 2019

Oh ok. Thanks for the explanation.

@avdv
Copy link

avdv commented May 3, 2019

Hi.

I am also looking for such a feature. Currently I am using a script which does a best effort centering for the preview inside fzf. But it would be much easier and better if bat could do it itself.

How would that work? We are not controlling scrolling in bat itself.

"Scrolling" is a misleading term in this context. No pager involved either. It's basically a special handling for a line range we are after. Let me explain...

The preview of fzf is a fixed size area where the output of bat is rendered.

That just requires to compute the start and end offsets for the --line-range option according the the height (/ width) constraints of the preview area in respect to the target line.

For example, when the preview area is 20 lines, and we want to preview line 50 of a large file, then bat should skip to line 40 and render 20 lines (+/- header if enabled plus taking line wrapping into account). That way line 50 of the file would be centered in the preview area of fzf.

Something like this: --line-range @50 could do the trick. Taking the width and height from the $COLUMN and $LINES variable, respectively.

What do you think @sharkdp ?

@sharkdp
Copy link
Owner

sharkdp commented May 10, 2019

Using $COLUMNS and $LINES is problematic (junegunn/fzf@8dc1377) and $FZF_PREVIEW_* is very fzf specific.

I tend to think that this is actually better solved with a script. This would be similar to https://github.com/junegunn/fzf.vim/blob/master/bin/preview.sh but use bats --line-range option (after doing some computations, involving things like subtracting a few lines if the header is shown). It would be great if such a script could be added to this repository (maybe doc/fzf-preview.sh).

One thing that complicates everything is bats wrapping, I agree. For simplicity, I would probably start by turning it off.

Another cool thing that could be added to such a script would be --highlight-line to highight that central line.

@AdamBD
Copy link

AdamBD commented Jul 1, 2020

Did this ever go anywhere?

@avdv
Copy link

avdv commented Jul 1, 2020

I am using this little script:

#!/usr/bin/env bash

set -eEuCo pipefail

declare -r file=$1
declare -i -r line=$2
declare -i -r lines=$LINES

# subtract 3 for the header
declare -i center=$(( (lines - 3) / 2 ))

if [ $line -lt $center ]; then
    center=$line
fi
declare -i -r start=$(( line - center ))
declare -i -r end=$(( lines + start ))

exec bat --color always --highlight-line $line --line-range $start:$end --paging never "$file"

with fzf --preview "fzf-bat-preview {1} {2}"

@ranelpadon
Copy link

@avdv Thanks for this script. Tried using the fzf.vim preview script (https://github.com/junegunn/fzf.vim/blob/master/bin/preview.sh) but it doesn't auto-center the highlighted line when used outside of Vim.

Your script is simpler and works. Just wanna add that the complete command is:

fzf --delimiter=: --preview "fzf-bat-preview {1} {2}"

since other users might be confused and encounter errors. Cheers

@Jasha10
Copy link

Jasha10 commented Jan 29, 2022

We somehow include this functionality in bat. I don't think that would be the best option, because we would still have to instruct the pager to do something, so that would probably also just work for less.

Here is a wrapper script around bat that passes the +123g "jump-to-line" argument to less. Remaining arguments are passed to bat.

#!/usr/bin/env bash

## batpager ##

# Wrapper around `bat` that can be used with the $PAGER variable.
# Reference: https://github.com/sharkdp/bat/issues/388#issuecomment-1024923102
#
# The motivation for this script is that setting `PAGER=bat` does not handle
# jump-to-line directives properly: running `bat +123 myfile` fails to jump to
# line 123 the way that `less +123 myfile` would.  The goal is for `batpager
# myfile +123` to fill this niche.

# Usage is as follows:
# $ chmod +x batpager
# $ batpager +80g my_file1 my_file2
# ...  # colorizes with bat, uses less to jump to line 80

set -euo pipefail

if [[ $1 =~ ^\+[0-9]+[gpP]?$ ]]
then
    bat --style=plain --pager="less $1 -RF" "${@:2:$(($#-1))}"
    # Explanation:
    # --style=plain to omit the header, line-numbers, and border decorations
    # --pager="less ... -RF" per `bat` defaults
    # "${@...}" to pass remaining args to bat
else
    bat --style=plain --pager="less -RF" "$@"
fi

Usage is as follows:

$ chmod +x batpager
$ batpager +80g my_file1 my_file2
...  # colorizes with bat, uses less to jump to line 80

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

7 participants