Skip to content

Commit

Permalink
cli: move description utils to description_util.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoineCezar committed Nov 6, 2023
1 parent f1898a3 commit afc2382
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 121 deletions.
2 changes: 1 addition & 1 deletion cli/src/commands/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use jj_lib::repo::Repo;
use jj_lib::rewrite::merge_commit_trees;
use tracing::instrument;

use super::{description_template_for_commit, edit_description};
use crate::cli_util::{join_message_paragraphs, user_error, CommandError, CommandHelper};
use crate::description_util::{description_template_for_commit, edit_description};
use crate::ui::Ui;

/// Update the description and create a new change on top.
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/describe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use std::io::{self, Read, Write};
use jj_lib::backend::ObjectId;
use tracing::instrument;

use super::{description_template_for_commit, edit_description};
use crate::cli_util::{join_message_paragraphs, CommandError, CommandHelper, RevisionArg};
use crate::description_util::{description_template_for_commit, edit_description};
use crate::ui::Ui;

/// Update the change description or other metadata
Expand Down
117 changes: 2 additions & 115 deletions cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,24 +55,14 @@ mod util;
mod version;
mod workspace;

use std::fmt;
use std::fmt::Debug;
use std::io::Write;
use std::{fmt, fs, io};

use clap::{Command, CommandFactory, FromArgMatches, Subcommand};
use itertools::Itertools;
use jj_lib::commit::Commit;
use jj_lib::matchers::EverythingMatcher;
use jj_lib::repo::ReadonlyRepo;
use jj_lib::settings::UserSettings;
use tracing::instrument;

use crate::cli_util::{
run_ui_editor, user_error, Args, CommandError, CommandHelper, WorkspaceCommandHelper,
};
use crate::diff_util::{self, DiffFormat};
use crate::formatter::PlainTextFormatter;
use crate::text_util;
use crate::cli_util::{Args, CommandError, CommandHelper};
use crate::ui::Ui;

#[derive(clap::Parser, Clone, Debug)]
Expand Down Expand Up @@ -145,109 +135,6 @@ enum Commands {
Workspace(workspace::WorkspaceCommands),
}

fn edit_description(
repo: &ReadonlyRepo,
description: &str,
settings: &UserSettings,
) -> Result<String, CommandError> {
let description_file_path = (|| -> Result<_, io::Error> {
let mut file = tempfile::Builder::new()
.prefix("editor-")
.suffix(".jjdescription")
.tempfile_in(repo.repo_path())?;
file.write_all(description.as_bytes())?;
file.write_all(b"\nJJ: Lines starting with \"JJ: \" (like this one) will be removed.\n")?;
let (_, path) = file.keep().map_err(|e| e.error)?;
Ok(path)
})()
.map_err(|e| {
user_error(format!(
r#"Failed to create description file in "{path}": {e}"#,
path = repo.repo_path().display()
))
})?;

run_ui_editor(settings, &description_file_path)?;

let description = fs::read_to_string(&description_file_path).map_err(|e| {
user_error(format!(
r#"Failed to read description file "{path}": {e}"#,
path = description_file_path.display()
))
})?;
// 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();
// Normalize line ending, remove leading and trailing blank lines.
let description = description
.lines()
.filter(|line| !line.starts_with("JJ: "))
.join("\n");
Ok(text_util::complete_newline(description.trim_matches('\n')))
}

fn combine_messages(
repo: &ReadonlyRepo,
source: &Commit,
destination: &Commit,
settings: &UserSettings,
abandon_source: bool,
) -> Result<String, CommandError> {
let description = if abandon_source {
if source.description().is_empty() {
destination.description().to_string()
} else if destination.description().is_empty() {
source.description().to_string()
} else {
let combined = "JJ: Enter a description for the combined commit.\n".to_string()
+ "JJ: Description from the destination commit:\n"
+ destination.description()
+ "\nJJ: Description from the source commit:\n"
+ source.description();
edit_description(repo, &combined, settings)?
}
} else {
destination.description().to_string()
};
Ok(description)
}

fn description_template_for_commit(
ui: &Ui,
settings: &UserSettings,
workspace_command: &WorkspaceCommandHelper,
commit: &Commit,
) -> Result<String, CommandError> {
let mut diff_summary_bytes = Vec::new();
diff_util::show_patch(
ui,
&mut PlainTextFormatter::new(&mut diff_summary_bytes),
workspace_command,
commit,
&EverythingMatcher,
&[DiffFormat::Summary],
)?;
let description = if commit.description().is_empty() {
settings.default_description()
} else {
commit.description().to_owned()
};
if diff_summary_bytes.is_empty() {
Ok(description)
} else {
Ok(description + "\n" + &diff_summary_to_description(&diff_summary_bytes))
}
}

fn diff_summary_to_description(bytes: &[u8]) -> String {
let text = std::str::from_utf8(bytes).expect(
"Summary diffs and repo paths must always be valid UTF8.",
// Double-check this assumption for diffs that include file content.
);
"JJ: This commit contains the following changes:\n".to_owned()
+ &textwrap::indent(text, "JJ: ")
}

fn make_branch_term(branch_names: &[impl fmt::Display]) -> String {
match branch_names {
[branch_name] => format!("branch {}", branch_name),
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/move.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use jj_lib::repo::Repo;
use jj_lib::rewrite::merge_commit_trees;
use tracing::instrument;

use super::combine_messages;
use crate::cli_util::{user_error, CommandError, CommandHelper, RevisionArg};
use crate::description_util::combine_messages;
use crate::ui::Ui;

/// Move changes from one revision into another
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/split.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ use jj_lib::settings::UserSettings;
use maplit::{hashmap, hashset};
use tracing::instrument;

use super::{diff_summary_to_description, edit_description};
use crate::cli_util::{CommandError, CommandHelper, RevisionArg, WorkspaceCommandHelper};
use crate::description_util::{diff_summary_to_description, edit_description};
use crate::diff_util::{self, DiffFormat};
use crate::formatter::PlainTextFormatter;
use crate::ui::Ui;
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/squash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use jj_lib::backend::ObjectId;
use jj_lib::revset;
use tracing::instrument;

use super::combine_messages;
use crate::cli_util::{self, user_error, CommandError, CommandHelper, RevisionArg};
use crate::description_util::combine_messages;
use crate::ui::Ui;

/// Move changes from a revision into its parent
Expand Down
2 changes: 1 addition & 1 deletion cli/src/commands/unsquash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use jj_lib::matchers::EverythingMatcher;
use jj_lib::rewrite::merge_commit_trees;
use tracing::instrument;

use super::combine_messages;
use crate::cli_util::{user_error, CommandError, CommandHelper, RevisionArg};
use crate::description_util::combine_messages;
use crate::ui::Ui;

/// Move changes from a revision's parent into the revision
Expand Down
117 changes: 117 additions & 0 deletions cli/src/description_util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
use std::io::Write;
use std::{fs, io};

use itertools::Itertools;
use jj_lib::commit::Commit;
use jj_lib::matchers::EverythingMatcher;
use jj_lib::repo::ReadonlyRepo;
use jj_lib::settings::UserSettings;

use crate::cli_util::{run_ui_editor, user_error, CommandError, WorkspaceCommandHelper};
use crate::diff_util::{self, DiffFormat};
use crate::formatter::PlainTextFormatter;
use crate::text_util;
use crate::ui::Ui;

pub fn edit_description(
repo: &ReadonlyRepo,
description: &str,
settings: &UserSettings,
) -> Result<String, CommandError> {
let description_file_path = (|| -> Result<_, io::Error> {
let mut file = tempfile::Builder::new()
.prefix("editor-")
.suffix(".jjdescription")
.tempfile_in(repo.repo_path())?;
file.write_all(description.as_bytes())?;
file.write_all(b"\nJJ: Lines starting with \"JJ: \" (like this one) will be removed.\n")?;
let (_, path) = file.keep().map_err(|e| e.error)?;
Ok(path)
})()
.map_err(|e| {
user_error(format!(
r#"Failed to create description file in "{path}": {e}"#,
path = repo.repo_path().display()
))
})?;

run_ui_editor(settings, &description_file_path)?;

let description = fs::read_to_string(&description_file_path).map_err(|e| {
user_error(format!(
r#"Failed to read description file "{path}": {e}"#,
path = description_file_path.display()
))
})?;
// 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();
// Normalize line ending, remove leading and trailing blank lines.
let description = description
.lines()
.filter(|line| !line.starts_with("JJ: "))
.join("\n");
Ok(text_util::complete_newline(description.trim_matches('\n')))
}

pub fn combine_messages(
repo: &ReadonlyRepo,
source: &Commit,
destination: &Commit,
settings: &UserSettings,
abandon_source: bool,
) -> Result<String, CommandError> {
let description = if abandon_source {
if source.description().is_empty() {
destination.description().to_string()
} else if destination.description().is_empty() {
source.description().to_string()
} else {
let combined = "JJ: Enter a description for the combined commit.\n".to_string()
+ "JJ: Description from the destination commit:\n"
+ destination.description()
+ "\nJJ: Description from the source commit:\n"
+ source.description();
edit_description(repo, &combined, settings)?
}
} else {
destination.description().to_string()
};
Ok(description)
}

pub fn description_template_for_commit(
ui: &Ui,
settings: &UserSettings,
workspace_command: &WorkspaceCommandHelper,
commit: &Commit,
) -> Result<String, CommandError> {
let mut diff_summary_bytes = Vec::new();
diff_util::show_patch(
ui,
&mut PlainTextFormatter::new(&mut diff_summary_bytes),
workspace_command,
commit,
&EverythingMatcher,
&[DiffFormat::Summary],
)?;
let description = if commit.description().is_empty() {
settings.default_description()
} else {
commit.description().to_owned()
};
if diff_summary_bytes.is_empty() {
Ok(description)
} else {
Ok(description + "\n" + &diff_summary_to_description(&diff_summary_bytes))
}
}

pub fn diff_summary_to_description(bytes: &[u8]) -> String {
let text = std::str::from_utf8(bytes).expect(
"Summary diffs and repo paths must always be valid UTF8.",
// Double-check this assumption for diffs that include file content.
);
"JJ: This commit contains the following changes:\n".to_owned()
+ &textwrap::indent(text, "JJ: ")
}
1 change: 1 addition & 0 deletions cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub mod cli_util;
pub mod commands;
pub mod commit_templater;
pub mod config;
pub mod description_util;
pub mod diff_util;
pub mod formatter;
pub mod graphlog;
Expand Down

0 comments on commit afc2382

Please sign in to comment.