diff.rs (3420B)
1 use super::super::file_update::{DiffLine, DiffTag, FileUpdate, FileUpdateType}; 2 use egui::{Color32, RichText, Ui}; 3 4 /// Colors for diff rendering 5 const DELETE_COLOR: Color32 = Color32::from_rgb(200, 60, 60); 6 const INSERT_COLOR: Color32 = Color32::from_rgb(60, 180, 60); 7 const LINE_NUMBER_COLOR: Color32 = Color32::from_rgb(128, 128, 128); 8 9 /// Render a file update diff view 10 pub fn file_update_ui(update: &FileUpdate, ui: &mut Ui) { 11 // Code block frame - no scroll, just show full diff height 12 egui::Frame::new() 13 .fill(ui.visuals().extreme_bg_color) 14 .inner_margin(8.0) 15 .corner_radius(4.0) 16 .show(ui, |ui| { 17 render_diff_lines(update.diff_lines(), &update.update_type, ui); 18 }); 19 } 20 21 /// Render the diff lines with proper coloring 22 fn render_diff_lines(lines: &[DiffLine], update_type: &FileUpdateType, ui: &mut Ui) { 23 // Track line numbers for old and new 24 let mut old_line = 1usize; 25 let mut new_line = 1usize; 26 27 for diff_line in lines { 28 ui.horizontal(|ui| { 29 // Line number gutter 30 let (old_num, new_num) = match diff_line.tag { 31 DiffTag::Equal => { 32 let result = (Some(old_line), Some(new_line)); 33 old_line += 1; 34 new_line += 1; 35 result 36 } 37 DiffTag::Delete => { 38 let result = (Some(old_line), None); 39 old_line += 1; 40 result 41 } 42 DiffTag::Insert => { 43 let result = (None, Some(new_line)); 44 new_line += 1; 45 result 46 } 47 }; 48 49 // Render line numbers (only for edits, not writes) 50 if matches!(update_type, FileUpdateType::Edit { .. }) { 51 let old_str = old_num 52 .map(|n| format!("{:4}", n)) 53 .unwrap_or_else(|| " ".to_string()); 54 let new_str = new_num 55 .map(|n| format!("{:4}", n)) 56 .unwrap_or_else(|| " ".to_string()); 57 58 ui.label( 59 RichText::new(format!("{} {}", old_str, new_str)) 60 .monospace() 61 .size(11.0) 62 .color(LINE_NUMBER_COLOR), 63 ); 64 } 65 66 // Render the prefix and content 67 let (prefix, color) = match diff_line.tag { 68 DiffTag::Equal => (" ", ui.visuals().text_color()), 69 DiffTag::Delete => ("-", DELETE_COLOR), 70 DiffTag::Insert => ("+", INSERT_COLOR), 71 }; 72 73 // Remove trailing newline for display 74 let content = diff_line.content.trim_end_matches('\n'); 75 76 ui.label( 77 RichText::new(format!("{} {}", prefix, content)) 78 .monospace() 79 .size(12.0) 80 .color(color), 81 ); 82 }); 83 } 84 } 85 86 /// Render the file path header (call within a horizontal layout) 87 pub fn file_path_header(update: &FileUpdate, ui: &mut Ui) { 88 let type_label = match &update.update_type { 89 FileUpdateType::Edit { .. } => "Edit", 90 FileUpdateType::Write { .. } => "Write", 91 }; 92 93 ui.label(RichText::new(type_label).strong()); 94 ui.label(RichText::new(&update.file_path).monospace()); 95 }