ripgrep
ripgrep copied to clipboard
invoke a pager to display results
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?
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.)
Indeed, I will probably alias rg to rg -p. Still, automatic paging is quite nice :-)
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 That is pretty slick. It won't work on Windows though. Doing it only on *nix is an option if we decide to proceed.
git does it the same way I believe, makes sure that the pager is the parent process.
+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 If you use less -R, does that help with the stray colors?
@BurntSushi Thanks, that does work :)
More typing than I would like. /me lazy ;) But it works!
@JohnVillalovos Yeah, I have alias less="less -R" in my .bashrc. :-)
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?
Oh.. oh.. :tired_face:
any brown paper bags available?
Hint: I made it spawn itself recursively. sigh.
I also support this feature, missing it badly from ag and git grep.
@bluss Perhaps as a function instead? Got this in .zshrc, works well.
function rg()
{
/usr/local/bin/rg -p "$@" | more -R
}
I use this in my bin directory, works well
#!/bin/sh
~/.cargo/bin/rg -p "$@" | less -RFX
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.
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)
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.
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.
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.)
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.
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.
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....
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. :-)
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.
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.)
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
}
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
}
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 quitlessif the entire example fits on the first page-X: do not use init/deinit strings; in other words: do not clear the screen-K: exitlessin response to Ctrl-C (^C)
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
}
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.