ripgrep icon indicating copy to clipboard operation
ripgrep copied to clipboard

invoke a pager to display results

Open c-cube opened this issue 9 years ago • 47 comments
trafficstars

Just tried the tool, it's great (as is the blostpost btw). I'm usually using grep -r foo | less -R for searching (with an alias to get colored output), since there might be several pages of results; rg coloring is nice but is lost if piped into a pager. Would it make sense to invoke a pager automatically if the tool detects that its output is not piped?

c-cube avatar Sep 25 '16 17:09 c-cube

You might consider passing the -p flag to rg, which should cause it to retain its formatting.

I'm a little skeptical about actually calling a pager from within rg. That kind of seems like it's doing too much. (I will note though that git grep seems to do it, and it seems smart. It will invoke the pager automatically if there are lots of results.)

BurntSushi avatar Sep 25 '16 17:09 BurntSushi

Indeed, I will probably alias rg to rg -p. Still, automatic paging is quite nice :-)

c-cube avatar Sep 25 '16 17:09 c-cube

BTW, there is a nice way to invoke pager from rust console CLI: https://gitlab.com/imp/pager-rs it does pager instantiation in a quite clever way

ayoshi avatar Sep 25 '16 19:09 ayoshi

@ayoshi That is pretty slick. It won't work on Windows though. Doing it only on *nix is an option if we decide to proceed.

BurntSushi avatar Sep 25 '16 19:09 BurntSushi

git does it the same way I believe, makes sure that the pager is the parent process.

bluss avatar Sep 26 '16 10:09 bluss

+1 from me on having a pager. I like how "git grep" will page the results. Something like that would be nice.

I can do:

$ rg -p foo | less -r

Mostly works. But it can leave stray colors. As in my prompt becomes green.

JohnVillalovos avatar Sep 26 '16 17:09 JohnVillalovos

@JohnVillalovos If you use less -R, does that help with the stray colors?

BurntSushi avatar Sep 26 '16 17:09 BurntSushi

@BurntSushi Thanks, that does work :)

More typing than I would like. /me lazy ;) But it works!

JohnVillalovos avatar Sep 26 '16 17:09 JohnVillalovos

@JohnVillalovos Yeah, I have alias less="less -R" in my .bashrc. :-)

BurntSushi avatar Sep 26 '16 17:09 BurntSushi

um I'm trying to make a shell script for that (better than alias, available in more contexts)

#!/bin/sh

rg -p "$@" | less -R

(chmod +x that thing and call it as rg test to try). This just shows a blank terminal and seems to eat memory. Warning: If you reproduce, be sure to Ctrl-C it quick. Am I doing something wrong or what's happening?

bluss avatar Sep 26 '16 18:09 bluss

Oh.. oh.. :tired_face:

any brown paper bags available?

Hint: I made it spawn itself recursively. sigh.

bluss avatar Sep 26 '16 18:09 bluss

I also support this feature, missing it badly from ag and git grep.

kugel- avatar Sep 27 '16 08:09 kugel-

@bluss Perhaps as a function instead? Got this in .zshrc, works well.

function rg()
{
   /usr/local/bin/rg -p "$@" | more -R
}

nextlogic-ono avatar Oct 08 '16 20:10 nextlogic-ono

I use this in my bin directory, works well

#!/bin/sh

~/.cargo/bin/rg -p "$@" | less -RFX

bluss avatar Oct 08 '16 22:10 bluss

I like @bluss's approach here. I'm not strongly opposed to adding this into ripgrep itself, but it seems better to at least try and get by without doing so.

BurntSushi avatar Oct 10 '16 23:10 BurntSushi

I just noticed the need for this and augmented my config-file wrapper to also pipe the output through less -RFX if it sees -p in the options.

https://github.com/ssokolow/profile/blob/master/home/.zshrc.d/rg

(Feel free to change that. I just needed something quick and didn't think I'd ever use -p for anything other than making the colors work when piped through less.)

I still think the need for the wrapper is a bit of a wart though, given that, in the abstract, such tools are competing on how convenient they can be and my wrapper feels fundamentally no different than "Oh? You want to ignore stuff in your .gitignore? Well, we offer a command-line flag to ignore things. You're free to write a wrapper." (Reading --type-add from a config file) or "Oh? You want colored output? Well, the colordiff people showed it can be done in a wrapper." (pager support)

ssokolow avatar Mar 13 '17 22:03 ssokolow

less doesn't seem to ANSI terminal control sequences on Windows. Would be really nice to have a built-in pager.

I guess what I don't understand behind the philosophy of trying to use external utilities for paging, is that ripgrep already takes care of some presentation issues through the use of ANSI coloring.

jason-s avatar May 17 '17 14:05 jason-s

Would be really nice to have a built-in pager.

This is a completely unreasonable request, so I'm just going to nip this one right in the bud: so long as I'm the maintainer, ripgrep will never ever never get a built-in pager.

BurntSushi avatar May 17 '17 14:05 BurntSushi

less doesn't seem to ANSI terminal control sequences on Windows.

From what I remember, cmd.exe doesn't use ANSI sequences. Last time I looked at making one of my utilities do portable colorization, it seemed that cmd.exe expected you to do text colorization through a side-channel more similar to the "set pen attributes" APIs you find in things like Qt's QPainter.

(Which would mean that less would have to be color-aware enough to parse the input and convert it to an interleaved sequence of text blocks and "set color" API calls.)

ssokolow avatar May 17 '17 15:05 ssokolow

From what I remember, cmd.exe doesn't use ANSI sequences.

Well, rg itself uses colors just fine, so either it's using some other mechanism for Windows, or Windows does support ANSI terminal sequences.

I've tried updating less to the latest version I can find for Windows (v381 from UnxUpdates.zip in http://unxutils.sourceforge.net/ which does support -R and -r; my previous version only supported -r) but it still turns the ANSI sequences into visible gobbledygook.

I understand the need to keep things simple but it really impairs the usability of rg on Windows when there is a lot of output.

jason-s avatar May 17 '17 15:05 jason-s

I understand the need to keep things simple

Simplicity is only part of it. The other part of it is that you're asking me or someone else to build an entire cross platform pager into ripgrep, and then you're asking me to maintain that. It's an unreasonable request not only because it completely violates the principle of responsibility, but that's unreasonable because it would be an ungodly amount of really annoying work. On top of all of that, I don't even know that such a thing is possible in Windows.


On coloring... The standard way to color things in Windows is through the various console APIs. It's completely unlike ANSI escape sequences. Instead of putting special codes into the output text, you instead need to: 1) stop writing output, 2) ask the console to change the color to X, 3) write output again and 4) ask the console to change the color back to the setting before X.

With that said, Windows 10 has some support for ANSI escape sequences, but it needs to be explicitly enabled. Alternatively, the various MSYS2 terminals for cygwin support ANSI escape sequences.

I understand the need to keep things simple but it really impairs the usability of rg on Windows when there is a lot of output.

I've spent a ton of time making ripgrep work well on Windows, but I have to draw the line somewhere. I don't know exactly where it is, but it certainly doesn't include a built-in pager.

BurntSushi avatar May 17 '17 15:05 BurntSushi

Fair enough, that explains some of the complexity.

Maybe by the time I get a new laptop later this year and it's Windows 10 then this becomes a non-issue for me. I certainly don't defend Microsoft's decisions for brain-dead implementations of things that otherwise work very well in Unix-land.

Looks like

DOSKEY rgl=rg --color never $* ^| less

works for me in my crippled Windows 7 world....

jason-s avatar May 17 '17 15:05 jason-s

Maybe by the time I get a new laptop later this year and it's Windows 10 then this becomes a non-issue for me.

FWIW, I don't think ripgrep quite works yet with ANSI support on Windows 10. I think it really needs a champion to make it happen who knows more about how to make it work. You can force ripgrep to emit ANSI escapes with --color ansi---even on Windows---but I think you actually need to enable some config knob to make ANSI support work on Windows.

DOSKEY rgl=rg --color never $* ^| less

Oh, I thought you wanted paging with coloring. Disabling coloring is certainly one way of getting rid of the escapes. Although, I do find it interesting that you're seeing ANSI escapes at all in a Windows console. That shouldn't happen.

I certainly don't defend Microsoft's decisions for brain-dead implementations of things that otherwise work very well in Unix-land.

I won't lie, sometimes I think this way too. But I try hard not to, and try extra hard not to actually say it because it tends to just ruffle everyone's feathers. And Unix has its fair share of strange things too. :-)

BurntSushi avatar May 17 '17 15:05 BurntSushi

Well, I'd like paging with coloring if I can get it, but I need paging and if the way to do that is disabling coloring, then it works well enough for me.

Although, I do find it interesting that you're seeing ANSI escapes at all in a Windows console. That shouldn't happen.

No idea. I just use rg without options, and I get the coloring, but if I pipe it through less then I see all the ANSI-looking gobbledygook like... oh wait a minute, it disappears when I pipe it through less. I only get it when I use rg -p otherstuff | less. Sigh. Never mind.

jason-s avatar May 17 '17 15:05 jason-s

I certainly don't defend Microsoft's decisions for brain-dead implementations of things that otherwise work very well in Unix-land.

It's not always Microsoft's fault. For example, they chose \ as a path separator when they updated DOS to support directories because they were already using CP/M-style / to denote command-line switches and I remember reading that the decision to follow CP/M on that front ultimately lay with IBM.

...and, the more layers of backward-compatibility abstraction you drop below, the more POSIX-compatible modern Windows tends to get. (I assume, purely out of practicality.)

For example, as far as I've been able to determine, DOS and Windows have accepted / as a path separator in APIs where it's not ambiguous since DOS 2.0 introduced directories. It's just the command-line parsing which requires paths to use \ to avoid ambiguity.

...and kernels of the Windows NT lineage don't use drive letters internally... they're just an artifact of the Win32 API subsystem and it's possible to specify paths using an internal, singly-rooted syntax. (Though, admittedly, that is the one notable exception to the / compatibility. You have to use \ in and after the escape prefix to bypass the Win32 path rules.)

(the NT kernel was written so that Win32, OS/2-compatibie, and POSIX-compliant APIs could be offered as pluggable subsystems and NTFS actually has a POSIX "personality" where, among other things, the only disallowed filename characters are \0 and /. WSL is just the latest in a lineage of POSIX subsystem modules for the NT kernel.)

ssokolow avatar May 17 '17 15:05 ssokolow

Here how I solved this, if others are looking: I used to use ag before and defined an alias in bashrc/zshrc to "invoke ag with less":

alias agl="ag --pager='less -XFR'"

For rg I am now using:

rgl() {
  rg -p "$@" | less -XFR
}

labianchin avatar Sep 24 '17 15:09 labianchin

I argue that it would be very convenient to have it built-in. As @ssokolow said: it's about convenience.

Having said that: The following snippet (a bash function) will invoke less only when the output is a terminal. That way, there won't be strange escape sequences when redirecting stdout.

rg() {
    if [ -t 1 ]; then
        command rg -p "$@" | less -RFX
    else
        command rg "$@"
    fi
}

ibotty avatar Feb 12 '18 16:02 ibotty

IMO, ripgrep should stick with searching and not involve any pager. The output can be easily paged as discussed above.

For those of you who use Fish Shell, here's the content of your ~/.config/fish/functions/rg.fish:

function rg
  if isatty stdout
    command rg -p $argv | less -RMFXK
  else
    command rg $argv
  end
end

For those wondering, less options explained:

  • -R: support color output (ANSI color sequences)
  • -M: show line number information in the bottom of screen (current/pages X%)
  • -F: automatically quit less if the entire example fits on the first page
  • -X: do not use init/deinit strings; in other words: do not clear the screen
  • -K: exit less in response to Ctrl-C (^C)

scorphus avatar May 07 '18 08:05 scorphus

The arguments presented against fixing this issue essentially boil down to simplicity of implementation, vs user convenience.

On the other hand, it seems to me. like @ayoshi's pager-rs suggestion would be extremely simple for the implementation. I agree that implementing an entire pager in ripgrep is excessive. But forking out to something like less, on platforms where it exists, is not unreasonable (IMO).

Fixing this seems beneficial for ripgrep users. I think making every single user that wants paging reimplement git or ag paging in shell has a definite cost, and is a barrier for adoption vs something like ag. ag has substantially similar performance and at least a history of substantially better ergonomics. rg can do better than it does today :-).

For zsh users looking to work around this issue, here's what I've got in my .zprofile (it is essentially identical to @ibotty's bash function; the long options to less are just -XFR):

export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"
function rg(){
    # If outputting (fd 1 = stdout) directly to a terminal, page automatically:
    if [ -t 1 ]; then
        command rg --pretty "$@" \
            | less --no-init --quit-if-one-screen --RAW-CONTROL-CHARS
    else
        command rg "$@"
    fi
}

cemeyer avatar Sep 30 '18 19:09 cemeyer

ag has substantially similar performance and at least a history of substantially better ergonomics.

Neither of these things are obviously true to me.

The work around to this issue is simple enough that I'm fine with the status quo for now.

Complexity of implementation vs user convenience is a valid trade off to make, because we live in the real world where maintenance effort is a limited finite resource. So simply pointing to the existence of that trade off is not an effective way to convince me something.

Something that I would consider to be a constructive contribution here would be a deep dive on how other widely deployed cross platform software implements automatic paging functionality.

BurntSushi avatar Sep 30 '18 20:09 BurntSushi