active_help_demo/
active_help_demo.rs1use flag_rs::{CommandBuilder, CompletionResult, Flag, FlagType};
7
8fn main() {
9 let app = CommandBuilder::new("active-help-demo")
10 .short("Demonstrates ActiveHelp system")
11 .long("This example shows how ActiveHelp provides contextual hints during tab completion")
12 .flag(
13 Flag::new("namespace")
14 .short('n')
15 .usage("Kubernetes namespace")
16 .value_type(FlagType::String),
17 )
18 .flag(
19 Flag::new("output")
20 .short('o')
21 .usage("Output format")
22 .value_type(FlagType::String),
23 )
24 .subcommand(
25 CommandBuilder::new("get")
26 .short("Get resources")
27 .subcommand(
28 CommandBuilder::new("pods")
29 .short("Get pods")
30 .arg_completion(|ctx, prefix| {
31 let mut result = CompletionResult::new();
32
33 if ctx.flag("namespace").is_none() {
35 result = result.add_help_text(
36 "Tip: Use -n <namespace> to list pods from a specific namespace",
37 );
38 }
39
40 if ctx.flag("output").is_none() {
41 result = result.add_conditional_help(
42 "Use -o json for machine-readable output",
43 |_| true, );
45 }
46
47 let namespace = ctx
49 .flag("namespace")
50 .map(String::as_str)
51 .unwrap_or("default");
52
53 let pods = match namespace {
54 "default" => vec![
55 ("nginx-abc123", "Running"),
56 ("redis-def456", "Running"),
57 ("postgres-ghi789", "CrashLoopBackOff"),
58 ],
59 "kube-system" => vec![
60 ("coredns-xyz789", "Running"),
61 ("kube-proxy-abc123", "Running"),
62 ("etcd-master", "Running"),
63 ],
64 _ => vec![],
65 };
66
67 for (pod, status) in &pods {
69 if pod.starts_with(prefix) {
70 result = result.add_with_description(
71 *pod,
72 format!("Status: {status}"),
73 );
74 }
75 }
76
77 if pods.iter().any(|(_, status)| status == &"CrashLoopBackOff") {
79 result = result.add_help_text(
80 "Warning: Some pods are in CrashLoopBackOff state. Use 'describe' to investigate.",
81 );
82 }
83
84 Ok(result)
85 })
86 .run(|ctx| {
87 let namespace = ctx
88 .flag("namespace")
89 .map(String::as_str)
90 .unwrap_or("default");
91 let output = ctx.flag("output").map(String::as_str).unwrap_or("table");
92
93 println!("Getting pods from namespace: {namespace}");
94 println!("Output format: {output}");
95
96 if let Some(pod) = ctx.args().first() {
97 println!("Getting specific pod: {pod}");
98 } else {
99 println!("Listing all pods");
100 }
101 Ok(())
102 })
103 .build(),
104 )
105 .subcommand(
106 CommandBuilder::new("services")
107 .short("Get services")
108 .arg_completion(|_ctx, _prefix| {
109 let mut result = CompletionResult::new()
110 .add_with_description("nginx-service", "Type: LoadBalancer")
111 .add_with_description("redis-service", "Type: ClusterIP")
112 .add_with_description("postgres-service", "Type: NodePort");
113
114 result = result.add_conditional_help(
116 "Tip: Use -o wide to see more details about services",
117 |ctx| {
118 ctx.flag("output")
119 .map(|o| o != "wide")
120 .unwrap_or(true)
121 },
122 );
123
124 Ok(result)
125 })
126 .build(),
127 )
128 .build(),
129 )
130 .subcommand(
131 CommandBuilder::new("create")
132 .short("Create resources")
133 .flag(
134 Flag::new("file")
135 .short('f')
136 .usage("Filename to use to create the resource")
137 .value_type(FlagType::String)
138 .required(),
139 )
140 .flag_completion("file", |_ctx, prefix| {
141 let mut result = CompletionResult::new();
142
143 let files = vec![
145 ("deployment.yaml", "Deployment configuration"),
146 ("service.yaml", "Service configuration"),
147 ("configmap.yaml", "ConfigMap configuration"),
148 ("secret.yaml", "Secret configuration"),
149 ("pod.yaml", "Pod configuration"),
150 ];
151
152 for (file, desc) in files {
153 if file.starts_with(prefix) {
154 result = result.add_with_description(file, desc);
155 }
156 }
157
158 result = result.add_help_text(
160 "Files should be valid Kubernetes manifests in YAML or JSON format",
161 );
162
163 if std::path::Path::new(prefix)
164 .extension()
165 .is_some_and(|ext| ext.eq_ignore_ascii_case("json"))
166 {
167 result = result.add_help_text(
168 "Note: JSON format is supported but YAML is more common in Kubernetes",
169 );
170 }
171
172 Ok(result)
173 })
174 .run(|ctx| {
175 let file = ctx.flag("file").expect("File is required");
176 println!("Creating resources from file: {file}");
177 Ok(())
178 })
179 .build(),
180 )
181 .subcommand(
182 CommandBuilder::new("debug")
183 .short("Debug and troubleshoot resources")
184 .arg_completion(|_ctx, _prefix| {
185 Ok(CompletionResult::new()
186 .add_with_description("pod/nginx-abc123", "Debug a specific pod")
187 .add_with_description("node/worker-1", "Debug a node")
188 .add_with_description("deployment/nginx", "Debug a deployment")
189 .add_help_text("Debug creates an interactive debugging session")
190 .add_help_text("Common debugging commands: kubectl logs, kubectl exec, kubectl describe")
191 .add_conditional_help(
192 "Tip: Use 'kubectl logs -f' to follow log output in real-time",
193 |ctx| ctx.args().is_empty(),
194 ))
195 })
196 .build(),
197 )
198 .build();
199
200 let args: Vec<String> = std::env::args().skip(1).collect();
201 if let Err(e) = app.execute(args) {
202 eprintln!("Error: {e}");
203 std::process::exit(1);
204 }
205}