1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use crate::grammar::parse_tree::Span;
use crate::message::Content;
use crate::style::Style;
use crate::tls::Tls;
use ascii_canvas::AsciiView;
use std::cmp;
use std::fmt::{Debug, Error, Formatter};

/// The top-level message display like this:
///
/// ```
/// <span>: <heading>
///
/// <body>
/// ```
///
/// This is equivalent to a
///
/// ```
/// Vert[separate=2] {
///     Horiz[separate=1] {
///         Horiz[separate=0] {
///             Citation { span },
///             Text { ":" },
///         },
///         <heading>,
///     },
///     <body>
/// }
/// ```
pub struct Message {
    span: Span,
    heading: Box<dyn Content>,
    body: Box<dyn Content>,
}

impl Message {
    pub fn new(span: Span, heading: Box<dyn Content>, body: Box<dyn Content>) -> Self {
        Message {
            span,
            heading,
            body,
        }
    }
}

impl Content for Message {
    fn min_width(&self) -> usize {
        let file_text = Tls::file_text();
        let span = file_text.span_str(self.span).chars().count();
        let heading = self.heading.min_width();
        let body = self.body.min_width();
        cmp::max(span + heading + 2, body + 2)
    }

    fn emit(&self, view: &mut dyn AsciiView) {
        let session = Tls::session();
        let file_text = Tls::file_text();

        let span = file_text.span_str(self.span);
        view.write_chars(0, 0, span.chars(), Style::new());
        let count = span.chars().count();
        view.write_chars(0, count, ":".chars(), Style::new());

        let (row, _) = self
            .heading
            .emit_at(&mut view.styled(session.heading), 0, count + 2);

        self.body.emit_at(view, row + 2, 2);
    }

    fn into_wrap_items(self: Box<Self>, wrap_items: &mut Vec<Box<dyn Content>>) {
        wrap_items.push(self);
    }
}

impl Debug for Message {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.debug_struct("Message")
            .field("span", &self.span)
            .field("heading", &self.heading)
            .field("body", &self.body)
            .finish()
    }
}