1use kdl::{KdlEntry, KdlNode};
2use serde::{Deserialize, Serialize};
3
4use crate::error::UsageErr;
5use crate::spec::context::ParsingContext;
6use crate::spec::helpers::NodeHelper;
7use crate::spec::is_false;
8
9#[derive(Debug, Default, Clone, Serialize, Deserialize)]
10pub struct SpecComplete {
11 pub name: String,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub run: Option<String>,
14 #[serde(skip_serializing_if = "is_false")]
15 pub descriptions: bool,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub type_: Option<String>,
18}
19
20impl SpecComplete {
21 pub(crate) fn parse(ctx: &ParsingContext, node: &NodeHelper) -> Result<Self, UsageErr> {
22 let mut config = Self::default();
23 node.ensure_arg_len(1..=1)?;
24 config.name = node.arg(0)?.ensure_string()?.to_string().to_lowercase();
25 for (k, v) in node.props() {
26 match k {
27 "run" => {
28 if config.type_.is_some() {
29 bail_parse!(ctx, v.entry.span(), "can set run or type, not both")
30 }
31 config.run = Some(v.ensure_string()?.to_string())
32 }
33 "descriptions" => config.descriptions = v.ensure_bool()?,
34 "type" => {
35 if config.run.is_some() {
36 bail_parse!(ctx, v.entry.span(), "can set run or type, not both")
37 }
38 config.type_ = Some(v.ensure_string()?.to_string())
39 }
40 k => bail_parse!(ctx, v.entry.span(), "unsupported complete key {k}"),
41 }
42 }
43 Ok(config)
44 }
45}
46
47impl From<&SpecComplete> for KdlNode {
48 fn from(complete: &SpecComplete) -> Self {
49 let mut node = KdlNode::new("complete");
50 node.push(KdlEntry::new(complete.name.clone()));
51 if let Some(run) = &complete.run {
52 node.push(KdlEntry::new_prop("run", run.clone()));
53 }
54 if let Some(type_) = &complete.type_ {
55 node.push(KdlEntry::new_prop("type", type_.clone()));
56 }
57 if complete.descriptions {
58 node.push(KdlEntry::new_prop("descriptions", "true".to_string()));
59 }
60 node
61 }
62}