From 52c72ae2b37647fa855c6330bd40cf407134e221 Mon Sep 17 00:00:00 2001 From: Evan Chen Date: Wed, 5 Aug 2026 14:32:09 -0700 Subject: [PATCH] fix(desktop): show complete repository trees Signed-off-by: Evan Chen Co-authored-by: Codex Ai-assisted: true --- desktop/src-tauri/src/commands/project_git.rs | 23 ++++++++++---- .../src/commands/project_git_tests.rs | 30 +++++++++++++++++++ 2 files changed, 47 insertions(+), 6 deletions(-) create mode 100644 desktop/src-tauri/src/commands/project_git_tests.rs diff --git a/desktop/src-tauri/src/commands/project_git.rs b/desktop/src-tauri/src/commands/project_git.rs index 201f3a050..38dbcd87d 100644 --- a/desktop/src-tauri/src/commands/project_git.rs +++ b/desktop/src-tauri/src/commands/project_git.rs @@ -8,6 +8,15 @@ use crate::app_state::AppState; use serde::Serialize; use std::time::UNIX_EPOCH; use tauri::State; + +// Bound eager snapshot payloads without truncating the repository tree. Later +// paths remain browseable without embedded content. +const MAX_EAGER_FILE_PREVIEWS: usize = 250; + +#[cfg(test)] +#[path = "project_git_tests.rs"] +mod tests; + #[derive(Clone, Serialize)] pub struct ProjectRepoCommitInfo { pub hash: String, @@ -251,7 +260,8 @@ fn parse_worktree_files( output .split('\0') .filter(|path| !path.trim().is_empty()) - .filter_map(|path| { + .enumerate() + .filter_map(|(index, path)| { let full_path = repo_dir.join(path); let metadata = std::fs::metadata(&full_path).ok()?; if !metadata.is_file() { @@ -263,7 +273,9 @@ fn parse_worktree_files( path: path.to_string(), kind: "blob".to_string(), size, - preview_content: read_preview_content(repo_dir, path, size), + preview_content: (index < MAX_EAGER_FILE_PREVIEWS) + .then(|| read_preview_content(repo_dir, path, size)) + .flatten(), last_changed_at: latest_commit .as_ref() .map(|commit| commit.timestamp) @@ -271,7 +283,6 @@ fn parse_worktree_files( latest_commit, }) }) - .take(250) .collect() } @@ -316,14 +327,15 @@ fn parse_ls_tree( ) -> Vec { output .lines() - .filter_map(|line| { + .enumerate() + .filter_map(|(index, line)| { let (meta, path) = line.split_once('\t')?; let mut parts = meta.split_whitespace(); let _mode = parts.next()?; let kind = parts.next()?.to_string(); let _object = parts.next()?; let size = parts.next().and_then(|value| value.parse::().ok()); - let preview_content = if kind == "blob" { + let preview_content = if kind == "blob" && index < MAX_EAGER_FILE_PREVIEWS { read_preview_content(repo_dir, path, size) } else { None @@ -339,7 +351,6 @@ fn parse_ls_tree( latest_commit: latest_commit_by_path.get(path).cloned(), }) }) - .take(250) .collect() } diff --git a/desktop/src-tauri/src/commands/project_git_tests.rs b/desktop/src-tauri/src/commands/project_git_tests.rs new file mode 100644 index 000000000..6e597cc6d --- /dev/null +++ b/desktop/src-tauri/src/commands/project_git_tests.rs @@ -0,0 +1,30 @@ +use super::*; + +#[test] +fn parse_ls_tree_keeps_paths_after_eager_preview_limit() { + let hidden_entries = (0..MAX_EAGER_FILE_PREVIEWS) + .map(|index| { + format!( + "100644 blob {} 1\t.agents/generated-{index:03}.txt", + "a".repeat(40) + ) + }) + .collect::>() + .join("\n"); + let output = format!( + "{hidden_entries}\n100644 blob {} 12\tsrc/application.rs", + "b".repeat(40) + ); + + let files = parse_ls_tree( + std::path::Path::new("/path/does/not/exist"), + &output, + &std::collections::HashMap::new(), + ); + + assert_eq!(files.len(), MAX_EAGER_FILE_PREVIEWS + 1); + assert_eq!( + files.last().map(|file| file.path.as_str()), + Some("src/application.rs") + ); +}