Skip to content

Commit a81dc31

Browse files
authored
Merge pull request #220 from Muscraft/add-short-message
feat: Add support for "short message"
2 parents b228756 + 7a77696 commit a81dc31

File tree

2 files changed

+258
-32
lines changed

2 files changed

+258
-32
lines changed

src/renderer/mod.rs

Lines changed: 162 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ pub struct Renderer {
6666
term_width: usize,
6767
theme: OutputTheme,
6868
stylesheet: Stylesheet,
69+
short_message: bool,
6970
}
7071

7172
impl Renderer {
@@ -76,6 +77,7 @@ impl Renderer {
7677
term_width: DEFAULT_TERM_WIDTH,
7778
theme: OutputTheme::Ascii,
7879
stylesheet: Stylesheet::plain(),
80+
short_message: false,
7981
}
8082
}
8183

@@ -137,6 +139,11 @@ impl Renderer {
137139
self
138140
}
139141

142+
pub const fn short_message(mut self, short_message: bool) -> Self {
143+
self.short_message = short_message;
144+
self
145+
}
146+
140147
// Set the terminal width
141148
pub const fn term_width(mut self, term_width: usize) -> Self {
142149
self.term_width = term_width;
@@ -199,19 +206,23 @@ impl Renderer {
199206

200207
impl Renderer {
201208
pub fn render(&self, mut message: Message<'_>) -> String {
202-
let max_line_num_len = if self.anonymized_line_numbers {
203-
ANONYMIZED_LINE_NUM.len()
209+
if self.short_message {
210+
self.render_short_message(message).unwrap()
204211
} else {
205-
let n = message.max_line_number();
206-
num_decimal_digits(n)
207-
};
208-
let title = message.groups.remove(0).elements.remove(0);
209-
if let Some(first) = message.groups.first_mut() {
210-
first.elements.insert(0, title);
211-
} else {
212-
message.groups.push(Group::new().element(title));
212+
let max_line_num_len = if self.anonymized_line_numbers {
213+
ANONYMIZED_LINE_NUM.len()
214+
} else {
215+
let n = message.max_line_number();
216+
num_decimal_digits(n)
217+
};
218+
let title = message.groups.remove(0).elements.remove(0);
219+
if let Some(first) = message.groups.first_mut() {
220+
first.elements.insert(0, title);
221+
} else {
222+
message.groups.push(Group::new().element(title));
223+
}
224+
self.render_message(message, max_line_num_len).unwrap()
213225
}
214-
self.render_message(message, max_line_num_len).unwrap()
215226
}
216227

217228
fn render_message(
@@ -320,6 +331,7 @@ impl Renderer {
320331
(true, false) => TitleStyle::Header,
321332
(false, _) => TitleStyle::Secondary,
322333
};
334+
let buffer_msg_line_offset = buffer.num_lines();
323335
self.render_title(
324336
&mut buffer,
325337
title,
@@ -333,6 +345,7 @@ impl Renderer {
333345
}
334346
}),
335347
matches!(peek, Some(Element::Title(_))),
348+
buffer_msg_line_offset,
336349
);
337350
last_was_suggestion = false;
338351
}
@@ -390,7 +403,13 @@ impl Renderer {
390403
}
391404

392405
Element::Origin(origin) => {
393-
self.render_origin(&mut buffer, max_line_num_len, origin);
406+
let buffer_msg_line_offset = buffer.num_lines();
407+
self.render_origin(
408+
&mut buffer,
409+
max_line_num_len,
410+
origin,
411+
buffer_msg_line_offset,
412+
);
394413
last_was_suggestion = false;
395414
}
396415
Element::Padding(_) => {
@@ -434,6 +453,91 @@ impl Renderer {
434453
Ok(out_string)
435454
}
436455

456+
fn render_short_message(&self, mut message: Message<'_>) -> Result<String, fmt::Error> {
457+
let mut buffer = StyledBuffer::new();
458+
459+
let Element::Title(title) = message.groups.remove(0).elements.remove(0) else {
460+
panic!(
461+
"Expected first element to be a Title, got: {:?}",
462+
message.groups
463+
);
464+
};
465+
466+
let mut labels = None;
467+
468+
if let Some(Element::Cause(cause)) = message.groups.first().and_then(|group| {
469+
group
470+
.elements
471+
.iter()
472+
.find(|e| matches!(e, Element::Cause(_)))
473+
}) {
474+
let labels_inner = cause
475+
.markers
476+
.iter()
477+
.filter_map(|ann| match ann.label {
478+
Some(msg) if ann.kind.is_primary() => {
479+
if !msg.trim().is_empty() {
480+
Some(msg.to_owned())
481+
} else {
482+
None
483+
}
484+
}
485+
_ => None,
486+
})
487+
.collect::<Vec<_>>()
488+
.join(", ");
489+
if !labels_inner.is_empty() {
490+
labels = Some(labels_inner);
491+
}
492+
493+
if let Some(origin) = cause.origin {
494+
let mut origin = Origin::new(origin);
495+
origin.primary = true;
496+
497+
let source_map = SourceMap::new(cause.source, cause.line_start);
498+
let (_depth, annotated_lines) =
499+
source_map.annotated_lines(cause.markers.clone(), cause.fold);
500+
501+
if let Some(primary_line) = annotated_lines
502+
.iter()
503+
.find(|l| l.annotations.iter().any(LineAnnotation::is_primary))
504+
.or(annotated_lines.iter().find(|l| !l.annotations.is_empty()))
505+
{
506+
origin.line = Some(primary_line.line_index);
507+
if let Some(first_annotation) = primary_line
508+
.annotations
509+
.iter()
510+
.min_by_key(|a| (Reverse(a.is_primary()), a.start.char))
511+
{
512+
origin.char_column = Some(first_annotation.start.char + 1);
513+
}
514+
}
515+
516+
self.render_origin(&mut buffer, 0, &origin, 0);
517+
buffer.append(0, ": ", ElementStyle::LineAndColumn);
518+
}
519+
}
520+
521+
self.render_title(
522+
&mut buffer,
523+
&title,
524+
0, // No line numbers in short messages
525+
TitleStyle::MainHeader,
526+
message.id.as_ref(),
527+
false,
528+
0,
529+
);
530+
531+
if let Some(labels) = labels {
532+
buffer.append(0, &format!(": {labels}"), ElementStyle::NoStyle);
533+
}
534+
535+
let mut out_string = String::new();
536+
buffer.render(title.level, &self.stylesheet, &mut out_string)?;
537+
538+
Ok(out_string)
539+
}
540+
437541
#[allow(clippy::too_many_arguments)]
438542
fn render_title(
439543
&self,
@@ -443,23 +547,27 @@ impl Renderer {
443547
title_style: TitleStyle,
444548
id: Option<&&str>,
445549
is_cont: bool,
550+
buffer_msg_line_offset: usize,
446551
) {
447-
let line_offset = buffer.num_lines();
448-
449552
if title_style == TitleStyle::Secondary {
450553
// This is a secondary message with no span info
451554
for _ in 0..max_line_num_len {
452-
buffer.prepend(line_offset, " ", ElementStyle::NoStyle);
555+
buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle);
453556
}
454557

455558
if title.level.name != Some(None) {
456-
self.draw_note_separator(buffer, line_offset, max_line_num_len + 1, is_cont);
559+
self.draw_note_separator(
560+
buffer,
561+
buffer_msg_line_offset,
562+
max_line_num_len + 1,
563+
is_cont,
564+
);
457565
buffer.append(
458-
line_offset,
566+
buffer_msg_line_offset,
459567
title.level.as_str(),
460568
ElementStyle::MainHeaderMsg,
461569
);
462-
buffer.append(line_offset, ": ", ElementStyle::NoStyle);
570+
buffer.append(buffer_msg_line_offset, ": ", ElementStyle::NoStyle);
463571
}
464572

465573
let printed_lines =
@@ -476,7 +584,7 @@ impl Renderer {
476584
// │ bar
477585
// ╰ note: foo
478586
// bar
479-
for i in line_offset + 1..=printed_lines {
587+
for i in buffer_msg_line_offset + 1..=printed_lines {
480588
self.draw_col_separator_no_space(buffer, i, max_line_num_len + 1);
481589
}
482590
}
@@ -485,31 +593,49 @@ impl Renderer {
485593

486594
if title.level.name != Some(None) {
487595
buffer.append(
488-
line_offset,
596+
buffer_msg_line_offset,
489597
title.level.as_str(),
490598
ElementStyle::Level(title.level.level),
491599
);
492600
}
493601
label_width += title.level.as_str().len();
494602
if let Some(id) = id {
495-
buffer.append(line_offset, "[", ElementStyle::Level(title.level.level));
496-
buffer.append(line_offset, id, ElementStyle::Level(title.level.level));
497-
buffer.append(line_offset, "]", ElementStyle::Level(title.level.level));
603+
buffer.append(
604+
buffer_msg_line_offset,
605+
"[",
606+
ElementStyle::Level(title.level.level),
607+
);
608+
buffer.append(
609+
buffer_msg_line_offset,
610+
id,
611+
ElementStyle::Level(title.level.level),
612+
);
613+
buffer.append(
614+
buffer_msg_line_offset,
615+
"]",
616+
ElementStyle::Level(title.level.level),
617+
);
498618
label_width += 2 + id.len();
499619
}
500620
let header_style = match title_style {
501-
TitleStyle::MainHeader => ElementStyle::MainHeaderMsg,
621+
TitleStyle::MainHeader => {
622+
if self.short_message {
623+
ElementStyle::NoStyle
624+
} else {
625+
ElementStyle::MainHeaderMsg
626+
}
627+
}
502628
TitleStyle::Header => ElementStyle::HeaderMsg,
503629
TitleStyle::Secondary => unreachable!(),
504630
};
505631
if title.level.name != Some(None) {
506-
buffer.append(line_offset, ": ", header_style);
632+
buffer.append(buffer_msg_line_offset, ": ", header_style);
507633
label_width += 2;
508634
}
509635
if !title.title.is_empty() {
510636
for (line, text) in normalize_whitespace(title.title).lines().enumerate() {
511637
buffer.append(
512-
line_offset + line,
638+
buffer_msg_line_offset + line,
513639
&format!(
514640
"{}{}",
515641
if line == 0 {
@@ -600,15 +726,15 @@ impl Renderer {
600726
buffer: &mut StyledBuffer,
601727
max_line_num_len: usize,
602728
origin: &Origin<'_>,
729+
buffer_msg_line_offset: usize,
603730
) {
604-
let buffer_msg_line_offset = buffer.num_lines();
605-
if origin.primary {
731+
if origin.primary && !self.short_message {
606732
buffer.prepend(
607733
buffer_msg_line_offset,
608734
self.file_start(),
609735
ElementStyle::LineNumber,
610736
);
611-
} else {
737+
} else if !self.short_message {
612738
// if !origin.standalone {
613739
// // Add spacing line, as shown:
614740
// // --> $DIR/file:54:15
@@ -643,9 +769,12 @@ impl Renderer {
643769
(Some(line), None) => format!("{}:{}", origin.origin, line),
644770
_ => origin.origin.to_owned(),
645771
};
772+
646773
buffer.append(buffer_msg_line_offset, &str, ElementStyle::LineAndColumn);
647-
for _ in 0..max_line_num_len {
648-
buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle);
774+
if !self.short_message {
775+
for _ in 0..max_line_num_len {
776+
buffer.prepend(buffer_msg_line_offset, " ", ElementStyle::NoStyle);
777+
}
649778
}
650779
}
651780

@@ -707,7 +836,8 @@ impl Renderer {
707836
}
708837
}
709838
}
710-
self.render_origin(buffer, max_line_num_len, &origin);
839+
let buffer_msg_line_offset = buffer.num_lines();
840+
self.render_origin(buffer, max_line_num_len, &origin, buffer_msg_line_offset);
711841
}
712842

713843
// Put in the spacer between the location and annotated source

0 commit comments

Comments
 (0)