//! Comparing the open file with its last committed version. use super::*; impl App { /// Load the diff for the current file, ready for the diff window. pub(super) fn open_diff(&mut self) { self.save_current(); let Some(name) = self.selected.and_then(|i| self.files.get(i)).cloned() else { self.status = "Open a file first".to_string(); return; }; // Git is run from the work tree, and the workspace may be below it. let root = self.repo_root.clone(); let Some(root) = root else { self.diff_text = "This workspace is not in a git repository.".to_string(); self.show_diff = true; return; }; if !gitsync::has_commits(&root) { self.diff_text = "The repository has no commits yet, so there is \ nothing to compare against." .to_string(); self.show_diff = true; return; } let abs = self.path_for(&name); let rel = abs .strip_prefix(&root) .map(|p| p.to_string_lossy().replace('\\', "/")) .unwrap_or_else(|_| name.clone()); self.diff_text = match gitsync::diff_file(&root, &rel) { Ok(text) if text.trim().is_empty() => { format!("{name} matches the last commit — no changes.") } Ok(text) => text, Err(e) => format!("Could not diff {name}:\n{e}"), }; self.diff_title = name; self.show_diff = true; } /// The diff window: added and removed lines since the last commit. pub(super) fn diff_window(&mut self, ctx: &egui::Context) { let mut open = self.show_diff; let mut refresh = false; egui::Window::new(format!("Changes — {}", self.diff_title)) .open(&mut open) .resizable(true) .collapsible(false) .default_width(680.0) .default_height(460.0) .show(ctx, |ui| { ui.horizontal(|ui| { if ui.button("⟳ Refresh").clicked() { refresh = true; } ui.label( egui::RichText::new("compared with the last commit") .small() .weak(), ); }); ui.separator(); egui::ScrollArea::vertical() .auto_shrink([false, false]) .show(ui, |ui| { for line in self.diff_text.lines() { // Colour the diff the way git does, so additions and // removals are separable at a glance. let (color, strong) = match line.as_bytes().first() { Some(b'+') if !line.starts_with("+++") => { (Some(egui::Color32::from_rgb(0x3F, 0x9E, 0x4F)), false) } Some(b'-') if !line.starts_with("---") => { (Some(egui::Color32::from_rgb(0xC0, 0x50, 0x50)), false) } Some(b'@') => { (Some(egui::Color32::from_rgb(0x3B, 0x82, 0xF6)), true) } _ => (None, false), }; let mut text = egui::RichText::new(line).monospace(); if let Some(color) = color { text = text.color(color); } if strong { text = text.strong(); } ui.label(text); } }); }); if refresh { self.open_diff(); } self.show_diff = open; } }