diff --git a/cli/src/complete.rs b/cli/src/complete.rs index 997c8908583..853c833fa00 100644 --- a/cli/src/complete.rs +++ b/cli/src/complete.rs @@ -218,18 +218,58 @@ fn revisions(revisions: &str) -> Vec { .arg("--revisions") .arg(revisions) .arg("--template") - .arg(r#"change_id.shortest() ++ " " ++ if(description, description.first_line(), "(no description set)") ++ "\n""#) + .arg( + r#" + change_id.shortest() ++ "\t" ++ + bookmarks.map(|b| separate("@", b.name(), b.remote())).join(",") ++ "\t" ++ + tags.map(|t| t.name()).join(",") ++ " " ++ + if(description, description.first_line(), "(no description set)") ++ "\n" + "#, + ) .output() .map_err(user_error)?; let stdout = String::from_utf8_lossy(&output.stdout); - Ok(stdout - .lines() - .map(|line| { - let (id, desc) = split_help_text(line); - CompletionCandidate::new(id).help(desc) - }) - .collect()) + let mut candidates = Vec::new(); + + // display order: + // - 0: local bookmarks + // - 1: regular revisions + // - 2: tags + // - 3: remote bookmarks + + for line in stdout.lines() { + let (id_and_refs, desc) = split_help_text(line); + let (id, bookmarks_and_tags) = id_and_refs + .split_once('\t') + .expect("template should contain a tab character"); + let (bookmarks, tags) = bookmarks_and_tags + .split_once('\t') + .expect("template should contain two tab characters"); + + for b in bookmarks.split(',').filter(|b| !b.is_empty()) { + let order = if b.contains('@') { 3 } else { 0 }; + candidates.push( + CompletionCandidate::new(b) + .help(desc.clone()) + .display_order(Some(order)), + ); + } + for t in tags.split(',').filter(|t| !t.is_empty()) { + candidates.push( + CompletionCandidate::new(t) + .help(desc.clone()) + .display_order(Some(2)), + ); + } + candidates.push( + CompletionCandidate::new(id) + .help(desc) + .display_order(Some(1)), + ); + } + + Ok(candidates) }) } diff --git a/cli/tests/test_completion.rs b/cli/tests/test_completion.rs index c3bea0ac68d..24c771f1836 100644 --- a/cli/tests/test_completion.rs +++ b/cli/tests/test_completion.rs @@ -316,10 +316,37 @@ fn test_revisions() { test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "repo"]); let repo_path = test_env.env_root().join("repo"); + // create remote to test remote branches + test_env.jj_cmd_ok(test_env.env_root(), &["git", "init", "origin"]); + let origin_path = test_env.env_root().join("origin"); + let origin_git_repo_path = origin_path + .join(".jj") + .join("repo") + .join("store") + .join("git"); + test_env.jj_cmd_ok( + &repo_path, + &[ + "git", + "remote", + "add", + "origin", + origin_git_repo_path.to_str().unwrap(), + ], + ); + test_env.jj_cmd_ok(&origin_path, &["b", "c", "remote_bookmark"]); + test_env.jj_cmd_ok(&origin_path, &["commit", "-m", "remote_commit"]); + test_env.jj_cmd_ok(&origin_path, &["git", "export"]); + test_env.jj_cmd_ok(&repo_path, &["git", "fetch"]); + + test_env.jj_cmd_ok(&repo_path, &["b", "c", "immutable_bookmark"]); test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "immutable"]); + test_env.add_config(r#"revset-aliases."immutable_heads()" = "immutable_bookmark""#); + + test_env.jj_cmd_ok(&repo_path, &["b", "c", "mutable_bookmark"]); test_env.jj_cmd_ok(&repo_path, &["commit", "-m", "mutable"]); - test_env.jj_cmd_ok(&repo_path, &["bookmark", "create", "main", "-r", "@--"]); - test_env.add_config(r#"revset-aliases."immutable_heads()" = "main""#); + + test_env.jj_cmd_ok(&repo_path, &["describe", "-m", "working_copy"]); let mut test_env = test_env; test_env.add_env_var("COMPLETE", "fish"); @@ -332,17 +359,24 @@ fn test_revisions() { // complete all revisions let stdout = test_env.jj_cmd_success(&repo_path, &["--", "jj", "diff", "--from", ""]); insta::assert_snapshot!(stdout, @r" - k (no description set) - r mutable + mutable_bookmark mutable + immutable_bookmark immutable + k working_copy + y mutable q immutable - z (no description set) + zq remote_commit + zz (no description set) + remote_bookmark@origin remote_commit "); // complete only mutable revisions let stdout = test_env.jj_cmd_success(&repo_path, &["--", "jj", "squash", "--into", ""]); insta::assert_snapshot!(stdout, @r" - k (no description set) - r mutable + mutable_bookmark mutable + k working_copy + y mutable + zq remote_commit + remote_bookmark@origin remote_commit "); }