ripgrep: --vimgrep doesn't satisfy vim's spec for multi-line searches
NOTE from BurntSushi: This issue has been re-classified as a bug that was discovered in the course of discussion. There’s too much context here to split it apart, which GitHub doesn’t really make easy to do anyway. So I’ve re-purposed this issue for the bug described in the title. The main details of the bug are described here: https://github.com/BurntSushi/ripgrep/issues/1866#issuecomment-843020533
Below is the original issue.
Describe your feature request
Vim recently added a new feature called “text properties” that can be used to highlight text. All it needs to know to highlight is:
- lnum : line number where match begins
- col : column (counted in bytes) where match begins
- end_lnum : line number where match ends
- end_col : column (counted in bytes) where match ends
Ideally there would be an option like --json-pos that just prints positions of matches for each file, perhaps in json format like following. If that is not possible or two cumbersome, is there a way I can already do this in a performance efficient way using ripgrep?
{
{
"file": "fileA.txt",
"positions": [
{
"lnum": 10,
"col": 4,
"end_lnum": 12,
"end_col": 7
},
{
"lnum": 15,
"col": 3,
"end_lnum": 15,
"end_col": 5
},
{
"lnum": 17,
"col": 12,
"end_lnum": 20,
"end_col": 10
}
]
},
{
"file": "fileB.txt",
"positions": [
{
"lnum": 1,
"col": 4,
"end_lnum": 1,
"end_col": 7
},
{
"lnum": 30,
"col": 3,
"end_lnum": 31,
"end_col": 5
}
]
}
}
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 28 (14 by maintainers)
Commits related to this issue
- printer: fix --vimgrep for multi-line mode It turned out that --vimgrep wasn't quite getting the column of each match correctly. Instead of printing column numbers relative to the current line, it wa... — committed to BurntSushi/ripgrep by BurntSushi 3 years ago
- printer: vimgrep now only prints one line It turns out that the vimgrep format really only wants one line per match, even when that match spans multiple lines. We continue to support the previous be... — committed to BurntSushi/ripgrep by BurntSushi 3 years ago
- printer: vimgrep now only prints one line It turns out that the vimgrep format really only wants one line per match, even when that match spans multiple lines. We continue to support the previous be... — committed to BurntSushi/ripgrep by BurntSushi 3 years ago
- printer: vimgrep now only prints one line It turns out that the vimgrep format really only wants one line per match, even when that match spans multiple lines. We continue to support the previous be... — committed to vors/ripgrep by BurntSushi 3 years ago
Yes, you’re right, I’m sorry. I spoke out of frustration.
Thank you for the follow up details. If you don’t mind, I’d like to classify this issue as a bug and re-purpose it to “
--vimgrepdoesn’t satisfy vim’s spec for multi-line searches.”If and when you get to a point where it’s clear that the
--jsonoutput needs more information, please open a new issue.@BurntSushi Regarding your “I don’t really know why you would expect the complete matches to not be printed.”. You are not printing complete matches, you are giving
\nsome special treatment and printing lines that don’t really “match” in rest of the industry’s terminology. In:vimgrepformat only starting lines of matches are printed, this also helps in counting the number of matches if someone uses the same output in other scripts/tools. If someone were to use use ripgrep to feed its--vimgrepoutput for 3 different consumers: 1) feed to a vim, 2) feed to another program that expects:vimgrepformat, 3) count the number of matches based on line count, in all the cases the results will be inconsistent because you aren’t really complying to:vimgrep’s format. Its never a good idea to just go by opinion (“…I don’t really know why you…”), because every format is a contract, something that ripgrep’s--vimgrepoption breaks by using its name, and describing it as such.Regarding
:vimgrep’s format, thecolthere actually refers to byteoffet/byteindex from start of line. Just FYI, so you don’t print “column number” as “character number”.But there are only two matches in the multi-line example. Hence, there should be only two lines in the
--vimgrepoutput (and not four). I would have expected to print only the line+column numbers where the match starts. Currently, every line which is part of the match is printed.In my opinion,
--vimgrepand multi-line mode can interact together. With Vim’s internal:vimgrepcommand, I get two matches (just like with ripgrep’s--jsonoption):Example file:
Open the file in Vim and run:
Vim will find the following two matches (open Vim’s
quickfixwindow with:copen):This is the same result that I also get with
--json, after transforming the byte offsets to line+column numbers.I tried to compare the behavior with GNU/grep and git-grep using their PCRE regex engines but neither one seems to work correctly.
Output:
Unfortunately, grep doesn’t provide a
--columnoption, and multi-line regex patterns work only with the-zoption which will treat the entire input as one line making it completely useless for Vim.(I will dig into your links when I get some time, and I’ll plan to have this fixed for the next release if it’s feasible to do so. I expect it will be.)
Thank you for the quick fix. But shouldn’t there be only two matches just like with the
--jsonoutput? Since the regex'foobar\nfoobar\nfoo|quux'is matched only for the firstfoobarin the first line or thequuxin the third line. Hence:or, to be consistent with the
textentry of the json output:For comparison:
Output:
@BurntSushi Your example from above doesn’t print the correct numbers with the
--vimgrepoption:Output:
I would have expected something like:
Or am I misunderstanding something here?