diff --git a/rust/rhg/src/commands/files.rs b/rust/rhg/src/commands/files.rs --- a/rust/rhg/src/commands/files.rs +++ b/rust/rhg/src/commands/files.rs @@ -1,14 +1,12 @@ use crate::error::CommandError; use crate::ui::Ui; -use crate::ui::UiError; -use crate::utils::path_utils::relativize_paths; +use crate::utils::path_utils::RelativizePaths; use clap::Arg; use hg::errors::HgError; use hg::operations::list_rev_tracked_files; use hg::operations::Dirstate; use hg::repo::Repo; use hg::utils::hg_path::HgPath; -use std::borrow::Cow; pub const HELP_TEXT: &str = " List tracked files. @@ -86,11 +84,14 @@ let mut stdout = ui.stdout_buffer(); let mut any = false; - relativize_paths(repo, files, |path: Cow<[u8]>| -> Result<(), UiError> { + let relativize = RelativizePaths::new(repo)?; + for result in files { + let path = result?; + stdout.write_all(&relativize.relativize(path))?; + stdout.write_all(b"\n")?; any = true; - stdout.write_all(path.as_ref())?; - stdout.write_all(b"\n") - })?; + } + stdout.flush()?; if any { Ok(()) diff --git a/rust/rhg/src/commands/status.rs b/rust/rhg/src/commands/status.rs --- a/rust/rhg/src/commands/status.rs +++ b/rust/rhg/src/commands/status.rs @@ -7,7 +7,7 @@ use crate::error::CommandError; use crate::ui::Ui; -use crate::utils::path_utils::relativize_paths; +use crate::utils::path_utils::RelativizePaths; use clap::{Arg, SubCommand}; use format_bytes::format_bytes; use hg; @@ -261,9 +261,12 @@ .unwrap_or(config.get_bool(b"ui", b"relative-paths")?); let output = DisplayStatusPaths { ui, - repo, no_status, - relative_paths, + relativize: if relative_paths { + Some(RelativizePaths::new(repo)?) + } else { + None + }, }; if display_states.modified { output.display(b"M", ds_status.modified)?; @@ -379,9 +382,8 @@ struct DisplayStatusPaths<'a> { ui: &'a Ui, - repo: &'a Repo, no_status: bool, - relative_paths: bool, + relativize: Option, } impl DisplayStatusPaths<'_> { @@ -393,27 +395,24 @@ mut paths: Vec, ) -> Result<(), CommandError> { paths.sort_unstable(); - let print_path = |path: &[u8]| { + for path in paths { + let relative; + let path = if let Some(relativize) = &self.relativize { + relative = relativize.relativize(&path); + &*relative + } else { + path.as_bytes() + }; // TODO optim, probably lots of unneeded copies here, especially // if out stream is buffered if self.no_status { - self.ui.write_stdout(&format_bytes!(b"{}\n", path)) + self.ui.write_stdout(&format_bytes!(b"{}\n", path))? } else { self.ui.write_stdout(&format_bytes!( b"{} {}\n", status_prefix, path - )) - } - }; - - if self.relative_paths { - relativize_paths(self.repo, paths.iter().map(Ok), |path| { - print_path(&path) - })?; - } else { - for path in paths { - print_path(path.as_bytes())? + ))? } } Ok(()) diff --git a/rust/rhg/src/utils/path_utils.rs b/rust/rhg/src/utils/path_utils.rs --- a/rust/rhg/src/utils/path_utils.rs +++ b/rust/rhg/src/utils/path_utils.rs @@ -3,8 +3,6 @@ // This software may be used and distributed according to the terms of the // GNU General Public License version 2 or any later version. -use crate::error::CommandError; -use crate::ui::UiError; use hg::errors::HgError; use hg::repo::Repo; use hg::utils::current_dir; @@ -13,37 +11,45 @@ use hg::utils::hg_path::HgPathBuf; use std::borrow::Cow; -pub fn relativize_paths( - repo: &Repo, - paths: impl IntoIterator, HgError>>, - mut callback: impl FnMut(Cow<[u8]>) -> Result<(), UiError>, -) -> Result<(), CommandError> { - let cwd = current_dir()?; - let repo_root = repo.working_directory_path(); - let repo_root = cwd.join(repo_root); // Make it absolute - let repo_root_hgpath = - HgPathBuf::from(get_bytes_from_path(repo_root.to_owned())); - let outside_repo: bool; - let cwd_hgpath: HgPathBuf; +pub struct RelativizePaths { + repo_root: HgPathBuf, + cwd: HgPathBuf, + outside_repo: bool, +} + +impl RelativizePaths { + pub fn new(repo: &Repo) -> Result { + let cwd = current_dir()?; + let repo_root = repo.working_directory_path(); + let repo_root = cwd.join(repo_root); // Make it absolute + let repo_root_hgpath = + HgPathBuf::from(get_bytes_from_path(repo_root.to_owned())); - if let Ok(cwd_relative_to_repo) = cwd.strip_prefix(&repo_root) { - // The current directory is inside the repo, so we can work with - // relative paths - outside_repo = false; - cwd_hgpath = - HgPathBuf::from(get_bytes_from_path(cwd_relative_to_repo)); - } else { - outside_repo = true; - cwd_hgpath = HgPathBuf::from(get_bytes_from_path(cwd)); + if let Ok(cwd_relative_to_repo) = cwd.strip_prefix(&repo_root) { + // The current directory is inside the repo, so we can work with + // relative paths + Ok(Self { + repo_root: repo_root_hgpath, + cwd: HgPathBuf::from(get_bytes_from_path( + cwd_relative_to_repo, + )), + outside_repo: false, + }) + } else { + Ok(Self { + repo_root: repo_root_hgpath, + cwd: HgPathBuf::from(get_bytes_from_path(cwd)), + outside_repo: true, + }) + } } - for file in paths { - if outside_repo { - let file = repo_root_hgpath.join(file?.as_ref()); - callback(relativize_path(&file, &cwd_hgpath))?; + pub fn relativize<'a>(&self, path: &'a HgPath) -> Cow<'a, [u8]> { + if self.outside_repo { + let joined = self.repo_root.join(path); + Cow::Owned(relativize_path(&joined, &self.cwd).into_owned()) } else { - callback(relativize_path(file?.as_ref(), &cwd_hgpath))?; + relativize_path(path, &self.cwd) } } - Ok(()) }