uni_core/primitives/
help.rs

1use crate::compat::{Rc, format, ToString};
2use crate::interpreter::Interpreter;
3use crate::value::{RuntimeError, Value};
4
5const IF_DOC: &str = "Conditional branching. Usage: condition true-branch false-branch if";
6const EXEC_DOC: &str =
7    "Execute the value at the top of the stack. Lists run as code, other values execute directly.";
8const QUIT_DOC: &str = "Exit the REPL or terminate script execution. Usage: quit";
9
10pub fn help_builtin(interp: &mut Interpreter) -> Result<(), RuntimeError> {
11    let word = interp.pop()?;
12    let atom = match word {
13        Value::Atom(name) => name,
14        _ => {
15            return Err(RuntimeError::TypeError(
16                "help expects an atom (use 'word help)".to_string(),
17            ));
18        }
19    };
20
21    let (doc, is_executable) = if atom.as_ref() == "if" {
22        (Some(Rc::<str>::from(IF_DOC)), true)
23    } else if atom.as_ref() == "exec" {
24        (Some(Rc::<str>::from(EXEC_DOC)), true)
25    } else if atom.as_ref() == "quit" {
26        (Some(Rc::<str>::from(QUIT_DOC)), true)
27    } else {
28        let entry = interp
29            .dictionary
30            .get(&atom)
31            .ok_or_else(|| RuntimeError::UndefinedWord(atom.to_string()))?;
32        (entry.doc.clone(), entry.is_executable)
33    };
34
35    let name_str = atom.to_string();
36
37    if let Some(doc_text) = doc {
38        if doc_text.trim().is_empty() {
39            let output = format!("{}: documentation is empty", name_str);
40            let _ = interp.writeln(&output);
41        } else {
42            // RUST CONCEPT: Split multi-line docs and write each line separately
43            // This ensures proper line handling on all platforms (Linux, micro:bit, etc.)
44            let output = format!("{}:", name_str);
45            let _ = interp.writeln(&output);
46
47            // Split by newline and write each line
48            for line in doc_text.split('\n') {
49                let _ = interp.writeln(line);
50            }
51        }
52    } else {
53        let kind = if is_executable { "word" } else { "constant" };
54        let output = format!("{} ({}) has no documentation yet", name_str, kind);
55        let _ = interp.writeln(&output);
56    }
57
58    Ok(())
59}