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

tonyb983 / ansirs / 17375782855

01 Sep 2025 11:06AM UTC coverage: 85.644% (+4.6%) from 81.066%
17375782855

Pull #23

github

web-flow
Update Rust crate string_cache to 0.9.0
Pull Request #23: Update Rust crate string_cache to 0.9.0

2595 of 3030 relevant lines covered (85.64%)

28.98 hits per line

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

86.42
/src/styled/mod.rs
1
// Copyright (c) 2022 Tony Barbitta
2
//
3
// This Source Code Form is subject to the terms of the Mozilla Public
4
// License, v. 2.0. If a copy of the MPL was not distributed with this
5
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6

7
use crate::{Ansi, IntoAnsi};
8

9
/// `string` Module
10
///
11
/// This module contains some experiments with storing a formatted string, i.e. a
12
/// wrapped [`String`] that also contains an [`Ansi`](crate::Ansi) style.
13
#[cfg(feature = "strings")]
14
pub mod string;
15

16
/// Styles the given [`Display`](std::fmt::Display) using the style described by `style`.
17
/// `S` can be either an [`Ansi`](Ansi) or a closure that returns an [`Ansi`](Ansi). This might
18
/// require bringing the [`IntoAnsi`](IntoAnsi) trait into scope.
19
#[cfg_attr(feature = "trace", tracing::instrument(skip(text, style), fields(text = %text, style_ansi)))]
20
pub fn style_text<S: IntoAnsi>(text: impl std::fmt::Display, style: S) -> String {
15✔
21
    let actual = format!("{text}");
15✔
22

23
    if actual.is_empty() {
15✔
24
        actual
×
25
    } else {
26
        let ansi: Ansi = style.into_ansi();
15✔
27
        #[cfg(feature = "trace")]
28
        {
15✔
29
            let style = format!("{ansi:?}");
15✔
30
            tracing::Span::current().record("style_ansi", style.as_str());
15✔
31
        }
15✔
32
        if ansi.is_default() {
15✔
33
            actual
4✔
34
        } else {
35
            format!("{}{}{}", ansi, text, Ansi::reset())
11✔
36
        }
37
    }
38
}
15✔
39

40
/// Shortcut to call `print!` with the output of `style_text`.
41
pub fn styled_print<S: IntoAnsi>(text: impl std::fmt::Display, style: S) {
×
42
    print!("{}", style_text(text, style));
×
43
}
×
44

45
/// Shortcut to call `println!` with the output of `style_text`.
46
#[cfg_attr(feature = "trace", tracing::instrument(skip(text, style), fields(text = %text, styled)))]
47
pub fn styled_println<S: IntoAnsi>(text: impl std::fmt::Display, style: S) {
×
48
    let styled = style_text(text, style);
×
49
    #[cfg(feature = "trace")]
50
    {
×
51
        tracing::Span::current().record("styled", styled.as_str());
×
52
    }
×
53
    println!("{styled}");
×
54
}
×
55

56
/// Trait used to add a `style` "extension method" to any type that implements [`Display`](std::fmt::Display)
57
/// as a convenience to call `style_text`.
58
pub trait Styled {
59
    /// Style this value using the given `style`.
60
    fn style(&self, style: impl IntoAnsi) -> String;
61
}
62

63
impl<T> Styled for T
64
where
65
    T: std::fmt::Display,
66
{
67
    fn style(&self, style: impl IntoAnsi) -> String {
6✔
68
        style_text(self.to_string(), style)
6✔
69
    }
6✔
70
}
71

72
/// Trait that is currently only used to try and normalize the interface between my variations
73
/// of styled strings.
74
pub trait StyledString {
75
    /// Get the "raw" (aka unstyled / original) text.
76
    #[must_use]
77
    fn raw(&self) -> &str;
78

79
    /// Get the [`Ansi`] styling applied to this text.
80
    #[must_use]
81
    fn style(&self) -> Option<&Ansi>;
82

83
    /// Modify the styling applied to this text using the given closure.
84
    fn modify_style<F: FnMut(Option<&Ansi>) -> Option<Ansi>>(&mut self, f: F);
85

86
    /// Get the formatted value of this [`StyledString`].
87
    #[must_use]
88
    fn value(&self) -> String;
89

90
    /// Gets the length of the ***original text***, i.e. the VISIBLE length.
91
    #[must_use]
92
    fn len(&self) -> usize;
93

94
    /// Checks if the original / **visible** text is empty
95
    #[must_use]
96
    fn is_empty(&self) -> bool;
97
}
98

99
#[cfg(test)]
100
mod tests {
101
    use super::*;
102
    use pretty_assertions::assert_eq;
103

104
    const DISPLAY_PRE: &str = "\u{1b}[";
105
    const DISPLAY_SUF: &str = "m";
106

107
    fn empty_style_function() -> Ansi {
2✔
108
        Ansi::new()
2✔
109
    }
2✔
110

111
    #[test]
112
    fn storing_styles() {
1✔
113
        let style1 = Ansi::new().fg((100, 200, 100)).underline();
1✔
114
        let style2 = Ansi::new().bg((0, 0, 75)).italic().strike();
1✔
115

116
        assert_eq!(
1✔
117
            style1.to_string(),
1✔
118
            format!("{DISPLAY_PRE}4;38;2;100;200;100{DISPLAY_SUF}")
1✔
119
        );
120
        assert_eq!(
1✔
121
            style2.to_string(),
1✔
122
            format!("{DISPLAY_PRE}3;9;48;2;0;0;75{DISPLAY_SUF}")
1✔
123
        );
124
        assert_eq!(
1✔
125
            style1.to_string(),
1✔
126
            format!("{DISPLAY_PRE}4;38;2;100;200;100{DISPLAY_SUF}")
1✔
127
        );
128
        assert_eq!(
1✔
129
            style2.to_string(),
1✔
130
            format!("{DISPLAY_PRE}3;9;48;2;0;0;75{DISPLAY_SUF}")
1✔
131
        );
132
    }
1✔
133

134
    #[test]
135
    fn style_text_basic() {
1✔
136
        let first = "first".to_string();
1✔
137
        let unstyled_val = style_text(&first, Ansi::new());
1✔
138
        assert_eq!(unstyled_val, first);
1✔
139
        let unstyled_fn = style_text(&first, empty_style_function);
1✔
140
        assert_eq!(unstyled_fn, first);
1✔
141

142
        let manual_prefix = format!("{}{}{}", DISPLAY_PRE, "4;38;2;255;0;0", DISPLAY_SUF);
1✔
143
        let manual_suffix = format!("{}{}{}", DISPLAY_PRE, "0", DISPLAY_SUF);
1✔
144
        let manual = format!("{manual_prefix}{first}{manual_suffix}");
1✔
145

146
        let styled_value = style_text(&first, Ansi::red().underline());
1✔
147

148
        assert_eq!(styled_value, manual);
1✔
149
    }
1✔
150

151
    #[test]
152
    fn style_text_inputs() {
1✔
153
        let first = "first".to_string();
1✔
154

155
        let st = style_text(&first, Ansi::new());
1✔
156
        let sf = style_text(&first, empty_style_function);
1✔
157
        let sc = style_text(&first, || {
1✔
158
            let style = Ansi::new()
1✔
159
                .underline()
1✔
160
                .italic()
1✔
161
                .fg((200, 100, 200))
1✔
162
                .bg((255, 255, 255));
1✔
163

164
            style.strike()
1✔
165
        });
1✔
166
        // Why the fuck cant i get this to work in another project.
167
        let _styled_colors = style_text(&first, crate::Colors::Yellow.into_ansi());
1✔
168
        let _styled_colors = style_text(&first, crate::Colors::Yellow);
1✔
169
        let yellow = crate::Colors::Yellow.into_color();
1✔
170
        let _styled_color = style_text(&first, yellow.into_ansi());
1✔
171

172
        let manual_prefix = format!(
1✔
173
            "{}{}{}",
1✔
174
            DISPLAY_PRE, "3;4;9;38;2;200;100;200;48;2;255;255;255", DISPLAY_SUF
175
        );
176
        let manual_suffix = format!("{}{}{}", DISPLAY_PRE, "0", DISPLAY_SUF);
1✔
177
        let third = format!("{manual_prefix}{first}{manual_suffix}");
1✔
178

179
        assert_eq!(&st, &first);
1✔
180
        assert_eq!(&sf, &first);
1✔
181
        assert_eq!(&sc, &third);
1✔
182
    }
1✔
183
}
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