diff --git a/src/cli_util.rs b/src/cli_util.rs index f2f2e1805..b1a2ddd07 100644 --- a/src/cli_util.rs +++ b/src/cli_util.rs @@ -1376,7 +1376,7 @@ impl AsRef for DescriptionArg { } } -fn complete_newline(s: &mut String) { +pub fn complete_newline(s: &mut String) { if !s.is_empty() && !s.ends_with('\n') { s.push('\n'); } diff --git a/src/commands.rs b/src/commands.rs index b296ef2ef..373f7fa81 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -51,10 +51,10 @@ use maplit::{hashmap, hashset}; use pest::Parser; use crate::cli_util::{ - check_stale_working_copy, print_checkout_stats, print_failed_git_export, resolve_base_revs, - short_commit_description, short_commit_hash, user_error, user_error_with_hint, - write_commit_summary, Args, CommandError, CommandHelper, DescriptionArg, RevisionArg, - WorkspaceCommandHelper, + self, check_stale_working_copy, print_checkout_stats, print_failed_git_export, + resolve_base_revs, short_commit_description, short_commit_hash, user_error, + user_error_with_hint, write_commit_summary, Args, CommandError, CommandHelper, DescriptionArg, + RevisionArg, WorkspaceCommandHelper, }; use crate::config::FullCommandArgs; use crate::diff_util::{self, DiffFormat, DiffFormatArgs}; @@ -1853,15 +1853,14 @@ fn edit_description( // Delete the file only if everything went well. // TODO: Tell the user the name of the file we left behind. std::fs::remove_file(description_file_path).ok(); - let mut lines = description - .split_inclusive('\n') + // Normalize line ending, remove trailing blank lines. + let mut description = description + .lines() .filter(|line| !line.starts_with("JJ: ")) - .collect_vec(); - // Remove trailing blank lines - while matches!(lines.last(), Some(&"\n") | Some(&"\r\n")) { - lines.pop().unwrap(); - } - Ok(lines.join("")) + .join("\n"); + description.truncate(description.trim_end_matches('\n').len()); + cli_util::complete_newline(&mut description); + Ok(description) } fn cmd_describe( diff --git a/tests/test_commit_command.rs b/tests/test_commit_command.rs index abdd60661..043f8b3d2 100644 --- a/tests/test_commit_command.rs +++ b/tests/test_commit_command.rs @@ -55,8 +55,8 @@ modified", .unwrap(); test_env.jj_cmd_success(&workspace_path, &["commit"]); insta::assert_snapshot!(get_log_output(&test_env, &workspace_path), @r###" - @ 3ea3453a773f (no description set) - o 792a60936c42 modified + @ 3df78bc2b9b5 (no description set) + o 30a8c2b3d6eb modified o 000000000000 (no description set) "###); } diff --git a/tests/test_describe_command.rs b/tests/test_describe_command.rs index 41b87e98a..7298e39ca 100644 --- a/tests/test_describe_command.rs +++ b/tests/test_describe_command.rs @@ -56,7 +56,7 @@ JJ: Lines starting with "JJ: " (like this one) will be removed. std::fs::write(&edit_script, "write\ndescription from editor").unwrap(); let stdout = test_env.jj_cmd_success(&repo_path, &["describe"]); insta::assert_snapshot!(stdout, @r###" - Working copy now at: bfdd972f9349 description from editor + Working copy now at: 100943aeee3f description from editor "###); // Lines in editor starting with "JJ: " are ignored @@ -70,6 +70,39 @@ JJ: Lines starting with "JJ: " (like this one) will be removed. Working copy now at: ccefa58bef47 description among comment "###); + // Multi-line description + std::fs::write(&edit_script, "write\nline1\nline2\n\nline4\n\n").unwrap(); + let stdout = test_env.jj_cmd_success(&repo_path, &["describe"]); + insta::assert_snapshot!(stdout, @r###" + Working copy now at: e932ba42cef0 line1 + "###); + let stdout = + test_env.jj_cmd_success(&repo_path, &["log", "--no-graph", "-r@", "-Tdescription"]); + insta::assert_snapshot!(stdout, @r###" + line1 + line2 + + line4 + "###); + + // Multi-line description again with CRLF, which should make no changes + std::fs::write(&edit_script, "write\nline1\r\nline2\r\n\r\nline4\r\n\r\n").unwrap(); + let stdout = test_env.jj_cmd_success(&repo_path, &["describe"]); + insta::assert_snapshot!(stdout, @r###" + Nothing changed. + "###); + + // Clear description + let stdout = test_env.jj_cmd_success(&repo_path, &["describe", "-m", ""]); + insta::assert_snapshot!(stdout, @r###" + Working copy now at: d6957294acdc (no description set) + "###); + std::fs::write(&edit_script, "write\n").unwrap(); + let stdout = test_env.jj_cmd_success(&repo_path, &["describe"]); + insta::assert_snapshot!(stdout, @r###" + Nothing changed. + "###); + // Fails if the editor fails std::fs::write(&edit_script, "fail").unwrap(); let stderr = test_env.jj_cmd_failure(&repo_path, &["describe"]); diff --git a/tests/test_obslog_command.rs b/tests/test_obslog_command.rs index d9f2727d2..0fb3257ef 100644 --- a/tests/test_obslog_command.rs +++ b/tests/test_obslog_command.rs @@ -136,7 +136,7 @@ fn test_obslog_squash() { let stdout = get_log_output(&test_env, &repo_path, &["obslog", "-p", "-r", "@-"]); insta::assert_snapshot!(stdout, @r###" - o test.user@example.com 2001-02-03 04:05:10.000 +07:00 9b6d4a272a6a + o test.user@example.com 2001-02-03 04:05:10.000 +07:00 27e721a5ba72 |\ squashed | | Modified regular file file1: | | 1 1: foo