]> git.proxmox.com Git - rustc.git/blobdiff - vendor/annotate-snippets/src/display_list/from_snippet.rs
New upstream version 1.46.0~beta.2+dfsg1
[rustc.git] / vendor / annotate-snippets / src / display_list / from_snippet.rs
index e3d79ed4b10e3bfeeb5ef1287cb3433ab546a6cd..b3ba5a3ddbd65ec8fa541fe5b530487cd1116ac9 100644 (file)
@@ -1,12 +1,59 @@
 //! Trait for converting `Snippet` to `DisplayList`.
 use super::*;
-use crate::snippet;
+use crate::{formatter::get_term_style, snippet};
 
-fn format_label(label: Option<&str>, style: Option<DisplayTextStyle>) -> Vec<DisplayTextFragment> {
+struct CursorLines<'a>(&'a str);
+
+impl<'a> CursorLines<'a> {
+    fn new(src: &str) -> CursorLines<'_> {
+        CursorLines(src)
+    }
+}
+
+enum EndLine {
+    EOF = 0,
+    CRLF = 1,
+    LF = 2,
+}
+
+impl<'a> Iterator for CursorLines<'a> {
+    type Item = (&'a str, EndLine);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.0.is_empty() {
+            None
+        } else {
+            self.0
+                .find('\n')
+                .map(|x| {
+                    let ret = if 0 < x {
+                        if self.0.as_bytes()[x - 1] == b'\r' {
+                            (&self.0[..x - 1], EndLine::LF)
+                        } else {
+                            (&self.0[..x], EndLine::CRLF)
+                        }
+                    } else {
+                        ("", EndLine::CRLF)
+                    };
+                    self.0 = &self.0[x + 1..];
+                    ret
+                })
+                .or_else(|| {
+                    let ret = Some((&self.0[..], EndLine::EOF));
+                    self.0 = "";
+                    ret
+                })
+        }
+    }
+}
+
+fn format_label(
+    label: Option<&str>,
+    style: Option<DisplayTextStyle>,
+) -> Vec<DisplayTextFragment<'_>> {
     let mut result = vec![];
     if let Some(label) = label {
-        let elements: Vec<&str> = label.split("__").collect();
-        for (idx, element) in elements.iter().enumerate() {
+        for (idx, element) in label.split("__").enumerate() {
             let element_style = match style {
                 Some(s) => s,
                 None => {
@@ -18,7 +65,7 @@ fn format_label(label: Option<&str>, style: Option<DisplayTextStyle>) -> Vec<Dis
                 }
             };
             result.push(DisplayTextFragment {
-                content: element.to_string(),
+                content: element,
                 style: element_style,
             });
         }
@@ -26,12 +73,12 @@ fn format_label(label: Option<&str>, style: Option<DisplayTextStyle>) -> Vec<Dis
     result
 }
 
-fn format_title(annotation: &snippet::Annotation) -> DisplayLine {
-    let label = annotation.label.clone().unwrap_or_default();
+fn format_title(annotation: snippet::Annotation<'_>) -> DisplayLine<'_> {
+    let label = annotation.label.unwrap_or_default();
     DisplayLine::Raw(DisplayRawLine::Annotation {
         annotation: Annotation {
             annotation_type: DisplayAnnotationType::from(annotation.annotation_type),
-            id: annotation.id.clone(),
+            id: annotation.id,
             label: format_label(Some(&label), Some(DisplayTextStyle::Emphasis)),
         },
         source_aligned: false,
@@ -39,9 +86,9 @@ fn format_title(annotation: &snippet::Annotation) -> DisplayLine {
     })
 }
 
-fn format_annotation(annotation: &snippet::Annotation) -> Vec<DisplayLine> {
+fn format_annotation(annotation: snippet::Annotation<'_>) -> Vec<DisplayLine<'_>> {
     let mut result = vec![];
-    let label = annotation.label.clone().unwrap_or_default();
+    let label = annotation.label.unwrap_or_default();
     for (i, line) in label.lines().enumerate() {
         result.push(DisplayLine::Raw(DisplayRawLine::Annotation {
             annotation: Annotation {
@@ -56,11 +103,18 @@ fn format_annotation(annotation: &snippet::Annotation) -> Vec<DisplayLine> {
     result
 }
 
-fn format_slice(slice: &snippet::Slice, is_first: bool, has_footer: bool) -> Vec<DisplayLine> {
+fn format_slice(
+    mut slice: snippet::Slice<'_>,
+    is_first: bool,
+    has_footer: bool,
+) -> Vec<DisplayLine<'_>> {
+    let main_range = slice.annotations.get(0).map(|x| x.range.0);
+    let row = slice.line_start;
+    let origin = slice.origin.take();
     let mut body = format_body(slice, has_footer);
+    let header = format_header(origin, main_range, row, &body, is_first);
     let mut result = vec![];
 
-    let header = format_header(slice, &body, is_first);
     if let Some(header) = header {
         result.push(header);
     }
@@ -68,47 +122,46 @@ fn format_slice(slice: &snippet::Slice, is_first: bool, has_footer: bool) -> Vec
     result
 }
 
-fn format_header(
-    slice: &snippet::Slice,
-    body: &[DisplayLine],
+fn format_header<'a>(
+    origin: Option<&'a str>,
+    main_range: Option<usize>,
+    mut row: usize,
+    body: &[DisplayLine<'_>],
     is_first: bool,
-) -> Option<DisplayLine> {
-    let main_annotation = slice.annotations.get(0);
-
+) -> Option<DisplayLine<'a>> {
     let display_header = if is_first {
         DisplayHeaderType::Initial
     } else {
         DisplayHeaderType::Continuation
     };
 
-    if let Some(annotation) = main_annotation {
+    if let Some(main_range) = main_range {
         let mut col = 1;
-        let mut row = slice.line_start;
 
-        for item in body.iter() {
+        for item in body {
             if let DisplayLine::Source {
                 line: DisplaySourceLine::Content { range, .. },
                 ..
             } = item
             {
-                if annotation.range.0 >= range.0 && annotation.range.0 <= range.1 {
-                    col = annotation.range.0 - range.0;
+                if main_range >= range.0 && main_range <= range.1 {
+                    col = main_range - range.0 + 1;
                     break;
                 }
                 row += 1;
             }
         }
-        if let Some(ref path) = slice.origin {
+        if let Some(path) = origin {
             return Some(DisplayLine::Raw(DisplayRawLine::Origin {
-                path: path.to_string(),
+                path,
                 pos: Some((row, col)),
                 header_type: display_header,
             }));
         }
     }
-    if let Some(ref path) = slice.origin {
+    if let Some(path) = origin {
         return Some(DisplayLine::Raw(DisplayRawLine::Origin {
-            path: path.to_string(),
+            path,
             pos: None,
             header_type: display_header,
         }));
@@ -116,17 +169,19 @@ fn format_header(
     None
 }
 
-fn fold_body(body: &[DisplayLine]) -> Vec<DisplayLine> {
-    let mut new_body = vec![];
+fn fold_body(mut body: Vec<DisplayLine<'_>>) -> Vec<DisplayLine<'_>> {
+    enum Line {
+        Fold(usize),
+        Source(usize),
+    };
 
+    let mut lines = vec![];
     let mut no_annotation_lines_counter = 0;
-    let mut idx = 0;
 
-    while idx < body.len() {
-        match body[idx] {
+    for (idx, line) in body.iter().enumerate() {
+        match line {
             DisplayLine::Source {
                 line: DisplaySourceLine::Annotation { .. },
-                ref inline_marks,
                 ..
             } => {
                 if no_annotation_lines_counter > 2 {
@@ -142,66 +197,109 @@ fn fold_body(body: &[DisplayLine]) -> Vec<DisplayLine> {
                     } else {
                         1
                     };
-                    for item in body.iter().take(fold_start + pre_len).skip(fold_start) {
-                        new_body.push(item.clone());
+                    for (i, _) in body
+                        .iter()
+                        .enumerate()
+                        .take(fold_start + pre_len)
+                        .skip(fold_start)
+                    {
+                        lines.push(Line::Source(i));
                     }
-                    new_body.push(DisplayLine::Fold {
-                        inline_marks: inline_marks.clone(),
-                    });
-                    for item in body.iter().take(fold_end).skip(fold_end - post_len) {
-                        new_body.push(item.clone());
+                    lines.push(Line::Fold(idx));
+                    for (i, _) in body
+                        .iter()
+                        .enumerate()
+                        .take(fold_end)
+                        .skip(fold_end - post_len)
+                    {
+                        lines.push(Line::Source(i));
                     }
                 } else {
                     let start = idx - no_annotation_lines_counter;
-                    for item in body.iter().take(idx).skip(start) {
-                        new_body.push(item.clone());
+                    for (i, _) in body.iter().enumerate().take(idx).skip(start) {
+                        lines.push(Line::Source(i));
                     }
                 }
                 no_annotation_lines_counter = 0;
             }
             DisplayLine::Source { .. } => {
                 no_annotation_lines_counter += 1;
-                idx += 1;
                 continue;
             }
             _ => {
                 no_annotation_lines_counter += 1;
             }
         }
-        new_body.push(body[idx].clone());
-        idx += 1;
+        lines.push(Line::Source(idx));
+    }
+
+    let mut new_body = vec![];
+    let mut removed = 0;
+    for line in lines {
+        match line {
+            Line::Source(i) => {
+                new_body.push(body.remove(i - removed));
+                removed += 1;
+            }
+            Line::Fold(i) => {
+                if let DisplayLine::Source {
+                    line: DisplaySourceLine::Annotation { .. },
+                    ref inline_marks,
+                    ..
+                } = body.get(i - removed).unwrap()
+                {
+                    new_body.push(DisplayLine::Fold {
+                        inline_marks: inline_marks.clone(),
+                    })
+                } else {
+                    unreachable!()
+                }
+            }
+        }
     }
 
     new_body
 }
 
-fn format_body(slice: &snippet::Slice, has_footer: bool) -> Vec<DisplayLine> {
-    let mut body = vec![];
+fn format_body(slice: snippet::Slice<'_>, has_footer: bool) -> Vec<DisplayLine<'_>> {
+    let source_len = slice.source.chars().count();
+    if let Some(bigger) = slice.annotations.iter().find_map(|x| {
+        if source_len < x.range.1 {
+            Some(x.range)
+        } else {
+            None
+        }
+    }) {
+        panic!(
+            "SourceAnnotation range `{:?}` is bigger than source length `{}`",
+            bigger, source_len
+        )
+    }
 
+    let mut body = vec![];
     let mut current_line = slice.line_start;
     let mut current_index = 0;
     let mut line_index_ranges = vec![];
 
-    for line in slice.source.lines() {
-        let line_length = line.chars().count() + 1;
+    for (line, end_line) in CursorLines::new(slice.source) {
+        let line_length = line.chars().count();
         let line_range = (current_index, current_index + line_length);
         body.push(DisplayLine::Source {
             lineno: Some(current_line),
             inline_marks: vec![],
             line: DisplaySourceLine::Content {
-                text: line.to_string(),
+                text: line,
                 range: line_range,
             },
         });
         line_index_ranges.push(line_range);
         current_line += 1;
-        current_index += line_length + 1;
+        current_index += line_length + end_line as usize;
     }
 
     let mut annotation_line_count = 0;
-    let mut annotations = slice.annotations.clone();
-    for idx in 0..body.len() {
-        let (line_start, line_end) = line_index_ranges[idx];
+    let mut annotations = slice.annotations;
+    for (idx, (line_start, line_end)) in line_index_ranges.into_iter().enumerate() {
         // It would be nice to use filter_drain here once it's stable.
         annotations = annotations
             .into_iter()
@@ -214,7 +312,10 @@ fn format_body(slice: &snippet::Slice, has_footer: bool) -> Vec<DisplayLine> {
                 };
                 match annotation.range {
                     (start, _) if start > line_end => true,
-                    (start, end) if start >= line_start && end <= line_end + 1 => {
+                    (start, end)
+                        if start >= line_start && end <= line_end
+                            || start == line_end && end - start <= 1 =>
+                    {
                         let range = (start - line_start, end - line_start);
                         body.insert(
                             body_idx + 1,
@@ -305,6 +406,7 @@ fn format_body(slice: &snippet::Slice, has_footer: bool) -> Vec<DisplayLine> {
                                 ),
                             });
                         }
+
                         let range = (end - line_start, end - line_start + 1);
                         body.insert(
                             body_idx + 1,
@@ -340,7 +442,7 @@ fn format_body(slice: &snippet::Slice, has_footer: bool) -> Vec<DisplayLine> {
     }
 
     if slice.fold {
-        body = fold_body(&body);
+        body = fold_body(body);
     }
 
     body.insert(
@@ -367,26 +469,38 @@ fn format_body(slice: &snippet::Slice, has_footer: bool) -> Vec<DisplayLine> {
     body
 }
 
-impl From<snippet::Snippet> for DisplayList {
-    fn from(snippet: snippet::Snippet) -> Self {
+impl<'a> From<snippet::Snippet<'a>> for DisplayList<'a> {
+    fn from(
+        snippet::Snippet {
+            title,
+            footer,
+            slices,
+            opt,
+        }: snippet::Snippet<'a>,
+    ) -> DisplayList<'a> {
         let mut body = vec![];
-        if let Some(annotation) = snippet.title {
-            body.push(format_title(&annotation));
+        if let Some(annotation) = title {
+            body.push(format_title(annotation));
         }
 
-        for (idx, slice) in snippet.slices.iter().enumerate() {
-            body.append(&mut format_slice(
-                &slice,
-                idx == 0,
-                !snippet.footer.is_empty(),
-            ));
+        for (idx, slice) in slices.into_iter().enumerate() {
+            body.append(&mut format_slice(slice, idx == 0, !footer.is_empty()));
         }
 
-        for annotation in snippet.footer {
-            body.append(&mut format_annotation(&annotation));
+        for annotation in footer {
+            body.append(&mut format_annotation(annotation));
         }
 
-        Self { body }
+        let FormatOptions {
+            color,
+            anonymized_line_numbers,
+        } = opt;
+
+        Self {
+            body,
+            stylesheet: get_term_style(color),
+            anonymized_line_numbers,
+        }
     }
 }