// `moui config` command — XDG-backed CLI configuration get/set/list/show-path/edit.
// All values are stored as JSON at `config_path(host)`. Reads gracefully
// degrade to `default_cli_config()` when the file is missing.

///|
priv struct ParsedConfig {
  help : Bool
  json : Bool
  action : String
  key : String?
  value : String?
}

///|
fn config_usage() -> String {
  (
    #|Usage: moui config  [args]
    #|
    #|Actions:
    #|  get             Print the value of 
.. #| set Set
. to and persist. #| list Print all non-empty config values. #| show-path Print the config file path. #| edit Print the path to edit manually. #| #|Sections: harmonyos, android, ios, paths. #|Run `moui config list` after `read_config` to see all known fields. #| #|Options: #| --json Emit machine-readable output. #| -h, --help Show this help. ) } ///| fn parse_config_args(args : Array[String]) -> Result[ParsedConfig, String] { let help = Ref(false) let json = Ref(false) let positional : Array[String] = [] let mut index = 0 while index < args.length() { let argument = args[index] let (name, inline) = option_parts(argument) match name { "--json" => { match flag_without_value(inline, name) { Ok(_) => () Err(message) => return Err(message) } json.val = true index += 1 } "-h" | "--help" => { match flag_without_value(inline, name) { Ok(_) => () Err(message) => return Err(message) } help.val = true index += 1 } _ if argument.has_prefix("-") => return Err("unknown option for moui config: " + name) _ => { positional.push(argument) index += 1 } } } if help.val { return Ok({ help: true, json: json.val, action: "", key: None, value: None, }) } if positional.is_empty() { return Err("moui config requires an action") } let action = positional[0] match action { "get" => { if positional.length() != 2 { return Err("usage: moui config get ") } Ok({ help: false, json: json.val, action, key: Some(positional[1]), value: None, }) } "set" => { if positional.length() != 3 { return Err("usage: moui config set ") } Ok({ help: false, json: json.val, action, key: Some(positional[1]), value: Some(positional[2]), }) } "list" | "show-path" | "edit" => if positional.length() == 1 { Ok({ help: false, json: json.val, action, key: None, value: None, }) } else { Err(action + " does not take arguments") } _ => Err("unknown moui config action: " + action) } } ///| fn run_config(parsed : ParsedConfig, host : HostPlatform) -> CliOutcome { if parsed.help { return stdout_outcome(config_usage()) } match parsed.action { "show-path" => { let path = config_path(host) if parsed.json { let value : Json = { "schemaVersion": 1, "ok": true, "path": Json::string(path), } stdout_outcome(value.stringify(indent=2) + "\n") } else { stdout_outcome(path + "\n") } } "edit" => { let path = config_path(host) let message = "edit manually: " + path + "\n" if parsed.json { let value : Json = { "schemaVersion": 1, "ok": true, "path": Json::string(path), } stdout_outcome(value.stringify(indent=2) + "\n") } else { stdout_outcome(message) } } "list" => match read_config(host) { Err(message) => failed_outcome(message, parsed.json, config_usage()) Ok(config) => { let lines = config_list_lines(config) if parsed.json { let entries : Array[Json] = [] for line in lines { match line.split_once(" = ") { Some((entry_key, entry_value)) => entries.push({ "key": Json::string(entry_key.to_owned()), "value": Json::string(entry_value.to_owned()), }) None => () } } let root : Json = { "schemaVersion": 1, "ok": true, "entries": Json::array(entries), } stdout_outcome(root.stringify(indent=2) + "\n") } else if lines.is_empty() { stdout_outcome("(no config values set)\n") } else { stdout_outcome(lines.join("\n") + "\n") } } } "get" => match parsed.key { None => failed_outcome("missing key", parsed.json, config_usage()) Some(key) => match read_config(host) { Err(message) => failed_outcome(message, parsed.json, config_usage()) Ok(config) => match config_get(config, key) { Ok(value) => if parsed.json { let root : Json = { "schemaVersion": 1, "ok": true, "key": Json::string(key), "value": Json::string(value), } stdout_outcome(root.stringify(indent=2) + "\n") } else { stdout_outcome(value + "\n") } Err(message) => failed_outcome(message, parsed.json, config_usage()) } } } "set" => match (parsed.key, parsed.value) { (None, _) | (_, None) => failed_outcome("missing key or value", parsed.json, config_usage()) (Some(key), Some(value)) => match read_config(host) { Err(message) => failed_outcome(message, parsed.json, config_usage()) Ok(config) => match config_set(config, key, value) { Ok(updated) => match write_config(updated, host) { Ok(_) => if parsed.json { let root : Json = { "schemaVersion": 1, "ok": true, "key": Json::string(key), "value": Json::string(value), } stdout_outcome(root.stringify(indent=2) + "\n") } else { stdout_outcome(key + " = " + value + "\n") } Err(message) => failed_outcome(message, parsed.json, config_usage()) } Err(message) => failed_outcome(message, parsed.json, config_usage()) } } } _ => failed_outcome("unknown action", parsed.json, config_usage()) } }