styler: rename Styler to more standard Formatter

This commit is contained in:
Martin von Zweigbergk 2021-06-02 15:50:08 -07:00
parent d34a651087
commit b50ef1410d
7 changed files with 158 additions and 152 deletions

View File

@ -826,7 +826,7 @@ mod tests {
fn test_diff_real_case_write_fmt() { fn test_diff_real_case_write_fmt() {
// This is from src/ui.rs in commit f44d246e3f88 in this repo. It highlights the // This is from src/ui.rs in commit f44d246e3f88 in this repo. It highlights the
// need for recursion into the range at the end: after splitting at "Arguments" // need for recursion into the range at the end: after splitting at "Arguments"
// and "styler", the region at the end has the unique words "write_fmt" // and "formatter", the region at the end has the unique words "write_fmt"
// and "fmt", but we forgot to recurse into that region, so we ended up // and "fmt", but we forgot to recurse into that region, so we ended up
// saying that "write_fmt(fmt).unwrap()" was replaced by b"write_fmt(fmt)". // saying that "write_fmt(fmt).unwrap()" was replaced by b"write_fmt(fmt)".
assert_eq!(diff( assert_eq!(diff(

View File

@ -59,8 +59,8 @@ use pest::Parser;
use self::chrono::{FixedOffset, TimeZone, Utc}; use self::chrono::{FixedOffset, TimeZone, Utc};
use crate::commands::CommandError::UserError; use crate::commands::CommandError::UserError;
use crate::diff_edit::DiffEditError; use crate::diff_edit::DiffEditError;
use crate::formatter::{ColorFormatter, Formatter};
use crate::graphlog::{AsciiGraphDrawer, Edge}; use crate::graphlog::{AsciiGraphDrawer, Edge};
use crate::styler::{ColorStyler, Styler};
use crate::template_parser::TemplateParser; use crate::template_parser::TemplateParser;
use crate::templater::Template; use crate::templater::Template;
use crate::ui::Ui; use crate::ui::Ui;
@ -938,7 +938,7 @@ fn cmd_files(
Ok(()) Ok(())
} }
fn print_diff(left: &[u8], right: &[u8], styler: &mut dyn Styler) -> io::Result<()> { fn print_diff(left: &[u8], right: &[u8], formatter: &mut dyn Formatter) -> io::Result<()> {
let num_context_lines = 3; let num_context_lines = 3;
let mut context = VecDeque::new(); let mut context = VecDeque::new();
// Have we printed "..." for any skipped context? // Have we printed "..." for any skipped context?
@ -956,66 +956,66 @@ fn print_diff(left: &[u8], right: &[u8], styler: &mut dyn Styler) -> io::Result<
} }
if !context_before { if !context_before {
for line in &context { for line in &context {
print_diff_line(styler, line)?; print_diff_line(formatter, line)?;
} }
context.clear(); context.clear();
context_before = true; context_before = true;
} }
if !skipped_context { if !skipped_context {
styler.write_bytes(b" ...\n")?; formatter.write_bytes(b" ...\n")?;
skipped_context = true; skipped_context = true;
} }
} }
} else { } else {
for line in &context { for line in &context {
print_diff_line(styler, line)?; print_diff_line(formatter, line)?;
} }
context.clear(); context.clear();
print_diff_line(styler, &diff_line)?; print_diff_line(formatter, &diff_line)?;
context_before = false; context_before = false;
skipped_context = false; skipped_context = false;
} }
} }
if !context_before { if !context_before {
for line in &context { for line in &context {
print_diff_line(styler, line)?; print_diff_line(formatter, line)?;
} }
} }
Ok(()) Ok(())
} }
fn print_diff_line(styler: &mut dyn Styler, diff_line: &DiffLine) -> io::Result<()> { fn print_diff_line(formatter: &mut dyn Formatter, diff_line: &DiffLine) -> io::Result<()> {
if diff_line.has_left_content { if diff_line.has_left_content {
styler.add_label(String::from("left"))?; formatter.add_label(String::from("left"))?;
styler.write_bytes(format!("{:>4}", diff_line.left_line_number).as_bytes())?; formatter.write_bytes(format!("{:>4}", diff_line.left_line_number).as_bytes())?;
styler.remove_label()?; formatter.remove_label()?;
styler.write_bytes(b" ")?; formatter.write_bytes(b" ")?;
} else { } else {
styler.write_bytes(b" ")?; formatter.write_bytes(b" ")?;
} }
if diff_line.has_right_content { if diff_line.has_right_content {
styler.add_label(String::from("right"))?; formatter.add_label(String::from("right"))?;
styler.write_bytes(format!("{:>4}", diff_line.right_line_number).as_bytes())?; formatter.write_bytes(format!("{:>4}", diff_line.right_line_number).as_bytes())?;
styler.remove_label()?; formatter.remove_label()?;
styler.write_bytes(b": ")?; formatter.write_bytes(b": ")?;
} else { } else {
styler.write_bytes(b" : ")?; formatter.write_bytes(b" : ")?;
} }
for hunk in &diff_line.hunks { for hunk in &diff_line.hunks {
match hunk { match hunk {
files::DiffHunk::Unmodified(data) => { files::DiffHunk::Unmodified(data) => {
styler.write_bytes(data)?; formatter.write_bytes(data)?;
} }
files::DiffHunk::Removed(data) => { files::DiffHunk::Removed(data) => {
styler.add_label(String::from("left"))?; formatter.add_label(String::from("left"))?;
styler.write_bytes(data)?; formatter.write_bytes(data)?;
styler.remove_label()?; formatter.remove_label()?;
} }
files::DiffHunk::Added(data) => { files::DiffHunk::Added(data) => {
styler.add_label(String::from("right"))?; formatter.add_label(String::from("right"))?;
styler.write_bytes(data)?; formatter.write_bytes(data)?;
styler.remove_label()?; formatter.remove_label()?;
} }
} }
} }
@ -1055,8 +1055,8 @@ fn cmd_diff(
let summary = from_tree.diff_summary(&to_tree); let summary = from_tree.diff_summary(&to_tree);
show_diff_summary(ui, repo.working_copy_path(), &summary)?; show_diff_summary(ui, repo.working_copy_path(), &summary)?;
} else { } else {
let mut styler = ui.styler(); let mut formatter = ui.formatter();
styler.add_label(String::from("diff"))?; formatter.add_label(String::from("diff"))?;
for (path, diff) in from_tree.diff(&to_tree) { for (path, diff) in from_tree.diff(&to_tree) {
let ui_path = ui.format_file_path(repo.working_copy_path(), &path); let ui_path = ui.format_file_path(repo.working_copy_path(), &path);
match diff { match diff {
@ -1064,11 +1064,11 @@ fn cmd_diff(
id, id,
executable: false, executable: false,
}) => { }) => {
styler.add_label(String::from("header"))?; formatter.add_label(String::from("header"))?;
styler.write_str(&format!("added file {}:\n", ui_path))?; formatter.write_str(&format!("added file {}:\n", ui_path))?;
styler.remove_label()?; formatter.remove_label()?;
let mut file_reader = repo.store().read_file(&path, &id).unwrap(); let mut file_reader = repo.store().read_file(&path, &id).unwrap();
styler.write_from_reader(&mut file_reader)?; formatter.write_from_reader(&mut file_reader)?;
} }
Diff::Modified( Diff::Modified(
TreeValue::Normal { TreeValue::Normal {
@ -1080,13 +1080,13 @@ fn cmd_diff(
executable: right_executable, executable: right_executable,
}, },
) if left_executable == right_executable => { ) if left_executable == right_executable => {
styler.add_label(String::from("header"))?; formatter.add_label(String::from("header"))?;
if left_executable { if left_executable {
styler.write_str(&format!("modified executable file {}:\n", ui_path))?; formatter.write_str(&format!("modified executable file {}:\n", ui_path))?;
} else { } else {
styler.write_str(&format!("modified file {}:\n", ui_path))?; formatter.write_str(&format!("modified file {}:\n", ui_path))?;
} }
styler.remove_label()?; formatter.remove_label()?;
let mut file_reader_left = repo.store().read_file(&path, &id_left).unwrap(); let mut file_reader_left = repo.store().read_file(&path, &id_left).unwrap();
let mut buffer_left = vec![]; let mut buffer_left = vec![];
@ -1098,7 +1098,7 @@ fn cmd_diff(
print_diff( print_diff(
buffer_left.as_slice(), buffer_left.as_slice(),
buffer_right.as_slice(), buffer_right.as_slice(),
styler.as_mut(), formatter.as_mut(),
)?; )?;
} }
Diff::Modified( Diff::Modified(
@ -1108,9 +1108,9 @@ fn cmd_diff(
executable: false, executable: false,
}, },
) => { ) => {
styler.add_label(String::from("header"))?; formatter.add_label(String::from("header"))?;
styler.write_str(&format!("resolved conflict in file {}:\n", ui_path))?; formatter.write_str(&format!("resolved conflict in file {}:\n", ui_path))?;
styler.remove_label()?; formatter.remove_label()?;
let conflict_left = repo.store().read_conflict(&id_left).unwrap(); let conflict_left = repo.store().read_conflict(&id_left).unwrap();
let mut buffer_left = vec![]; let mut buffer_left = vec![];
@ -1127,7 +1127,7 @@ fn cmd_diff(
print_diff( print_diff(
buffer_left.as_slice(), buffer_left.as_slice(),
buffer_right.as_slice(), buffer_right.as_slice(),
styler.as_mut(), formatter.as_mut(),
)?; )?;
} }
Diff::Modified( Diff::Modified(
@ -1137,9 +1137,9 @@ fn cmd_diff(
}, },
TreeValue::Conflict(id_right), TreeValue::Conflict(id_right),
) => { ) => {
styler.add_label(String::from("header"))?; formatter.add_label(String::from("header"))?;
styler.write_str(&format!("new conflict in file {}:\n", ui_path))?; formatter.write_str(&format!("new conflict in file {}:\n", ui_path))?;
styler.remove_label()?; formatter.remove_label()?;
let mut file_reader_left = repo.store().read_file(&path, &id_left).unwrap(); let mut file_reader_left = repo.store().read_file(&path, &id_left).unwrap();
let mut buffer_left = vec![]; let mut buffer_left = vec![];
file_reader_left.read_to_end(&mut buffer_left).unwrap(); file_reader_left.read_to_end(&mut buffer_left).unwrap();
@ -1155,30 +1155,30 @@ fn cmd_diff(
print_diff( print_diff(
buffer_left.as_slice(), buffer_left.as_slice(),
buffer_right.as_slice(), buffer_right.as_slice(),
styler.as_mut(), formatter.as_mut(),
)?; )?;
} }
Diff::Removed(TreeValue::Normal { Diff::Removed(TreeValue::Normal {
id, id,
executable: false, executable: false,
}) => { }) => {
styler.add_label(String::from("header"))?; formatter.add_label(String::from("header"))?;
styler.write_str(&format!("removed file {}:\n", ui_path))?; formatter.write_str(&format!("removed file {}:\n", ui_path))?;
styler.remove_label()?; formatter.remove_label()?;
let mut file_reader = repo.store().read_file(&path, &id).unwrap(); let mut file_reader = repo.store().read_file(&path, &id).unwrap();
styler.write_from_reader(&mut file_reader)?; formatter.write_from_reader(&mut file_reader)?;
} }
other => { other => {
writeln!( writeln!(
styler, formatter,
"unhandled diff case in path {:?}: {:?}", "unhandled diff case in path {:?}: {:?}",
path, other path, other
)?; )?;
} }
} }
} }
styler.remove_label()?; formatter.remove_label()?;
} }
Ok(()) Ok(())
} }
@ -1296,12 +1296,12 @@ fn cmd_log(
let template = let template =
crate::template_parser::parse_commit_template(repo.as_repo_ref(), &template_string); crate::template_parser::parse_commit_template(repo.as_repo_ref(), &template_string);
let mut styler = ui.styler(); let mut formatter = ui.formatter();
let mut styler = styler.as_mut(); let mut formatter = formatter.as_mut();
styler.add_label(String::from("log"))?; formatter.add_label(String::from("log"))?;
if use_graph { if use_graph {
let mut graph = AsciiGraphDrawer::new(&mut styler); let mut graph = AsciiGraphDrawer::new(&mut formatter);
for (index_entry, edges) in revset.iter().graph() { for (index_entry, edges) in revset.iter().graph() {
let mut graphlog_edges = vec![]; let mut graphlog_edges = vec![];
// TODO: Should we update RevsetGraphIterator to yield this flag instead of all // TODO: Should we update RevsetGraphIterator to yield this flag instead of all
@ -1330,9 +1330,9 @@ fn cmd_log(
// TODO: only use color if requested // TODO: only use color if requested
{ {
let writer = Box::new(&mut buffer); let writer = Box::new(&mut buffer);
let mut styler = ColorStyler::new(writer, ui.settings()); let mut formatter = ColorFormatter::new(writer, ui.settings());
let commit = store.get_commit(&index_entry.commit_id()).unwrap(); let commit = store.get_commit(&index_entry.commit_id()).unwrap();
template.format(&commit, &mut styler)?; template.format(&commit, &mut formatter)?;
} }
if !buffer.ends_with(b"\n") { if !buffer.ends_with(b"\n") {
buffer.push(b'\n'); buffer.push(b'\n');
@ -1352,7 +1352,7 @@ fn cmd_log(
} else { } else {
for index_entry in revset.iter() { for index_entry in revset.iter() {
let commit = store.get_commit(&index_entry.commit_id()).unwrap(); let commit = store.get_commit(&index_entry.commit_id()).unwrap();
template.format(&commit, styler)?; template.format(&commit, formatter)?;
} }
} }
@ -1385,9 +1385,9 @@ fn cmd_obslog(
&template_string, &template_string,
); );
let mut styler = ui.styler(); let mut formatter = ui.formatter();
let mut styler = styler.as_mut(); let mut formatter = formatter.as_mut();
styler.add_label(String::from("log"))?; formatter.add_label(String::from("log"))?;
let commits = topo_order_reverse( let commits = topo_order_reverse(
vec![start_commit], vec![start_commit],
@ -1395,7 +1395,7 @@ fn cmd_obslog(
Box::new(|commit: &Commit| commit.predecessors()), Box::new(|commit: &Commit| commit.predecessors()),
); );
if use_graph { if use_graph {
let mut graph = AsciiGraphDrawer::new(&mut styler); let mut graph = AsciiGraphDrawer::new(&mut formatter);
for commit in commits { for commit in commits {
let mut edges = vec![]; let mut edges = vec![];
for predecessor in commit.predecessors() { for predecessor in commit.predecessors() {
@ -1405,8 +1405,8 @@ fn cmd_obslog(
// TODO: only use color if requested // TODO: only use color if requested
{ {
let writer = Box::new(&mut buffer); let writer = Box::new(&mut buffer);
let mut styler = ColorStyler::new(writer, ui.settings()); let mut formatter = ColorFormatter::new(writer, ui.settings());
template.format(&commit, &mut styler)?; template.format(&commit, &mut formatter)?;
} }
if !buffer.ends_with(b"\n") { if !buffer.ends_with(b"\n") {
buffer.push(b'\n'); buffer.push(b'\n');
@ -1420,7 +1420,7 @@ fn cmd_obslog(
} }
} else { } else {
for commit in commits { for commit in commits {
template.format(&commit, styler)?; template.format(&commit, formatter)?;
} }
} }
@ -2227,45 +2227,45 @@ fn cmd_op_log(
let repo = repo_command.repo(); let repo = repo_command.repo();
let head_op = repo.operation().clone(); let head_op = repo.operation().clone();
let head_op_id = head_op.id().clone(); let head_op_id = head_op.id().clone();
let mut styler = ui.styler(); let mut formatter = ui.formatter();
let mut styler = styler.as_mut(); let mut formatter = formatter.as_mut();
struct OpTemplate; struct OpTemplate;
impl Template<Operation> for OpTemplate { impl Template<Operation> for OpTemplate {
fn format(&self, op: &Operation, styler: &mut dyn Styler) -> io::Result<()> { fn format(&self, op: &Operation, formatter: &mut dyn Formatter) -> io::Result<()> {
// TODO: why can't this label be applied outside of the template? // TODO: why can't this label be applied outside of the template?
styler.add_label("op-log".to_string())?; formatter.add_label("op-log".to_string())?;
// TODO: Make this templated // TODO: Make this templated
styler.add_label("id".to_string())?; formatter.add_label("id".to_string())?;
styler.write_str(&op.id().hex()[0..12])?; formatter.write_str(&op.id().hex()[0..12])?;
styler.remove_label()?; formatter.remove_label()?;
styler.write_str(" ")?; formatter.write_str(" ")?;
let metadata = &op.store_operation().metadata; let metadata = &op.store_operation().metadata;
styler.add_label("user".to_string())?; formatter.add_label("user".to_string())?;
styler.write_str(&format!("{}@{}", metadata.username, metadata.hostname))?; formatter.write_str(&format!("{}@{}", metadata.username, metadata.hostname))?;
styler.remove_label()?; formatter.remove_label()?;
styler.write_str(" ")?; formatter.write_str(" ")?;
styler.add_label("time".to_string())?; formatter.add_label("time".to_string())?;
styler.write_str(&format!( formatter.write_str(&format!(
"{} - {}", "{} - {}",
format_timestamp(&metadata.start_time), format_timestamp(&metadata.start_time),
format_timestamp(&metadata.end_time) format_timestamp(&metadata.end_time)
))?; ))?;
styler.remove_label()?; formatter.remove_label()?;
styler.write_str("\n")?; formatter.write_str("\n")?;
styler.add_label("description".to_string())?; formatter.add_label("description".to_string())?;
styler.write_str(&metadata.description)?; formatter.write_str(&metadata.description)?;
styler.remove_label()?; formatter.remove_label()?;
for (key, value) in &metadata.tags { for (key, value) in &metadata.tags {
styler.write_str(&format!("\n{}: {}", key, value))?; formatter.write_str(&format!("\n{}: {}", key, value))?;
} }
styler.remove_label()?; formatter.remove_label()?;
Ok(()) Ok(())
} }
} }
let template = OpTemplate; let template = OpTemplate;
let mut graph = AsciiGraphDrawer::new(&mut styler); let mut graph = AsciiGraphDrawer::new(&mut formatter);
for op in topo_order_reverse( for op in topo_order_reverse(
vec![head_op], vec![head_op],
Box::new(|op: &Operation| op.id().clone()), Box::new(|op: &Operation| op.id().clone()),
@ -2279,8 +2279,8 @@ fn cmd_op_log(
// TODO: only use color if requested // TODO: only use color if requested
{ {
let writer = Box::new(&mut buffer); let writer = Box::new(&mut buffer);
let mut styler = ColorStyler::new(writer, ui.settings()); let mut formatter = ColorFormatter::new(writer, ui.settings());
template.format(&op, &mut styler)?; template.format(&op, &mut formatter)?;
} }
if !buffer.ends_with(b"\n") { if !buffer.ends_with(b"\n") {
buffer.push(b'\n'); buffer.push(b'\n');

View File

@ -19,7 +19,7 @@ use std::io::{Error, Read, Write};
use jujutsu_lib::settings::UserSettings; use jujutsu_lib::settings::UserSettings;
// Lets the caller label strings and translates the labels to colors // Lets the caller label strings and translates the labels to colors
pub trait Styler: Write { pub trait Formatter: Write {
fn write_bytes(&mut self, data: &[u8]) -> io::Result<()> { fn write_bytes(&mut self, data: &[u8]) -> io::Result<()> {
self.write_all(data) self.write_all(data)
} }
@ -39,17 +39,17 @@ pub trait Styler: Write {
fn remove_label(&mut self) -> io::Result<()>; fn remove_label(&mut self) -> io::Result<()>;
} }
pub struct PlainTextStyler<'a> { pub struct PlainTextFormatter<'output> {
output: Box<dyn Write + 'a>, output: Box<dyn Write + 'output>,
} }
impl<'a> PlainTextStyler<'a> { impl<'output> PlainTextFormatter<'output> {
pub fn new(output: Box<dyn Write + 'a>) -> PlainTextStyler<'a> { pub fn new(output: Box<dyn Write + 'output>) -> PlainTextFormatter<'output> {
Self { output } Self { output }
} }
} }
impl Write for PlainTextStyler<'_> { impl Write for PlainTextFormatter<'_> {
fn write(&mut self, data: &[u8]) -> Result<usize, Error> { fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
self.output.write(data) self.output.write(data)
} }
@ -59,7 +59,7 @@ impl Write for PlainTextStyler<'_> {
} }
} }
impl Styler for PlainTextStyler<'_> { impl Formatter for PlainTextFormatter<'_> {
fn add_label(&mut self, _label: String) -> io::Result<()> { fn add_label(&mut self, _label: String) -> io::Result<()> {
Ok(()) Ok(())
} }
@ -69,8 +69,8 @@ impl Styler for PlainTextStyler<'_> {
} }
} }
pub struct ColorStyler<'a> { pub struct ColorFormatter<'output> {
output: Box<dyn Write + 'a>, output: Box<dyn Write + 'output>,
colors: HashMap<String, String>, colors: HashMap<String, String>,
labels: Vec<String>, labels: Vec<String>,
cached_colors: HashMap<Vec<String>, Vec<u8>>, cached_colors: HashMap<Vec<String>, Vec<u8>>,
@ -111,9 +111,12 @@ fn config_colors(user_settings: &UserSettings) -> HashMap<String, String> {
result result
} }
impl<'a> ColorStyler<'a> { impl<'output> ColorFormatter<'output> {
pub fn new(output: Box<dyn Write + 'a>, user_settings: &UserSettings) -> ColorStyler<'a> { pub fn new(
ColorStyler { output: Box<dyn Write + 'output>,
user_settings: &UserSettings,
) -> ColorFormatter<'output> {
ColorFormatter {
output, output,
colors: config_colors(user_settings), colors: config_colors(user_settings),
labels: vec![], labels: vec![],
@ -175,7 +178,7 @@ impl<'a> ColorStyler<'a> {
} }
} }
impl Write for ColorStyler<'_> { impl Write for ColorFormatter<'_> {
fn write(&mut self, data: &[u8]) -> Result<usize, Error> { fn write(&mut self, data: &[u8]) -> Result<usize, Error> {
self.output.write(data) self.output.write(data)
} }
@ -185,7 +188,7 @@ impl Write for ColorStyler<'_> {
} }
} }
impl Styler for ColorStyler<'_> { impl Formatter for ColorFormatter<'_> {
fn add_label(&mut self, label: String) -> io::Result<()> { fn add_label(&mut self, label: String) -> io::Result<()> {
self.labels.push(label); self.labels.push(label);
let new_color = self.current_color(); let new_color = self.current_color();

View File

@ -19,8 +19,8 @@ extern crate pest_derive;
pub mod commands; pub mod commands;
pub mod diff_edit; pub mod diff_edit;
pub mod formatter;
pub mod graphlog; pub mod graphlog;
pub mod styler;
pub mod template_parser; pub mod template_parser;
pub mod templater; pub mod templater;
pub mod ui; pub mod ui;

View File

@ -21,7 +21,7 @@ use jujutsu_lib::store::{CommitId, Signature};
use pest::iterators::{Pair, Pairs}; use pest::iterators::{Pair, Pairs};
use pest::Parser; use pest::Parser;
use crate::styler::PlainTextStyler; use crate::formatter::PlainTextFormatter;
use crate::templater::{ use crate::templater::{
AuthorProperty, ChangeIdProperty, CommitIdKeyword, CommitterProperty, ConditionalTemplate, AuthorProperty, ChangeIdProperty, CommitIdKeyword, CommitterProperty, ConditionalTemplate,
ConflictProperty, ConstantTemplateProperty, CurrentCheckoutProperty, DescriptionProperty, ConflictProperty, ConstantTemplateProperty, CurrentCheckoutProperty, DescriptionProperty,
@ -345,8 +345,8 @@ fn parse_commit_term<'a>(repo: RepoRef<'a>, pair: Pair<Rule>) -> Box<dyn Templat
let mut buf: Vec<u8> = vec![]; let mut buf: Vec<u8> = vec![];
{ {
let writer = Box::new(&mut buf); let writer = Box::new(&mut buf);
let mut styler = PlainTextStyler::new(writer); let mut formatter = PlainTextFormatter::new(writer);
label_template.format(commit, &mut styler).unwrap(); label_template.format(commit, &mut formatter).unwrap();
} }
String::from_utf8(buf).unwrap() String::from_utf8(buf).unwrap()
}; };

View File

@ -20,33 +20,36 @@ use jujutsu_lib::commit::Commit;
use jujutsu_lib::repo::RepoRef; use jujutsu_lib::repo::RepoRef;
use jujutsu_lib::store::{CommitId, Signature}; use jujutsu_lib::store::{CommitId, Signature};
use crate::styler::Styler; use crate::formatter::Formatter;
pub trait Template<C> { pub trait Template<C> {
fn format(&self, context: &C, styler: &mut dyn Styler) -> io::Result<()>; fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()>;
} }
// TODO: Extract a trait for this type? // TODO: Extract a trait for this type?
pub struct TemplateFormatter<'s, 't: 's, C> { pub struct TemplateFormatter<'f, 't: 'f, C> {
template: Box<dyn Template<C> + 't>, template: Box<dyn Template<C> + 't>,
styler: &'s mut dyn Styler, formatter: &'f mut dyn Formatter,
} }
impl<'s, 't: 's, C> TemplateFormatter<'s, 't, C> { impl<'f, 't: 'f, C> TemplateFormatter<'f, 't, C> {
pub fn new(template: Box<dyn Template<C> + 't>, styler: &'s mut dyn Styler) -> Self { pub fn new(template: Box<dyn Template<C> + 't>, formatter: &'f mut dyn Formatter) -> Self {
TemplateFormatter { template, styler } TemplateFormatter {
template,
formatter,
}
} }
pub fn format<'c, 'a: 'c>(&'a mut self, context: &'c C) -> io::Result<()> { pub fn format<'c, 'a: 'c>(&'a mut self, context: &'c C) -> io::Result<()> {
self.template.format(context, self.styler.borrow_mut()) self.template.format(context, self.formatter.borrow_mut())
} }
} }
pub struct LiteralTemplate(pub String); pub struct LiteralTemplate(pub String);
impl<C> Template<C> for LiteralTemplate { impl<C> Template<C> for LiteralTemplate {
fn format(&self, _context: &C, styler: &mut dyn Styler) -> io::Result<()> { fn format(&self, _context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
styler.write_str(&self.0) formatter.write_str(&self.0)
} }
} }
@ -67,13 +70,13 @@ impl<'a, C> LabelTemplate<'a, C> {
} }
impl<'a, C> Template<C> for LabelTemplate<'a, C> { impl<'a, C> Template<C> for LabelTemplate<'a, C> {
fn format(&self, context: &C, styler: &mut dyn Styler) -> io::Result<()> { fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
for label in &self.labels { for label in &self.labels {
styler.add_label(label.clone())?; formatter.add_label(label.clone())?;
} }
self.content.format(context, styler)?; self.content.format(context, formatter)?;
for _label in &self.labels { for _label in &self.labels {
styler.remove_label()?; formatter.remove_label()?;
} }
Ok(()) Ok(())
} }
@ -98,18 +101,18 @@ impl<'a, C> DynamicLabelTemplate<'a, C> {
} }
impl<'a, C> Template<C> for DynamicLabelTemplate<'a, C> { impl<'a, C> Template<C> for DynamicLabelTemplate<'a, C> {
fn format(&self, context: &C, styler: &mut dyn Styler) -> io::Result<()> { fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
let labels = self.label_property.as_ref()(context); let labels = self.label_property.as_ref()(context);
let labels: Vec<String> = labels let labels: Vec<String> = labels
.split_whitespace() .split_whitespace()
.map(|label| label.to_string()) .map(|label| label.to_string())
.collect(); .collect();
for label in &labels { for label in &labels {
styler.add_label(label.clone())?; formatter.add_label(label.clone())?;
} }
self.content.format(context, styler)?; self.content.format(context, formatter)?;
for _label in &labels { for _label in &labels {
styler.remove_label()?; formatter.remove_label()?;
} }
Ok(()) Ok(())
} }
@ -119,9 +122,9 @@ impl<'a, C> Template<C> for DynamicLabelTemplate<'a, C> {
pub struct ListTemplate<'a, C>(pub Vec<Box<dyn Template<C> + 'a>>); pub struct ListTemplate<'a, C>(pub Vec<Box<dyn Template<C> + 'a>>);
impl<'a, C> Template<C> for ListTemplate<'a, C> { impl<'a, C> Template<C> for ListTemplate<'a, C> {
fn format(&self, context: &C, styler: &mut dyn Styler) -> io::Result<()> { fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
for template in &self.0 { for template in &self.0 {
template.format(context, styler)? template.format(context, formatter)?
} }
Ok(()) Ok(())
} }
@ -147,9 +150,9 @@ pub struct StringPropertyTemplate<'a, C> {
} }
impl<'a, C> Template<C> for StringPropertyTemplate<'a, C> { impl<'a, C> Template<C> for StringPropertyTemplate<'a, C> {
fn format(&self, context: &C, styler: &mut dyn Styler) -> io::Result<()> { fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
let text = self.property.extract(context); let text = self.property.extract(context);
styler.write_str(&text) formatter.write_str(&text)
} }
} }
@ -294,11 +297,11 @@ impl<'a, C> ConditionalTemplate<'a, C> {
} }
impl<'a, C> Template<C> for ConditionalTemplate<'a, C> { impl<'a, C> Template<C> for ConditionalTemplate<'a, C> {
fn format(&self, context: &C, styler: &mut dyn Styler) -> io::Result<()> { fn format(&self, context: &C, formatter: &mut dyn Formatter) -> io::Result<()> {
if self.condition.extract(context) { if self.condition.extract(context) {
self.true_template.format(context, styler)?; self.true_template.format(context, formatter)?;
} else if let Some(false_template) = &self.false_template { } else if let Some(false_template) = &self.false_template {
false_template.format(context, styler)?; false_template.format(context, formatter)?;
} }
Ok(()) Ok(())
} }

View File

@ -22,31 +22,31 @@ use jujutsu_lib::repo::RepoRef;
use jujutsu_lib::repo_path::RepoPath; use jujutsu_lib::repo_path::RepoPath;
use jujutsu_lib::settings::UserSettings; use jujutsu_lib::settings::UserSettings;
use crate::styler::{ColorStyler, PlainTextStyler, Styler}; use crate::formatter::{ColorFormatter, Formatter, PlainTextFormatter};
use crate::templater::TemplateFormatter; use crate::templater::TemplateFormatter;
pub struct Ui<'a> { pub struct Ui<'a> {
cwd: PathBuf, cwd: PathBuf,
styler: Mutex<Box<dyn Styler + 'a>>, formatter: Mutex<Box<dyn Formatter + 'a>>,
settings: UserSettings, settings: UserSettings,
} }
impl<'a> Ui<'a> { impl<'stdout> Ui<'stdout> {
pub fn new( pub fn new(
cwd: PathBuf, cwd: PathBuf,
stdout: Box<dyn Write + 'a>, stdout: Box<dyn Write + 'stdout>,
is_atty: bool, is_atty: bool,
settings: UserSettings, settings: UserSettings,
) -> Ui<'a> { ) -> Ui<'stdout> {
let styler: Box<dyn Styler + 'a> = if is_atty { let formatter: Box<dyn Formatter + 'stdout> = if is_atty {
Box::new(ColorStyler::new(stdout, &settings)) Box::new(ColorFormatter::new(stdout, &settings))
} else { } else {
Box::new(PlainTextStyler::new(stdout)) Box::new(PlainTextFormatter::new(stdout))
}; };
let styler = Mutex::new(styler); let formatter = Mutex::new(formatter);
Ui { Ui {
cwd, cwd,
styler, formatter,
settings, settings,
} }
} }
@ -65,23 +65,23 @@ impl<'a> Ui<'a> {
&self.settings &self.settings
} }
pub fn styler(&self) -> MutexGuard<Box<dyn Styler + 'a>> { pub fn formatter(&self) -> MutexGuard<Box<dyn Formatter + 'stdout>> {
self.styler.lock().unwrap() self.formatter.lock().unwrap()
} }
pub fn write(&mut self, text: &str) -> io::Result<()> { pub fn write(&mut self, text: &str) -> io::Result<()> {
self.styler().write_str(text) self.formatter().write_str(text)
} }
pub fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { pub fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> {
self.styler().write_fmt(fmt) self.formatter().write_fmt(fmt)
} }
pub fn write_error(&mut self, text: &str) -> io::Result<()> { pub fn write_error(&mut self, text: &str) -> io::Result<()> {
let mut styler = self.styler(); let mut formatter = self.formatter();
styler.add_label(String::from("error"))?; formatter.add_label(String::from("error"))?;
styler.write_str(text)?; formatter.write_str(text)?;
styler.remove_label()?; formatter.remove_label()?;
Ok(()) Ok(())
} }
@ -96,8 +96,8 @@ impl<'a> Ui<'a> {
) )
}); });
let template = crate::template_parser::parse_commit_template(repo, &template_string); let template = crate::template_parser::parse_commit_template(repo, &template_string);
let mut styler = self.styler(); let mut formatter = self.formatter();
let mut template_writer = TemplateFormatter::new(template, styler.as_mut()); let mut template_writer = TemplateFormatter::new(template, formatter.as_mut());
template_writer.format(commit)?; template_writer.format(commit)?;
Ok(()) Ok(())
} }