Add save functionality and shortcuts

This commit is contained in:
Michael Schimmel
2026-02-17 23:19:08 +01:00
parent 98d3344912
commit 83f6cfb8e1
6 changed files with 116 additions and 11 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
;; Closure Scope Test
;; Benchmark: 7.9us
;; Benchmark: 9.0us
;; Output: 15
(do
(def make-adder (fn [x]
+1 -1
View File
@@ -1,5 +1,5 @@
;; Complex Data Structure Test
;; Benchmark: 66.8us
;; Benchmark: 72.7us
;; Output: {:input 10, :name "Fibonacci", :output 55}
(do
(def fib (fn [n]
+1 -1
View File
@@ -1,5 +1,5 @@
;; Fibonacci Recursive
;; Benchmark: 62.9us
;; Benchmark: 68.3us
;; Output: 55
(do
(def fib (fn [n]
+1 -1
View File
@@ -1,5 +1,5 @@
;; Higher-Order Function Example
;; Benchmark: 7.4us
;; Benchmark: 8.4us
;; Output: 25
(do
(def apply (fn [f x] (f x)))
+3 -1
View File
@@ -1,8 +1,10 @@
;; Benchmark: 2.7ms
;; Output: "done"
(do
(def count_down (fn [n]
(if (< n 1)
"done"
(count_down (- n 1)))))
(count_down 1000000)
(count_down 10000)
)
+109 -6
View File
@@ -1,5 +1,6 @@
use eframe::egui;
use myc::ast::environment::Environment;
use std::path::PathBuf;
fn main() -> eframe::Result {
let options = eframe::NativeOptions {
@@ -15,11 +16,15 @@ fn main() -> eframe::Result {
struct Example {
name: String,
path: PathBuf,
content: String,
}
struct CompilerApp {
source_code: String,
current_example_path: Option<PathBuf>,
save_as_name: String,
show_save_as: bool,
output_log: String,
env: Environment,
is_first_frame: bool,
@@ -34,9 +39,10 @@ impl Default for CompilerApp {
.filter_map(|e| e.ok())
.filter(|e| e.path().extension().map_or(false, |ext| ext == "myc"))
.filter_map(|e| {
let path = e.path();
let name = e.file_name().into_string().ok()?;
let content = std::fs::read_to_string(e.path()).ok()?;
Some(Example { name, content })
let content = std::fs::read_to_string(&path).ok()?;
Some(Example { name, path, content })
})
.collect()
})
@@ -53,6 +59,9 @@ impl Default for CompilerApp {
(fib 10)
)
"#),
current_example_path: None,
save_as_name: String::new(),
show_save_as: false,
output_log: String::from("Ready to compile..."),
env: Environment::new(),
is_first_frame: true,
@@ -81,6 +90,66 @@ impl CompilerApp {
}
}
fn save(&mut self) {
if let Some(path) = &self.current_example_path {
match std::fs::write(path, &self.source_code) {
Ok(_) => {
self.output_log = format!("Successfully saved to {:?}", path);
// Update the cached content in examples list so it stays in sync
if let Some(ex) = self.examples.iter_mut().find(|e| e.path == *path) {
ex.content = self.source_code.clone();
}
}
Err(e) => {
self.output_log = format!("Failed to save: {}", e);
}
}
} else {
self.output_log = "No file loaded to save. Use 'Examples' to load one.".to_string();
}
}
fn save_as(&mut self) {
if self.save_as_name.trim().is_empty() {
self.output_log = "Error: Please enter a filename.".to_string();
return;
}
let mut filename = self.save_as_name.trim().to_string();
if !filename.ends_with(".myc") {
filename.push_str(".myc");
}
let path = PathBuf::from("examples").join(filename);
match std::fs::write(&path, &self.source_code) {
Ok(_) => {
self.output_log = format!("Successfully saved new file to {:?}", path);
self.current_example_path = Some(path);
self.show_save_as = false;
self.save_as_name.clear();
self.refresh_examples();
}
Err(e) => {
self.output_log = format!("Failed to save: {}", e);
}
}
}
fn refresh_examples(&mut self) {
if let Ok(entries) = std::fs::read_dir("examples") {
self.examples = entries
.filter_map(|e| e.ok())
.filter(|e| e.path().extension().map_or(false, |ext| ext == "myc"))
.filter_map(|e| {
let path = e.path();
let name = e.file_name().into_string().ok()?;
let content = std::fs::read_to_string(&path).ok()?;
Some(Example { name, path, content })
})
.collect();
}
}
fn run_all_tests(&mut self) {
use myc::ast::tester;
let results = tester::run_functional_tests();
@@ -125,6 +194,7 @@ impl eframe::App for CompilerApp {
for example in &self.examples {
if ui.button(&example.name).clicked() {
self.source_code = example.content.clone();
self.current_example_path = Some(example.path.clone());
}
}
});
@@ -139,10 +209,25 @@ impl eframe::App for CompilerApp {
// Compile Button (at the top of the bottom panel)
ui.horizontal(|ui| {
if ui.button("Compile").clicked() {
if ui.button("Compile (Shift+Enter)").clicked() {
self.compile();
}
if let Some(path) = &self.current_example_path {
let file_name = path.file_name().unwrap_or_default().to_string_lossy();
if ui.button(format!("Save {} (Ctrl+S)", file_name)).clicked() {
self.save();
}
} else {
ui.add_enabled_ui(false, |ui| {
ui.button("Save (None loaded)");
});
}
if ui.button("Save As...").clicked() {
self.show_save_as = !self.show_save_as;
}
if ui.button("Test All").clicked() {
self.run_all_tests();
}
@@ -168,7 +253,20 @@ impl eframe::App for CompilerApp {
});
});
ui.add_space(5.0);
if self.show_save_as {
ui.horizontal(|ui| {
ui.label("New Filename:");
ui.text_edit_singleline(&mut self.save_as_name);
if ui.button("Save Now").clicked() {
self.save_as();
}
if ui.button("Cancel").clicked() {
self.show_save_as = false;
}
});
ui.add_space(5.0);
}
ui.horizontal(|ui| {
ui.label("Output / Logs:");
if ui.button("Copy to Clipboard").clicked() {
@@ -198,11 +296,16 @@ impl eframe::App for CompilerApp {
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)) {
let compile_shortcut = egui::KeyboardShortcut::new(egui::Modifiers::SHIFT, egui::Key::Enter);
if ui.input_mut(|i| i.consume_shortcut(&compile_shortcut)) {
self.compile();
}
let save_shortcut = egui::KeyboardShortcut::new(egui::Modifiers::COMMAND, egui::Key::S);
if ui.input_mut(|i| i.consume_shortcut(&save_shortcut)) {
self.save();
}
// Set initial focus
if self.is_first_frame {
ui.ctx().memory_mut(|m| m.request_focus(editor_id));