The refactoring from this change makes things a lot cleaner, so it should also come with a few less bugs
B7YKJDKD7ZQ2JV4FLKZUHMIH6BQXH57ALGQOGQ4YTFGITBYMWY4QC fn get_hunks(cx: &mut FunctionContext,path: Option<PathBuf>,stop_early: bool,) -> Result<Vec<PrintableHunk>, anyhow::Error> {let repo = Repository::find_root(path.clone()).expect("Could not find root");
fn get_hunks(path: &Path, stop_early: bool) -> Result<Vec<PrintableHunk>, anyhow::Error> {let repo = Repository::find_root(Some(path.to_owned())).expect("Could not find root");
let prefix = if let Some(path) = path {path.strip_prefix(&repo.path)?.to_string_lossy().to_string()} else {String::new()};console_log(cx, format!("Prefix: {prefix} root: {:?}", repo.path)).unwrap();
let prefix = path.strip_prefix(&repo.path)?.to_string_lossy().to_string();
Annotation::Added => "A",Annotation::Modified => "M",
Self::Tracked(annotations) => annotations.iter().map(|annotation| {match annotation {Annotation::Modified => "M",}.to_string()}).collect::<Vec<String>>().join(", "),Self::Added => String::from("A"),Self::Untracked => String::from("U"),Self::Ignored => String::new(),
Annotation::Added => "Added",Annotation::Modified => "Modified",
Self::Tracked(annotations) => annotations.iter().map(|annotation| {match annotation {Annotation::Modified => "Modified",}.to_string()}).collect::<Vec<String>>().join(", "),Self::Added => String::from("Added"),Self::Untracked => String::from("Untracked"),Self::Ignored => String::new(),
fn short_diff(mut cx: FunctionContext) -> JsResult<JsArray> {let path: Handle<JsString> = cx.argument(0)?;let path = PathBuf::from(path.value(&mut cx));let hunks = get_hunks(&mut cx, Some(path), true).expect("Unable to load hunks");
pub fn untracked(path: &Path) -> Result<Vec<PathBuf>, anyhow::Error> {let repo = Repository::find_root(Some(path.to_owned())).expect("Could not find root");let txn = repo.pristine.arc_txn_begin()?;let channel_name = txn.read().current_channel().unwrap_or(libpijul::DEFAULT_CHANNEL).to_string();let channel = txn.write().open_or_create_channel(&channel_name)?;let prefix = path.strip_prefix(&repo.path)?.to_string_lossy().to_string();let mut record_builder = RecordBuilder::new();if let Err(libpijul::record::RecordError::PathNotInRepo(_)) = record_builder.record(txn.clone(),libpijul::Algorithm::default(),true,&libpijul::DEFAULT_SEPARATOR,channel.clone(),&repo.working_copy,&repo.changes,&prefix,std::thread::available_parallelism()?.into(),) {// `path` is a single file, no more work neededassert!(path.is_file());return Ok(vec![path.to_owned()]);}
let mut annotations: HashMap<String, Vec<Annotation>> = HashMap::new();console_log(&mut cx, format!("Hunk length: {}", hunks.len()))?;for hunk in hunks.iter() {let (path, annotation) = match hunk {PrintableHunk::FileAddition { name, parent, .. } => {(PathBuf::from(parent).join(name), Annotation::Added)
let repo_path = CanonicalPathBuf::canonicalize(&repo.path)?;let given_path = CanonicalPathBuf::canonicalize(&path)?;let threads = std::thread::available_parallelism()?.into();Ok(repo.working_copy.iterate_prefix_rec(repo_path.clone(), given_path.clone(), false, threads)?.filter_map(move |x| {let (path, _) = x.unwrap();use path_slash::PathExt;let path_str = path.to_slash_lossy();let read_txn = &*txn.read();if !read_txn.is_tracked(&path_str).unwrap_or(false) {Some(path)} else {None
PrintableHunk::Replace { path, .. } => (PathBuf::from(path), Annotation::Modified),PrintableHunk::Edit { path, .. } => (PathBuf::from(path), Annotation::Modified),_ => continue,};
}).collect())}pub fn annotate_path(path: PathBuf) -> Result<HashMap<String, State>, anyhow::Error> {let untracked = untracked(&path).unwrap();let mut annotations: HashMap<String, State> = HashMap::new();if path.is_file() && untracked == vec![path.clone()] {annotations.insert(path.to_string_lossy().to_string(), State::Untracked);} else {let hunks = get_hunks(&path, true).expect("Unable to load hunks");for hunk in hunks.iter() {match hunk {PrintableHunk::FileAddition { name, parent, .. } => {let path = PathBuf::from(parent).join(name);annotations.try_insert(path.to_string_lossy().to_string(), State::Added).expect("File additions should be a unique hunk");}PrintableHunk::Replace { path, .. } | PrintableHunk::Edit { path, .. } => {if let State::Tracked(tracked) = annotations.entry(path.to_owned()).or_insert(State::Tracked(vec![])){tracked.push(Annotation::Modified);} else {unreachable!();}}_ => continue,};}
let entry = annotations.entry(path.to_string_lossy().to_string()).or_insert(vec![]);if !entry.contains(&annotation) {entry.push(annotation);
for untracked_file in untracked {let key = untracked_file.to_string_lossy().to_string();debug_assert!(annotations.get(&key).is_none());annotations.insert(key, State::Untracked);
let badge_annotations = cx.string(file_annotations.iter().map(|i| i.badge()).collect::<Vec<String>>().join(", "),);let tooltip_annotations = cx.string(file_annotations.iter().map(|i| i.tooltip()).collect::<Vec<String>>().join(", "),);
let badge_annotations = cx.string(file_annotations.badge());let tooltip_annotations = cx.string(file_annotations.tooltip());