Let-else reformatting (#23)

* Use let-else in App::post_rendering

* Use let-else in diff::reloc_eq

* Use let-else in diff::diff_objs

* Use let-else in views::data_diff::data_diff_ui

* Use let-else in views::function_diff::function_diff_ui

* Use let-else in views::function_diff::asm_row_ui

* Use let-else in views::jobs::jobs_ui

* Update rust-version in Cargo.toml
This commit is contained in:
Nick Condron 2023-01-16 16:51:40 -05:00 committed by GitHub
parent c7b6ec83d7
commit 20dcc50695
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 346 additions and 364 deletions

View File

@ -2,7 +2,7 @@
name = "objdiff" name = "objdiff"
version = "0.2.3" version = "0.2.3"
edition = "2021" edition = "2021"
rust-version = "1.62" rust-version = "1.65"
authors = ["Luke Street <luke@street.dev>"] authors = ["Luke Street <luke@street.dev>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
repository = "https://github.com/encounter/objdiff" repository = "https://github.com/encounter/objdiff"

View File

@ -398,69 +398,64 @@ impl eframe::App for App {
fn post_rendering(&mut self, _window_size_px: [u32; 2], _frame: &eframe::Frame) { fn post_rendering(&mut self, _window_size_px: [u32; 2], _frame: &eframe::Frame) {
for job in &mut self.view_state.jobs { for job in &mut self.view_state.jobs {
if let Some(handle) = &job.handle { let Some(handle) = &job.handle else {
if !handle.is_finished() { continue;
continue; };
} if !handle.is_finished() {
match job.handle.take().unwrap().join() { continue;
Ok(result) => { }
log::info!("Job {} finished", job.id); match job.handle.take().unwrap().join() {
match result { Ok(result) => {
JobResult::None => { log::info!("Job {} finished", job.id);
if let Some(err) = &job.status.read().unwrap().error { match result {
log::error!("{:?}", err); JobResult::None => {
} if let Some(err) = &job.status.read().unwrap().error {
} log::error!("{:?}", err);
JobResult::ObjDiff(state) => {
self.view_state.build = Some(state);
}
JobResult::BinDiff(state) => {
self.view_state.build = Some(Box::new(ObjDiffResult {
first_status: BuildStatus {
success: true,
log: "".to_string(),
},
second_status: BuildStatus {
success: true,
log: "".to_string(),
},
first_obj: Some(state.first_obj),
second_obj: Some(state.second_obj),
time: OffsetDateTime::now_utc(),
}));
}
JobResult::CheckUpdate(state) => {
self.view_state.check_update = Some(state);
}
JobResult::Update(state) => {
if let Ok(mut guard) = self.relaunch_path.lock() {
*guard = Some(state.exe_path);
}
self.should_relaunch = true;
} }
} }
} JobResult::ObjDiff(state) => {
Err(err) => { self.view_state.build = Some(state);
let err = if let Some(msg) = err.downcast_ref::<&'static str>() { }
anyhow::Error::msg(*msg) JobResult::BinDiff(state) => {
} else if let Some(msg) = err.downcast_ref::<String>() { self.view_state.build = Some(Box::new(ObjDiffResult {
anyhow::Error::msg(msg.clone()) first_status: BuildStatus { success: true, log: "".to_string() },
} else { second_status: BuildStatus { success: true, log: "".to_string() },
anyhow::Error::msg("Thread panicked") first_obj: Some(state.first_obj),
}; second_obj: Some(state.second_obj),
let result = job.status.write(); time: OffsetDateTime::now_utc(),
if let Ok(mut guard) = result {
guard.error = Some(err);
} else {
drop(result);
job.status = Arc::new(RwLock::new(JobStatus {
title: "Error".to_string(),
progress_percent: 0.0,
progress_items: None,
status: "".to_string(),
error: Some(err),
})); }));
} }
JobResult::CheckUpdate(state) => {
self.view_state.check_update = Some(state);
}
JobResult::Update(state) => {
if let Ok(mut guard) = self.relaunch_path.lock() {
*guard = Some(state.exe_path);
}
self.should_relaunch = true;
}
}
}
Err(err) => {
let err = if let Some(msg) = err.downcast_ref::<&'static str>() {
anyhow::Error::msg(*msg)
} else if let Some(msg) = err.downcast_ref::<String>() {
anyhow::Error::msg(msg.clone())
} else {
anyhow::Error::msg("Thread panicked")
};
let result = job.status.write();
if let Ok(mut guard) = result {
guard.error = Some(err);
} else {
drop(result);
job.status = Arc::new(RwLock::new(JobStatus {
title: "Error".to_string(),
progress_percent: 0.0,
progress_items: None,
status: "".to_string(),
error: Some(err),
}));
} }
} }
} }

View File

@ -211,25 +211,25 @@ fn address_eq(left: &ObjSymbol, right: &ObjSymbol) -> bool {
} }
fn reloc_eq(left_reloc: Option<&ObjReloc>, right_reloc: Option<&ObjReloc>) -> bool { fn reloc_eq(left_reloc: Option<&ObjReloc>, right_reloc: Option<&ObjReloc>) -> bool {
if let (Some(left), Some(right)) = (left_reloc, right_reloc) { let (Some(left), Some(right)) = (left_reloc, right_reloc) else {
if left.kind != right.kind { return false;
return false; };
if left.kind != right.kind {
return false;
}
let name_matches = left.target.name == right.target.name;
match (&left.target_section, &right.target_section) {
(Some(sl), Some(sr)) => {
// Match if section and name or address match
sl == sr && (name_matches || address_eq(&left.target, &right.target))
} }
let name_matches = left.target.name == right.target.name; (Some(_), None) => false,
match (&left.target_section, &right.target_section) { (None, Some(_)) => {
(Some(sl), Some(sr)) => { // Match if possibly stripped weak symbol
// Match if section and name or address match name_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak)
sl == sr && (name_matches || address_eq(&left.target, &right.target))
}
(Some(_), None) => false,
(None, Some(_)) => {
// Match if possibly stripped weak symbol
name_matches && right.target.flags.0.contains(ObjSymbolFlags::Weak)
}
(None, None) => name_matches,
} }
} else { (None, None) => name_matches,
false
} }
} }
@ -363,48 +363,49 @@ fn find_symbol<'a>(symbols: &'a mut [ObjSymbol], name: &str) -> Option<&'a mut O
pub fn diff_objs(left: &mut ObjInfo, right: &mut ObjInfo, _diff_config: &DiffConfig) -> Result<()> { pub fn diff_objs(left: &mut ObjInfo, right: &mut ObjInfo, _diff_config: &DiffConfig) -> Result<()> {
for left_section in &mut left.sections { for left_section in &mut left.sections {
if let Some(right_section) = find_section(right, &left_section.name) { let Some(right_section) = find_section(right, &left_section.name) else {
if left_section.kind == ObjSectionKind::Code { continue;
for left_symbol in &mut left_section.symbols { };
if let Some(right_symbol) = if left_section.kind == ObjSectionKind::Code {
find_symbol(&mut right_section.symbols, &left_symbol.name) for left_symbol in &mut left_section.symbols {
{ if let Some(right_symbol) =
left_symbol.diff_symbol = Some(right_symbol.name.clone()); find_symbol(&mut right_section.symbols, &left_symbol.name)
right_symbol.diff_symbol = Some(left_symbol.name.clone()); {
diff_code( left_symbol.diff_symbol = Some(right_symbol.name.clone());
left.architecture, right_symbol.diff_symbol = Some(left_symbol.name.clone());
&left_section.data, diff_code(
&right_section.data, left.architecture,
left_symbol, &left_section.data,
right_symbol, &right_section.data,
&left_section.relocations, left_symbol,
&right_section.relocations, right_symbol,
)?; &left_section.relocations,
} else { &right_section.relocations,
no_diff_code( )?;
left.architecture, } else {
&left_section.data, no_diff_code(
left_symbol, left.architecture,
&left_section.relocations, &left_section.data,
)?; left_symbol,
} &left_section.relocations,
)?;
} }
for right_symbol in &mut right_section.symbols {
if right_symbol.instructions.is_empty() {
no_diff_code(
left.architecture,
&right_section.data,
right_symbol,
&right_section.relocations,
)?;
}
}
} else if left_section.kind == ObjSectionKind::Data {
diff_data(left_section, right_section);
// diff_data_symbols(left_section, right_section)?;
} else if left_section.kind == ObjSectionKind::Bss {
diff_bss_symbols(&mut left_section.symbols, &mut right_section.symbols)?;
} }
for right_symbol in &mut right_section.symbols {
if right_symbol.instructions.is_empty() {
no_diff_code(
left.architecture,
&right_section.data,
right_symbol,
&right_section.relocations,
)?;
}
}
} else if left_section.kind == ObjSectionKind::Data {
diff_data(left_section, right_section);
// diff_data_symbols(left_section, right_section)?;
} else if left_section.kind == ObjSectionKind::Bss {
diff_bss_symbols(&mut left_section.symbols, &mut right_section.symbols)?;
} }
} }
diff_bss_symbols(&mut left.common, &mut right.common)?; diff_bss_symbols(&mut left.common, &mut right.common)?;

View File

@ -165,99 +165,91 @@ fn data_table_ui(
pub fn data_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) -> bool { pub fn data_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) -> bool {
let mut rebuild = false; let mut rebuild = false;
if let (Some(result), Some(selected_symbol)) = (&view_state.build, &view_state.selected_symbol) let (Some(result), Some(selected_symbol)) = (&view_state.build, &view_state.selected_symbol) else {
{ return rebuild;
StripBuilder::new(ui) };
.size(Size::exact(20.0)) StripBuilder::new(ui)
.size(Size::exact(40.0)) .size(Size::exact(20.0))
.size(Size::remainder()) .size(Size::exact(40.0))
.vertical(|mut strip| { .size(Size::remainder())
strip.strip(|builder| { .vertical(|mut strip| {
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| { strip.strip(|builder| {
strip.cell(|ui| { builder.sizes(Size::remainder(), 2).horizontal(|mut strip| {
ui.horizontal(|ui| { strip.cell(|ui| {
if ui.button("Back").clicked() { ui.horizontal(|ui| {
view_state.current_view = View::SymbolDiff; if ui.button("Back").clicked() {
} view_state.current_view = View::SymbolDiff;
}); }
});
strip.cell(|ui| {
ui.horizontal(|ui| {
if ui.button("Build").clicked() {
rebuild = true;
}
ui.scope(|ui| {
ui.style_mut().override_text_style =
Some(egui::TextStyle::Monospace);
ui.style_mut().wrap = Some(false);
if view_state
.jobs
.iter()
.any(|job| job.job_type == Job::ObjDiff)
{
ui.label("Building...");
} else {
ui.label("Last built:");
let format =
format_description::parse("[hour]:[minute]:[second]")
.unwrap();
ui.label(
result
.time
.to_offset(view_state.utc_offset)
.format(&format)
.unwrap(),
);
}
});
});
}); });
}); });
}); strip.cell(|ui| {
strip.strip(|builder| { ui.horizontal(|ui| {
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| { if ui.button("Build").clicked() {
strip.cell(|ui| { rebuild = true;
}
ui.scope(|ui| { ui.scope(|ui| {
ui.style_mut().override_text_style = ui.style_mut().override_text_style =
Some(egui::TextStyle::Monospace); Some(egui::TextStyle::Monospace);
ui.style_mut().wrap = Some(false); ui.style_mut().wrap = Some(false);
ui.colored_label(Color32::WHITE, &selected_symbol.symbol_name); if view_state.jobs.iter().any(|job| job.job_type == Job::ObjDiff) {
ui.label("Diff target:"); ui.label("Building...");
ui.separator(); } else {
}); ui.label("Last built:");
}); let format =
strip.cell(|ui| { format_description::parse("[hour]:[minute]:[second]")
ui.scope(|ui| { .unwrap();
ui.style_mut().override_text_style = ui.label(
Some(egui::TextStyle::Monospace); result
ui.style_mut().wrap = Some(false); .time
ui.label(""); .to_offset(view_state.utc_offset)
ui.label("Diff base:"); .format(&format)
ui.separator(); .unwrap(),
);
}
}); });
}); });
}); });
}); });
strip.cell(|ui| {
if let (Some(left_obj), Some(right_obj)) =
(&result.first_obj, &result.second_obj)
{
let table = TableBuilder::new(ui)
.striped(false)
.cell_layout(egui::Layout::left_to_right(egui::Align::Min))
.column(Size::relative(0.5))
.column(Size::relative(0.5))
.resizable(false);
data_table_ui(
table,
left_obj,
right_obj,
selected_symbol,
&view_state.view_config,
);
}
});
}); });
} strip.strip(|builder| {
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| {
strip.cell(|ui| {
ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
ui.style_mut().wrap = Some(false);
ui.colored_label(Color32::WHITE, &selected_symbol.symbol_name);
ui.label("Diff target:");
ui.separator();
});
});
strip.cell(|ui| {
ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
ui.style_mut().wrap = Some(false);
ui.label("");
ui.label("Diff base:");
ui.separator();
});
});
});
});
strip.cell(|ui| {
if let (Some(left_obj), Some(right_obj)) = (&result.first_obj, &result.second_obj) {
let table = TableBuilder::new(ui)
.striped(false)
.cell_layout(egui::Layout::left_to_right(egui::Align::Min))
.column(Size::relative(0.5))
.column(Size::relative(0.5))
.resizable(false);
data_table_ui(
table,
left_obj,
right_obj,
selected_symbol,
&view_state.view_config,
);
}
});
});
rebuild rebuild
} }

View File

@ -251,46 +251,47 @@ fn asm_row_ui(ui: &mut egui::Ui, ins_diff: &ObjInsDiff, symbol: &ObjSymbol, conf
ui.painter().rect_filled(ui.available_rect_before_wrap(), 0.0, ui.visuals().faint_bg_color); ui.painter().rect_filled(ui.available_rect_before_wrap(), 0.0, ui.visuals().faint_bg_color);
} }
let mut job = LayoutJob::default(); let mut job = LayoutJob::default();
if let Some(ins) = &ins_diff.ins { let Some(ins) = &ins_diff.ins else {
let base_color = match ins_diff.kind { ui.label("");
ObjInsDiffKind::None | ObjInsDiffKind::OpMismatch | ObjInsDiffKind::ArgMismatch => { return;
Color32::GRAY };
}
ObjInsDiffKind::Replace => Color32::LIGHT_BLUE, let base_color = match ins_diff.kind {
ObjInsDiffKind::Delete => COLOR_RED, ObjInsDiffKind::None | ObjInsDiffKind::OpMismatch | ObjInsDiffKind::ArgMismatch => {
ObjInsDiffKind::Insert => Color32::GREEN, Color32::GRAY
}; }
ObjInsDiffKind::Replace => Color32::LIGHT_BLUE,
ObjInsDiffKind::Delete => COLOR_RED,
ObjInsDiffKind::Insert => Color32::GREEN,
};
write_text(
&format!("{:<6}", format!("{:x}:", ins.address - symbol.address as u32)),
base_color,
&mut job,
config.code_font.clone(),
);
if let Some(branch) = &ins_diff.branch_from {
write_text( write_text(
&format!("{:<6}", format!("{:x}:", ins.address - symbol.address as u32)), "~> ",
base_color, config.diff_colors[branch.branch_idx % config.diff_colors.len()],
&mut job, &mut job,
config.code_font.clone(), config.code_font.clone(),
); );
if let Some(branch) = &ins_diff.branch_from {
write_text(
"~> ",
config.diff_colors[branch.branch_idx % config.diff_colors.len()],
&mut job,
config.code_font.clone(),
);
} else {
write_text(" ", base_color, &mut job, config.code_font.clone());
}
write_ins(ins, &ins_diff.kind, &ins_diff.arg_diff, symbol.address as u32, &mut job, config);
if let Some(branch) = &ins_diff.branch_to {
write_text(
" ~>",
config.diff_colors[branch.branch_idx % config.diff_colors.len()],
&mut job,
config.code_font.clone(),
);
}
ui.add(Label::new(job).sense(Sense::click()))
.on_hover_ui_at_pointer(|ui| ins_hover_ui(ui, ins))
.context_menu(|ui| ins_context_menu(ui, ins));
} else { } else {
ui.label(""); write_text(" ", base_color, &mut job, config.code_font.clone());
} }
write_ins(ins, &ins_diff.kind, &ins_diff.arg_diff, symbol.address as u32, &mut job, config);
if let Some(branch) = &ins_diff.branch_to {
write_text(
" ~>",
config.diff_colors[branch.branch_idx % config.diff_colors.len()],
&mut job,
config.code_font.clone(),
);
}
ui.add(Label::new(job).sense(Sense::click()))
.on_hover_ui_at_pointer(|ui| ins_hover_ui(ui, ins))
.context_menu(|ui| ins_context_menu(ui, ins));
} }
fn asm_table_ui( fn asm_table_ui(
@ -322,113 +323,105 @@ fn asm_table_ui(
pub fn function_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) -> bool { pub fn function_diff_ui(ui: &mut egui::Ui, view_state: &mut ViewState) -> bool {
let mut rebuild = false; let mut rebuild = false;
if let (Some(result), Some(selected_symbol)) = (&view_state.build, &view_state.selected_symbol) let (Some(result), Some(selected_symbol)) = (&view_state.build, &view_state.selected_symbol) else {
{ return rebuild;
StripBuilder::new(ui) };
.size(Size::exact(20.0)) StripBuilder::new(ui)
.size(Size::exact(40.0)) .size(Size::exact(20.0))
.size(Size::remainder()) .size(Size::exact(40.0))
.vertical(|mut strip| { .size(Size::remainder())
strip.strip(|builder| { .vertical(|mut strip| {
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| { strip.strip(|builder| {
strip.cell(|ui| { builder.sizes(Size::remainder(), 2).horizontal(|mut strip| {
ui.horizontal(|ui| { strip.cell(|ui| {
if ui.button("Back").clicked() { ui.horizontal(|ui| {
view_state.current_view = View::SymbolDiff; if ui.button("Back").clicked() {
} view_state.current_view = View::SymbolDiff;
}); }
});
strip.cell(|ui| {
ui.horizontal(|ui| {
if ui.button("Build").clicked() {
rebuild = true;
}
ui.scope(|ui| {
ui.style_mut().override_text_style =
Some(egui::TextStyle::Monospace);
ui.style_mut().wrap = Some(false);
if view_state
.jobs
.iter()
.any(|job| job.job_type == Job::ObjDiff)
{
ui.label("Building...");
} else {
ui.label("Last built:");
let format =
format_description::parse("[hour]:[minute]:[second]")
.unwrap();
ui.label(
result
.time
.to_offset(view_state.utc_offset)
.format(&format)
.unwrap(),
);
}
});
});
}); });
}); });
}); strip.cell(|ui| {
strip.strip(|builder| { ui.horizontal(|ui| {
builder.sizes(Size::remainder(), 2).horizontal(|mut strip| { if ui.button("Build").clicked() {
let demangled = demangle(&selected_symbol.symbol_name, &Default::default()); rebuild = true;
strip.cell(|ui| { }
ui.scope(|ui| { ui.scope(|ui| {
ui.style_mut().override_text_style = ui.style_mut().override_text_style =
Some(egui::TextStyle::Monospace); Some(egui::TextStyle::Monospace);
ui.style_mut().wrap = Some(false); ui.style_mut().wrap = Some(false);
ui.colored_label( if view_state.jobs.iter().any(|job| job.job_type == Job::ObjDiff) {
Color32::WHITE, ui.label("Building...");
demangled.as_ref().unwrap_or(&selected_symbol.symbol_name), } else {
); ui.label("Last built:");
ui.label("Diff target:"); let format =
ui.separator(); format_description::parse("[hour]:[minute]:[second]")
}); .unwrap();
}); ui.label(
strip.cell(|ui| { result
ui.scope(|ui| { .time
ui.style_mut().override_text_style = .to_offset(view_state.utc_offset)
Some(egui::TextStyle::Monospace); .format(&format)
ui.style_mut().wrap = Some(false); .unwrap(),
if let Some(match_percent) = result
.second_obj
.as_ref()
.and_then(|obj| find_symbol(obj, selected_symbol))
.and_then(|symbol| symbol.match_percent)
{
ui.colored_label(
match_color_for_symbol(match_percent),
&format!("{match_percent:.0}%"),
); );
} }
ui.label("Diff base:");
ui.separator();
}); });
}); });
}); });
}); });
strip.cell(|ui| { });
if let (Some(left_obj), Some(right_obj)) = strip.strip(|builder| {
(&result.first_obj, &result.second_obj) builder.sizes(Size::remainder(), 2).horizontal(|mut strip| {
{ let demangled = demangle(&selected_symbol.symbol_name, &Default::default());
let table = TableBuilder::new(ui) strip.cell(|ui| {
.striped(false) ui.scope(|ui| {
.cell_layout(egui::Layout::left_to_right(egui::Align::Min)) ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
.column(Size::relative(0.5)) ui.style_mut().wrap = Some(false);
.column(Size::relative(0.5)) ui.colored_label(
.resizable(false); Color32::WHITE,
asm_table_ui( demangled.as_ref().unwrap_or(&selected_symbol.symbol_name),
table, );
left_obj, ui.label("Diff target:");
right_obj, ui.separator();
selected_symbol, });
&view_state.view_config, });
); strip.cell(|ui| {
} ui.scope(|ui| {
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
ui.style_mut().wrap = Some(false);
if let Some(match_percent) = result
.second_obj
.as_ref()
.and_then(|obj| find_symbol(obj, selected_symbol))
.and_then(|symbol| symbol.match_percent)
{
ui.colored_label(
match_color_for_symbol(match_percent),
&format!("{match_percent:.0}%"),
);
}
ui.label("Diff base:");
ui.separator();
});
});
}); });
}); });
} strip.cell(|ui| {
if let (Some(left_obj), Some(right_obj)) = (&result.first_obj, &result.second_obj) {
let table = TableBuilder::new(ui)
.striped(false)
.cell_layout(egui::Layout::left_to_right(egui::Align::Min))
.column(Size::relative(0.5))
.column(Size::relative(0.5))
.resizable(false);
asm_table_ui(
table,
left_obj,
right_obj,
selected_symbol,
&view_state.view_config,
);
}
});
});
rebuild rebuild
} }

View File

@ -7,46 +7,47 @@ pub fn jobs_ui(ui: &mut egui::Ui, view_state: &mut ViewState) {
let mut remove_job: Option<usize> = None; let mut remove_job: Option<usize> = None;
for (idx, job) in view_state.jobs.iter_mut().enumerate() { for (idx, job) in view_state.jobs.iter_mut().enumerate() {
if let Ok(status) = job.status.read() { let Ok(status) = job.status.read() else {
ui.group(|ui| { continue;
ui.horizontal(|ui| { };
ui.label(&status.title); ui.group(|ui| {
if ui.small_button("").clicked() { ui.horizontal(|ui| {
if job.handle.is_some() { ui.label(&status.title);
job.should_remove = true; if ui.small_button("").clicked() {
if let Err(e) = job.cancel.send(()) { if job.handle.is_some() {
eprintln!("Failed to cancel job: {e:?}"); job.should_remove = true;
} if let Err(e) = job.cancel.send(()) {
} else { eprintln!("Failed to cancel job: {e:?}");
remove_job = Some(idx);
} }
}
});
let mut bar = ProgressBar::new(status.progress_percent);
if let Some(items) = &status.progress_items {
bar = bar.text(format!("{} / {}", items[0], items[1]));
}
bar.ui(ui);
const STATUS_LENGTH: usize = 80;
if let Some(err) = &status.error {
let err_string = err.to_string();
ui.colored_label(
Color32::from_rgb(255, 0, 0),
if err_string.len() > STATUS_LENGTH - 10 {
format!("Error: {}...", &err_string[0..STATUS_LENGTH - 10])
} else {
format!("Error: {:width$}", err_string, width = STATUS_LENGTH - 7)
},
);
} else {
ui.label(if status.status.len() > STATUS_LENGTH - 3 {
format!("{}...", &status.status[0..STATUS_LENGTH - 3])
} else { } else {
format!("{:width$}", &status.status, width = STATUS_LENGTH) remove_job = Some(idx);
}); }
} }
}); });
} let mut bar = ProgressBar::new(status.progress_percent);
if let Some(items) = &status.progress_items {
bar = bar.text(format!("{} / {}", items[0], items[1]));
}
bar.ui(ui);
const STATUS_LENGTH: usize = 80;
if let Some(err) = &status.error {
let err_string = err.to_string();
ui.colored_label(
Color32::from_rgb(255, 0, 0),
if err_string.len() > STATUS_LENGTH - 10 {
format!("Error: {}...", &err_string[0..STATUS_LENGTH - 10])
} else {
format!("Error: {:width$}", err_string, width = STATUS_LENGTH - 7)
},
);
} else {
ui.label(if status.status.len() > STATUS_LENGTH - 3 {
format!("{}...", &status.status[0..STATUS_LENGTH - 3])
} else {
format!("{:width$}", &status.status, width = STATUS_LENGTH)
});
}
});
} }
if let Some(idx) = remove_job { if let Some(idx) = remove_job {