• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

veeso / tui-realm-stdlib / 20413729334

21 Dec 2025 06:03PM UTC coverage: 69.86% (-0.3%) from 70.169%
20413729334

Pull #46

github

web-flow
Merge e5d91f732 into 9528c3045
Pull Request #46: Apply changes for core `TextSpan` changes

221 of 271 new or added lines in 6 files covered. (81.55%)

3 existing lines in 2 files now uncovered.

3187 of 4562 relevant lines covered (69.86%)

2.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.45
/src/components/span.rs
1
//! ## Span
2
//!
3
//! `Span` represents a read-only text component without any container, but with the possibility to define multiple text parts.
4
//! The main difference with `Label` is that the Span allows different styles inside the same component for the texsts.
5

6
use tuirealm::command::{Cmd, CmdResult};
7
use tuirealm::props::{
8
    Alignment, AttrValue, Attribute, Color, PropPayload, PropValue, Props, SpanStatic, Style,
9
    TextModifiers,
10
};
11
use tuirealm::ratatui::{
12
    layout::Rect,
13
    text::{Line, Span as RSpan, Text},
14
    widgets::Paragraph,
15
};
16
use tuirealm::{Frame, MockComponent, State};
17

18
use crate::utils;
19

20
// -- Component
21

22
/// ## Span
23
///
24
/// Represents a read-only, single-line text component without any container, but with multi-style text parts
25
#[derive(Default)]
26
#[must_use]
27
pub struct Span {
28
    props: Props,
29
}
30

31
impl Span {
32
    pub fn foreground(mut self, fg: Color) -> Self {
1✔
33
        self.attr(Attribute::Foreground, AttrValue::Color(fg));
1✔
34
        self
1✔
35
    }
1✔
36

37
    pub fn background(mut self, bg: Color) -> Self {
1✔
38
        self.attr(Attribute::Background, AttrValue::Color(bg));
1✔
39
        self
1✔
40
    }
1✔
41

42
    pub fn modifiers(mut self, m: TextModifiers) -> Self {
1✔
43
        self.attr(Attribute::TextProps, AttrValue::TextModifiers(m));
1✔
44
        self
1✔
45
    }
1✔
46

47
    pub fn alignment(mut self, a: Alignment) -> Self {
1✔
48
        self.attr(Attribute::Alignment, AttrValue::Alignment(a));
1✔
49
        self
1✔
50
    }
1✔
51

52
    pub fn spans<T>(mut self, s: impl IntoIterator<Item = T>) -> Self
5✔
53
    where
5✔
54
        T: Into<SpanStatic>,
5✔
55
    {
56
        self.attr(
5✔
57
            Attribute::Text,
5✔
58
            AttrValue::Payload(PropPayload::Vec(
5✔
59
                s.into_iter()
5✔
60
                    .map(Into::into)
5✔
61
                    .map(PropValue::TextSpan)
5✔
62
                    .collect(),
5✔
63
            )),
5✔
64
        );
65
        self
5✔
66
    }
5✔
67
}
68

69
impl MockComponent for Span {
70
    fn view(&mut self, render: &mut Frame, area: Rect) {
×
71
        // Make a Span
72
        if self.props.get_or(Attribute::Display, AttrValue::Flag(true)) == AttrValue::Flag(true) {
×
73
            // Make text
74
            let foreground = self
×
75
                .props
×
76
                .get_or(Attribute::Foreground, AttrValue::Color(Color::Reset))
×
77
                .unwrap_color();
×
78
            let background = self
×
79
                .props
×
80
                .get_or(Attribute::Background, AttrValue::Color(Color::Reset))
×
81
                .unwrap_color();
×
82
            // binding required as "spans" is a reference and otherwise would not live long enough
83
            let payload = self
×
84
                .props
×
85
                .get_ref(Attribute::Text)
×
86
                .and_then(|x| x.as_payload());
×
NEW
87
            let text = match payload {
×
NEW
88
                Some(PropPayload::Vec(lines)) => {
×
NEW
89
                    let lines: Vec<RSpan> = lines
×
NEW
90
                        .iter()
×
91
                        // this will skip any "PropValue" that is not a "TextSpan", instead of panicing
NEW
92
                        .filter_map(|x| x.as_textspan())
×
NEW
93
                        .map(utils::borrow_clone_span)
×
NEW
94
                        .collect();
×
NEW
95
                    Text::from(Line::from(lines))
×
96
                }
NEW
97
                _ => Text::default(),
×
98
            };
99
            // Text properties
UNCOV
100
            let alignment: Alignment = self
×
101
                .props
×
102
                .get_or(Attribute::Alignment, AttrValue::Alignment(Alignment::Left))
×
103
                .unwrap_alignment();
×
104
            render.render_widget(
×
105
                Paragraph::new(text)
×
106
                    .alignment(alignment)
×
107
                    .style(Style::default().bg(background).fg(foreground)),
×
108
                area,
×
109
            );
110
        }
×
111
    }
×
112

113
    fn query(&self, attr: Attribute) -> Option<AttrValue> {
×
114
        self.props.get(attr)
×
115
    }
×
116

117
    fn attr(&mut self, attr: Attribute, value: AttrValue) {
9✔
118
        self.props.set(attr, value);
9✔
119
    }
9✔
120

121
    fn state(&self) -> State {
1✔
122
        State::None
1✔
123
    }
1✔
124

125
    fn perform(&mut self, _cmd: Cmd) -> CmdResult {
×
126
        CmdResult::None
×
127
    }
×
128
}
129

130
#[cfg(test)]
131
mod tests {
132

133
    use super::*;
134

135
    use pretty_assertions::assert_eq;
136
    use tuirealm::{props::SpanStatic, ratatui::style::Stylize};
137

138
    #[test]
139
    fn test_components_span() {
1✔
140
        let component = Span::default()
1✔
141
            .background(Color::Blue)
1✔
142
            .foreground(Color::Red)
1✔
143
            .modifiers(TextModifiers::BOLD)
1✔
144
            .alignment(Alignment::Center)
1✔
145
            .spans([
1✔
146
                SpanStatic::from("Press "),
1✔
147
                SpanStatic::from("<ESC>").fg(Color::Cyan).bold(),
1✔
148
                SpanStatic::from(" to quit"),
1✔
149
            ]);
1✔
150
        // Get value
151
        assert_eq!(component.state(), State::None);
1✔
152
    }
1✔
153

154
    #[test]
155
    fn various_spans_types() {
1✔
156
        // Vec
157
        let _ = Span::default().spans(vec![SpanStatic::raw("hello")]);
1✔
158
        // static array
159
        let _ = Span::default().spans([SpanStatic::raw("hello")]);
1✔
160
        // boxed array
161
        let _ = Span::default().spans(vec![SpanStatic::raw("hello")].into_boxed_slice());
1✔
162
        // already a iterator
163
        let _ = Span::default().spans(["Hello"].map(SpanStatic::raw));
1✔
164
    }
1✔
165
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc