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
|
//! Example Completion
//!
//! > This example demonstrates how to use **Mingling** to create fully dynamic command-line completions
//!
//! ## About Completion Scripts
//!
//! To make your completions work, you need to generate a completion script using Mingling's tools
//!
//! 1. Enable features
//! You need to enable the `builds` and `comp` features for `mingling` in `[build-dependencies]`
//!
//! 2. Write `build.rs`
//! Write the following in `build.rs`
//!
//! ```rust,ignore
//! fn main() {
//! build_scripts();
//! }
//!
//! /// Generate completion scripts
//! fn build_scripts() {
//! // `env!("CARGO_PKG_NAME")` equals the crate name, which matches the binary name.
//! // If your binary name differs from the crate name, specify it explicitly.
//! mingling::build::build_comp_scripts(
//! // Your binary name:
//! env!("CARGO_PKG_NAME"),
//! )
//! .unwrap();
//! }
//! ```
//!
//! 3. Verify
//! Build your project with `cargo build --release`. The completion scripts will be generated in `target/release/`
//!
//! Execute the script or have it be automatically sourced by your Shell
//!
//! Run:
//! ```bash
//! cargo run --manifest-path examples/example-completion/Cargo.toml --quiet -- greet Alice --repeat 3
//! ```
//!
//! Output:
//! ```plaintext
//! Hello, Alice, Alice, Alice!
//! ```
use mingling::{macros::suggest, prelude::*, ShellContext, Suggest};
fn main() {
let mut program = ThisProgram::new();
program.with_dispatcher(CMDGreet);
// --------- IMPORTANT ---------
// The `comp` feature makes `gen_program!()` generate a CompletionDispatcher automatically
// It adds a hidden `__comp` subcommand for communication with the completion script
program.with_dispatcher(crate::CompletionDispatcher);
// --------- IMPORTANT ---------
// TIP: Note that the completion script reads stdout,
// so make sure no output is produced before the CompletionDispatcher is dispatched.
program.exec_and_exit();
}
// --------- IMPORTANT ---------
// __________________________________________ Entry point bound to completion behavior
// / _________________________ Shell context for obtaining user input state
// | / ________ Suggest, used to return completion results
// vvvvvvvvvv | /
#[completion(EntryGreet)] // vvvvvvvvvvvv vvvvvvv
fn complete_greet_entry(ctx: &ShellContext) -> Suggest {
// When the previous word is `greet` (the current command being typed)
if ctx.previous_word == "greet" {
// Return suggestions
return suggest! {
"Bob": "Likes to pass messages",
"Alice": "Likes to receive messages",
"Hacker": "YOU",
"World"
};
}
// When the user is typing `--repeat`
if ctx.filling_argument(["-r", "--repeat"]) {
return suggest! {}; // Don't suggest anything
}
// When the user is typing `-`
if ctx.typing_argument() {
return suggest! {
"-r": "Number of repetitions",
"--repeat": "Number of repetitions",
}
// Remove arguments that have already been typed by the user
.strip_typed_argument(ctx);
}
// Otherwise, suggest nothing
suggest!()
// // You can also enable file completions using the following code,
// // which will invoke the Shell's default behavior
// Suggest::file_comp()
}
// --------- IMPORTANT ---------
dispatcher!("greet", CMDGreet => EntryGreet);
pack!(ResultName = (u8, String));
#[chain]
fn handle_greet(args: EntryGreet) -> Next {
let result: ResultName = args
.pick(["-r", "--repeat"])
.pick_or((), "World")
.unpack()
.into();
result
}
#[renderer]
fn render_name(result: ResultName) {
let (repeat, name) = result.inner;
let mut parts = Vec::with_capacity(repeat as usize);
for _ in 0..repeat {
parts.push(name.clone());
}
r_println!("Hello, {}!", parts.join(", "));
}
gen_program!();
|