Skip to content

Commit ec3aca6

Browse files
authored
fix: find-block off-by-one line_count for files with trailing newline (#91)
* fix: find-block off-by-one line_count for files with trailing newline The find_block command was using `entries.len()` for line_count, but `entries` comes from `normalized.split('\n')` which includes an empty trailing entry when the file ends with a newline. The fix uses `fc.len()` which correctly counts newlines (matching the `read` command behavior). Added regression tests for both cases: - Files without trailing newline - Files with trailing newline (the off-by-one scenario) * fix: same off-by-one line_count in MCP handle_find_block
1 parent 1f54bd7 commit ec3aca6

2 files changed

Lines changed: 30 additions & 2 deletions

File tree

crates/core/src/commands/find_block.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub fn find_block_payload(
8181

8282
Ok(FindBlockPayload {
8383
file: fc.path.display().to_string(),
84-
line_count: entries.len(),
84+
line_count: fc.len(),
8585
language,
8686
block_lines,
8787
})
@@ -634,4 +634,32 @@ mod tests {
634634
assert_eq!(payload.block_lines.len(), 3);
635635
assert!(payload.block_lines[0].content.contains("if true"));
636636
}
637+
638+
/// Regression: line_count must match fc.len(), not entries.len(), so files
639+
/// with a trailing newline do not report an off-by-one count (Issue #90).
640+
#[test]
641+
fn test_line_count_no_trailing_newline() {
642+
let content = "line1\nline2\nline3";
643+
let (fc, entries) = make_fc(content, "test.txt");
644+
let payload = find_block_payload(&fc, &entries, &anchor_for(1, &entries)).unwrap();
645+
assert!(!fc.trailing_newline);
646+
assert_eq!(fc.len(), 3);
647+
// When there is no trailing newline, entries and fc.len() happen to
648+
// agree, but we assert the semantic field regardless.
649+
assert_eq!(payload.line_count, fc.len());
650+
assert_eq!(payload.line_count, 3);
651+
}
652+
653+
#[test]
654+
fn test_line_count_with_trailing_newline() {
655+
let content = "line1\nline2\nline3\n";
656+
let (fc, entries) = make_fc(content, "test.txt");
657+
let payload = find_block_payload(&fc, &entries, &anchor_for(1, &entries)).unwrap();
658+
assert!(fc.trailing_newline);
659+
assert_eq!(fc.len(), 3);
660+
// entries.len() would be 4 here (includes the empty split tail).
661+
// The fix ensures line_count comes from fc.len().
662+
assert_eq!(payload.line_count, fc.len());
663+
assert_eq!(payload.line_count, 3);
664+
}
637665
}

crates/core/src/mcp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ fn handle_find_block(file: &str, anchor_str: &str) -> String {
263263
let mut out = format!(
264264
"File: {} ({} lines)\nLanguage: {language}\n",
265265
fc.path.display(),
266-
entries.len()
266+
fc.len()
267267
);
268268
for i in start..=end {
269269
let entry = &entries[i];

0 commit comments

Comments
 (0)