Skip to main content

org_gdocs/
envelope.rs

1//! The CLI ↔ Emacs result envelope (A5): a single s-expression the binary prints
2//! for domain commands, which `org-gdocs.el` reads with `(read …)`.
3//!
4//! Shape:
5//!
6//! ```text
7//! (ok    <command> (<key> <value>) …)
8//! (error <command> "<message>")
9//! ```
10//!
11//! `<command>` is a bare symbol (`push`/`pull`/`clean`/`open`/`auth`); each field
12//! is a `(key value)` list so elisp can `assq` it. This is JSON-free by design —
13//! see [`crate::sexp`].
14
15use crate::sexp::Sexp;
16
17/// Build a success envelope: `(ok <command> (key value) …)`.
18#[must_use]
19pub fn ok(command: &str, fields: Vec<(&str, Sexp)>) -> Sexp {
20    let mut items = Vec::with_capacity(fields.len() + 2);
21    items.push(Sexp::symbol("ok"));
22    items.push(Sexp::symbol(command));
23    for (key, value) in fields {
24        items.push(Sexp::list(vec![Sexp::symbol(key), value]));
25    }
26    Sexp::list(items)
27}
28
29/// Build an error envelope: `(error <command> "<message>")`.
30#[must_use]
31pub fn error(command: &str, message: &str) -> Sexp {
32    Sexp::list(vec![
33        Sexp::symbol("error"),
34        Sexp::symbol(command),
35        Sexp::string(message),
36    ])
37}
38
39/// The Emacs-lisp boolean symbol for a flag.
40#[must_use]
41pub const fn flag(value: bool) -> &'static str {
42    if value { "t" } else { "nil" }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::{error, flag, ok};
48    use crate::sexp::Sexp;
49
50    #[test]
51    fn ok_envelope_renders_command_and_fields() {
52        let rendered = ok(
53            "push",
54            vec![
55                ("document-id", Sexp::string("DOC1")),
56                ("created", Sexp::symbol(flag(true))),
57            ],
58        )
59        .render();
60        assert_eq!(rendered, "(ok push (document-id \"DOC1\") (created t))");
61    }
62
63    #[test]
64    fn error_envelope_renders_message() {
65        assert_eq!(
66            error("open", "no linked document").render(),
67            "(error open \"no linked document\")"
68        );
69    }
70}