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 @@ -6,9 +6,10 @@ // GNU General Public License version 2 or any later version. use crate::error::CommandError; -use crate::ui::Ui; +use crate::ui::{Ui, UiError}; use clap::{Arg, SubCommand}; use hg; +use hg::config::Config; use hg::dirstate_tree::dirstate_map::DirstateMap; use hg::errors::HgResultExt; use hg::errors::IoResultExt; @@ -16,6 +17,9 @@ use hg::operations::cat; use hg::repo::Repo; use hg::revlog::node::Node; +use hg::utils::current_dir; +use hg::utils::files::{get_bytes_from_path, relativize_path}; +use hg::utils::hg_path::HgPathBuf; use hg::utils::hg_path::{hg_path_to_os_string, HgPath}; use hg::StatusError; use hg::{HgPathCow, StatusOptions}; @@ -154,6 +158,7 @@ } let ui = invocation.ui; + let config = invocation.config; let args = invocation.subcommand_args; let display_states = if args.is_present("all") { // TODO when implementing `--quiet`: it excludes clean files @@ -247,25 +252,25 @@ } } if display_states.modified { - display_status_paths(ui, &mut ds_status.modified, b"M")?; + display_status_paths(ui, repo, config, &mut ds_status.modified, b"M")?; } if display_states.added { - display_status_paths(ui, &mut ds_status.added, b"A")?; + display_status_paths(ui, repo, config, &mut ds_status.added, b"A")?; } if display_states.removed { - display_status_paths(ui, &mut ds_status.removed, b"R")?; + display_status_paths(ui, repo, config, &mut ds_status.removed, b"R")?; } if display_states.deleted { - display_status_paths(ui, &mut ds_status.deleted, b"!")?; + display_status_paths(ui, repo, config, &mut ds_status.deleted, b"!")?; } if display_states.unknown { - display_status_paths(ui, &mut ds_status.unknown, b"?")?; + display_status_paths(ui, repo, config, &mut ds_status.unknown, b"?")?; } if display_states.ignored { - display_status_paths(ui, &mut ds_status.ignored, b"I")?; + display_status_paths(ui, repo, config, &mut ds_status.ignored, b"I")?; } if display_states.clean { - display_status_paths(ui, &mut ds_status.clean, b"C")?; + display_status_paths(ui, repo, config, &mut ds_status.clean, b"C")?; } Ok(()) } @@ -274,16 +279,66 @@ // harcode HgPathBuf, but probably not really useful at this point fn display_status_paths( ui: &Ui, + repo: &Repo, + config: &Config, paths: &mut [HgPathCow], status_prefix: &[u8], ) -> Result<(), CommandError> { paths.sort_unstable(); - for path in paths { - // Same TODO as in commands::root - let bytes: &[u8] = path.as_bytes(); - // TODO optim, probably lots of unneeded copies here, especially - // if out stream is buffered - ui.write_stdout(&[status_prefix, b" ", bytes, b"\n"].concat())?; + let mut relative: bool = + config.get_bool(b"ui", b"relative-paths").unwrap_or(false); + relative = config + .get_bool(b"commands", b"status.relative") + .unwrap_or(relative); + if relative { + let cwd = current_dir()?; + let working_directory = repo.working_directory_path(); + let working_directory = cwd.join(working_directory); // Make it absolute + let working_directory_hgpath = + HgPathBuf::from(get_bytes_from_path(working_directory.to_owned())); + let outside_repo: bool; + let cwd_hgpath: HgPathBuf; + + if let Ok(cwd_relative_to_repo) = cwd.strip_prefix(&working_directory) + { + // 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)); + } + + let print_path = |path: &HgPath| -> Result<(), UiError> { + ui.write_stdout( + &[ + status_prefix, + b" ", + relativize_path(path, &cwd_hgpath).as_ref(), + b"\n", + ] + .concat(), + ) + }; + + for file in paths { + if outside_repo { + let file = working_directory_hgpath.join(file); + print_path(&file)?; + } else { + print_path(file)?; + } + } + } else { + for path in paths { + // Same TODO as in commands::root + let bytes: &[u8] = path.as_bytes(); + // TODO optim, probably lots of unneeded copies here, especially + // if out stream is buffered + ui.write_stdout(&[status_prefix, b" ", bytes, b"\n"].concat())?; + } } Ok(()) }