From 97caee37cc3da7ece3e9d5e7185b6129dc8386fb Mon Sep 17 00:00:00 2001 From: Stanislav Pastushenko Date: Tue, 9 Dec 2025 18:46:12 +0100 Subject: [PATCH] export filtered results --- src/main.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/src/main.rs b/src/main.rs index 2c1e78e..03b159a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,6 +132,76 @@ impl LogViewerApp { } } + fn handle_export_filtered(&mut self) { + use std::fs::File; + use std::io::Write; + use std::time::SystemTime; + + if let Some(tab) = self.active_tab() { + if tab.filtered_lines.is_empty() { + return; + } + + // Generate timestamped filename + let original_path = &tab.file_path; + let file_stem = original_path + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or("export"); + let extension = original_path + .extension() + .and_then(|s| s.to_str()) + .unwrap_or("log"); + + // Generate timestamp + let timestamp = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs(); + + // Create new filename: filename_timestamp.extension + let export_filename = format!("{}_{}.{}", file_stem, timestamp, extension); + let export_path = original_path.with_file_name(export_filename); + + // Write filtered lines to file + match File::create(&export_path) { + Ok(mut file) => { + // Get the line index and file handle + let line_index = Arc::clone(&tab.line_index); + let file_path = tab.file_path.clone(); + + // Open the original file for reading + if let Ok(original_file) = File::open(&file_path) { + let mut reader = std::io::BufReader::new(original_file); + + // Write each filtered line to the export file + for filtered_line in &tab.filtered_lines { + if let Some(content) = line_index.read_line(&mut reader, filtered_line.line_number) { + writeln!(file, "{}", content).ok(); + } + } + + // Open the exported file in a new tab + if let Ok(line_index) = crate::line_index::LineIndex::build(&export_path) { + if let Ok(exported_file) = File::open(&export_path) { + let new_tab = crate::file_tab::FileTab::new( + export_path, + line_index, + exported_file, + ); + self.tabs.push(new_tab); + self.active_tab_index = self.tabs.len() - 1; + } + } + } + } + Err(e) => { + eprintln!("Failed to create export file: {}", e); + } + } + } + } + fn handle_keyboard_input(&mut self, ctx: &egui::Context) { if let Some(tab) = self.active_tab_mut() { tab.page_scroll_direction = ctx.input(|i| { @@ -239,6 +309,7 @@ impl eframe::App for LogViewerApp { let show_filtered = !self.search_panel_state.query.is_empty(); let highlight_rules = self.highlight_manager.rules.clone(); + let mut export_clicked = false; if show_filtered { if let Some(tab) = self.active_tab_mut() { if !tab.filtered_lines.is_empty() { @@ -270,6 +341,13 @@ impl eframe::App for LogViewerApp { .size(14.0) .color(palette.accent_bright); ui.label(count); + + ui.add_space(16.0); + + // Export button + if ui.button("📤 Export").clicked() { + export_clicked = true; + } }); }); @@ -288,6 +366,11 @@ impl eframe::App for LogViewerApp { } } + // Handle export after rendering the filtered view + if export_clicked { + self.handle_export_filtered(); + } + // Handle keyboard input self.handle_keyboard_input(ctx);