Skip to content

Commit 6ec4104

Browse files
authored
Merge pull request #296 from epage/refactor
fix(fmt): Address a couple of bugs
2 parents 7bc51b0 + 939687d commit 6ec4104

File tree

7 files changed

+343
-319
lines changed

7 files changed

+343
-319
lines changed

src/fmt/mod.rs

+64-1
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,19 @@ use std::io::prelude::*;
3535
use std::rc::Rc;
3636
use std::{fmt, io, mem};
3737

38+
#[cfg(feature = "color")]
39+
use log::Level;
3840
use log::Record;
3941

4042
#[cfg(feature = "humantime")]
4143
mod humantime;
4244
pub(crate) mod writer;
4345

46+
#[cfg(feature = "color")]
47+
mod style;
48+
#[cfg(feature = "color")]
49+
pub use style::{Color, Style, StyledValue};
50+
4451
#[cfg(feature = "humantime")]
4552
pub use self::humantime::Timestamp;
4653
pub use self::writer::glob::*;
@@ -122,6 +129,62 @@ impl Formatter {
122129
}
123130
}
124131

132+
#[cfg(feature = "color")]
133+
impl Formatter {
134+
/// Begin a new [`Style`].
135+
///
136+
/// # Examples
137+
///
138+
/// Create a bold, red colored style and use it to print the log level:
139+
///
140+
/// ```
141+
/// use std::io::Write;
142+
/// use env_logger::fmt::Color;
143+
///
144+
/// let mut builder = env_logger::Builder::new();
145+
///
146+
/// builder.format(|buf, record| {
147+
/// let mut level_style = buf.style();
148+
///
149+
/// level_style.set_color(Color::Red).set_bold(true);
150+
///
151+
/// writeln!(buf, "{}: {}",
152+
/// level_style.value(record.level()),
153+
/// record.args())
154+
/// });
155+
/// ```
156+
///
157+
/// [`Style`]: struct.Style.html
158+
pub fn style(&self) -> Style {
159+
Style {
160+
buf: self.buf.clone(),
161+
spec: termcolor::ColorSpec::new(),
162+
}
163+
}
164+
165+
/// Get the default [`Style`] for the given level.
166+
///
167+
/// The style can be used to print other values besides the level.
168+
pub fn default_level_style(&self, level: Level) -> Style {
169+
let mut level_style = self.style();
170+
match level {
171+
Level::Trace => level_style.set_color(Color::Cyan),
172+
Level::Debug => level_style.set_color(Color::Blue),
173+
Level::Info => level_style.set_color(Color::Green),
174+
Level::Warn => level_style.set_color(Color::Yellow),
175+
Level::Error => level_style.set_color(Color::Red).set_bold(true),
176+
};
177+
level_style
178+
}
179+
180+
/// Get a printable [`Style`] for the given level.
181+
///
182+
/// The style can only be used to print the level.
183+
pub fn default_styled_level(&self, level: Level) -> StyledValue<'static, Level> {
184+
self.default_level_style(level).into_value(level)
185+
}
186+
}
187+
125188
impl Write for Formatter {
126189
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
127190
self.buf.borrow_mut().write(buf)
@@ -405,7 +468,7 @@ mod tests {
405468
fmt.write(&record).expect("failed to write record");
406469

407470
let buf = buf.borrow();
408-
String::from_utf8(buf.bytes().to_vec()).expect("failed to read record")
471+
String::from_utf8(buf.as_bytes().to_vec()).expect("failed to read record")
409472
}
410473

411474
fn write_target(target: &str, fmt: DefaultFormat) -> String {

src/fmt/writer/termcolor/extern_impl.rs renamed to src/fmt/style.rs

+19-200
Original file line numberDiff line numberDiff line change
@@ -1,190 +1,9 @@
11
use std::borrow::Cow;
22
use std::cell::RefCell;
33
use std::fmt;
4-
use std::io::{self, Write};
54
use std::rc::Rc;
6-
use std::sync::Mutex;
75

8-
use log::Level;
9-
use termcolor::{self, ColorChoice, ColorSpec, WriteColor};
10-
11-
use crate::fmt::{Formatter, WritableTarget, WriteStyle};
12-
13-
pub(in crate::fmt::writer) mod glob {
14-
pub use super::*;
15-
}
16-
17-
impl Formatter {
18-
/// Begin a new [`Style`].
19-
///
20-
/// # Examples
21-
///
22-
/// Create a bold, red colored style and use it to print the log level:
23-
///
24-
/// ```
25-
/// use std::io::Write;
26-
/// use env_logger::fmt::Color;
27-
///
28-
/// let mut builder = env_logger::Builder::new();
29-
///
30-
/// builder.format(|buf, record| {
31-
/// let mut level_style = buf.style();
32-
///
33-
/// level_style.set_color(Color::Red).set_bold(true);
34-
///
35-
/// writeln!(buf, "{}: {}",
36-
/// level_style.value(record.level()),
37-
/// record.args())
38-
/// });
39-
/// ```
40-
///
41-
/// [`Style`]: struct.Style.html
42-
pub fn style(&self) -> Style {
43-
Style {
44-
buf: self.buf.clone(),
45-
spec: ColorSpec::new(),
46-
}
47-
}
48-
49-
/// Get the default [`Style`] for the given level.
50-
///
51-
/// The style can be used to print other values besides the level.
52-
pub fn default_level_style(&self, level: Level) -> Style {
53-
let mut level_style = self.style();
54-
match level {
55-
Level::Trace => level_style.set_color(Color::Cyan),
56-
Level::Debug => level_style.set_color(Color::Blue),
57-
Level::Info => level_style.set_color(Color::Green),
58-
Level::Warn => level_style.set_color(Color::Yellow),
59-
Level::Error => level_style.set_color(Color::Red).set_bold(true),
60-
};
61-
level_style
62-
}
63-
64-
/// Get a printable [`Style`] for the given level.
65-
///
66-
/// The style can only be used to print the level.
67-
pub fn default_styled_level(&self, level: Level) -> StyledValue<'static, Level> {
68-
self.default_level_style(level).into_value(level)
69-
}
70-
}
71-
72-
pub(in crate::fmt::writer) struct BufferWriter {
73-
inner: termcolor::BufferWriter,
74-
uncolored_target: Option<WritableTarget>,
75-
}
76-
77-
pub(in crate::fmt) struct Buffer {
78-
inner: termcolor::Buffer,
79-
has_uncolored_target: bool,
80-
}
81-
82-
impl BufferWriter {
83-
pub(in crate::fmt::writer) fn stderr(is_test: bool, write_style: WriteStyle) -> Self {
84-
BufferWriter {
85-
inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
86-
uncolored_target: if is_test {
87-
Some(WritableTarget::Stderr)
88-
} else {
89-
None
90-
},
91-
}
92-
}
93-
94-
pub(in crate::fmt::writer) fn stdout(is_test: bool, write_style: WriteStyle) -> Self {
95-
BufferWriter {
96-
inner: termcolor::BufferWriter::stdout(write_style.into_color_choice()),
97-
uncolored_target: if is_test {
98-
Some(WritableTarget::Stdout)
99-
} else {
100-
None
101-
},
102-
}
103-
}
104-
105-
pub(in crate::fmt::writer) fn pipe(
106-
write_style: WriteStyle,
107-
pipe: Box<Mutex<dyn io::Write + Send + 'static>>,
108-
) -> Self {
109-
BufferWriter {
110-
// The inner Buffer is never printed from, but it is still needed to handle coloring and other formatting
111-
inner: termcolor::BufferWriter::stderr(write_style.into_color_choice()),
112-
uncolored_target: Some(WritableTarget::Pipe(pipe)),
113-
}
114-
}
115-
116-
pub(in crate::fmt::writer) fn buffer(&self) -> Buffer {
117-
Buffer {
118-
inner: self.inner.buffer(),
119-
has_uncolored_target: self.uncolored_target.is_some(),
120-
}
121-
}
122-
123-
pub(in crate::fmt::writer) fn print(&self, buf: &Buffer) -> io::Result<()> {
124-
if let Some(target) = &self.uncolored_target {
125-
// This impl uses the `eprint` and `print` macros
126-
// instead of `termcolor`'s buffer.
127-
// This is so their output can be captured by `cargo test`
128-
let log = String::from_utf8_lossy(buf.bytes());
129-
130-
match target {
131-
WritableTarget::Stderr => eprint!("{}", log),
132-
WritableTarget::Stdout => print!("{}", log),
133-
WritableTarget::Pipe(pipe) => write!(pipe.lock().unwrap(), "{}", log)?,
134-
}
135-
136-
Ok(())
137-
} else {
138-
self.inner.print(&buf.inner)
139-
}
140-
}
141-
}
142-
143-
impl Buffer {
144-
pub(in crate::fmt) fn clear(&mut self) {
145-
self.inner.clear()
146-
}
147-
148-
pub(in crate::fmt) fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
149-
self.inner.write(buf)
150-
}
151-
152-
pub(in crate::fmt) fn flush(&mut self) -> io::Result<()> {
153-
self.inner.flush()
154-
}
155-
156-
pub(in crate::fmt) fn bytes(&self) -> &[u8] {
157-
self.inner.as_slice()
158-
}
159-
160-
fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
161-
// Ignore styles for test captured logs because they can't be printed
162-
if !self.has_uncolored_target {
163-
self.inner.set_color(spec)
164-
} else {
165-
Ok(())
166-
}
167-
}
168-
169-
fn reset(&mut self) -> io::Result<()> {
170-
// Ignore styles for test captured logs because they can't be printed
171-
if !self.has_uncolored_target {
172-
self.inner.reset()
173-
} else {
174-
Ok(())
175-
}
176-
}
177-
}
178-
179-
impl WriteStyle {
180-
fn into_color_choice(self) -> ColorChoice {
181-
match self {
182-
WriteStyle::Always => ColorChoice::Always,
183-
WriteStyle::Auto => ColorChoice::Auto,
184-
WriteStyle::Never => ColorChoice::Never,
185-
}
186-
}
187-
}
6+
use super::Buffer;
1887

1898
/// A set of styles to apply to the terminal output.
1909
///
@@ -240,18 +59,8 @@ impl WriteStyle {
24059
/// [`value`]: #method.value
24160
#[derive(Clone)]
24261
pub struct Style {
243-
buf: Rc<RefCell<Buffer>>,
244-
spec: ColorSpec,
245-
}
246-
247-
/// A value that can be printed using the given styles.
248-
///
249-
/// It is the result of calling [`Style::value`].
250-
///
251-
/// [`Style::value`]: struct.Style.html#method.value
252-
pub struct StyledValue<'a, T> {
253-
style: Cow<'a, Style>,
254-
value: T,
62+
pub(in crate::fmt) buf: Rc<RefCell<Buffer>>,
63+
pub(in crate::fmt) spec: termcolor::ColorSpec,
25564
}
25665

25766
impl Style {
@@ -426,6 +235,22 @@ impl Style {
426235
}
427236
}
428237

238+
impl fmt::Debug for Style {
239+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240+
f.debug_struct("Style").field("spec", &self.spec).finish()
241+
}
242+
}
243+
244+
/// A value that can be printed using the given styles.
245+
///
246+
/// It is the result of calling [`Style::value`].
247+
///
248+
/// [`Style::value`]: struct.Style.html#method.value
249+
pub struct StyledValue<'a, T> {
250+
style: Cow<'a, Style>,
251+
value: T,
252+
}
253+
429254
impl<'a, T> StyledValue<'a, T> {
430255
fn write_fmt<F>(&self, f: F) -> fmt::Result
431256
where
@@ -445,12 +270,6 @@ impl<'a, T> StyledValue<'a, T> {
445270
}
446271
}
447272

448-
impl fmt::Debug for Style {
449-
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
450-
f.debug_struct("Style").field("spec", &self.spec).finish()
451-
}
452-
}
453-
454273
macro_rules! impl_styled_value_fmt {
455274
($($fmt_trait:path),*) => {
456275
$(

src/fmt/writer/termcolor/mod.rs renamed to src/fmt/writer/buffer/mod.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ Its public API is available when the `termcolor` crate is available.
55
The terminal printing is shimmed when the `termcolor` crate is not available.
66
*/
77

8-
#[cfg_attr(feature = "color", path = "extern_impl.rs")]
9-
#[cfg_attr(not(feature = "color"), path = "shim_impl.rs")]
10-
mod imp;
11-
12-
pub(in crate::fmt) use self::imp::*;
8+
#[cfg(feature = "color")]
9+
mod termcolor;
10+
#[cfg(feature = "color")]
11+
pub(in crate::fmt) use self::termcolor::*;
12+
#[cfg(not(feature = "color"))]
13+
mod plain;
14+
#[cfg(not(feature = "color"))]
15+
pub(in crate::fmt) use plain::*;

0 commit comments

Comments
 (0)