beyondgrep / ack3

ack is a grep-like search tool optimized for source code.
https://beyondgrep.com/
Other
684 stars 66 forks source link

Feature request: Show horizontal context (and one hit per string occurrence) #234

Open forthrin opened 4 years ago

forthrin commented 4 years ago

Some times, like when Web authors think it's a good idea to put 5 megabytes of inline JSON objects on a single line in HTML files, it gets difficult to grep/ack sanely for content.

This can be resolved by introducing horizontal context, which snugly centres the desired content on the terminal line. As a related necessity (or possibly a separate option), the mode should show one search hit per occurrence on the line, as illustrated in the example below:

$ ack --horizontal-context FOO
1,40: ... lorem ipsum dolor sit amet FOO consectetur adipiscing vel ...
1,40960: ... erat velit scelerisque in FOO egestas egestas fringilla ...
1,384350: ... vel turpis nunc eget lorem FOO dolor sed viverra dolor ...
43,150: ... diam donec adipiscing tristique FOO risus egestas lorem ...

The form "line,column" can be conveniently fed to editors like nano via the "+" goto syntax.

If the found text itself surpasses terminal width, the following form would be appropriate:

$ ack --horizontal-context "var \w+ = .*;"
1,40960: ... var foo = ["foo": 1, "bar": 2 ... "almost": 999, "finished": 1000]; ...
christianlittle7 commented 2 months ago

I'd be in favor of this. I have a lot of files that I DO want to search, but when they add a full screens worth of content for a single result it kind of ruins the point of ack. I've seen some (in my opinion) janky workarounds involving piping ack and doing things similar to it, but it's absolutely not ideal.

Even a flag that can be set in ackrc that sets an amount of characters before or after to show would be awesome. Then I could set it once and forget it.

forthrin commented 2 months ago

Thanks for your +1, but wouldn't get my hopes up as this was suggested five years ago, and strictly speaking this edge case can be made with a few lines of Ruby code. Though of course it would be nice to have it in a standard utility.

[
  'hay' * 17 + 'NEEDLE' + 'hay' * 23,
  'hay' * 29 + 'NEEDLE' + 'hay' * 31
].each_with_index do |item, i|
  item.scan(/^(.*)(NEEDLE)(.*)/)
  a = format '%d,%d', i + 1, $1.length
  b = ((80 - a.length - 1 - 3 - $2.length - 3) / 2)
  puts a + ':...' + $1[-b..] + "\033[93m" + $2 + "\033[m" + $3[0..b] + '...'
end
n1vux commented 2 months ago

five years ago

(if you count ack2 suggestions, 8 years 1 month.)

There are several ugly workarounds given in comments on #325 and old ack2:596. (I don't think I've added those to the CookBook page; not all my bad ideas have made it to the CookBook! For which we should mostly be thankful.)

An additional workaround not previously mentioned is --pager='less --chop-long-lines -iR' which will frequently hide the match instead of centering but at least only uses one line, but allows arrow-key or emacs scrolling, and provides reverse video > affordances at ends of lines to show that those lines are cropped/scrollable. This is abbreviatable as less -S. ack-234-scroll-right-1 ➔➔ ack-234-scroll-right-2

Those of you even more afflicted by improperly minified JS clogging your project or archive directories than I am should probably put this in ${HOME}/.ackrc as a default, or in ./.ackrc .
(in $HOME/.ackrc, might want to include less option -F aka --quit-if-one-screen so that it DWIMishly emulates ack --nopager when vertical scroll isn't needed. Right now, I'm trying

ACK_PAGER_COLOR='less -FSiR'  ; export ACK_PAGER_COLOR

in one terminal shell to see if i like it before putting it in ~/.ackrc, but first impressions, I'm liking it! I wish I'd thought of this 5, or 8, years ago!!)

less ... -F or --quit-if-one-screen Causes less to automatically exit if the entire file can be displayed on the first screen. -S or --chop-long-lines Causes lines longer than the screen width to be chopped (truncated) rather than wrapped. That is, the portion of a long line that does not fit in the screen width is not displayed until you press RIGHT-ARROW. The default is to wrap long lines; that is, display the remainder on the next line. See also the --wordwrap option. --wordwrap When the -S option is not in use, wrap each line at a space or tab if possible, so that a word is not split between two lines. The default is to wrap at any character.

Regarding

get ... hopes up

Andy has tagged this feature and #325 also has proposed --[no]width=999 syntax, suggested for ag compatibility (which, when there isn't a grep option to be compatible with, is a decent choice), so this could happen if & when Andy or I get the tuits (or someone sends a complete Pull Request).

And I do want to see this in the next significant release, whenever that is, as this bites me too, in mirrored websites on the archive drive. (I could just --nojs when I'm not looking for javascript but that doesn't help those who care about js.)

nice to have it in a standard utility

Indeed. We should do it.

(As noted on other issues, in the half-century that computers mostly output paper, I was a big fan of KWIC/KWOC indices, and I recently even produced one in this century despite progress. Providing a trim of overly-long matching lines of (e.g. gnarly stealth-minified js) code that centered the beginning of match if trimming both ends almost would be using the KWIC affordance of aligning matches. Even better would be if less automatically centered the bold bit in -RS mode but ... that's not our circus.)

As noted, Silver Surfer ag has --width already, so for working environments with too much (stealth-)minified .js (w/o the ignorable .min.js marking), switching to ag might be advisable in the meantime, if the ACK_PAGER_COLOR workaround above isn't sufficient. (One could alias ack=ag to preserve muscle memory, or not.) ( I'm going to add an issue to add --widthag to the feature comparison table in web doc. )

few lines of Ruby

I suspect it's smol in Perl too, in isolation. If it were actually that easy, I'd have already done it, five or eight years ago! In the Ack codebase, it will interact with the bolding logic and the overlapping vertical context logic and only-show-first (or N) logic and ... etc.

FWIW, the major work in adding a small feature like this is not in coding the feature itself, but in expanding the test suite to to verify it's correct (and so stays correct when future supposedly separate changes are made), in combination with various other features. (The new feature also needs to be added to embedded and web documentation. And consideration given to what options are incompatible with it, if any; test and doc required for those combinations too. So a feature-only, no-tests PR doesn't really help a project that takes testing and documentation seriously.)