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: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ All notable changes to rtk (Rust Token Killer) will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Bug Fixes

* **diff:** correct truncation overflow count in condense_unified_diff ([#833](https://github.com/rtk-ai/rtk/pull/833)) ([5399f83](https://github.com/rtk-ai/rtk/commit/5399f83))
* **git:** replace vague truncation markers with exact counts in log and grep output ([#833](https://github.com/rtk-ai/rtk/pull/833)) ([185fb97](https://github.com/rtk-ai/rtk/commit/185fb97))


## [0.33.0-rc.54](https://github.com/rtk-ai/rtk/compare/v0.32.0-rc.54...v0.33.0-rc.54) (2026-03-24)


Expand Down
87 changes: 62 additions & 25 deletions src/diff_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ fn condense_unified_diff(diff: &str) -> String {
for c in &changes {
result.push(format!(" {}", c));
}
let total = added + removed;
if total > 10 {
result.push(format!(" ... +{} more", total - 10));
}
}
current_file = line
.trim_start_matches("+++ ")
Expand All @@ -192,6 +196,10 @@ fn condense_unified_diff(diff: &str) -> String {
for c in &changes {
result.push(format!(" {}", c));
}
let total = added + removed;
if total > 10 {
result.push(format!(" ... +{} more", total - 10));
}
}

result.join("\n")
Expand Down Expand Up @@ -334,9 +342,57 @@ diff --git a/b.rs b/b.rs
assert!(result.is_empty());
}

// --- truncation accuracy ---

fn make_large_unified_diff(added: usize, removed: usize) -> String {
let mut lines = vec![
"diff --git a/config.yaml b/config.yaml".to_string(),
"--- a/config.yaml".to_string(),
"+++ b/config.yaml".to_string(),
"@@ -1,200 +1,200 @@".to_string(),
];
for i in 0..removed {
lines.push(format!("-old_value_{}", i));
}
for i in 0..added {
lines.push(format!("+new_value_{}", i));
}
lines.join("\n")
}

#[test]
fn test_condense_unified_diff_overflow_count_accuracy() {
// 100 added + 100 removed = 200 total changes, only 10 shown
// True overflow = 200 - 10 = 190
// Bug: changes vec capped at 15, so old code showed "+5 more" (15-10) instead of "+190 more"
let diff = make_large_unified_diff(100, 100);
let result = condense_unified_diff(&diff);
assert!(
result.contains("+190 more"),
"Expected '+190 more' but got:\n{}",
result
);
assert!(
!result.contains("+5 more"),
"Bug still present: showing '+5 more' instead of true overflow"
);
}

#[test]
fn test_condense_unified_diff_no_false_overflow() {
// 8 changes total — all fit within the 10-line display cap, no overflow message
let diff = make_large_unified_diff(4, 4);
let result = condense_unified_diff(&diff);
assert!(
!result.contains("more"),
"No overflow message expected for 8 changes, got:\n{}",
result
);
}

#[test]
fn test_no_truncation_large_diff() {
// Verify all changes are shown, not truncated
// Verify compute_diff returns all changes without truncation
let mut a = Vec::new();
let mut b = Vec::new();
for i in 0..500 {
Expand All @@ -351,9 +407,11 @@ diff --git a/b.rs b/b.rs
let b_refs: Vec<&str> = b.iter().map(|s| s.as_str()).collect();
let result = compute_diff(&a_refs, &b_refs);

// Should have ~167 changes (every 3rd line), all present
assert!(result.changes.len() > 100, "Expected 100+ changes, got {}", result.changes.len());
// No truncation — changes count matches what we generate
assert!(
result.changes.len() > 100,
"Expected 100+ changes, got {}",
result.changes.len()
);
assert!(!result.changes.is_empty());
}

Expand All @@ -363,7 +421,6 @@ diff --git a/b.rs b/b.rs
let a = vec![long_line.as_str()];
let b = vec!["short"];
let result = compute_diff(&a, &b);
// The removed line should contain the full 500-char string
match &result.changes[0] {
DiffChange::Removed(_, content) | DiffChange::Added(_, content) => {
assert_eq!(content.len(), 500, "Line was truncated!");
Expand All @@ -373,24 +430,4 @@ diff --git a/b.rs b/b.rs
}
}
}

#[test]
fn test_condense_unified_no_truncation() {
// Generate a large unified diff
let mut lines = Vec::new();
lines.push("diff --git a/big.yaml b/big.yaml".to_string());
lines.push("--- a/big.yaml".to_string());
lines.push("+++ b/big.yaml".to_string());
for i in 0..200 {
lines.push(format!("+added_line_{}", i));
}
let diff = lines.join("\n");
let result = condense_unified_diff(&diff);

// All 200 added lines should be present
assert!(result.contains("added_line_0"));
assert!(result.contains("added_line_199"));
assert!(!result.contains("not shown"), "Should not truncate");
assert!(!result.contains("more"), "Should not have '... more'");
}
}
45 changes: 45 additions & 0 deletions src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,4 +491,49 @@ fn main() {
assert!(!result.contains("// This is a comment"));
assert!(result.contains("fn main()"));
}

// --- truncation accuracy ---

#[test]
fn test_smart_truncate_overflow_count_exact() {
// 200 plain-text lines with max_lines=20.
// smart_truncate keeps the first max_lines/2=10 lines, then skips the rest.
// The overflow message "// ... N more lines (total: T)" must satisfy:
// kept_count + N == T
let total_lines = 200usize;
let max_lines = 20usize;
let content: String = (0..total_lines)
.map(|i| format!("plain text line number {}", i))
.collect::<Vec<_>>()
.join("\n");

let output = smart_truncate(&content, max_lines, &Language::Rust);

// Extract the overflow message
let overflow_line = output
.lines()
.find(|l| l.contains("more lines"))
.unwrap_or_else(|| panic!("No overflow message found in:\n{}", output));

// Parse "// ... N more lines (total: T)"
let reported_more: usize = overflow_line
.split_whitespace()
.find(|w| w.parse::<usize>().is_ok())
.and_then(|w| w.parse().ok())
.unwrap_or_else(|| panic!("Could not parse overflow count from: {}", overflow_line));

let kept_count = output
.lines()
.filter(|l| !l.contains("more lines") && !l.contains("omitted"))
.count();

assert_eq!(
kept_count + reported_more,
total_lines,
"kept ({}) + reported_more ({}) must equal total ({})",
kept_count,
reported_more,
total_lines
);
}
}
Loading
Loading