rust/rhg/src/commands/status.rs
changeset 51155 ac3859a8b796
parent 51153 976403c95ba3
child 51191 13f58ce70299
--- a/rust/rhg/src/commands/status.rs	Wed Nov 15 18:41:33 2023 +0000
+++ b/rust/rhg/src/commands/status.rs	Wed Nov 15 18:43:03 2023 +0000
@@ -30,11 +30,13 @@
 use hg::utils::hg_path::{hg_path_to_path_buf, HgPath};
 use hg::DirstateStatus;
 use hg::PatternFileWarning;
+use hg::Revision;
 use hg::StatusError;
 use hg::StatusOptions;
 use hg::{self, narrow, sparse};
 use log::info;
 use rayon::prelude::*;
+use std::borrow::Cow;
 use std::io;
 use std::mem::take;
 use std::path::PathBuf;
@@ -141,6 +143,38 @@
                 .action(clap::ArgAction::SetTrue)
                 .long("verbose"),
         )
+        .arg(
+            Arg::new("rev")
+                .help("show difference from/to revision")
+                .long("rev")
+                .num_args(1)
+                .action(clap::ArgAction::Append)
+                .value_name("REV"),
+        )
+}
+
+fn parse_revpair(
+    repo: &Repo,
+    revs: Option<Vec<String>>,
+) -> Result<Option<(Revision, Revision)>, CommandError> {
+    let revs = match revs {
+        None => return Ok(None),
+        Some(revs) => revs,
+    };
+    if revs.is_empty() {
+        return Ok(None);
+    }
+    if revs.len() != 2 {
+        return Err(CommandError::unsupported("expected 0 or 2 --rev flags"));
+    }
+
+    let rev1 = &revs[0];
+    let rev2 = &revs[1];
+    let rev1 = hg::revset::resolve_single(rev1, repo)
+        .map_err(|e| (e, rev1.as_str()))?;
+    let rev2 = hg::revset::resolve_single(rev2, repo)
+        .map_err(|e| (e, rev2.as_str()))?;
+    Ok(Some((rev1, rev2)))
 }
 
 /// Pure data type allowing the caller to specify file states to display
@@ -230,6 +264,7 @@
     let config = invocation.config;
     let args = invocation.subcommand_args;
 
+    let revs = args.get_many::<String>("rev");
     let print0 = args.get_flag("print0");
     let verbose = args.get_flag("verbose")
         || config.get_bool(b"ui", b"verbose")?
@@ -263,6 +298,7 @@
         || config.get_bool(b"ui", b"statuscopies")?;
 
     let repo = invocation.repo?;
+    let revpair = parse_revpair(repo, revs.map(|i| i.cloned().collect()))?;
 
     if verbose && has_unfinished_state(repo)? {
         return Err(CommandError::unsupported(
@@ -407,6 +443,57 @@
         ))
     };
     let (narrow_matcher, narrow_warnings) = narrow::matcher(repo)?;
+
+    match revpair {
+        Some((rev1, rev2)) => {
+            let mut ds_status = DirstateStatus::default();
+            if list_copies {
+                return Err(CommandError::unsupported(
+                    "status --rev --rev with copy information is not implemented yet",
+                ));
+            }
+
+            let stat = hg::operations::status_rev_rev_no_copies(
+                repo,
+                rev1,
+                rev2,
+                narrow_matcher,
+            )?;
+            for entry in stat.iter() {
+                let (path, status) = entry?;
+                let path = StatusPath {
+                    path: Cow::Borrowed(path),
+                    copy_source: None,
+                };
+                match status {
+                    hg::operations::DiffStatus::Removed => {
+                        if display_states.removed {
+                            ds_status.removed.push(path)
+                        }
+                    }
+                    hg::operations::DiffStatus::Added => {
+                        if display_states.added {
+                            ds_status.added.push(path)
+                        }
+                    }
+                    hg::operations::DiffStatus::Modified => {
+                        if display_states.modified {
+                            ds_status.modified.push(path)
+                        }
+                    }
+                    hg::operations::DiffStatus::Matching => {
+                        if display_states.clean {
+                            ds_status.clean.push(path)
+                        }
+                    }
+                }
+            }
+            output.output(display_states, ds_status)?;
+            return Ok(());
+        }
+        None => (),
+    }
+
     let (sparse_matcher, sparse_warnings) = sparse::matcher(repo)?;
     let matcher = match (repo.has_narrow(), repo.has_sparse()) {
         (true, true) => {