Skip to content

Commit 70d8d9f

Browse files
committed
refactor: Use Origin for Snippet::origin
1 parent 1198546 commit 70d8d9f

File tree

2 files changed

+109
-52
lines changed

2 files changed

+109
-52
lines changed

src/renderer/mod.rs

Lines changed: 66 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -239,14 +239,14 @@ impl Renderer {
239239
group.elements.iter().find_map(|s| match &s {
240240
Element::Cause(cause) => {
241241
if cause.markers.iter().any(|m| m.kind.is_primary()) {
242-
Some(cause.origin)
242+
Some(cause.origin.as_ref())
243243
} else {
244244
None
245245
}
246246
}
247247
Element::Origin(origin) => {
248248
if origin.primary {
249-
Some(Some(origin.origin))
249+
Some(Some(origin))
250250
} else {
251251
None
252252
}
@@ -260,30 +260,30 @@ impl Renderer {
260260
.iter()
261261
.find_map(|group| {
262262
group.elements.iter().find_map(|s| match &s {
263-
Element::Cause(cause) => Some(cause.origin),
264-
Element::Origin(origin) => Some(Some(origin.origin)),
263+
Element::Cause(cause) => Some(cause.origin.as_ref()),
264+
Element::Origin(origin) => Some(Some(origin)),
265265
_ => None,
266266
})
267267
})
268268
.unwrap_or_default(),
269269
);
270270
let group_len = message.groups.len();
271-
for (g, group) in message.groups.into_iter().enumerate() {
271+
for (g, group) in message.groups.iter().enumerate() {
272272
let mut buffer = StyledBuffer::new();
273273
let primary_origin = group
274274
.elements
275275
.iter()
276276
.find_map(|s| match &s {
277277
Element::Cause(cause) => {
278278
if cause.markers.iter().any(|m| m.kind.is_primary()) {
279-
Some(cause.origin)
279+
Some(cause.origin.as_ref())
280280
} else {
281281
None
282282
}
283283
}
284284
Element::Origin(origin) => {
285285
if origin.primary {
286-
Some(Some(origin.origin))
286+
Some(Some(origin))
287287
} else {
288288
None
289289
}
@@ -295,8 +295,8 @@ impl Renderer {
295295
.elements
296296
.iter()
297297
.find_map(|s| match &s {
298-
Element::Cause(cause) => Some(cause.origin),
299-
Element::Origin(origin) => Some(Some(origin.origin)),
298+
Element::Cause(cause) => Some(cause.origin.as_ref()),
299+
Element::Origin(origin) => Some(Some(origin)),
300300
_ => None,
301301
})
302302
.unwrap_or_default(),
@@ -490,26 +490,27 @@ impl Renderer {
490490
labels = Some(labels_inner);
491491
}
492492

493-
if let Some(origin) = cause.origin {
494-
let mut origin = Origin::new(origin);
493+
if let Some(mut origin) = cause.origin.clone() {
495494
origin.primary = true;
496495

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);
496+
if origin.line.is_none() || origin.char_column.is_none() {
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);
500500

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
501+
if let Some(primary_line) = annotated_lines
509502
.iter()
510-
.min_by_key(|a| (Reverse(a.is_primary()), a.start.char))
503+
.find(|l| l.annotations.iter().any(LineAnnotation::is_primary))
504+
.or(annotated_lines.iter().find(|l| !l.annotations.is_empty()))
511505
{
512-
origin.char_column = Some(first_annotation.start.char + 1);
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+
}
513514
}
514515
}
515516

@@ -784,32 +785,40 @@ impl Renderer {
784785
buffer: &mut StyledBuffer,
785786
max_line_num_len: usize,
786787
snippet: &Snippet<'_, Annotation<'_>>,
787-
primary_origin: Option<&str>,
788+
primary_origin: Option<&Origin<'_>>,
788789
sm: &SourceMap<'_>,
789790
annotated_lines: &[AnnotatedLineInfo<'_>],
790791
multiline_depth: usize,
791792
is_cont: bool,
792793
) {
793-
if let Some(origin) = snippet.origin {
794-
let mut origin = Origin::new(origin);
794+
if let Some(mut origin) = snippet.origin.clone() {
795795
// print out the span location and spacer before we print the annotated source
796796
// to do this, we need to know if this span will be primary
797-
let is_primary = primary_origin == Some(origin.origin);
797+
let is_primary = origin.primary || primary_origin == Some(&origin);
798798

799799
if is_primary {
800800
origin.primary = true;
801-
if let Some(primary_line) = annotated_lines
802-
.iter()
803-
.find(|l| l.annotations.iter().any(LineAnnotation::is_primary))
804-
.or(annotated_lines.iter().find(|l| !l.annotations.is_empty()))
805-
{
806-
origin.line = Some(primary_line.line_index);
807-
if let Some(first_annotation) = primary_line
808-
.annotations
801+
802+
if origin.line.is_none() || origin.char_column.is_none() {
803+
if let Some(primary_line) = annotated_lines
809804
.iter()
810-
.min_by_key(|a| (Reverse(a.is_primary()), a.start.char))
805+
.find(|l| l.annotations.iter().any(LineAnnotation::is_primary))
806+
.or(annotated_lines.iter().find(|l| !l.annotations.is_empty()))
811807
{
812-
origin.char_column = Some(first_annotation.start.char + 1);
808+
if origin.line.is_none() {
809+
origin.line = Some(primary_line.line_index);
810+
}
811+
812+
// Always set the char column, as it is either `None`
813+
// or we set the line and now need to set the column on
814+
// that line.
815+
if let Some(first_annotation) = primary_line
816+
.annotations
817+
.iter()
818+
.min_by_key(|a| (Reverse(a.is_primary()), a.start.char))
819+
{
820+
origin.char_column = Some(first_annotation.start.char + 1);
821+
}
813822
}
814823
}
815824
} else {
@@ -829,10 +838,12 @@ impl Renderer {
829838
buffer_msg_line_offset,
830839
max_line_num_len + 1,
831840
);
832-
if let Some(first_line) = annotated_lines.first() {
833-
origin.line = Some(first_line.line_index);
834-
if let Some(first_annotation) = first_line.annotations.first() {
835-
origin.char_column = Some(first_annotation.start.char + 1);
841+
if origin.line.is_none() {
842+
if let Some(first_line) = annotated_lines.first() {
843+
origin.line = Some(first_line.line_index);
844+
if let Some(first_annotation) = first_line.annotations.first() {
845+
origin.char_column = Some(first_annotation.start.char + 1);
846+
}
836847
}
837848
}
838849
}
@@ -1648,7 +1659,7 @@ impl Renderer {
16481659
suggestion: &Snippet<'_, Patch<'_>>,
16491660
max_line_num_len: usize,
16501661
sm: &SourceMap<'_>,
1651-
primary_origin: Option<&str>,
1662+
primary_origin: Option<&Origin<'_>>,
16521663
is_cont: bool,
16531664
) {
16541665
let suggestions = sm.splice_lines(suggestion.markers.clone());
@@ -1671,14 +1682,22 @@ impl Renderer {
16711682
ElementStyle::LineNumber,
16721683
);
16731684
}
1674-
if suggestion.origin != primary_origin {
1675-
if let Some(origin) = suggestion.origin {
1676-
let (loc, _) = sm.span_to_locations(parts[0].span.clone());
1685+
1686+
if suggestion.origin.as_ref() != primary_origin && primary_origin.is_some() {
1687+
if let Some(origin) = suggestion.origin.clone() {
1688+
let (line, char_col) =
1689+
if let (Some(line), Some(char_col)) = (origin.line, origin.char_column) {
1690+
(line, char_col)
1691+
} else {
1692+
let (loc, _) = sm.span_to_locations(parts[0].span.clone());
1693+
(loc.line, loc.char + 1)
1694+
};
1695+
16771696
// --> file.rs:line:col
16781697
// |
16791698
let arrow = self.file_start();
16801699
buffer.puts(row_num - 1, 0, arrow, ElementStyle::LineNumber);
1681-
let message = format!("{}:{}:{}", origin, loc.line, loc.char + 1);
1700+
let message = format!("{}:{}:{}", origin.origin, line, char_col);
16821701
if is_cont {
16831702
buffer.append(row_num - 1, &message, ElementStyle::LineAndColumn);
16841703
} else {

src/snippet.rs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ pub struct Title<'a> {
164164
/// A source view [`Element`] in a [`Group`]
165165
#[derive(Clone, Debug)]
166166
pub struct Snippet<'a, T> {
167-
pub(crate) origin: Option<&'a str>,
167+
pub(crate) origin: Option<Origin<'a>>,
168168
pub(crate) line_start: usize,
169169
pub(crate) source: &'a str,
170170
pub(crate) markers: Vec<T>,
@@ -200,15 +200,20 @@ impl<'a, T: Clone> Snippet<'a, T> {
200200

201201
/// The location of the [`source`][Self::source] (e.g. a path)
202202
///
203+
/// If only a location is provided (i.e. a `String`) then the rest of the
204+
/// [`Origin`] is inferred (e.g. line and column numbers). To adjust line
205+
/// numbers, consider using [`Snippet::line_start`] instead as it will also
206+
/// adjust line numbers for the [`Snippet::source`].
207+
///
203208
/// <div class="warning">
204209
///
205210
/// Text passed to this function is considered "untrusted input", as such
206211
/// all text is passed through a normalization function. Pre-styled text is
207212
/// not allowed to be passed to this function.
208213
///
209214
/// </div>
210-
pub fn origin(mut self, origin: &'a str) -> Self {
211-
self.origin = Some(origin);
215+
pub fn origin(mut self, origin: impl Into<Origin<'a>>) -> Self {
216+
self.origin = Some(origin.into());
212217
self
213218
}
214219

@@ -375,8 +380,16 @@ impl<'a> Patch<'a> {
375380
}
376381
}
377382

378-
/// The location of the [`Snippet`] (e.g. a path)
379-
#[derive(Clone, Debug)]
383+
/// The location of the [`Snippet`] (e.g. a path).
384+
///
385+
/// This should be used if you want to set the line number and column
386+
/// explicitly for a [`Snippet`], or if you need to render a location without
387+
/// an accompanying [`Snippet`].
388+
///
389+
/// Note: `line` is always respected if set, but `char_column` is only
390+
/// respected if `line` has been set. `primary` is respected unless the origin
391+
/// is the first one in a [`Group`], in which case it is ignored.
392+
#[derive(Clone, Debug, Eq, PartialEq)]
380393
pub struct Origin<'a> {
381394
pub(crate) origin: &'a str,
382395
pub(crate) line: Option<usize>,
@@ -412,17 +425,42 @@ impl<'a> Origin<'a> {
412425
/// Set the default column to display
413426
///
414427
/// Otherwise this will be inferred from the primary [`Annotation`]
428+
///
429+
/// <div class="warning">
430+
///
431+
/// When [`Origin`] is passed into [`Snippet::origin`], `char_column` is
432+
/// only be respected if [`Origin::line`] is also set.
433+
///
434+
/// </div>
415435
pub fn char_column(mut self, char_column: usize) -> Self {
416436
self.char_column = Some(char_column);
417437
self
418438
}
419439

440+
/// <div class="warning">
441+
///
442+
/// When [`Origin`] is passed into [`Snippet::origin`], `primary` is
443+
/// respected as long as the first [`Origin`] in a [`Group`].
444+
///
445+
/// </div>
420446
pub fn primary(mut self, primary: bool) -> Self {
421447
self.primary = primary;
422448
self
423449
}
424450
}
425451

452+
impl<'a> From<&'a str> for Origin<'a> {
453+
fn from(origin: &'a str) -> Self {
454+
Self::new(origin)
455+
}
456+
}
457+
458+
impl<'a> From<&'a String> for Origin<'a> {
459+
fn from(origin: &'a String) -> Self {
460+
Self::new(origin)
461+
}
462+
}
463+
426464
fn newline_count(body: &str) -> usize {
427465
#[cfg(feature = "simd")]
428466
{

0 commit comments

Comments
 (0)