Conversation
| clap = { version = "4.3.0", features = ["derive", "wrap_help"] } | ||
| encoding_rs = "0.8.14" | ||
| encoding_rs_io = "0.1.6" | ||
| grep-cli = "0.1.8" |
There was a problem hiding this comment.
This is another one of the ripgrep-derived crates
| }; | ||
|
|
||
| #[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)] | ||
| pub enum ColorChoiceArg { |
There was a problem hiding this comment.
This is almost identical to the termcolor::ColorChoice that it ends up getting mapped to but I thought it made sense not to "conflate" those since (a) there is some mapping logic involved and (b) doing it this way we can tap into clap ValueEnum stuff
| /// | ||
| /// When the --vimgrep flag is given to tree-sitter-grep, then the default | ||
| /// value for the --color flag changes to 'never'. | ||
| #[arg(long, value_name = "WHEN"/*, default_value_t = ColorChoiceArg::Auto*/)] |
There was a problem hiding this comment.
When I tried to add the default value here it complained about Display not being implemented (not sure why exactly) so I just resolved to the default at the (single) point of usage instead
There was a problem hiding this comment.
(also ended up running into the fact that the default is in fact not "static" (when in --vimgrep mode the default is ColorChoiceArg::Never instead) so using default_value_t would presumably not be appropriate, removing)
| #[arg(long)] | ||
| pub column: bool, | ||
|
|
||
| #[arg(long, hide = true, overrides_with = "column")] |
There was a problem hiding this comment.
The hide/overrides_with seem (per a little reading) to be the most reasonable way to do these --no-* argument variants
|
|
||
| impl Args { | ||
| fn use_paths(&self) -> Vec<PathBuf> { | ||
| pub fn use_paths(&self) -> Vec<PathBuf> { |
There was a problem hiding this comment.
This is getting called in a couple different places now which seems like some unnecessary repeated allocations
So maybe I should make this effectively "memoized"
There was a problem hiding this comment.
You could probably write a macro which does the once-cell thing that you want to the function it annotates?
There was a problem hiding this comment.
I certainly like that concept
Here though my instinct (now that we're starting to venture into crate-level API territory) is that we should only "cache"/"memoize" at the level of this particular Args instance (vs my understanding would be that a "purely-declarative" once-cell-ish thing would have to be using something static in "scope" under the hood?)
And so then interesting to think if that version is also something that could be expressed declaratively/via a macro
I don't know, what I'm picturing now is just an interior-mutable "private" field on Args that we call eg .get_or_init() on?
I guess you could avoid writing the .get_or_init() boilerplate (so keeping the function body as just the "actual value-calculation logic") by writing a macro eg #[memoize_via_once_cell_field(name_of_once_cell_field)]?
There was a problem hiding this comment.
Ah yeah, I didn't really think about how it'd have to be per-instance.
That seems like a reasonable approach to me (the once cell field). I wonder if clap exposes some option to call a constructor for Args so that you could at startup calculate this stuff rather than having to do it lazily. (It's not like it's not going to be used, so having to do work to make it smartly lazy seems kind of silly.)
| let path_stdin = Path::new("-"); | ||
| self.with_filename | ||
| || self.vimgrep | ||
| || paths.len() > 1 |
There was a problem hiding this comment.
And this is causing it to not show the filename in the match output when you just pass a single file path (which is what ripgrep does)
| vec![ | ||
| #[cfg(unix)] | ||
| "path:fg:magenta".parse().unwrap(), | ||
| "path:fg:green".parse().unwrap(), |
There was a problem hiding this comment.
I forgot that I had ripgrep's default colors overridden in a local config file
I can't with the default ripgrep colors they're disgusting
So this is "my" color scheme (don't remember where I got it from or if I made it up)
There was a problem hiding this comment.
Hmm ya they probably chose theirs out of trying to be light-background- vs dark-background-terminal-agnostic
But I have a hard time stomaching using their default ones
Maybe (a) a more minimal version as the default
And (b) supporting a ripgrep-style config file?
We could even be sneaky and (ultimately in addition to looking for "our own" config file) look for someone's actual ripgrep config file (on the assumption that they would like similar "defaults" applied here vs ripgrep)?
Either way the fact that with n = 2 we have different desired highlighting tells me that making it (easily, vs passing --colors every time you use it) configurable is worth doing?
There was a problem hiding this comment.
Ha yes, 100% of people want it to be configurable, I guess, and I definitely couldn't be bothered to pass --colors every time I used it.
| r#" | ||
| $ tree-sitter-grep -q '(value_argument) @c' --language swift | ||
| example.swift:2: atPath: "native" | ||
| example.swift: atPath: "native" |
There was a problem hiding this comment.
Most of the existing test output changed because (a) those tests are running in "non-terminal-output" mode and (b) now in that mode we don't show line numbers by default (like ripgrep)
| src/lib.rs-6- | ||
| src/lib.rs-7-#[cfg(test)] | ||
| src/stop.rs:fn stop_it() {} | ||
| -- |
There was a problem hiding this comment.
Per above here are some new -- separators between files when passing a "context" option
| .stdout(predicate::function(|stdout: &str| { | ||
| let stdout = massage_error_output(stdout); | ||
| if stdout != output { | ||
| print_diff(&stdout, &output, " "); |
There was a problem hiding this comment.
This was a hacky approximation of a "pretty assertion diff" that I'm kind of inclined to keep in (it only kicks in if the test is failing)?
There was a problem hiding this comment.
What happens when color command codes are in the diff?
There was a problem hiding this comment.
Mm not sure what that would show, this is only in the assert_non_match_output() helper (ie something that prints to stdout but what it prints isn't match output) so has pretty narrow usage, specifically I was using it to help me wrangle the --help output (which I don't think we are nor do I have a strong desire to test the "pretty" version of)
| - run: cargo test | ||
| if: matrix.os == 'ubuntu-latest' | ||
| env: | ||
| TERM: linux |
There was a problem hiding this comment.
Apparently the TERM environment variable wasn't set at all in the Ubuntu CI environment so that was causing (per the --color docs) it to not print colors even when using eg --pretty which was causing tests to fail
So tried setting to what apparently is a pretty "generic" $TERM setting and it passed
There was a problem hiding this comment.
That seems reasonable, but maybe that suggests that you should be able to control environment variables in tests?
There was a problem hiding this comment.
Ya that could make sense
Here my specific understanding would be that then we'd have to eg "#[cfg(unix/windows)]-split" those particular tests (so that we could only set that environment variable for the Unix version), and would have to add that environment variable to every individual test that's using --pretty
To me that sounds clunkier vs putting it in the one place here that is basically saying "for all tests (on this platform) (by default) act like you're in this kind of underlying terminal environment"
| /// | ||
| /// When the --vimgrep flag is given to tree-sitter-grep, then the default | ||
| /// value for the --color flag changes to 'never'. | ||
| #[arg(long, value_name = "WHEN"/*, default_value_t = ColorChoiceArg::Auto*/)] |
There was a problem hiding this comment.
(also ended up running into the fact that the default is in fact not "static" (when in --vimgrep mode the default is ColorChoiceArg::Never instead) so using default_value_t would presumably not be appropriate, removing)
| "rust_project", | ||
| r#" | ||
| $ tree-sitter-grep -q '(function_item) @c' -l rust --pretty | ||
| [0m[1m[32msrc/stop.rs[0m |
There was a problem hiding this comment.
You could picture having a "cuter" test-syntax for this
But not sure it's worth it?
Surprisingly this passed on Windows too I guess they use the same terminal color escape codes or whatever?
There was a problem hiding this comment.
Huh, I find that pretty surprising given how incompatible the terminals are in most other ways. (But they do somehow run git and whatever else, so maybe they are trying to be compatible.)
There was a problem hiding this comment.
You could picture having a "cuter" test-syntax for this
I can't really 😄 — what were you thinking?
But not sure it's worth it?
Yeah, doesn't seem like it's worth a ton of effort.
There was a problem hiding this comment.
Like some kind of "readable markup" of what the colors/styles should be?
Ya it might not be that cute anyway
|
|
||
| fn strip_trailing_carriage_return(line: &str) -> Cow<'_, str> { | ||
| regex!(r#"\r$"#).replace(line, "") | ||
| regex!(r#"\r((?:\u{1b}\[\d+m)*)$"#).replace(line, "$1") |
There was a problem hiding this comment.
I was seeing terminal color escape codes after \r's (not sure if that's expected?) so this handles that
There was a problem hiding this comment.
That's not where I'd have guessed they'd go, but why not 🤷🏻
|
|
||
| fn normalize_match_path(line: &str) -> Cow<'_, str> { | ||
| regex!(r#"^[^:]+[:-]\d+[:-]"#) | ||
| regex!(r#"^(?:\u{1b}\[\d+m)*[a-zA-Z_\-\\/]+\.(?:rs|js|tsx)"#) |
There was a problem hiding this comment.
And here this regex for finding "paths" (for changing \ -> / on Windows) keeps getting re-worked, now it really can't really on "context" at all (since eg heading lines are just paths by themselves)
So just expressed it in a way that works for all current tests with filename output
peterstuart
left a comment
There was a problem hiding this comment.
Nice, looks good 👍🏻
| - run: cargo test | ||
| if: matrix.os == 'ubuntu-latest' | ||
| env: | ||
| TERM: linux |
There was a problem hiding this comment.
That seems reasonable, but maybe that suggests that you should be able to control environment variables in tests?
| /// will be shown as a prefix for each matched line. | ||
| /// | ||
| /// This flag overrides --no-filename. | ||
| #[arg(short = 'H', long)] |
There was a problem hiding this comment.
Assuming you took this from ripgrep, but what's the "H" mean? "heading-ish"?
There was a problem hiding this comment.
Good question. At some point their algorithm may be "if we start running out of the "obvious short codes" then give the "less obvious" ones to less-used options"?
|
|
||
| impl Args { | ||
| fn use_paths(&self) -> Vec<PathBuf> { | ||
| pub fn use_paths(&self) -> Vec<PathBuf> { |
There was a problem hiding this comment.
You could probably write a macro which does the once-cell thing that you want to the function it annotates?
| vec![ | ||
| #[cfg(unix)] | ||
| "path:fg:magenta".parse().unwrap(), | ||
| "path:fg:green".parse().unwrap(), |
| "rust_project", | ||
| r#" | ||
| $ tree-sitter-grep -q '(function_item) @c' -l rust --pretty | ||
| [0m[1m[32msrc/stop.rs[0m |
There was a problem hiding this comment.
Huh, I find that pretty surprising given how incompatible the terminals are in most other ways. (But they do somehow run git and whatever else, so maybe they are trying to be compatible.)
| "rust_project", | ||
| r#" | ||
| $ tree-sitter-grep -q '(function_item) @c' -l rust --pretty | ||
| [0m[1m[32msrc/stop.rs[0m |
There was a problem hiding this comment.
You could picture having a "cuter" test-syntax for this
I can't really 😄 — what were you thinking?
But not sure it's worth it?
Yeah, doesn't seem like it's worth a ton of effort.
|
|
||
| fn strip_trailing_carriage_return(line: &str) -> Cow<'_, str> { | ||
| regex!(r#"\r$"#).replace(line, "") | ||
| regex!(r#"\r((?:\u{1b}\[\d+m)*)$"#).replace(line, "$1") |
There was a problem hiding this comment.
That's not where I'd have guessed they'd go, but why not 🤷🏻
| .stdout(predicate::function(|stdout: &str| { | ||
| let stdout = massage_error_output(stdout); | ||
| if stdout != output { | ||
| print_diff(&stdout, &output, " "); |
There was a problem hiding this comment.
What happens when color command codes are in the diff?

In this PR:
ripgrep's heading/filename/line/column formatting (at least much more closely), eg showing a per-file "heading" and colors by default when outputting to a terminalTo test:
Now when running in a terminal by default you should see
ripgrep-style output formatting (but with a different default set of colors)If you eg redirect the output by doing
| cat -, you should see different formatting that is more like our existing formatting but without showing line numbers (by default)You should be able to use the newly exposed command-line arguments to modify those behaviors, eg use
--prettywhen redirecting the output to still get color/headings etc, use--line-numberwhen redirecting the output to still get line numbers