Skip to main content

sphinx_ultra/doctree/
messages.rs

1//! `system_message` node construction with docutils-exact shape.
2
3use super::{kinds, AttrValue, Node, Span};
4
5pub const INFO: u8 = 1;
6pub const WARNING: u8 = 2;
7pub const ERROR: u8 = 3;
8pub const SEVERE: u8 = 4;
9
10fn type_name(level: u8) -> &'static str {
11    match level {
12        1 => "INFO",
13        2 => "WARNING",
14        3 => "ERROR",
15        _ => "SEVERE",
16    }
17}
18
19/// `<system_message level line source type><paragraph>text`.
20///
21/// `line` is the absolute 1-based line of the triggering source line
22/// (the underline for title problems, the indented line for indent errors).
23pub fn system_message(level: u8, text: &str, line: u32, source: &str) -> Node {
24    let mut msg = Node::elem(kinds::SYSTEM_MESSAGE, Span::ZERO);
25    msg.set("level", AttrValue::Int(i64::from(level)));
26    msg.set("line", AttrValue::Int(i64::from(line)));
27    msg.set("source", AttrValue::Str(source.to_string()));
28    msg.set("type", AttrValue::Str(type_name(level).to_string()));
29    let mut para = Node::elem(kinds::PARAGRAPH, Span::ZERO);
30    para.children.push(Node::text_node(text, Span::ZERO));
31    msg.children.push(para);
32    msg
33}
34
35/// Append the offending source block as `<literal_block xml:space="preserve">`
36/// (docutils reproduces e.g. the title + underline inside the message).
37pub fn with_literal(mut msg: Node, raw: &str) -> Node {
38    let mut lb = Node::elem(kinds::LITERAL_BLOCK, Span::ZERO);
39    lb.set("xml:space", AttrValue::Str("preserve".to_string()));
40    lb.children.push(Node::text_node(raw, Span::ZERO));
41    msg.children.push(lb);
42    msg
43}
44
45/// Append a plain paragraph child (docutils' "Established title styles: …").
46pub fn with_paragraph(mut msg: Node, text: &str) -> Node {
47    let mut para = Node::elem(kinds::PARAGRAPH, Span::ZERO);
48    para.children.push(Node::text_node(text, Span::ZERO));
49    msg.children.push(para);
50    msg
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn system_message_shape() {
59        let m = system_message(WARNING, "Title underline too short.", 3, "<snippet>");
60        assert_eq!(
61            m.pformat(),
62            "<system_message level=\"2\" line=\"3\" source=\"<snippet>\" type=\"WARNING\">\n    <paragraph>\n        Title underline too short.\n"
63        );
64    }
65
66    #[test]
67    fn with_literal_appends_preserved_block() {
68        let m = with_literal(
69            system_message(WARNING, "Title underline too short.", 2, "<snippet>"),
70            "Long Section Title\n======",
71        );
72        assert_eq!(
73            m.pformat(),
74            "<system_message level=\"2\" line=\"2\" source=\"<snippet>\" type=\"WARNING\">\n    <paragraph>\n        Title underline too short.\n    <literal_block xml:space=\"preserve\">\n        Long Section Title\n        ======\n"
75        );
76    }
77}