use eframe::egui; use myc::ast::environment::Environment; fn main() -> eframe::Result { let options = eframe::NativeOptions { viewport: egui::ViewportBuilder::default().with_inner_size([800.0, 600.0]), ..Default::default() }; eframe::run_native( "Compiler GUI", options, Box::new(|_cc| Ok(Box::new(CompilerApp::default()))), ) } struct Example { name: String, content: String, is_benchmark: bool, } struct CompilerApp { source_code: String, output_log: String, env: Environment, is_first_frame: bool, examples: Vec, } impl Default for CompilerApp { fn default() -> Self { let examples = std::fs::read_dir("examples") .map(|entries| { entries .filter_map(|e| e.ok()) .filter(|e| e.path().extension().map_or(false, |ext| ext == "myc")) .filter_map(|e| { let name = e.file_name().into_string().ok()?; let content = std::fs::read_to_string(e.path()).ok()?; let is_benchmark = content.contains(";; Benchmark"); Some(Example { name, content, is_benchmark }) }) .collect() }) .unwrap_or_default(); Self { source_code: String::from(r#" (do (def fib (fn [n] (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))) (fib 10) ) "#), output_log: String::from("Ready to compile..."), env: Environment::new(), is_first_frame: true, examples, } } } impl CompilerApp { fn compile(&mut self) { let start = std::time::Instant::now(); match self.env.run_script(&self.source_code) { Ok(result) => { let duration = start.elapsed(); let now = chrono::Local::now().format("%H:%M:%S").to_string(); self.output_log = format!( "Execution Successful.\nResult: {}\n\nDuration: {:?}\nFinished at: {}", result, duration, now, ); } Err(e) => { self.output_log = format!("Error: {}", e); } } } } impl eframe::App for CompilerApp { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { // Left Side Panel: Examples egui::SidePanel::left("examples_panel") .resizable(true) .default_width(150.0) .show(ctx, |ui| { ui.heading("Examples"); ui.add_space(5.0); for example in &self.examples { let label = if example.is_benchmark { format!("⚡ {}", example.name) } else { example.name.clone() }; if ui.button(label).clicked() { self.source_code = example.content.clone(); } } }); // Bottom Panel: Output Log & Controls (Resizable) egui::TopBottomPanel::bottom("bottom_panel") .resizable(true) .min_height(150.0) .default_height(250.0) .show(ctx, |ui| { ui.add_space(5.0); // Compile Button (at the top of the bottom panel) if ui.button("Compile").clicked() { self.compile(); } ui.add_space(5.0); ui.horizontal(|ui| { ui.label("Output / Logs:"); if ui.button("Copy to Clipboard").clicked() { ui.ctx().copy_text(self.output_log.clone()); } }); // Log Output Area egui::ScrollArea::vertical() .id_salt("output_log_scroll") .show(ui, |ui| { ui.add_sized( ui.available_size(), egui::TextEdit::multiline(&mut self.output_log) .font(egui::TextStyle::Monospace) .desired_width(f32::INFINITY) .interactive(true) ); }); }); // Central Panel: Source Code Editor (Fills remaining space) egui::CentralPanel::default().show(ctx, |ui| { ui.heading("Source Code Editor"); ui.label("Input Source:"); let editor_id = ui.id().with("source_code_editor"); // Handle Shift+Enter shortcut BEFORE the editor handles it let shortcut = egui::KeyboardShortcut::new(egui::Modifiers::SHIFT, egui::Key::Enter); if ui.input_mut(|i| i.consume_shortcut(&shortcut)) { self.compile(); } // Set initial focus if self.is_first_frame { ui.ctx().memory_mut(|m| m.request_focus(editor_id)); self.is_first_frame = false; } egui::ScrollArea::vertical() .id_salt("source_code_scroll") .show(ui, |ui| { ui.add_sized( ui.available_size(), egui::TextEdit::multiline(&mut self.source_code) .id(editor_id) .font(egui::TextStyle::Monospace) .desired_width(f32::INFINITY) .lock_focus(true), ); }); }); } }