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
|
use mingling::{
LazyRes, Routable, ShellContext, Suggest,
macros::{
arg, buffer, chain, command, completion, metadata, pack, r_println, renderer, suggest,
},
metadata::Description,
picker::{EntryPicker, PickerArg, value::Flag},
};
use crate::{Entry, Next, config::ResMlingConfig};
const FLAG_PAIR: PickerArg<Flag> = 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<String>])
.pick(&arg![Option<String>])
.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<ResMlingConfig>) {
let config = config.get_mut();
config.edit(&kv.0, &kv.1);
}
#[renderer(buffer)]
pub fn render_config_kvp(r: ResultConfigKeyValuePair, config: &mut LazyRes<ResMlingConfig>) {
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<ResMlingConfig>) {
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<ResMlingConfig>) {
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<ResMlingConfig>) -> Suggest {
let config = config.get_ref();
let keys = config.get_hash_map().keys().cloned().collect::<Vec<_>>();
Suggest::from(keys).combine(suggest! {
FLAG_PAIR: "Whether to output in the form \"key\" = \"value\""
})
}
#[metadata(EntryCfg)]
pub fn desc_cfg() -> Description {
"View and edit Mling's user configuration file".into()
}
|