1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
//! `Mingling` Example - Completion
//!
//! # How to Deploy
//! 1. Enable the `comp` feature
//! ```toml
//! [dependencies]
//! mingling = { version = "...", features = [
//! "comp", // Enable this feature
//! "parser"
//! ] }
//! ```
//!
//! 2. Add `mingling` as a build dependency, enabling the `builds` and `comp` features
//! ```toml
//! [build-dependencies]
//! mingling = { version = "...", features = [
//! "builds", // Enable this feature for build scripts
//! "comp"
//! ] }
//! ```
//!
//! 3. Write `build.rs` to generate completion scripts at compile time
//! ```ignore
//! use mingling::build::{build_comp_scripts, build_comp_scripts_with_bin_name};
//! fn main() {
//! // Generate completion scripts for the current program, using the Cargo package name as the binary filename
//! build_comp_scripts(env!("CARGO_PKG_NAME")).unwrap();
//!
//! // Or, explicitly specify the binary filename
//! // build_comp_scripts("your_bin").unwrap();
//! }
//! ```
//!
//! 4. Write `main.rs`, adding completion logic for your command entry point
//! 5. Execute `cargo install --path ./`, then run the corresponding completion script in your shell
use mingling::{
EnumTag, Groupped, ShellContext, Suggest,
macros::{
chain, completion, dispatcher, gen_program, r_println, renderer, suggest, suggest_enum,
},
parser::{PickableEnum, Picker},
};
// Define dispatcher `FruitCommand`, directing subcommand "fruit" to `FruitEntry`
dispatcher!("fruit", FruitCommand => FruitEntry);
#[completion(FruitEntry)]
fn comp_fruit_command(ctx: &ShellContext) -> Suggest {
if ctx.filling_argument_first("--name") {
return suggest!();
}
if ctx.filling_argument_first("--type") {
return suggest_enum!(FruitType);
}
if ctx.typing_argument() {
return suggest! {
"--name": "Fruit name",
"--type": "Fruit type"
}
.strip_typed_argument(ctx);
}
return suggest!();
}
fn main() {
let mut program = ThisProgram::new();
program.with_dispatcher(CompletionDispatcher);
program.with_dispatcher(FruitCommand);
program.exec();
}
#[derive(Groupped)]
struct FruitInfo {
name: String,
fruit_type: FruitType,
}
#[derive(Default, Debug, EnumTag)]
enum FruitType {
#[enum_desc("It's Apple")]
#[enum_rename("apple")]
FruitApple,
#[enum_desc("It's Banana")]
#[enum_rename("banana")]
FruitBanana,
#[enum_desc("It's Cherry")]
#[enum_rename("cherry")]
FruitCherry,
#[enum_desc("It's Date")]
#[enum_rename("date")]
FruitDate,
#[enum_desc("It's Elderberry")]
#[enum_rename("elderberry")]
FruitElderberry,
#[default]
#[enum_rename("unknown")]
Unknown,
}
impl PickableEnum for FruitType {}
#[chain]
fn parse_fruit_info(prev: FruitEntry) -> NextProcess {
let picker = Picker::from(prev.inner);
let (fruit_name, fruit_type) = picker.pick("--name").pick("--type").unpack();
let info = FruitInfo {
name: fruit_name,
fruit_type,
};
info.to_render()
}
#[renderer]
fn render_fruit(prev: FruitInfo) {
match (prev.name.is_empty(), prev.fruit_type) {
(true, FruitType::Unknown) => {
r_println!("Fruit name is empty and type is unknown");
}
(true, fruit_type) => {
r_println!("Fruit name is empty, Type: {:?}", fruit_type);
}
(false, FruitType::Unknown) => {
r_println!("Fruit name: {}, Type is unknown", prev.name);
}
(false, fruit_type) => {
r_println!("Fruit name: {}, Type: {:?}", prev.name, fruit_type);
}
}
}
gen_program!();
|