diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-05-19 22:48:23 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-05-19 22:48:23 +0800 |
| commit | 39d66182f0290bacc10886c2659874bd9edc2d4b (patch) | |
| tree | 7b0e9463575a8350cd5a61bd0d02c9bada892b7f /examples/example-repl/src | |
| parent | bd4b09b06181093c95e865b04d4a9cdda7dd0728 (diff) | |
Add `empty_result!` macro and `REPL` resource, improve examples
Diffstat (limited to 'examples/example-repl/src')
| -rw-r--r-- | examples/example-repl/src/main.rs | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/examples/example-repl/src/main.rs b/examples/example-repl/src/main.rs new file mode 100644 index 0000000..2eb92e1 --- /dev/null +++ b/examples/example-repl/src/main.rs @@ -0,0 +1,142 @@ +use mingling::{REPL, hook::ProgramHook, prelude::*, this}; +use std::{env::current_dir, path::PathBuf}; + +// Resource to store the current directory +#[derive(Clone)] +struct CurrentDir { + dir: PathBuf, +} + +impl Default for CurrentDir { + fn default() -> Self { + Self { + dir: current_dir().unwrap(), + } + } +} + +fn main() { + let mut program = ThisProgram::new(); + + // Add resource + program.with_resource(CurrentDir::default()); + + // Add dispatchers + program.with_dispatcher(ChangeDirectoryCommand); + program.with_dispatcher(ListCommand); + program.with_dispatcher(ExitCommand); + + // Add hooks to handle REPL-related events + program.with_hook( + ProgramHook::empty() + .on_repl_begin(|| { + // Print welcome message + println!("Welcome!") + }) + .on_repl_pre_readline(|| { + // Print prompt + let res = this::<ThisProgram>().res::<CurrentDir>().unwrap(); + let dir_str: String = res.dir.to_string_lossy().into(); + let prompt = format!( + "{}> ", + dir_str + .replace(&['/', '\\'][..], ">") + .trim_start_matches('>') + .trim_end_matches('>') + ); + print!("{}", prompt) + }) + .on_repl_receive_result(|r| { + // Print output + if !r.is_empty() { + println!("{}", r.trim()) + } + }), + ); + + // Start the REPL loop + program.exec_repl(); +} + +// Create error route +pack!(ErrorDirectoryNotExist = PathBuf); + +// Create commands: cd ls exit +dispatcher!("cd", ChangeDirectoryCommand => ChangeDirectoryEntry); +dispatcher!("ls", ListCommand => ListEntry); +dispatcher!("exit", ExitCommand => ExitEntry); + +// Define data needed for the cd command's execution phase +pack!(StateChangeDirectory = String); + +// Define data needed for the ls command's rendering phase +pack!(ResultList = Vec<String>); + +// Parse cd command arguments +#[chain] +fn parse_cd_args(prev: ChangeDirectoryEntry) -> Next { + let join = prev.pick(()).unpack(); + StateChangeDirectory::new(join) +} + +// Execute directory change +#[chain] +fn handle_cd(prev: StateChangeDirectory, current_dir: &mut CurrentDir) -> Next { + let join = prev.inner; + let new_dir = just_fmt::fmt_path::fmt_path(current_dir.dir.join(join)).unwrap_or_default(); + + // If the path is not found, route to error handling + if !new_dir.exists() { + return ErrorDirectoryNotExist::new(new_dir).to_render(); + } + + current_dir.dir = new_dir; + empty_result!() +} + +// Get directory contents via the CurrentDir resource +#[chain] +fn handle_ls(_prev: ListEntry, current_dir: &CurrentDir) -> Next { + let dir = ¤t_dir.dir; + let entries: Vec<String> = std::fs::read_dir(dir) + .into_iter() + .flat_map(|rd| rd.filter_map(|e| e.ok())) + .map(|e| { + let name = e.file_name().to_string_lossy().to_string(); + if e.file_type().map(|t| t.is_dir()).unwrap_or(false) { + format!("{}/", name) + } else { + name + } + }) + .collect(); + + // Render ResultList + ResultList::new(entries).to_render() +} + +// Render ResultList data +#[renderer] +fn render_list(list: ResultList) { + for item in list.inner { + r_println!("{}", item) + } +} + +// Handle exit command event +#[chain] +fn handle_exit( + _prev: ExitEntry, + repl: &mut REPL, // Import REPL resource, registered in `exec_repl`, usable directly +) { + // Set the REPL exit flag; REPL will exit after this loop iteration + repl.exit = true; +} + +// Handle path not found event +#[renderer] +fn render_error_directory_not_exist(err: ErrorDirectoryNotExist) { + r_println!("Directory not found: {}", err.inner.display()) +} + +gen_program!(); |
