use std::cmp::{max, min};
use std::fmt;
use crate::formatter::{get_term_style, style::Stylesheet};
pub struct DisplayList<'a> {
pub body: Vec<DisplayLine<'a>>,
pub stylesheet: Box<dyn Stylesheet>,
pub anonymized_line_numbers: bool,
pub margin: Option<Margin>,
}
impl<'a> From<Vec<DisplayLine<'a>>> for DisplayList<'a> {
fn from(body: Vec<DisplayLine<'a>>) -> DisplayList<'a> {
Self {
body,
anonymized_line_numbers: false,
stylesheet: get_term_style(false),
margin: None,
}
}
}
impl<'a> PartialEq for DisplayList<'a> {
fn eq(&self, other: &Self) -> bool {
self.body == other.body && self.anonymized_line_numbers == other.anonymized_line_numbers
}
}
impl<'a> fmt::Debug for DisplayList<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DisplayList")
.field("body", &self.body)
.field("anonymized_line_numbers", &self.anonymized_line_numbers)
.finish()
}
}
#[derive(Debug, Default, Copy, Clone)]
pub struct FormatOptions {
pub color: bool,
pub anonymized_line_numbers: bool,
pub margin: Option<Margin>,
}
#[derive(Clone, Copy, Debug)]
pub struct Margin {
whitespace_left: usize,
span_left: usize,
span_right: usize,
computed_left: usize,
computed_right: usize,
column_width: usize,
label_right: usize,
}
impl Margin {
pub fn new(
whitespace_left: usize,
span_left: usize,
span_right: usize,
label_right: usize,
column_width: usize,
max_line_len: usize,
) -> Self {
let mut m = Margin {
whitespace_left: whitespace_left.saturating_sub(6),
span_left: span_left.saturating_sub(6),
span_right: span_right + 6,
computed_left: 0,
computed_right: 0,
column_width,
label_right: label_right + 6,
};
m.compute(max_line_len);
m
}
pub(crate) fn was_cut_left(&self) -> bool {
self.computed_left > 0
}
pub(crate) fn was_cut_right(&self, line_len: usize) -> bool {
let right =
if self.computed_right == self.span_right || self.computed_right == self.label_right {
self.computed_right - 6
} else {
self.computed_right
};
right < line_len && self.computed_left + self.column_width < line_len
}
fn compute(&mut self, max_line_len: usize) {
self.computed_left = if self.whitespace_left > 20 {
self.whitespace_left - 16
} else {
0
};
self.computed_right = max(max_line_len, self.computed_left);
if self.computed_right - self.computed_left > self.column_width {
if self.label_right - self.whitespace_left <= self.column_width {
self.computed_left = self.whitespace_left;
self.computed_right = self.computed_left + self.column_width;
} else if self.label_right - self.span_left <= self.column_width {
let padding_left = (self.column_width - (self.label_right - self.span_left)) / 2;
self.computed_left = self.span_left.saturating_sub(padding_left);
self.computed_right = self.computed_left + self.column_width;
} else if self.span_right - self.span_left <= self.column_width {
let padding_left = (self.column_width - (self.span_right - self.span_left)) / 5 * 2;
self.computed_left = self.span_left.saturating_sub(padding_left);
self.computed_right = self.computed_left + self.column_width;
} else {
self.computed_left = self.span_left;
self.computed_right = self.span_right;
}
}
}
pub(crate) fn left(&self, line_len: usize) -> usize {
min(self.computed_left, line_len)
}
pub(crate) fn right(&self, line_len: usize) -> usize {
if line_len.saturating_sub(self.computed_left) <= self.column_width {
line_len
} else {
min(line_len, self.computed_right)
}
}
}
#[derive(Debug, PartialEq)]
pub struct Annotation<'a> {
pub annotation_type: DisplayAnnotationType,
pub id: Option<&'a str>,
pub label: Vec<DisplayTextFragment<'a>>,
}
#[derive(Debug, PartialEq)]
pub enum DisplayLine<'a> {
Source {
lineno: Option<usize>,
inline_marks: Vec<DisplayMark>,
line: DisplaySourceLine<'a>,
},
Fold { inline_marks: Vec<DisplayMark> },
Raw(DisplayRawLine<'a>),
}
#[derive(Debug, PartialEq)]
pub enum DisplaySourceLine<'a> {
Content {
text: &'a str,
range: (usize, usize),
},
Annotation {
annotation: Annotation<'a>,
range: (usize, usize),
annotation_type: DisplayAnnotationType,
annotation_part: DisplayAnnotationPart,
},
Empty,
}
#[derive(Debug, PartialEq)]
pub enum DisplayRawLine<'a> {
Origin {
path: &'a str,
pos: Option<(usize, usize)>,
header_type: DisplayHeaderType,
},
Annotation {
annotation: Annotation<'a>,
source_aligned: bool,
continuation: bool,
},
}
#[derive(Debug, PartialEq)]
pub struct DisplayTextFragment<'a> {
pub content: &'a str,
pub style: DisplayTextStyle,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DisplayTextStyle {
Regular,
Emphasis,
}
#[derive(Debug, Clone, PartialEq)]
pub enum DisplayAnnotationPart {
Standalone,
LabelContinuation,
Consequitive,
MultilineStart,
MultilineEnd,
}
#[derive(Debug, Clone, PartialEq)]
pub struct DisplayMark {
pub mark_type: DisplayMarkType,
pub annotation_type: DisplayAnnotationType,
}
#[derive(Debug, Clone, PartialEq)]
pub enum DisplayMarkType {
AnnotationThrough,
AnnotationStart,
}
#[derive(Debug, Clone, PartialEq)]
pub enum DisplayAnnotationType {
None,
Error,
Warning,
Info,
Note,
Help,
}
#[derive(Debug, Clone, PartialEq)]
pub enum DisplayHeaderType {
Initial,
Continuation,
}