hara_native/native_cli/
documentation.rs1use crate::lang::data::MetadataValue;
2use crate::Runtime;
3
4#[derive(Clone, Debug, PartialEq)]
5pub enum DocumentationValue {
6 Nil,
7 Boolean(bool),
8 Integer(i64),
9 String(String),
10 Array(Vec<DocumentationValue>),
11}
12
13#[derive(Clone, Debug, PartialEq)]
14pub struct Documentation {
15 pub symbol: String,
16 pub doc: Option<String>,
17 pub arglists: DocumentationValue,
18 pub file: Option<String>,
19 pub line: Option<i64>,
20 pub column: Option<i64>,
21}
22
23fn value(metadata: &MetadataValue) -> DocumentationValue {
24 match metadata {
25 MetadataValue::Nil => DocumentationValue::Nil,
26 MetadataValue::Boolean(value) => DocumentationValue::Boolean(*value),
27 MetadataValue::Number(value) => DocumentationValue::Integer(*value),
28 MetadataValue::Float(value) => DocumentationValue::String(value.to_string()),
29 MetadataValue::BigInteger(value) => DocumentationValue::String(value.to_string()),
30 MetadataValue::Regex(value) => DocumentationValue::String(value.clone()),
31 MetadataValue::Character(value) => DocumentationValue::String(value.to_string()),
32 MetadataValue::Tagged(tag, tagged) => {
33 DocumentationValue::Array(vec![DocumentationValue::String(tag.clone()), value(tagged)])
34 }
35 MetadataValue::String(value) => DocumentationValue::String(value.clone()),
36 MetadataValue::Keyword(value) => DocumentationValue::String(format!(":{}", value.as_str())),
37 MetadataValue::Symbol(value) => DocumentationValue::String(value.as_str().to_owned()),
38 MetadataValue::Vector(values)
39 | MetadataValue::List(values)
40 | MetadataValue::Set(values) => {
41 DocumentationValue::Array(values.iter().map(value).collect())
42 }
43 MetadataValue::Map(values) => DocumentationValue::Array(
44 values
45 .iter()
46 .flat_map(|(key, item)| [value(key), value(item)])
47 .collect(),
48 ),
49 }
50}
51
52fn string(value: Option<&MetadataValue>) -> Option<String> {
53 match value {
54 Some(MetadataValue::String(value)) => Some(value.clone()),
55 Some(MetadataValue::Symbol(value)) => Some(value.as_str().to_owned()),
56 _ => None,
57 }
58}
59
60fn integer(value: Option<&MetadataValue>) -> Option<i64> {
61 match value {
62 Some(MetadataValue::Number(value)) => Some(*value),
63 Some(MetadataValue::String(value)) => value.parse().ok(),
64 _ => None,
65 }
66}
67
68pub(super) fn lookup(runtime: &Runtime, symbol: &str) -> Result<Documentation, String> {
69 let metadata = runtime
70 .var_metadata(symbol)
71 .ok_or_else(|| format!("No documentation symbol: {symbol}"))?;
72 let hara = metadata.hara.as_deref();
73 let doc = hara
74 .and_then(|value| value.doc().map(str::to_owned))
75 .or(metadata.doc);
76 let arglists = hara
77 .and_then(|value| value.get_keyword("arglists"))
78 .map(value)
79 .unwrap_or_else(|| {
80 DocumentationValue::Array(
81 metadata
82 .arglists
83 .into_iter()
84 .map(DocumentationValue::String)
85 .collect(),
86 )
87 });
88 Ok(Documentation {
89 symbol: symbol.into(),
90 doc,
91 arglists,
92 file: string(hara.and_then(|value| value.get_keyword("file"))),
93 line: integer(hara.and_then(|value| value.get_keyword("line"))),
94 column: integer(hara.and_then(|value| value.get_keyword("column"))),
95 })
96}