#![allow(clippy::or_fun_call)]
use flag_rs::completion_cache::CompletionCache;
use flag_rs::{CommandBuilder, CompletionResult, Flag, FlagType};
use std::sync::Arc;
use std::thread;
use std::time::{Duration, Instant};
fn expensive_completion(prefix: &str) -> Vec<String> {
thread::sleep(Duration::from_millis(500));
let items = vec![
"nginx-deployment-abc123",
"nginx-deployment-def456",
"redis-cache-ghi789",
"redis-cache-jkl012",
"postgres-db-mno345",
"postgres-db-pqr678",
"mongodb-cluster-stu901",
"mongodb-cluster-vwx234",
];
items
.into_iter()
.filter(|item| item.starts_with(prefix))
.map(String::from)
.collect()
}
fn main() {
let cache = Arc::new(CompletionCache::new(Duration::from_secs(10)));
let app = CommandBuilder::new("kubectl")
.short("Kubernetes command-line tool with cached completions")
.flag(
Flag::new("namespace")
.short('n')
.usage("The namespace scope for this CLI request")
.value_type(FlagType::String)
.default(flag_rs::FlagValue::String("default".to_string())),
)
.subcommand({
let cache_clone = Arc::clone(&cache);
CommandBuilder::new("get")
.short("Display one or many resources")
.subcommand({
let cache_for_pods = Arc::clone(&cache_clone);
CommandBuilder::new("pods")
.short("List pods with cached completion")
.arg_completion(move |ctx, prefix| {
let start = Instant::now();
let cache_key = CompletionCache::make_key(
&["kubectl".to_string(), "get".to_string(), "pods".to_string()],
prefix,
ctx.flags(),
);
if let Some(cached_result) = cache_for_pods.get(&cache_key) {
eprintln!("✓ Cache hit! Completed in {:?}", start.elapsed());
return Ok(cached_result);
}
eprintln!("✗ Cache miss - fetching completions...");
let items = expensive_completion(prefix);
let mut result = CompletionResult::new();
for item in items {
result = result.add_with_description(
item.clone(),
format!(
"Pod in namespace {}",
ctx.flag("namespace").unwrap_or(&"default".to_string())
),
);
}
if prefix.is_empty() {
result =
result.add_help_text("Tip: Start typing to filter pod names");
}
cache_for_pods.put(cache_key, result.clone());
eprintln!(
"✓ Completed in {:?} (cached for future use)",
start.elapsed()
);
Ok(result)
})
.build()
})
.subcommand({
let cache_for_services = Arc::clone(&cache_clone);
CommandBuilder::new("services")
.short("List services with cached completion")
.arg_completion(move |ctx, prefix| {
let cache_key = CompletionCache::make_key(
&[
"kubectl".to_string(),
"get".to_string(),
"services".to_string(),
],
prefix,
ctx.flags(),
);
if let Some(cached) = cache_for_services.get(&cache_key) {
eprintln!("✓ Using cached service completions");
return Ok(cached);
}
let services = expensive_completion(prefix);
let result = CompletionResult::new().extend(services);
cache_for_services.put(cache_key, result.clone());
Ok(result)
})
.build()
})
.build()
})
.build();
println!("=== Cached Completion Demo ===\n");
println!("This demo shows how completion caching improves performance.\n");
println!("To test completions with caching:");
println!("1. Set up bash completion:");
println!(
" source <({} completion bash)",
std::env::args().next().unwrap_or_default()
);
println!();
println!("2. Try tab completion multiple times:");
println!(
" {} get pods n<TAB> # First time: ~500ms (cache miss)",
std::env::args().next().unwrap_or_default()
);
println!(
" {} get pods n<TAB> # Second time: <1ms (cache hit!)",
std::env::args().next().unwrap_or_default()
);
println!();
println!("3. Different prefixes have separate cache entries:");
println!(
" {} get pods r<TAB> # Different prefix = cache miss",
std::env::args().next().unwrap_or_default()
);
println!();
println!("4. Flags affect the cache key:");
println!(
" {} -n prod get pods n<TAB> # Different namespace = different cache",
std::env::args().next().unwrap_or_default()
);
println!();
println!("Note: Cache entries expire after 10 seconds in this demo.\n");
println!("---\n");
let args: Vec<String> = std::env::args().skip(1).collect();
if std::env::var("KUBECTL_COMPLETE").is_ok() {
eprintln!("Cache size: {} entries", cache.size());
}
if let Err(e) = app.execute(args) {
eprintln!("{}", e);
std::process::exit(1);
}
}