mirror of
https://github.com/Dummi26/mers.git
synced 2025-04-29 02:26:03 +02:00
131 lines
5.6 KiB
Rust
Executable File
131 lines
5.6 KiB
Rust
Executable File
/// creates a temporary file, then opens it in the user's default editor. watches the fs for changes to the file and acts upon them.
|
|
pub mod fs_watcher {
|
|
use notify::Watcher;
|
|
use std::{
|
|
fs,
|
|
path::PathBuf,
|
|
thread::{self, JoinHandle},
|
|
};
|
|
|
|
#[derive(Debug)]
|
|
pub struct Error(String);
|
|
|
|
/// on each file change, recompiles and runs the code. lets people experiment with mers without having to put a file anywhere
|
|
pub fn playground(spawn_new_terminal_for_editor: bool) -> Result<(), Error> {
|
|
main(
|
|
spawn_new_terminal_for_editor,
|
|
"// Welcome to mers! (interactive mode)
|
|
|
|
// put your name here, then save the file to run the script.
|
|
your_name = \"\"
|
|
greeting = \"Hello, {0}!\".format(your_name)
|
|
println(greeting)
|
|
",
|
|
Box::new(|temp_file: &PathBuf| {
|
|
println!();
|
|
if let Ok(file_contents) = fs::read_to_string(&temp_file) {
|
|
let mut file =
|
|
crate::parse::file::File::new(file_contents, temp_file.to_path_buf());
|
|
match crate::parse::parse::parse(&mut file) {
|
|
Ok(func) => {
|
|
println!(" - - - - -");
|
|
let output = func.run(vec![]);
|
|
println!(" - - - - -");
|
|
println!("{}", output);
|
|
}
|
|
Err(e) => println!("{}", e.0.with_file_and_gsinfo(&file, e.1.as_ref())),
|
|
}
|
|
} else {
|
|
println!("can't read file at {:?}!", temp_file);
|
|
std::process::exit(105);
|
|
}
|
|
}),
|
|
)?
|
|
.0
|
|
.join()
|
|
.unwrap();
|
|
Ok(())
|
|
}
|
|
|
|
/// when the file is changed, calls the provided closure with the file's path.
|
|
/// returns a JoinHandle which will finish when the user closes the editor and the file that is being used.
|
|
pub fn main(
|
|
spawn_new_terminal_for_editor: bool,
|
|
initial_file_contents: &str,
|
|
mut on_file_change: Box<dyn FnMut(&PathBuf) + Send>,
|
|
) -> Result<(JoinHandle<()>, PathBuf), Error> {
|
|
let temp_file_edit = edit::Builder::new().suffix(".mers").tempfile().unwrap();
|
|
let temp_file = temp_file_edit.path().to_path_buf();
|
|
eprintln!(
|
|
"Using temporary file at {temp_file:?}. Save the file to update the output here."
|
|
);
|
|
if let Ok(_) = std::fs::write(&temp_file, initial_file_contents) {
|
|
if let Ok(mut watcher) = {
|
|
let temp_file = temp_file.clone();
|
|
// the file watcher
|
|
notify::recommended_watcher(move |event: Result<notify::Event, notify::Error>| {
|
|
if let Ok(event) = event {
|
|
match &event.kind {
|
|
notify::EventKind::Modify(notify::event::ModifyKind::Data(_)) => {
|
|
on_file_change(&temp_file);
|
|
}
|
|
_ => (),
|
|
}
|
|
}
|
|
})
|
|
} {
|
|
if let Ok(_) = watcher.watch(&temp_file, notify::RecursiveMode::NonRecursive) {
|
|
let out = if spawn_new_terminal_for_editor {
|
|
if let Ok(term) = std::env::var("TERM") {
|
|
let editor = edit::get_editor().unwrap();
|
|
eprintln!("launching \"{term} -e {editor:?} {temp_file:?}...");
|
|
let mut editor = std::process::Command::new(term)
|
|
.arg("-e")
|
|
.arg(&editor)
|
|
.arg(&temp_file)
|
|
.spawn()
|
|
.unwrap();
|
|
(
|
|
thread::spawn(move || {
|
|
// wait for the editor to finish
|
|
editor.wait().unwrap();
|
|
// stop the watcher (this is absolutely necessary because it also moves the watcher into the closure,
|
|
// which prevents it from being dropped too early)
|
|
drop(watcher);
|
|
// close and remove the temporary file
|
|
temp_file_edit.close().unwrap();
|
|
}),
|
|
temp_file,
|
|
)
|
|
} else {
|
|
return Err(Error(format!("TERM environment variable not set.")));
|
|
}
|
|
} else {
|
|
let tf = temp_file.clone();
|
|
(
|
|
thread::spawn(move || {
|
|
edit::edit_file(temp_file).unwrap();
|
|
drop(watcher);
|
|
temp_file_edit.close().unwrap();
|
|
}),
|
|
tf,
|
|
)
|
|
};
|
|
Ok(out)
|
|
} else {
|
|
return Err(Error(format!(
|
|
"Cannot watch the file at \"{:?}\" for hot-reload.",
|
|
temp_file
|
|
)));
|
|
}
|
|
} else {
|
|
return Err(Error(format!(
|
|
"Cannot use filesystem watcher for hot-reload."
|
|
)));
|
|
}
|
|
} else {
|
|
return Err(Error(format!("could not write file \"{:?}\".", temp_file)));
|
|
}
|
|
}
|
|
}
|