Skip to content

Commit 7a147fb

Browse files
committed
Write terminal styles using stream without constructing String
1 parent 6f9a095 commit 7a147fb

File tree

2 files changed

+49
-92
lines changed

2 files changed

+49
-92
lines changed

spdlog/src/sink/std_stream_sink.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use if_chain::if_chain;
99

1010
use crate::{
1111
sink::{helper, Sink},
12-
terminal_style::{LevelStyleCodes, Style, StyleMode},
12+
terminal_style::{LevelStyles, Style, StyleMode},
1313
Error, Level, Record, Result, StringBuf,
1414
};
1515

@@ -88,7 +88,7 @@ pub struct StdStreamSink {
8888
common_impl: helper::CommonImpl,
8989
dest: StdStreamDest<io::Stdout, io::Stderr>,
9090
should_render_style: bool,
91-
level_style_codes: LevelStyleCodes,
91+
level_styles: LevelStyles,
9292
}
9393

9494
impl StdStreamSink {
@@ -134,7 +134,7 @@ impl StdStreamSink {
134134

135135
/// Sets the style of the specified log level.
136136
pub fn set_style(&mut self, level: Level, style: Style) {
137-
self.level_style_codes.set_code(level, style);
137+
self.level_styles.set_style(level, style);
138138
}
139139

140140
/// Sets the style mode.
@@ -174,12 +174,12 @@ impl Sink for StdStreamSink {
174174
if self.should_render_style;
175175
if let Some(style_range) = extra_info.style_range();
176176
then {
177-
let style_code = self.level_style_codes.code(record.level());
177+
let style = self.level_styles.style(record.level());
178178

179179
dest.write_all(string_buf[..style_range.start].as_bytes())?;
180-
dest.write_all(style_code.start.as_bytes())?;
180+
style.write_start(&mut dest)?;
181181
dest.write_all(string_buf[style_range.start..style_range.end].as_bytes())?;
182-
dest.write_all(style_code.end.as_bytes())?;
182+
style.write_end(&mut dest)?;
183183
dest.write_all(string_buf[style_range.end..].as_bytes())?;
184184
} else {
185185
dest.write_all(string_buf.as_bytes())?;
@@ -259,7 +259,7 @@ impl StdStreamSinkBuilder<StdStream> {
259259
self.style_mode,
260260
self.std_stream,
261261
),
262-
level_style_codes: LevelStyleCodes::default(),
262+
level_styles: LevelStyles::default(),
263263
})
264264
}
265265
}

spdlog/src/terminal_style.rs

Lines changed: 42 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//!
55
//! [ANSI escape code]: https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_(Select_Graphic_Rendition)_parameters
66
7+
use std::io;
8+
79
use crate::Level;
810

911
/// Text color for terminal rendering.
@@ -102,56 +104,54 @@ impl Style {
102104
}
103105
}
104106

105-
#[must_use]
106-
pub(crate) fn code(&self) -> StyleCode {
107+
pub(crate) fn write_start(&self, dest: &mut impl io::Write) -> io::Result<()> {
107108
if self.reset {
108-
return StyleCode {
109-
start: Style::reset_code(),
110-
end: Style::reset_code(),
111-
};
109+
dest.write_all(Self::reset_code().as_bytes())?;
110+
return Ok(());
112111
}
113-
114-
let mut res = String::new();
115-
116-
macro_rules! push_escape_code {
117-
() => {};
118-
($field_name:ident: Option => $code:expr, $($tail:tt)*) => {
119-
if let Some($field_name) = self.$field_name {
120-
res.push_str($code);
121-
}
122-
push_escape_code! { $($tail)* }
123-
};
124-
($field_name:ident: bool => $code:expr, $($tail:tt)*) => {
125-
if self.$field_name {
126-
res.push_str($code);
127-
}
128-
push_escape_code! { $($tail)* }
129-
};
112+
if let Some(color) = self.color {
113+
dest.write_all(color.fg_code().as_bytes())?;
130114
}
131-
132-
push_escape_code! {
133-
color: Option => color.fg_code(),
134-
bg_color: Option => bg_color.bg_code(),
135-
bold: bool => "\x1b[1m",
136-
faint: bool => "\x1b[2m",
137-
italic: bool => "\x1b[3m",
138-
underline: bool => "\x1b[4m",
139-
slow_blink: bool => "\x1b[5m",
140-
rapid_blink: bool => "\x1b[6m",
141-
invert: bool => "\x1b[7m",
142-
conceal: bool => "\x1b[8m",
143-
strikethrough: bool => "\x1b[9m",
115+
if let Some(color) = self.bg_color {
116+
dest.write_all(color.bg_code().as_bytes())?;
144117
}
145-
146-
StyleCode {
147-
start: res,
148-
end: Style::reset_code(),
118+
if self.bold {
119+
dest.write_all("\x1b[1m".as_bytes())?;
120+
}
121+
if self.faint {
122+
dest.write_all("\x1b[2m".as_bytes())?;
123+
}
124+
if self.italic {
125+
dest.write_all("\x1b[3m".as_bytes())?;
126+
}
127+
if self.underline {
128+
dest.write_all("\x1b[4m".as_bytes())?;
129+
}
130+
if self.slow_blink {
131+
dest.write_all("\x1b[5m".as_bytes())?;
149132
}
133+
if self.rapid_blink {
134+
dest.write_all("\x1b[6m".as_bytes())?;
135+
}
136+
if self.invert {
137+
dest.write_all("\x1b[7m".as_bytes())?;
138+
}
139+
if self.conceal {
140+
dest.write_all("\x1b[8m".as_bytes())?;
141+
}
142+
if self.strikethrough {
143+
dest.write_all("\x1b[9m".as_bytes())?;
144+
}
145+
Ok(())
146+
}
147+
148+
pub(crate) fn write_end(&self, dest: &mut impl io::Write) -> io::Result<()> {
149+
dest.write_all(Self::reset_code().as_bytes())
150150
}
151151

152152
#[must_use]
153-
fn reset_code() -> String {
154-
"\x1b[m".to_string()
153+
fn reset_code() -> &'static str {
154+
"\x1b[m"
155155
}
156156
}
157157

@@ -247,12 +247,6 @@ impl LevelStyles {
247247
}
248248
}
249249

250-
impl From<LevelStyles> for LevelStyleCodes {
251-
fn from(level_styles: LevelStyles) -> LevelStyleCodes {
252-
LevelStyleCodes(level_styles.0.map(|style| style.into()))
253-
}
254-
}
255-
256250
impl Default for LevelStyles {
257251
fn default() -> LevelStyles {
258252
LevelStyles([
@@ -265,40 +259,3 @@ impl Default for LevelStyles {
265259
])
266260
}
267261
}
268-
269-
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
270-
pub(crate) struct StyleCode {
271-
/// The start escape code for rendering style text.
272-
pub(crate) start: String,
273-
/// The end escape code for rendering style text.
274-
pub(crate) end: String,
275-
}
276-
277-
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
278-
pub(crate) struct LevelStyleCodes([StyleCode; Level::count()]);
279-
280-
impl LevelStyleCodes {
281-
#[must_use]
282-
pub(crate) fn code(&self, level: Level) -> &StyleCode {
283-
&self.0[level as usize]
284-
}
285-
286-
pub(crate) fn set_code<C>(&mut self, level: Level, code: C)
287-
where
288-
C: Into<StyleCode>,
289-
{
290-
self.0[level as usize] = code.into();
291-
}
292-
}
293-
294-
impl From<Style> for StyleCode {
295-
fn from(style: Style) -> StyleCode {
296-
style.code()
297-
}
298-
}
299-
300-
impl Default for LevelStyleCodes {
301-
fn default() -> LevelStyleCodes {
302-
LevelStyles::default().into()
303-
}
304-
}

0 commit comments

Comments
 (0)