Add save functionality and shortcuts
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
;; Closure Scope Test
|
||||
;; Benchmark: 7.9us
|
||||
;; Benchmark: 9.0us
|
||||
;; Output: 15
|
||||
(do
|
||||
(def make-adder (fn [x]
|
||||
|
||||
+1
-1
@@ -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
@@ -1,5 +1,5 @@
|
||||
;; Fibonacci Recursive
|
||||
;; Benchmark: 62.9us
|
||||
;; Benchmark: 68.3us
|
||||
;; Output: 55
|
||||
(do
|
||||
(def fib (fn [n]
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
;; Higher-Order Function Example
|
||||
;; Benchmark: 7.4us
|
||||
;; Benchmark: 8.4us
|
||||
;; Output: 25
|
||||
(do
|
||||
(def apply (fn [f x] (f x)))
|
||||
|
||||
@@ -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
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user