sharkdp / bat

A cat(1) clone with wings.
Apache License 2.0
49.47k stars 1.25k forks source link

Open file starting at line number #1185

Open DanielCardonaRojas opened 4 years ago

DanielCardonaRojas commented 4 years ago

First of all great work! Loving this CLI

I checked the man page and did not see an option to open a file starting a line number, otherwise if this feature does exist please document.

Kienyew commented 4 years ago

I think there's a --line-range option in bat, which might does what you need 😄

...
       -r, --line-range <N:M>...

              Only print the specified range of lines for each file. For example:

              --line-range 30:40
                     prints lines 30 to 40

              --line-range :40
                     prints lines 1 to 40

              --line-range 40:
                     prints lines 40 to the end of the file
...
DanielCardonaRojas commented 4 years ago

Kind of does but does not let scroll to lines previous to start of range.

sharkdp commented 4 years ago

You can try to use --pager=… to pass explicit options to less. Something like:

bat --pager="less -FR +10" src/assets_metadata.rs

You will need to add an offset of 3 lines for the bat header.

Andriamanitra commented 3 years ago

It would be beneficial if bat let line offset arguments pass through to less (or another pager, I think all of the most common ones use similar line offset argument syntax). This would allow users to easily get syntax highlighting from bat when an external program runs a command like $PAGER +263 /foo/bar/baz.

I specifically ran into this issue with Julia's less function -- as it stands you'd need to set $PAGER to quite an impressive bash spell in order to make this work.

sontek commented 3 years ago

@sharkdp That doesn't seem to work:

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

Page never jumps down to the line needed to start at. {2} is the correct line number because -H does work

sharkdp commented 3 years ago

If you run that with a echo in front of the bat command, you can see what the problem is. This calls less with something like

less -RF +'17'

because fzf seems to include these single quotes. Unfortunately, since there is the + in front, the whole +'17' string will be sent to less as an argument. This causes less to run the command '17' which does not scroll to line 17.

You somehow need to either teach fzf to skip adding these quotes. Or teach less to run you command anyway. I couldn't find a solution after a quick search.

QuarticCat commented 3 years ago

It seems that --pager="less -FR +10" cannot correctly handle wrappings. When there are wrapping lines, less jumps to a wrong position. This also happens when we want to set line offset in fzf because fzf doesn't know what is the actual "line". We still need a starting line number flag.

sharkdp commented 3 years ago

When there are wrapping lines, less jumps to a wrong position. This also happens when we want to set line offset in fzf because fzf doesn't know what is the actual "line". We still need a starting line number flag.

Fair point. If we would add a feature like --scroll-to <LINE>, that would be less-specific. So far, we have avoided pager-specific features. Or do you have any other ideas on how to implement this?

QuarticCat commented 3 years ago

@sharkdp Can we pass the calculated line number to the --pager flag like fzf? For example, --pager="less -FR +{l}".

sharkdp commented 3 years ago

That sounds like a cool idea. Maybe there would be more variables that could be useful:

However, how can we provide this feature by default? We would need to modify the default value for --pager to be something like

less --other --default --options +{effective-scroll-line}

But what if --scroll-to isn't used? Should we simply set effective-scroll-line = 0? What other side-effects would this have?

Also, this would require every bat user with a custom --pager command in their config to now add the new +{effective-scroll-line} argument to make --scroll-to work.

If we don't add +{effective-scroll-line} by default, users of --scroll-to would be required to specify --pager="… +{effective-scroll-line}" themselves.

QuarticCat commented 3 years ago

@sharkdp I have another proposal: make the content of --pager flag a shell script statement, and provide those variables as environment variables, so that we don't need to create one more DSL to deal with complex situations.

For example, bat --pager='less -FR ${line:++$line}'. When $line is set, this is equivalent to bat --pager='less -FR +$line'. Otherwise, this is equivalent to bat --pager='less -FR '. We can also give $line a default value 0 or 1, which will make the default --pager flag simpler. If someone's pager cannot handle these values, he can use shell script to solve this problem.

As far as I know, the configuration of fzf-tab is done this way. See https://github.com/Aloxaf/fzf-tab/wiki/Configuration

Also, this would require every bat user with a custom --pager command in their config to now add the new +{effective-scroll-line} argument to make --scroll-to work.

Maybe we can add some hints to the help message of --scroll-to to reduce confusion. Besides, if the shell that executes the pager command is fixed, it is possible to detect which variables are set but not used and prompt some warnings. But I rather not do that.

sharkdp commented 3 years ago

@QuarticCat Thank you. I think I also like this better.

Unfortunately, the questions from my comment still remain, right?

sharkdp commented 3 years ago

Maybe this also opens up some new problems though. Especially concerning cross-platform. Which shell do you call on Windows, on macOS, etc.?

QuarticCat commented 3 years ago

@sharkdp

Unfortunately, the questions from my comment still remain, right?

That's right. I have no idea how to solve them.

Which shell do you call on Windows, on macOS, etc.?

Maybe get the current shell from $SHELL env variable, and provide default config for common shells. For other shells, we fall back to a less powerful config that has no variable usage.

I don't know whether Windows has $SHELL. If not, there must be some way to determine which shell we are using.

Apart from that, users can use $BAT_SHELL to override this value, just as $BAT_PAGER and $PAGER.

Honestly, I don't like this solution. fzf-tab is a Zsh plugin so it doesn't need to consider this problem. I can't find a similar example of the situation of bat.

QuarticCat commented 3 years ago

I have a new idea. If bat has a utility to print the actual line number, we don't need to modify any flags. For example:

$ bat --pager="sh -c 'less -FR +$(bat-line --flags --line-at=15)'" --flags

Users can shorten this command by defining their own functions.

I know this is absolutely not elegant. Hope it can bring you some inspiration.

BuonOmo commented 2 years ago

For fzf users, there is actually no need for such an option. fzf's --preview-window actually solves that issue very well.

To open a preview with a fixed header (the title) and the highlighted-line in sight (at the first quarter of the preview):

rg --line-number some_regex |
    fzf \
        --delimiter=: \
        --preview='bat --color=always {1} --highlight-line={2}' \
        --preview-window='~3,+{2}+3/4'

And here's a bit more advanced function to open vscode with a similar command.

And after reading the doc, here's the explanation in fzf repo

juanMarinero commented 1 month ago

Related topic: regex-search line of file I want to open (and open it).

fzf Ctrl+T is used to search a file (or dir) based on a pattern in its name, what about to search a file based on a pattern in its written text?

rga-fzf function is great! Though, thanks @BuonOmo, I coded a short function (here) to search regex and vim open it directly at line of match

QtRoS commented 3 weeks ago

@juanMarinero thank you for mentioning rga-fzf, it's really great! It is coded directly in rga now as a separate executable. But how can I use bat as preview now? Seems there is no way...

juanMarinero commented 3 weeks ago

Hi @QtRoS ! I edited the short function I coded (here) to add a MWE and the output I see (right window is the bat preview window).

how can I use bat as preview now?

--preview='batcat --color=always {1} --highlight-line={2}' This line commands "bat" for preview in my function.

For more fzf preview-window please check the specific docu and its wiki.

About the function you mentioned of rga, I guess the answer must be related to: "--preview={preproc_exe} --pretty --context 5 {{q}} --rga-fzf-path=_{{}}" I read it diagonal, --context 5 tells rga to show 5 lines of context around each match (I think), so maybe fixing that shows whole file preview. If your question is specific to that function, please search for FAQ or issues in that rga repo. Note: rga has "a" for "all", so it's coded to be quite general purpose. For example one cannot vim a PDF result (of rga), my function can vim all (though accordingly it just rip-greps text-code files).