From 55a208fdbbc6468b732192bf63ec69877ee20b34 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Sun, 9 Aug 2026 14:39:54 +0800 Subject: feat(config): add cfg --pair flag and refactor config path Add `--pair` flag to output config values as `"key" = "value"` pairs, and provide escaped formatting for display. Move config path resolution to a helper function and expose the underlying hash map for rendering and completion. --- mingling_cli/src/config/cmd_cfg.rs | 110 +++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 mingling_cli/src/config/cmd_cfg.rs (limited to 'mingling_cli/src/config') diff --git a/mingling_cli/src/config/cmd_cfg.rs b/mingling_cli/src/config/cmd_cfg.rs new file mode 100644 index 0000000..f0e4c2b --- /dev/null +++ b/mingling_cli/src/config/cmd_cfg.rs @@ -0,0 +1,110 @@ +use mingling::{ + LazyRes, Routable, ShellContext, Suggest, + macros::{arg, buffer, chain, command, completion, pack, r_println, renderer, suggest}, + picker::{EntryPicker, PickerArg, value::Flag}, +}; + +use crate::{Entry, Next, config::ResMlingConfig}; + +const FLAG_PAIR: PickerArg = arg![pair: Flag]; + +pack!(StateConfigEdit = (String, String)); +pack!(ResultConfigKeyValuePair = String); +pack!(ResultConfigValue = String); +pack!(ResultConfig = ()); + +#[command] +pub fn cfg(args: Entry) -> Next { + let (key, value, show_pair) = args + .pick(&arg![Option]) + .pick(&arg![Option]) + .pick(&FLAG_PAIR) + .unwrap(); + + match (key, value) { + (Some(k), Some(v)) => { + // Edit + StateConfigEdit::new((k, v)).into() + } + (Some(k), None) => { + // Display + if *show_pair { + ResultConfigKeyValuePair::new(k).to_render() + } else { + ResultConfigValue::new(k).to_render() + } + } + (None, None) => { + // List + ResultConfig::new(()).to_render() + } + _ => { + unreachable!("This path is unreachable given the positional parsing done by arg-picker") + } + } +} + +#[chain] +pub fn handle_state_config_edit(kv: StateConfigEdit, config: &mut LazyRes) { + let config = config.get_mut(); + config.edit(&kv.0, &kv.1); +} + +#[renderer(buffer)] +pub fn render_config_kvp(r: ResultConfigKeyValuePair, config: &mut LazyRes) { + let config = config.get_ref(); + let key = r.inner; + let value = config.get(&key); + r_println!( + "\"{}\" = \"{}\"", + escape_config_value(&key), + escape_config_value(value) + ) +} + +#[renderer(buffer)] +pub fn render_config_value(r: ResultConfigValue, config: &mut LazyRes) { + let config = config.get_ref(); + let key = r.inner; + let value = config.get(&key); + r_println!("{}", value) +} + +#[renderer(buffer)] +pub fn render_config(_: ResultConfig, config: &mut LazyRes) { + let config = config.get_ref(); + for (k, v) in config.get_hash_map().iter() { + r_println!( + "\"{}\" = \"{}\"", + escape_config_value(k), + escape_config_value(v) + ) + } +} + +/// Utility function: escapes `\t`, `\n`, `\b`, `\r` in the string to their +/// literal representations `\\t`, `\\n`, `\\b`, `\\r`, then trims leading and +/// trailing whitespace, and escapes `"` to `\"`. +pub fn escape_config_value(input: &str) -> String { + let mut result = String::with_capacity(input.len()); + for ch in input.trim().chars() { + match ch { + '\t' => result.push_str("\\t"), + '\n' => result.push_str("\\n"), + '\u{0008}' => result.push_str("\\b"), + '\r' => result.push_str("\\r"), + '"' => result.push_str("\\\""), + _ => result.push(ch), + } + } + result +} + +#[completion(EntryCfg)] +pub fn complete_config(_ctx: &ShellContext, config: &mut LazyRes) -> Suggest { + let config = config.get_ref(); + let keys = config.get_hash_map().keys().cloned().collect::>(); + Suggest::from(keys).combine(suggest! { + FLAG_PAIR + }) +} -- cgit