Skip to main content

taskr/
taskr.rs

1//! vecli example, a toy task manager CLI.
2//!
3//! Demonstrates all vecli features: commands, subcommands, global flags,
4//! per-command flags, strict flags, positionals, Terminal prompts, and
5//! the app-level main entry point.
6//!
7//! Run with:
8//!   cargo run -- --help
9//!   cargo run -- add "buy milk" --priority high
10//!   cargo run -- list
11//!   cargo run -- list urgent
12//!   cargo run -- done "buy milk"
13//!   cargo run -- clear
14
15use vecli::*;
16
17// --- Handlers ---
18
19fn config_set(ctx: &CommandContext) {
20    let key = ctx
21        .positionals
22        .first()
23        .map(String::as_str)
24        .unwrap_or("<key>");
25    let value = ctx
26        .positionals
27        .get(1)
28        .map(String::as_str)
29        .unwrap_or("<value>");
30
31    if ctx.flags.contains_key("verbose") {
32        println!(
33            "[verbose] config set called with key='{}', value='{}'",
34            key, value
35        );
36    }
37
38    println!("Set config '{}' to '{}'.", key, value);
39}
40
41fn config_show(ctx: &CommandContext) {
42    if ctx.flags.contains_key("verbose") {
43        println!("[verbose] config show called.");
44    }
45
46    println!("Current config:");
47    println!("  theme   = dark");
48    println!("  sort-by = priority");
49}
50
51fn add(ctx: &CommandContext) {
52    // Demonstrates: positionals, per-command flags, strict flags, Choice prompt
53    let task = ctx
54        .positionals
55        .first()
56        .map(String::as_str)
57        .unwrap_or("<unnamed>");
58
59    let priority = if let Some(p) = ctx.flags.get("priority") {
60        p.clone()
61    } else {
62        // If --priority not passed, ask interactively
63        Choice::new("Priority:", &["low", "medium", "high"])
64            .default("medium")
65            .ask()
66    };
67
68    if ctx.flags.contains_key("verbose") {
69        println!(
70            "[verbose] add called with task='{}', priority='{}'",
71            task, priority
72        );
73    }
74
75    println!("Added task '{}' with priority {}.", task, priority);
76}
77
78fn list(ctx: &CommandContext) {
79    // Demonstrates: global flag, per-command flag
80    if ctx.flags.contains_key("verbose") {
81        println!("[verbose] listing tasks...");
82    }
83
84    if ctx.flags.contains_key("all") {
85        println!("Tasks (all):");
86        println!("  [ ] buy milk       — high");
87        println!("  [x] write docs     — medium");
88        println!("  [ ] fix that bug   — low");
89    } else {
90        println!("Tasks (pending):");
91        println!("  [ ] buy milk       — high");
92        println!("  [ ] fix that bug   — low");
93    }
94}
95
96fn list_urgent(ctx: &CommandContext) {
97    // Demonstrates: subcommand handler
98    if ctx.flags.contains_key("verbose") {
99        println!("[verbose] listing urgent tasks...");
100    }
101
102    println!("Urgent tasks:");
103    println!("  [ ] buy milk       — high");
104}
105
106fn done(ctx: &CommandContext) {
107    // Demonstrates: positionals, global flag
108    let task = ctx
109        .positionals
110        .first()
111        .map(String::as_str)
112        .unwrap_or("<unnamed>");
113
114    if ctx.flags.contains_key("verbose") {
115        println!("[verbose] marking '{}' as done...", task);
116    }
117
118    println!("Marked '{}' as done.", task);
119}
120
121fn clear(ctx: &CommandContext) {
122    // Demonstrates: Confirm prompt, global flag
123    if ctx.flags.contains_key("verbose") {
124        println!("[verbose] clear called.");
125    }
126
127    let confirmed = Confirm::new("Clear all tasks?").default(false).ask();
128
129    if confirmed {
130        println!("All tasks cleared.");
131    } else {
132        println!("Aborted.");
133    }
134}
135
136fn entry(flags: PassedFlags) {
137    // Demonstrates: app-level main entry point with PassedFlags
138    if flags.contains_flag("verbose") {
139        println!("taskr: verbose mode active.");
140    } else {
141        println!("taskr: a toy task manager. Try 'taskr --help'.");
142    }
143}
144
145// --- Main ---
146
147fn main() {
148    App::new("taskr")
149        .name("Taskr")
150        .description("A toy task manager. Demonstrates all vecli features.")
151        .version("0.1.0")
152        .main(entry)
153        .flag(
154            Flag::global("verbose")
155                .alias("v")
156                .description("Enable verbose output."),
157        )
158        .print_help_on_fail(true)
159        .add_command(
160            Command::new("add", add)
161                .description("Add a new task.")
162                .usage("<task> [--priority <level>]")
163                .flag(
164                    Flag::new("priority")
165                        .alias("p")
166                        .description("Task priority: low, medium, or high."),
167                )
168                .strict_flags(true),
169        )
170        .add_command(
171            Command::new("list", list)
172                .description("List pending tasks.")
173                .flag(
174                    Flag::new("all")
175                        .alias("a")
176                        .description("Include completed tasks."),
177                )
178                .subcommand(
179                    Command::new("urgent", list_urgent)
180                        .description("List only high-priority tasks."),
181                ),
182        )
183        .add_command(
184            Command::new("done", done)
185                .description("Mark a task as done.")
186                .usage("<task>"),
187        )
188        .add_command(
189            Command::parent("config")
190                .description("Manage taskr configuration.")
191                .print_help_if_no_args(true)
192                .subcommand(
193                    Command::new("set", config_set)
194                        .description("Set a config value.")
195                        .usage("<key> <value>"),
196                )
197                .subcommand(Command::new("show", config_show).description("Show current config.")),
198        )
199        .add_command(Command::new("clear", clear).description("Clear all tasks."))
200        .run();
201}