diff --git a/yazi-core/src/manager/commands/bulk_rename.rs b/yazi-core/src/manager/commands/bulk_rename.rs index 88bf79d2c..7e0545387 100644 --- a/yazi-core/src/manager/commands/bulk_rename.rs +++ b/yazi-core/src/manager/commands/bulk_rename.rs @@ -53,7 +53,7 @@ impl Manager { return Ok(()); } - let todo: Vec<_> = old.into_iter().zip(new).filter(|(o, n)| o != n).collect(); + let todo = Self::sort(old, new); if todo.is_empty() { return Ok(()); } @@ -117,4 +117,44 @@ impl Manager { stdin().read_exact(&mut [0]).await?; Ok(()) } + + fn sort(old: Vec, new: Vec) -> Vec<(PathBuf, PathBuf)> { + let mut income_map: HashMap = + old.iter().map(|path| (path.clone(), false)).collect(); + let mut todos: HashMap = old + .into_iter() + .zip(new) + .map(|(old, new)| { + if let Some(has_income) = income_map.get_mut(&new) { + *has_income = true; + } + (old, new) + }) + .collect(); + + let mut sorted = vec![]; + while !todos.is_empty() { + let mut has_no_incomes = vec![]; + income_map.iter().for_each(|(old, has_income)| { + if !has_income { + has_no_incomes.push(old.clone()) + } + }); + + if has_no_incomes.is_empty() { + todo!("Consider cycle") + } + + for old in has_no_incomes { + income_map.remove(&old); + let Some(new) = todos.remove(&old) else { unreachable!("") }; + if let Some(has_income) = income_map.get_mut(&new) { + *has_income = false; + } + sorted.push((old, new)); + } + } + sorted.reverse(); + sorted + } }