Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/cmds/python/ruff_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ pub fn run(args: &[String], verbose: u8) -> Result<i32> {
|| (a == "--output-format" && args.get(i + 1).is_some_and(|n| n == "json"))
});
let use_json_filter = !user_set_output_format || user_json_format;
// `[]` is a clean run only when rtk chose the format; a user who asked for JSON gets `[]` back.
let clean_outputs: &[&str] = if is_check && !user_set_output_format {
&["[]"]
} else {
&[]
};

if is_check {
if user_set_output_format {
Expand Down Expand Up @@ -111,7 +117,7 @@ pub fn run(args: &[String], verbose: u8) -> Result<i32> {
truncate(stdout.trim(), config::limits().passthrough_max_chars)
}
},
runner::RunOptions::stdout_only(),
runner::RunOptions::stdout_only().clean_outputs(clean_outputs),
)
}

Expand Down
6 changes: 5 additions & 1 deletion src/core/guard.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Never-worse output guard: RTK never emits more tokens than the raw command.
//!
//! One caller is allowed past it. `rtk diff` prints a one-line message for a
//! Two callers are allowed past it. `rtk diff` prints a one-line message for a
//! difference `str::lines()` cannot render — CRLF against LF, or a missing
//! final newline — where the raw fallback is two blobs that look identical and
//! answer the question worse at any size. The exception is bounded by the case
Expand All @@ -10,6 +10,10 @@
//! the shortest form of the message is ~20 tokens and a one-line pair is ~2, so
//! the ceiling sat under the message's own floor and dropped it on 90% of
//! one-line pairs.
//!
//! The other is a clean run of a command whose output format rtk injected
//! (`runner::RunOptions::clean_outputs`): ruff's `[]` answers a question the
//! user never asked, so the filter's summary is shown although it is longer.

use crate::core::tracking::estimate_tokens;

Expand Down
42 changes: 41 additions & 1 deletion src/core/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ pub struct RunOptions<'a> {
/// can read from a pipe (e.g. `cat file | rtk wc`); without it the child
/// gets an empty stdin and reports zero.
pub inherit_stdin: bool,
/// What the tool prints on a clean run in the output format rtk injected, e.g. ruff's
/// `[]`. See [`guard_stdout`]. Not consulted when `tee_label` is set.
pub clean_outputs: &'a [&'a str],
}

impl<'a> RunOptions<'a> {
Expand Down Expand Up @@ -80,6 +83,23 @@ impl<'a> RunOptions<'a> {
self.inherit_stdin = true;
self
}

pub fn clean_outputs(mut self, outputs: &'a [&'a str]) -> Self {
self.clean_outputs = outputs;
self
}
}

/// The stdout to show: `filtered`, unless it costs more tokens than `raw`.
///
/// A `raw` that is exactly one of `clean_outputs` is the empty form of a format rtk injected,
/// not output the user asked for, so the filter's summary is shown even though it is longer.
fn guard_stdout<'a>(raw: &'a str, filtered: &'a str, clean_outputs: &[&str]) -> &'a str {
if clean_outputs.contains(&raw.trim()) {
filtered
} else {
crate::core::guard::never_worse(raw, filtered)
}
}

pub type CaptureFilter<'a> = Box<dyn Fn(&str) -> String + 'a>;
Expand Down Expand Up @@ -144,7 +164,7 @@ where
let shown = if let Some(label) = opts.tee_label {
print_with_hint(&filtered, raw, raw_for_tracking, label, exit_code)
} else {
let guarded = crate::core::guard::never_worse(raw_for_tracking, &filtered).to_string();
let guarded = guard_stdout(raw_for_tracking, &filtered, opts.clean_outputs).to_string();
if opts.no_trailing_newline {
print!("{}", guarded);
} else {
Expand Down Expand Up @@ -990,6 +1010,26 @@ fn is_bun_count_line(trimmed: &str) -> bool {
)
}

#[cfg(test)]
mod guard_stdout_tests {
use super::*;

const SUMMARY: &str = "Ruff: No issues found";

#[test]
fn an_injected_clean_output_shows_the_summary() {
assert_eq!(guard_stdout("[]\n", SUMMARY, &["[]"]), SUMMARY);
assert_eq!(guard_stdout("[]\r\n", SUMMARY, &["[]"]), SUMMARY);
}

#[test]
fn any_other_short_output_still_goes_through_never_worse() {
assert_eq!(guard_stdout("{}\n", SUMMARY, &["[]"]), "{}\n");
assert_eq!(guard_stdout("[ ]\n", SUMMARY, &["[]"]), "[ ]\n");
assert_eq!(guard_stdout("[]\n", SUMMARY, &[]), "[]\n");
}
}

#[cfg(test)]
mod forwarded_stderr_tests {
use super::*;
Expand Down
Loading