Skip to content

Commit 8f2370f

Browse files
committed
feat: Add support for hyperlinks in snippet origin
1 parent a7f19f5 commit 8f2370f

7 files changed

Lines changed: 300 additions & 8 deletions

src/renderer/render.rs

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use crate::renderer::source_map::{
2020
use crate::renderer::styled_buffer::StyledBuffer;
2121
use crate::snippet::Id;
2222
use crate::{
23-
Annotation, AnnotationKind, Element, Group, Message, Origin, Padding, Patch, Report, Snippet,
24-
Title,
23+
Annotation, AnnotationKind, Element, Group, Message, Origin, Padding, Patch, PathUrlFormatter,
24+
Report, Snippet, Title,
2525
};
2626

2727
const ANONYMIZED_LINE_NUM: &str = "LL";
@@ -271,6 +271,13 @@ fn render_short_message(renderer: &Renderer, groups: &[Group<'_>]) -> Result<Str
271271
let mut origin = Origin::path(path.as_ref());
272272

273273
let source_map = SourceMap::new(&cause.source, cause.line_start);
274+
if let Some(primary_span) = cause.primary_span()
275+
&& let Some(path_url_formatter) = &cause.url
276+
{
277+
let (line, byte_col) = source_map.byte_to_line_byte_col(primary_span.start);
278+
let url = path_url_formatter.format_url(line, byte_col);
279+
origin.url = Some(Cow::from(url));
280+
}
274281
let (_depth, annotated_lines) =
275282
source_map.annotated_lines(cause.markers.clone(), cause.fold);
276283

@@ -483,6 +490,9 @@ fn render_origin(
483490
_ => origin.path.to_string(),
484491
};
485492

493+
let link = Hyperlink::from(origin.url.as_deref());
494+
let str = format!("{link}{str}{link:#}");
495+
486496
buffer.append(buffer_msg_line_offset, &str, ElementStyle::LineAndColumn);
487497
if !renderer.short_message {
488498
for _ in 0..max_line_num_len {
@@ -550,6 +560,15 @@ fn render_snippet_annotations(
550560
}
551561
}
552562
}
563+
564+
if let Some(primary_span) = snippet.primary_span()
565+
&& let Some(url_formatter) = &snippet.url
566+
{
567+
let (line, byte_col) = sm.byte_to_line_byte_col(primary_span.start);
568+
let url = url_formatter.format_url(line, byte_col);
569+
origin.url = Some(Cow::from(url));
570+
}
571+
553572
let buffer_msg_line_offset = buffer.num_lines();
554573
render_origin(
555574
renderer,
@@ -1445,11 +1464,18 @@ fn emit_suggestion_default(
14451464
&& let Some(path) = suggestion.path.as_ref()
14461465
&& !matches_previous_suggestion
14471466
{
1448-
let (loc, _) = sm.span_to_locations(parts[0].span.clone());
1449-
let origin = Origin::path(path.as_ref())
1467+
let span = parts[0].span.clone();
1468+
let (loc, _) = sm.span_to_locations(span.clone());
1469+
let mut origin = Origin::path(path.as_ref())
14501470
.line(loc.line)
14511471
.char_column(loc.char + 1);
14521472

1473+
if let Some(formatter) = &suggestion.url {
1474+
let (line, byte_col) = sm.byte_to_line_byte_col(span.start);
1475+
let url = formatter.format_url(line, byte_col);
1476+
origin.url = Some(Cow::from(url));
1477+
}
1478+
14531479
render_origin(
14541480
renderer,
14551481
buffer,

src/renderer/source_map.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,19 @@ impl<'a> SourceMap<'a> {
566566
Some((buf, trimmed_patches, highlights))
567567
}
568568
}
569+
570+
pub(crate) fn byte_to_line_byte_col(&self, byte: usize) -> (usize, usize) {
571+
let start_info = self
572+
.lines
573+
.iter()
574+
.find(|info| byte >= info.start_byte && byte < info.end_byte)
575+
.unwrap_or(self.lines.last().unwrap());
576+
577+
let line = start_info.line_index;
578+
let byte_col = byte - start_info.start_byte;
579+
580+
(line, byte_col)
581+
}
569582
}
570583

571584
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]

0 commit comments

Comments
 (0)