Skip to main content

hara_native/native_cli/
documentation.rs

1use 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}