aboutsummaryrefslogtreecommitdiff
path: root/examples/full-todolist/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/full-todolist/src/main.rs')
-rw-r--r--examples/full-todolist/src/main.rs197
1 files changed, 197 insertions, 0 deletions
diff --git a/examples/full-todolist/src/main.rs b/examples/full-todolist/src/main.rs
new file mode 100644
index 0000000..fdac1c7
--- /dev/null
+++ b/examples/full-todolist/src/main.rs
@@ -0,0 +1,197 @@
+//! Full Example - Todo List
+//!
+//! This example introduces how to use Mingling's features to build a complete CLI program
+//!
+//! > HAHA:
+//! >
+//! > This is truly a cliché example, as common as `Hello World`!
+
+use mingling::{
+ macros::route,
+ prelude::*,
+ res::ResExitCode,
+ setup::{ExitCodeSetup, GeneralRendererSetup, HelpFlagSetup},
+ LazyInit, LazyRes,
+};
+
+mod help;
+pub use help::*;
+
+mod todolist;
+pub use todolist::*;
+
+#[derive(Default, Clone)]
+pub struct ResProgramFlags {
+ pub all: bool,
+}
+
+// Define dispatchers
+
+dispatcher!("add");
+dispatcher!("list");
+dispatcher!("complete");
+dispatcher!("clean");
+
+// Define states
+
+pack!(StateAddTodo = String);
+pack!(StateCompleteTodo = i32);
+pack!(StateListTodo = bool);
+
+// Define errors
+
+pack!(ErrorNoTaskDescriptionProvided = ());
+pack!(ErrorNoIndexProvided = ());
+pack!(ErrorIndexOutOfBounds = ());
+
+fn main() {
+ let mut program = ThisProgram::new();
+
+ // Setups
+ program.with_setup(ExitCodeSetup::default());
+ program.with_setup(GeneralRendererSetup);
+ program.with_setup(HelpFlagSetup::new(["--help", "-h"]));
+
+ // Flags
+ let all = program.pick_global_flag(["-A", "--all"]);
+
+ // Resources
+ program.with_resource(
+ // Load on use
+ ResTodoList::lazy_init(read_todo_list)
+ // Write on drop
+ .with_on_drop(write_todo_list),
+ );
+ program.with_resource(ResProgramFlags { all });
+
+ // Dispatchers
+ program.with_dispatcher(CMDAdd);
+ program.with_dispatcher(CMDComplete);
+ program.with_dispatcher(CMDList);
+ program.with_dispatcher(CMDClean);
+
+ program.exec_and_exit();
+}
+
+// Command `add`
+
+#[chain]
+fn handle_add(args: EntryAdd) -> Next {
+ let task: String = route! {
+ args
+ .pick_or_route((), ErrorNoTaskDescriptionProvided::new(()).to_render())
+ .unpack()
+ };
+ StateAddTodo::new(task).to_chain()
+}
+
+#[chain]
+fn handle_state_add_todo(
+ state: StateAddTodo,
+ // Inject ResTodoList resource
+ todolist: &mut LazyRes<ResTodoList>,
+) -> Next {
+ let todolist = todolist.get_mut();
+
+ // Unpack state and read description
+ let description = state.inner;
+
+ todolist.items.push(Todo {
+ item: description,
+ completed: false,
+ });
+
+ // Clone todolist to render
+ let todolist = todolist.clone();
+ todolist.to_render()
+}
+
+// Command `list`
+
+#[chain]
+fn handle_list(_args: EntryList, todolist: &mut LazyRes<ResTodoList>) -> Next {
+ let todolist = todolist.get_mut().clone();
+ todolist.to_render()
+}
+
+// Command `complete`
+
+#[chain]
+fn handle_complete(args: EntryComplete) -> Next {
+ let index: i32 = route! {
+ args.pick_or_route((), ErrorNoIndexProvided::new(()).to_render()).unpack()
+ };
+ StateCompleteTodo::new(index).to_chain()
+}
+
+#[chain]
+fn handle_state_complete_todo(
+ state: StateCompleteTodo,
+ todolist: &mut LazyRes<ResTodoList>,
+) -> Next {
+ let todolist = todolist.get_mut();
+ let index = state.inner as usize;
+ if index < todolist.items.len() {
+ todolist.items[index].completed = true;
+ todolist.clone().to_render()
+ } else {
+ ErrorIndexOutOfBounds::new(()).to_render()
+ }
+}
+
+// Command `clean`
+
+#[chain]
+fn handle_clean(
+ _args: EntryClean,
+ todolist: &mut LazyRes<ResTodoList>,
+ program_flags: &ResProgramFlags,
+) -> Next {
+ let todolist = todolist.get_mut();
+ if program_flags.all {
+ todolist.items.clear();
+ } else {
+ todolist.items.retain(|item| !item.completed);
+ }
+ if todolist.items.is_empty() {
+ empty_result!()
+ } else {
+ todolist.clone().to_render()
+ }
+}
+
+#[renderer]
+fn render_error_no_task_description_provided(
+ _err: ErrorNoTaskDescriptionProvided,
+ // ExitCode
+ ec: &mut ResExitCode,
+) {
+ r_println!("No task description provided!");
+ r_println!("");
+ r_println!("Use `todolist add <desc>` to add a task");
+ ec.exit_code = 1;
+}
+
+#[renderer]
+fn render_error_no_index_provided(
+ _err: ErrorNoIndexProvided,
+ // ExitCode
+ ec: &mut ResExitCode,
+) {
+ r_println!("No index provided!");
+ r_println!("");
+ r_println!("Use `todolist list` to query indexes");
+ ec.exit_code = 2;
+}
+
+#[renderer]
+fn render_error_index_out_of_bounds(
+ _err: ErrorIndexOutOfBounds,
+ // ExitCode
+ ec: &mut ResExitCode,
+) {
+ r_println!("Index out of bounds!");
+ ec.exit_code = 3;
+}
+
+gen_program!();