forked from mirrors/jj
formatter: add a with_label()
helper
There's a risk of forgetting to call `remove_label()` and I've wanted to reduce that risk for a long time. I considered creating RAII adapters that implement `Drop`, but I didn't like that that would ignore errors (such as `BrokenPipe`) that can happen while emitting an escape sequence in `remove_label()`. I would ideally have liked Python's context managers here, but Rust doesn't have that. Instead, we get to use closures. That works pretty well, except that we can't return other errors than `io::Error` inside the closures. Even with that limitation, we can use the new `with_label()` method in all but a few cases. We can't define the `with_label()` method directly in the trait because `&mut self` is not a trait object, so we can't pass it on to the closure (which expects a trait object). The solution is to use `impl dyn Formatter` (thanks to @kupiakos for figuring that out!). That unfortunately means that we can *only* call the function on trait objects, so if `f` is a concrete formatter type (e.g. `PlainTextFormatter`), then `f.with_label()` won't compile. Since we only ever access the formatters as trait objects, that's not really a problem, however.
This commit is contained in:
parent
a5f7e09cbb
commit
a061ac022e
2 changed files with 201 additions and 198 deletions
386
src/commands.rs
386
src/commands.rs
|
@ -1330,17 +1330,17 @@ fn show_color_words_diff_line(
|
|||
diff_line: &DiffLine,
|
||||
) -> io::Result<()> {
|
||||
if diff_line.has_left_content {
|
||||
formatter.add_label("removed")?;
|
||||
formatter.write_bytes(format!("{:>4}", diff_line.left_line_number).as_bytes())?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("removed", |formatter| {
|
||||
formatter.write_bytes(format!("{:>4}", diff_line.left_line_number).as_bytes())
|
||||
})?;
|
||||
formatter.write_bytes(b" ")?;
|
||||
} else {
|
||||
formatter.write_bytes(b" ")?;
|
||||
}
|
||||
if diff_line.has_right_content {
|
||||
formatter.add_label("added")?;
|
||||
formatter.write_bytes(format!("{:>4}", diff_line.right_line_number).as_bytes())?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("added", |formatter| {
|
||||
formatter.write_bytes(format!("{:>4}", diff_line.right_line_number).as_bytes())
|
||||
})?;
|
||||
formatter.write_bytes(b": ")?;
|
||||
} else {
|
||||
formatter.write_bytes(b" : ")?;
|
||||
|
@ -1354,14 +1354,10 @@ fn show_color_words_diff_line(
|
|||
let before = data[0];
|
||||
let after = data[1];
|
||||
if !before.is_empty() {
|
||||
formatter.add_label("removed")?;
|
||||
formatter.write_bytes(before)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("removed", |formatter| formatter.write_bytes(before))?;
|
||||
}
|
||||
if !after.is_empty() {
|
||||
formatter.add_label("added")?;
|
||||
formatter.write_bytes(after)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("added", |formatter| formatter.write_bytes(after))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1547,9 +1543,9 @@ fn show_color_words_diff(
|
|||
tree::Diff::Added(right_value) => {
|
||||
let right_content = diff_content(repo, &path, &right_value)?;
|
||||
let description = basic_diff_file_type(&right_value);
|
||||
formatter.add_label("header")?;
|
||||
formatter.write_str(&format!("Added {} {}:\n", description, ui_path))?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("header", |formatter| {
|
||||
formatter.write_str(&format!("Added {} {}:\n", description, ui_path))
|
||||
})?;
|
||||
show_color_words_diff_hunks(&[], &right_content, formatter)?;
|
||||
}
|
||||
tree::Diff::Modified(left_value, right_value) => {
|
||||
|
@ -1596,17 +1592,17 @@ fn show_color_words_diff(
|
|||
)
|
||||
}
|
||||
};
|
||||
formatter.add_label("header")?;
|
||||
formatter.write_str(&format!("{} {}:\n", description, ui_path))?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("header", |formatter| {
|
||||
formatter.write_str(&format!("{} {}:\n", description, ui_path))
|
||||
})?;
|
||||
show_color_words_diff_hunks(&left_content, &right_content, formatter)?;
|
||||
}
|
||||
tree::Diff::Removed(left_value) => {
|
||||
let left_content = diff_content(repo, &path, &left_value)?;
|
||||
let description = basic_diff_file_type(&left_value);
|
||||
formatter.add_label("header")?;
|
||||
formatter.write_str(&format!("Removed {} {}:\n", description, ui_path))?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("header", |formatter| {
|
||||
formatter.write_str(&format!("Removed {} {}:\n", description, ui_path))
|
||||
})?;
|
||||
show_color_words_diff_hunks(&left_content, &[], formatter)?;
|
||||
}
|
||||
}
|
||||
|
@ -1771,35 +1767,35 @@ fn show_unified_diff_hunks(
|
|||
right_content: &[u8],
|
||||
) -> Result<(), CommandError> {
|
||||
for hunk in unified_diff_hunks(left_content, right_content, 3) {
|
||||
formatter.add_label("hunk_header")?;
|
||||
writeln!(
|
||||
formatter,
|
||||
"@@ -{},{} +{},{} @@",
|
||||
hunk.left_line_range.start,
|
||||
hunk.left_line_range.len(),
|
||||
hunk.right_line_range.start,
|
||||
hunk.right_line_range.len()
|
||||
)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("hunk_header", |formatter| {
|
||||
writeln!(
|
||||
formatter,
|
||||
"@@ -{},{} +{},{} @@",
|
||||
hunk.left_line_range.start,
|
||||
hunk.left_line_range.len(),
|
||||
hunk.right_line_range.start,
|
||||
hunk.right_line_range.len()
|
||||
)
|
||||
})?;
|
||||
for (line_type, content) in hunk.lines {
|
||||
match line_type {
|
||||
DiffLineType::Context => {
|
||||
formatter.add_label("context")?;
|
||||
formatter.write_str(" ")?;
|
||||
formatter.write_all(content)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("context", |formatter| {
|
||||
formatter.write_str(" ")?;
|
||||
formatter.write_all(content)
|
||||
})?;
|
||||
}
|
||||
DiffLineType::Removed => {
|
||||
formatter.add_label("removed")?;
|
||||
formatter.write_str("-")?;
|
||||
formatter.write_all(content)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("removed", |formatter| {
|
||||
formatter.write_str("-")?;
|
||||
formatter.write_all(content)
|
||||
})?;
|
||||
}
|
||||
DiffLineType::Added => {
|
||||
formatter.add_label("added")?;
|
||||
formatter.write_str("+")?;
|
||||
formatter.write_all(content)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("added", |formatter| {
|
||||
formatter.write_str("+")?;
|
||||
formatter.write_all(content)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
if !content.ends_with(b"\n") {
|
||||
|
@ -1819,48 +1815,53 @@ fn show_git_diff(
|
|||
formatter.add_label("diff")?;
|
||||
for (path, diff) in tree_diff {
|
||||
let path_string = path.to_internal_file_string();
|
||||
formatter.add_label("file_header")?;
|
||||
writeln!(formatter, "diff --git a/{} b/{}", path_string, path_string)?;
|
||||
match diff {
|
||||
tree::Diff::Added(right_value) => {
|
||||
let right_part = git_diff_part(repo, &path, &right_value)?;
|
||||
writeln!(formatter, "new file mode {}", &right_part.mode)?;
|
||||
writeln!(formatter, "index 0000000000..{}", &right_part.hash)?;
|
||||
writeln!(formatter, "--- /dev/null")?;
|
||||
writeln!(formatter, "+++ b/{}", path_string)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("file_header", |formatter| {
|
||||
writeln!(formatter, "diff --git a/{} b/{}", path_string, path_string)?;
|
||||
writeln!(formatter, "new file mode {}", &right_part.mode)?;
|
||||
writeln!(formatter, "index 0000000000..{}", &right_part.hash)?;
|
||||
writeln!(formatter, "--- /dev/null")?;
|
||||
writeln!(formatter, "+++ b/{}", path_string)
|
||||
})?;
|
||||
show_unified_diff_hunks(formatter, &[], &right_part.content)?;
|
||||
}
|
||||
tree::Diff::Modified(left_value, right_value) => {
|
||||
let left_part = git_diff_part(repo, &path, &left_value)?;
|
||||
let right_part = git_diff_part(repo, &path, &right_value)?;
|
||||
if left_part.mode != right_part.mode {
|
||||
writeln!(formatter, "old mode {}", &left_part.mode)?;
|
||||
writeln!(formatter, "new mode {}", &right_part.mode)?;
|
||||
if left_part.hash != right_part.hash {
|
||||
writeln!(formatter, "index {}...{}", &left_part.hash, right_part.hash)?;
|
||||
formatter.with_label("file_header", |formatter| {
|
||||
writeln!(formatter, "diff --git a/{} b/{}", path_string, path_string)?;
|
||||
if left_part.mode != right_part.mode {
|
||||
writeln!(formatter, "old mode {}", &left_part.mode)?;
|
||||
writeln!(formatter, "new mode {}", &right_part.mode)?;
|
||||
if left_part.hash != right_part.hash {
|
||||
writeln!(formatter, "index {}...{}", &left_part.hash, right_part.hash)?;
|
||||
}
|
||||
} else if left_part.hash != right_part.hash {
|
||||
writeln!(
|
||||
formatter,
|
||||
"index {}...{} {}",
|
||||
&left_part.hash, right_part.hash, left_part.mode
|
||||
)?;
|
||||
}
|
||||
} else if left_part.hash != right_part.hash {
|
||||
writeln!(
|
||||
formatter,
|
||||
"index {}...{} {}",
|
||||
&left_part.hash, right_part.hash, left_part.mode
|
||||
)?;
|
||||
}
|
||||
if left_part.content != right_part.content {
|
||||
writeln!(formatter, "--- a/{}", path_string)?;
|
||||
writeln!(formatter, "+++ b/{}", path_string)?;
|
||||
}
|
||||
formatter.remove_label()?;
|
||||
if left_part.content != right_part.content {
|
||||
writeln!(formatter, "--- a/{}", path_string)?;
|
||||
writeln!(formatter, "+++ b/{}", path_string)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
show_unified_diff_hunks(formatter, &left_part.content, &right_part.content)?;
|
||||
}
|
||||
tree::Diff::Removed(left_value) => {
|
||||
let left_part = git_diff_part(repo, &path, &left_value)?;
|
||||
writeln!(formatter, "deleted file mode {}", &left_part.mode)?;
|
||||
writeln!(formatter, "index {}..0000000000", &left_part.hash)?;
|
||||
writeln!(formatter, "--- a/{}", path_string)?;
|
||||
writeln!(formatter, "+++ /dev/null")?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("file_header", |formatter| {
|
||||
writeln!(formatter, "diff --git a/{} b/{}", path_string, path_string)?;
|
||||
writeln!(formatter, "deleted file mode {}", &left_part.mode)?;
|
||||
writeln!(formatter, "index {}..0000000000", &left_part.hash)?;
|
||||
writeln!(formatter, "--- a/{}", path_string)?;
|
||||
writeln!(formatter, "+++ /dev/null")
|
||||
})?;
|
||||
show_unified_diff_hunks(formatter, &left_part.content, &[])?;
|
||||
}
|
||||
}
|
||||
|
@ -1874,40 +1875,40 @@ fn show_diff_summary(
|
|||
workspace_command: &WorkspaceCommandHelper,
|
||||
tree_diff: TreeDiffIterator,
|
||||
) -> io::Result<()> {
|
||||
formatter.add_label("diff")?;
|
||||
for (repo_path, diff) in tree_diff {
|
||||
match diff {
|
||||
tree::Diff::Modified(_, _) => {
|
||||
formatter.add_label("modified")?;
|
||||
writeln!(
|
||||
formatter,
|
||||
"M {}",
|
||||
workspace_command.format_file_path(&repo_path)
|
||||
)?;
|
||||
formatter.remove_label()?;
|
||||
}
|
||||
tree::Diff::Added(_) => {
|
||||
formatter.add_label("added")?;
|
||||
writeln!(
|
||||
formatter,
|
||||
"A {}",
|
||||
workspace_command.format_file_path(&repo_path)
|
||||
)?;
|
||||
formatter.remove_label()?;
|
||||
}
|
||||
tree::Diff::Removed(_) => {
|
||||
formatter.add_label("removed")?;
|
||||
writeln!(
|
||||
formatter,
|
||||
"R {}",
|
||||
workspace_command.format_file_path(&repo_path)
|
||||
)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("diff", |formatter| {
|
||||
for (repo_path, diff) in tree_diff {
|
||||
match diff {
|
||||
tree::Diff::Modified(_, _) => {
|
||||
formatter.with_label("modified", |formatter| {
|
||||
writeln!(
|
||||
formatter,
|
||||
"M {}",
|
||||
workspace_command.format_file_path(&repo_path)
|
||||
)
|
||||
})?;
|
||||
}
|
||||
tree::Diff::Added(_) => {
|
||||
formatter.with_label("added", |formatter| {
|
||||
writeln!(
|
||||
formatter,
|
||||
"A {}",
|
||||
workspace_command.format_file_path(&repo_path)
|
||||
)
|
||||
})?;
|
||||
}
|
||||
tree::Diff::Removed(_) => {
|
||||
formatter.with_label("removed", |formatter| {
|
||||
writeln!(
|
||||
formatter,
|
||||
"R {}",
|
||||
workspace_command.format_file_path(&repo_path)
|
||||
)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
formatter.remove_label()?;
|
||||
Ok(())
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn cmd_status(
|
||||
|
@ -1964,14 +1965,12 @@ fn cmd_status(
|
|||
}
|
||||
}
|
||||
if !conflicted_local_branches.is_empty() {
|
||||
formatter.add_label("conflict")?;
|
||||
writeln!(formatter, "These branches have conflicts:")?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("conflict", |formatter| {
|
||||
writeln!(formatter, "These branches have conflicts:")
|
||||
})?;
|
||||
for branch_name in conflicted_local_branches {
|
||||
write!(formatter, " ")?;
|
||||
formatter.add_label("branch")?;
|
||||
write!(formatter, "{}", branch_name)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("branch", |formatter| write!(formatter, "{}", branch_name))?;
|
||||
writeln!(formatter)?;
|
||||
}
|
||||
writeln!(
|
||||
|
@ -1981,14 +1980,14 @@ fn cmd_status(
|
|||
)?;
|
||||
}
|
||||
if !conflicted_remote_branches.is_empty() {
|
||||
formatter.add_label("conflict")?;
|
||||
writeln!(formatter, "These remote branches have conflicts:")?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("conflict", |formatter| {
|
||||
writeln!(formatter, "These remote branches have conflicts:")
|
||||
})?;
|
||||
for (branch_name, remote_name) in conflicted_remote_branches {
|
||||
write!(formatter, " ")?;
|
||||
formatter.add_label("branch")?;
|
||||
write!(formatter, "{}@{}", branch_name, remote_name)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("branch", |formatter| {
|
||||
write!(formatter, "{}@{}", branch_name, remote_name)
|
||||
})?;
|
||||
writeln!(formatter)?;
|
||||
}
|
||||
writeln!(
|
||||
|
@ -2013,9 +2012,9 @@ fn cmd_status(
|
|||
|
||||
let conflicts = tree.conflicts();
|
||||
if !conflicts.is_empty() {
|
||||
formatter.add_label("conflict")?;
|
||||
writeln!(formatter, "There are unresolved conflicts at these paths:")?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("conflict", |formatter| {
|
||||
writeln!(formatter, "There are unresolved conflicts at these paths:")
|
||||
})?;
|
||||
for (path, _) in conflicts {
|
||||
writeln!(formatter, "{}", &workspace_command.format_file_path(&path))?;
|
||||
}
|
||||
|
@ -2126,11 +2125,11 @@ fn cmd_log(ui: &mut Ui, command: &CommandHelper, args: &LogArgs) -> Result<(), C
|
|||
{
|
||||
let mut formatter = ui.new_formatter(&mut buffer);
|
||||
if is_checkout {
|
||||
formatter.add_label("working_copy")?;
|
||||
}
|
||||
template.format(&commit, formatter.as_mut())?;
|
||||
if is_checkout {
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("working_copy", |formatter| {
|
||||
template.format(&commit, formatter)
|
||||
})?;
|
||||
} else {
|
||||
template.format(&commit, formatter.as_mut())?;
|
||||
}
|
||||
}
|
||||
if !buffer.ends_with(b"\n") {
|
||||
|
@ -3411,12 +3410,29 @@ fn list_branches(
|
|||
let repo = workspace_command.repo();
|
||||
|
||||
let workspace_id = workspace_command.workspace_id();
|
||||
let print_branch_target =
|
||||
|formatter: &mut dyn Formatter, target: Option<&RefTarget>| -> Result<(), CommandError> {
|
||||
match target {
|
||||
Some(RefTarget::Normal(id)) => {
|
||||
write!(formatter, ": ")?;
|
||||
let print_branch_target = |formatter: &mut dyn Formatter,
|
||||
target: Option<&RefTarget>|
|
||||
-> Result<(), CommandError> {
|
||||
match target {
|
||||
Some(RefTarget::Normal(id)) => {
|
||||
write!(formatter, ": ")?;
|
||||
let commit = repo.store().get_commit(id)?;
|
||||
write_commit_summary(
|
||||
formatter,
|
||||
repo.as_repo_ref(),
|
||||
&workspace_id,
|
||||
&commit,
|
||||
ui.settings(),
|
||||
)?;
|
||||
writeln!(formatter)?;
|
||||
}
|
||||
Some(RefTarget::Conflict { adds, removes }) => {
|
||||
write!(formatter, " ")?;
|
||||
formatter.with_label("conflict", |formatter| write!(formatter, "(conflicted)"))?;
|
||||
writeln!(formatter, ":")?;
|
||||
for id in removes {
|
||||
let commit = repo.store().get_commit(id)?;
|
||||
write!(formatter, " - ")?;
|
||||
write_commit_summary(
|
||||
formatter,
|
||||
repo.as_repo_ref(),
|
||||
|
@ -3426,51 +3442,31 @@ fn list_branches(
|
|||
)?;
|
||||
writeln!(formatter)?;
|
||||
}
|
||||
Some(RefTarget::Conflict { adds, removes }) => {
|
||||
write!(formatter, " ")?;
|
||||
formatter.add_label("conflict")?;
|
||||
write!(formatter, "(conflicted)")?;
|
||||
formatter.remove_label()?;
|
||||
writeln!(formatter, ":")?;
|
||||
for id in removes {
|
||||
let commit = repo.store().get_commit(id)?;
|
||||
write!(formatter, " - ")?;
|
||||
write_commit_summary(
|
||||
formatter,
|
||||
repo.as_repo_ref(),
|
||||
&workspace_id,
|
||||
&commit,
|
||||
ui.settings(),
|
||||
)?;
|
||||
writeln!(formatter)?;
|
||||
}
|
||||
for id in adds {
|
||||
let commit = repo.store().get_commit(id)?;
|
||||
write!(formatter, " + ")?;
|
||||
write_commit_summary(
|
||||
formatter,
|
||||
repo.as_repo_ref(),
|
||||
&workspace_id,
|
||||
&commit,
|
||||
ui.settings(),
|
||||
)?;
|
||||
writeln!(formatter)?;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
writeln!(formatter, " (deleted)")?;
|
||||
for id in adds {
|
||||
let commit = repo.store().get_commit(id)?;
|
||||
write!(formatter, " + ")?;
|
||||
write_commit_summary(
|
||||
formatter,
|
||||
repo.as_repo_ref(),
|
||||
&workspace_id,
|
||||
&commit,
|
||||
ui.settings(),
|
||||
)?;
|
||||
writeln!(formatter)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
None => {
|
||||
writeln!(formatter, " (deleted)")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let mut formatter = ui.stdout_formatter();
|
||||
let formatter = formatter.as_mut();
|
||||
let index = repo.index();
|
||||
for (name, branch_target) in repo.view().branches() {
|
||||
formatter.add_label("branch")?;
|
||||
write!(formatter, "{}", name)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("branch", |formatter| write!(formatter, "{}", name))?;
|
||||
print_branch_target(formatter, branch_target.local_target.as_ref())?;
|
||||
|
||||
for (remote, remote_target) in branch_target
|
||||
|
@ -3482,9 +3478,7 @@ fn list_branches(
|
|||
continue;
|
||||
}
|
||||
write!(formatter, " ")?;
|
||||
formatter.add_label("branch")?;
|
||||
write!(formatter, "@{}", remote)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("branch", |formatter| write!(formatter, "@{}", remote))?;
|
||||
if let Some(local_target) = branch_target.local_target.as_ref() {
|
||||
let remote_ahead_count = index
|
||||
.walk_revs(&remote_target.adds(), &local_target.adds())
|
||||
|
@ -3617,30 +3611,28 @@ fn cmd_op_log(
|
|||
impl Template<Operation> for OpTemplate {
|
||||
fn format(&self, op: &Operation, formatter: &mut dyn Formatter) -> io::Result<()> {
|
||||
// TODO: Make this templated
|
||||
formatter.add_label("id")?;
|
||||
formatter.write_str(&op.id().hex()[0..12])?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("id", |formatter| formatter.write_str(&op.id().hex()[0..12]))?;
|
||||
formatter.write_str(" ")?;
|
||||
let metadata = &op.store_operation().metadata;
|
||||
formatter.add_label("user")?;
|
||||
formatter.write_str(&format!("{}@{}", metadata.username, metadata.hostname))?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("user", |formatter| {
|
||||
formatter.write_str(&format!("{}@{}", metadata.username, metadata.hostname))
|
||||
})?;
|
||||
formatter.write_str(" ")?;
|
||||
formatter.add_label("time")?;
|
||||
formatter.write_str(&format!(
|
||||
"{} - {}",
|
||||
format_timestamp(&metadata.start_time),
|
||||
format_timestamp(&metadata.end_time)
|
||||
))?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("time", |formatter| {
|
||||
formatter.write_str(&format!(
|
||||
"{} - {}",
|
||||
format_timestamp(&metadata.start_time),
|
||||
format_timestamp(&metadata.end_time)
|
||||
))
|
||||
})?;
|
||||
formatter.write_str("\n")?;
|
||||
formatter.add_label("description")?;
|
||||
formatter.write_str(&metadata.description)?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("description", |formatter| {
|
||||
formatter.write_str(&metadata.description)
|
||||
})?;
|
||||
for (key, value) in &metadata.tags {
|
||||
formatter.add_label("tags")?;
|
||||
formatter.write_str(&format!("\n{}: {}", key, value))?;
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("tags", |formatter| {
|
||||
formatter.write_str(&format!("\n{}: {}", key, value))
|
||||
})?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -3661,15 +3653,13 @@ fn cmd_op_log(
|
|||
let mut buffer = vec![];
|
||||
{
|
||||
let mut formatter = ui.new_formatter(&mut buffer);
|
||||
formatter.add_label("op-log")?;
|
||||
if is_head_op {
|
||||
formatter.add_label("head")?;
|
||||
}
|
||||
template.format(&op, formatter.as_mut())?;
|
||||
if is_head_op {
|
||||
formatter.remove_label()?;
|
||||
}
|
||||
formatter.remove_label()?;
|
||||
formatter.with_label("op-log", |formatter| {
|
||||
if is_head_op {
|
||||
formatter.with_label("head", |formatter| template.format(&op, formatter))
|
||||
} else {
|
||||
template.format(&op, formatter)
|
||||
}
|
||||
})?;
|
||||
}
|
||||
if !buffer.ends_with(b"\n") {
|
||||
buffer.push(b'\n');
|
||||
|
|
|
@ -40,6 +40,19 @@ pub trait Formatter: Write {
|
|||
fn remove_label(&mut self) -> io::Result<()>;
|
||||
}
|
||||
|
||||
impl dyn Formatter + '_ {
|
||||
pub fn with_label(
|
||||
&mut self,
|
||||
label: &str,
|
||||
write_inner: impl FnOnce(&mut dyn Formatter) -> io::Result<()>,
|
||||
) -> io::Result<()> {
|
||||
self.add_label(label)?;
|
||||
// Call `remove_label()` whether or not `write_inner()` fails, but don't let
|
||||
// its error replace the one from `write_inner()`.
|
||||
write_inner(self).and(self.remove_label())
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates `Formatter` instances with preconfigured parameters.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FormatterFactory {
|
||||
|
|
Loading…
Reference in a new issue