use std::path::Path;
use crate::files_view::{FileEntry, FilesView, MAX_ENTRIES, Preview, classify};
use crate::git_tree::{REPO_DIR, ls_tree_long, show_file};
const LS_FIELDS: usize = 4;
const EXCLUDE_AT_ROOT: [&str; 1] = ["messages"];
pub fn files_at(workspace: &Path, commit: &str) -> FilesView {
let Ok(out) = ls_tree_long(&workspace.join(REPO_DIR), commit) else {
return FilesView::AbsentWorktree;
};
let mut entries: Vec<FileEntry> = String::from_utf8_lossy(&out)
.lines()
.filter_map(parse_row)
.filter(|entry| !hidden_at_root(&entry.rel_path))
.collect();
entries.sort_by(|a, b| a.rel_path.cmp(&b.rel_path));
let truncated = entries.len() > MAX_ENTRIES;
entries.truncate(MAX_ENTRIES);
FilesView::Present { entries, truncated }
}
pub(super) fn parse_row(line: &str) -> Option<FileEntry> {
let (head, path) = line.split_once('\t')?;
let size = head.split_whitespace().nth(LS_FIELDS - 1)?.parse().ok()?;
Some(FileEntry {
rel_path: path.to_owned(),
size,
is_dir: false,
})
}
fn hidden_at_root(rel_path: &str) -> bool {
let root = rel_path.split('/').next().unwrap_or(rel_path);
EXCLUDE_AT_ROOT.contains(&root)
}
pub fn preview_at(workspace: &Path, commit: &str, path: &str) -> Preview {
let bytes = show_file(&workspace.join(REPO_DIR), commit, path).unwrap_or_default();
let size = u64::try_from(bytes.len()).unwrap_or(u64::MAX);
classify(&bytes, size)
}