Skip to content

Commit 40cec7a

Browse files
authored
Merge pull request #30 from botika/master
Fix to no copy when format with yansi_term
2 parents 5cde073 + fc191d0 commit 40cec7a

File tree

6 files changed

+115
-87
lines changed

6 files changed

+115
-87
lines changed

Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ coveralls = { repository = "rust-lang/annotate-snippets-rs", branch = "master",
1616
maintenance = { status = "actively-developed" }
1717

1818
[dependencies]
19-
ansi_term = { version = "0.12", optional = true }
19+
yansi-term = { version = "0.1", optional = true }
2020

2121
[dev-dependencies]
2222
glob = "0.3"
2323
serde_yaml = "0.8"
2424
serde = { version = "1.0", features = ["derive"] }
2525
difference = "2.0"
26-
ansi_term = "0.12"
26+
yansi-term = "0.1"
2727
criterion = "0.3"
2828

2929
[[bench]]
@@ -32,4 +32,4 @@ harness = false
3232

3333
[features]
3434
default = []
35-
color = ["ansi_term"]
35+
color = ["yansi-term"]

src/formatter/mod.rs

+84-76
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::{
2-
cell::Cell,
32
cmp,
4-
fmt::{self, Display, Formatter, Write},
3+
fmt::{self, Display, Write},
54
};
65

76
pub mod style;
@@ -12,28 +11,6 @@ use self::style::{Style, StyleClass, Stylesheet};
1211
use crate::stylesheets::color::AnsiTermStylesheet;
1312
use crate::{display_list::*, stylesheets::no_color::NoColorStylesheet};
1413

15-
pub struct DisplayFn<F: FnOnce(&mut Formatter<'_>) -> fmt::Result>(std::cell::Cell<Option<F>>);
16-
17-
impl<F: FnOnce(&mut Formatter<'_>) -> fmt::Result> DisplayFn<F> {
18-
pub fn new(f: F) -> Self {
19-
Self(Cell::new(Some(f)))
20-
}
21-
}
22-
23-
impl<F: FnOnce(&mut Formatter<'_>) -> fmt::Result> Display for DisplayFn<F> {
24-
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
25-
self.0.take().ok_or(fmt::Error).and_then(|cl| cl(f))
26-
}
27-
}
28-
29-
fn repeat_char(c: char, n: usize) -> String {
30-
let mut s = String::with_capacity(c.len_utf8() * n);
31-
for _ in 0..n {
32-
s.push(c);
33-
}
34-
s
35-
}
36-
3714
fn format_repeat_char(c: char, n: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3815
for _ in 0..n {
3916
f.write_char(c)?;
@@ -72,14 +49,18 @@ impl fmt::Display for DisplayList {
7249
lineno: Some(lineno),
7350
..
7451
} => {
75-
if self.anonymized_line_numbers {
76-
Self::ANONYMIZED_LINE_NUM.len()
77-
} else {
78-
cmp::max(lineno.to_string().len(), max)
79-
}
52+
// The largest line is the largest width.
53+
cmp::max(*lineno, max)
8054
}
8155
_ => max,
8256
});
57+
let lineno_width = if lineno_width == 0 {
58+
lineno_width
59+
} else if self.anonymized_line_numbers {
60+
Self::ANONYMIZED_LINE_NUM.len()
61+
} else {
62+
((lineno_width as f64).log10().floor() as usize) + 1
63+
};
8364
let inline_marks_width = self.body.iter().fold(0, |max, line| match line {
8465
DisplayLine::Source { inline_marks, .. } => cmp::max(inline_marks.len(), max),
8566
_ => max,
@@ -97,22 +78,38 @@ impl fmt::Display for DisplayList {
9778

9879
impl DisplayList {
9980
const ANONYMIZED_LINE_NUM: &'static str = "LL";
81+
const ERROR_TXT: &'static str = "error";
82+
const HELP_TXT: &'static str = "help";
83+
const INFO_TXT: &'static str = "info";
84+
const NOTE_TXT: &'static str = "note";
85+
const WARNING_TXT: &'static str = "warning";
10086

87+
#[inline]
10188
fn format_annotation_type(
102-
&self,
10389
annotation_type: &DisplayAnnotationType,
10490
f: &mut fmt::Formatter<'_>,
10591
) -> fmt::Result {
10692
match annotation_type {
107-
DisplayAnnotationType::Error => f.write_str("error"),
108-
DisplayAnnotationType::Warning => f.write_str("warning"),
109-
DisplayAnnotationType::Info => f.write_str("info"),
110-
DisplayAnnotationType::Note => f.write_str("note"),
111-
DisplayAnnotationType::Help => f.write_str("help"),
93+
DisplayAnnotationType::Error => f.write_str(Self::ERROR_TXT),
94+
DisplayAnnotationType::Help => f.write_str(Self::HELP_TXT),
95+
DisplayAnnotationType::Info => f.write_str(Self::INFO_TXT),
96+
DisplayAnnotationType::Note => f.write_str(Self::NOTE_TXT),
97+
DisplayAnnotationType::Warning => f.write_str(Self::WARNING_TXT),
11298
DisplayAnnotationType::None => Ok(()),
11399
}
114100
}
115101

102+
fn annotation_type_len(annotation_type: &DisplayAnnotationType) -> usize {
103+
match annotation_type {
104+
DisplayAnnotationType::Error => Self::ERROR_TXT.len(),
105+
DisplayAnnotationType::Help => Self::HELP_TXT.len(),
106+
DisplayAnnotationType::Info => Self::INFO_TXT.len(),
107+
DisplayAnnotationType::Note => Self::NOTE_TXT.len(),
108+
DisplayAnnotationType::Warning => Self::WARNING_TXT.len(),
109+
DisplayAnnotationType::None => 0,
110+
}
111+
}
112+
116113
fn get_annotation_style(&self, annotation_type: &DisplayAnnotationType) -> Box<dyn Style> {
117114
self.stylesheet.get_style(match annotation_type {
118115
DisplayAnnotationType::Error => StyleClass::Error,
@@ -148,37 +145,38 @@ impl DisplayList {
148145
f: &mut fmt::Formatter<'_>,
149146
) -> fmt::Result {
150147
let color = self.get_annotation_style(&annotation.annotation_type);
151-
152-
let formatted_type = if let Some(id) = &annotation.id {
153-
DisplayFn::new(|f| {
154-
self.format_annotation_type(&annotation.annotation_type, f)?;
155-
f.write_char('[')?;
156-
f.write_str(id)?;
157-
f.write_char(']')
158-
})
159-
.to_string()
148+
let formatted_len = if let Some(id) = &annotation.id {
149+
2 + id.len() + Self::annotation_type_len(&annotation.annotation_type)
160150
} else {
161-
DisplayFn::new(|f| self.format_annotation_type(&annotation.annotation_type, f))
162-
.to_string()
151+
Self::annotation_type_len(&annotation.annotation_type)
163152
};
164153

165154
if continuation {
166-
let indent = formatted_type.len() + 2;
167-
format_repeat_char(' ', indent, f)?;
155+
format_repeat_char(' ', formatted_len + 2, f)?;
168156
return self.format_label(&annotation.label, f);
169157
}
170-
if formatted_type.is_empty() {
158+
if formatted_len == 0 {
171159
self.format_label(&annotation.label, f)
172160
} else {
173-
color.paint(&formatted_type, f)?;
161+
color.paint_fn(
162+
Box::new(|f| {
163+
Self::format_annotation_type(&annotation.annotation_type, f)?;
164+
if let Some(id) = &annotation.id {
165+
f.write_char('[')?;
166+
f.write_str(id)?;
167+
f.write_char(']')?;
168+
}
169+
Ok(())
170+
}),
171+
f,
172+
)?;
174173
if !is_annotation_empty(annotation) {
175174
if in_source {
176-
color.paint(
177-
&DisplayFn::new(|f| {
175+
color.paint_fn(
176+
Box::new(|f| {
178177
f.write_str(": ")?;
179178
self.format_label(&annotation.label, f)
180-
})
181-
.to_string(),
179+
}),
182180
f,
183181
)?;
184182
} else {
@@ -230,21 +228,25 @@ impl DisplayList {
230228
_ => range.0,
231229
};
232230

233-
color.paint(&repeat_char(indent_char, indent_length + 1), f)?;
234-
color.paint(&repeat_char(mark, range.1 - indent_length), f)?;
231+
color.paint_fn(
232+
Box::new(|f| {
233+
format_repeat_char(indent_char, indent_length + 1, f)?;
234+
format_repeat_char(mark, range.1 - indent_length, f)
235+
}),
236+
f,
237+
)?;
235238

236239
if !is_annotation_empty(&annotation) {
237240
f.write_char(' ')?;
238-
color.paint(
239-
&DisplayFn::new(|f| {
241+
color.paint_fn(
242+
Box::new(|f| {
240243
self.format_annotation(
241244
annotation,
242245
annotation_part == &DisplayAnnotationPart::LabelContinuation,
243246
true,
244247
f,
245248
)
246-
})
247-
.to_string(),
249+
}),
248250
f,
249251
)?;
250252
}
@@ -254,14 +256,6 @@ impl DisplayList {
254256
}
255257
}
256258

257-
#[inline]
258-
fn format_lineno(&self, lineno: Option<usize>, lineno_width: usize) -> String {
259-
match lineno {
260-
Some(n) => format!("{:>width$}", n, width = lineno_width),
261-
None => repeat_char(' ', lineno_width),
262-
}
263-
}
264-
265259
#[inline]
266260
fn format_raw_line(
267261
&self,
@@ -337,10 +331,22 @@ impl DisplayList {
337331
} => {
338332
let lineno_color = self.stylesheet.get_style(StyleClass::LineNo);
339333
if self.anonymized_line_numbers && lineno.is_some() {
340-
lineno_color.paint(&format!("{} |", Self::ANONYMIZED_LINE_NUM), f)?;
334+
lineno_color.paint_fn(
335+
Box::new(|f| {
336+
f.write_str(Self::ANONYMIZED_LINE_NUM)?;
337+
f.write_str(" |")
338+
}),
339+
f,
340+
)?;
341341
} else {
342-
lineno_color.paint(
343-
&format!("{} |", self.format_lineno(*lineno, lineno_width)),
342+
lineno_color.paint_fn(
343+
Box::new(|f| {
344+
match lineno {
345+
Some(n) => write!(f, "{:>width$}", n, width = lineno_width),
346+
None => format_repeat_char(' ', lineno_width, f),
347+
}?;
348+
f.write_str(" |")
349+
}),
344350
f,
345351
)?;
346352
}
@@ -376,11 +382,13 @@ impl DisplayList {
376382
) -> fmt::Result {
377383
format_repeat_char(' ', inline_marks_width - inline_marks.len(), f)?;
378384
for mark in inline_marks {
379-
self.get_annotation_style(&mark.annotation_type).paint(
380-
match mark.mark_type {
381-
DisplayMarkType::AnnotationThrough => "|",
382-
DisplayMarkType::AnnotationStart => "/",
383-
},
385+
self.get_annotation_style(&mark.annotation_type).paint_fn(
386+
Box::new(|f| {
387+
f.write_char(match mark.mark_type {
388+
DisplayMarkType::AnnotationThrough => '|',
389+
DisplayMarkType::AnnotationStart => '/',
390+
})
391+
}),
384392
f,
385393
)?;
386394
}

src/formatter/style.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//! Set of structures required to implement a stylesheet for
2-
//! [DisplayListFormatter](super::DisplayListFormatter).
1+
//! Set of structures required to implement a stylesheet
32
//!
43
//! In order to provide additional styling information for the
54
//! formatter, a structs can implement `Stylesheet` and `Style`
@@ -8,7 +7,6 @@
87
use std::fmt;
98

109
/// StyleClass is a collection of named variants of style classes
11-
/// that DisplayListFormatter uses.
1210
pub enum StyleClass {
1311
/// Message indicating an error.
1412
Error,
@@ -33,8 +31,14 @@ pub enum StyleClass {
3331

3432
/// This trait implements a return value for the `Stylesheet::get_style`.
3533
pub trait Style {
36-
/// The method used by the DisplayListFormatter to style the message.
34+
/// The method used to write text with formatter
3735
fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result;
36+
/// The method used to write display function with formatter
37+
fn paint_fn<'a>(
38+
&self,
39+
c: Box<dyn FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result + 'a>,
40+
f: &mut fmt::Formatter<'_>,
41+
) -> fmt::Result;
3842
/// The method used by the DisplayListFormatter to display the message
3943
/// in bold font.
4044
fn bold(&self) -> Box<dyn Style>;

src/stylesheets/color.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::fmt;
1+
use std::fmt::{self, Display};
22

3-
use ansi_term::{Color::Fixed, Style as AnsiTermStyle};
3+
use yansi_term::{Color::Fixed, Style as AnsiTermStyle};
44

55
use crate::formatter::style::{Style, StyleClass, Stylesheet};
66

@@ -10,7 +10,15 @@ struct AnsiTermStyleWrapper {
1010

1111
impl Style for AnsiTermStyleWrapper {
1212
fn paint(&self, text: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13-
fmt::Display::fmt(&self.style.paint(text), f)
13+
self.style.paint(text).fmt(f)
14+
}
15+
16+
fn paint_fn<'a>(
17+
&self,
18+
c: Box<dyn FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result + 'a>,
19+
f: &mut fmt::Formatter<'_>,
20+
) -> fmt::Result {
21+
self.style.paint_fn(c).fmt(f)
1422
}
1523

1624
fn bold(&self) -> Box<dyn Style> {

src/stylesheets/no_color.rs

+8
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ impl Style for NoOpStyle {
99
f.write_str(text)
1010
}
1111

12+
fn paint_fn<'a>(
13+
&self,
14+
c: Box<dyn FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result + 'a>,
15+
f: &mut fmt::Formatter<'_>,
16+
) -> fmt::Result {
17+
c(f)
18+
}
19+
1220
fn bold(&self) -> Box<dyn Style> {
1321
Box::new(NoOpStyle {})
1422
}

tests/diff/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
use ansi_term::Color::{Black, Green, Red};
21
use difference::{Changeset, Difference};
2+
use yansi_term::Color::{Black, Green, Red};
33

44
pub fn get_diff(left: &str, right: &str) -> String {
55
let mut output = String::new();

0 commit comments

Comments
 (0)