1use std::cmp::{max, min};
23const ELLIPSIS_PASSING: usize = 6;
4const LONG_WHITESPACE: usize = 20;
5const LONG_WHITESPACE_PADDING: usize = 4;
67#[derive(Clone, Copy, Debug, PartialEq)]
8pub(crate) struct Margin {
9/// The available whitespace in the left that can be consumed when centering.
10whitespace_left: usize,
11/// The column of the beginning of left-most span.
12span_left: usize,
13/// The column of the end of right-most span.
14span_right: usize,
15/// The beginning of the line to be displayed.
16computed_left: usize,
17/// The end of the line to be displayed.
18computed_right: usize,
19/// The current width of the terminal. 140 by default and in tests.
20term_width: usize,
21/// The end column of a span label, including the span. Doesn't account for labels not in the
22 /// same line as the span.
23label_right: usize,
24}
2526impl Margin {
27pub(crate) fn new(
28 whitespace_left: usize,
29 span_left: usize,
30 span_right: usize,
31 label_right: usize,
32 term_width: usize,
33 max_line_len: usize,
34 ) -> Self {
35// The 6 is padding to give a bit of room for `...` when displaying:
36 // ```
37 // error: message
38 // --> file.rs:16:58
39 // |
40 // 16 | ... fn foo(self) -> Self::Bar {
41 // | ^^^^^^^^^
42 // ```
4344let mut m = Margin {
45 whitespace_left: whitespace_left.saturating_sub(ELLIPSIS_PASSING),
46 span_left: span_left.saturating_sub(ELLIPSIS_PASSING),
47 span_right: span_right + ELLIPSIS_PASSING,
48 computed_left: 0,
49 computed_right: 0,
50term_width,
51 label_right: label_right + ELLIPSIS_PASSING,
52 };
53m.compute(max_line_len);
54m55 }
5657pub(crate) fn was_cut_left(&self) -> bool {
58self.computed_left > 0
59}
6061pub(crate) fn was_cut_right(&self, line_len: usize) -> bool {
62let right =
63if self.computed_right == self.span_right || self.computed_right == self.label_right {
64// Account for the "..." padding given above. Otherwise we end up with code lines that
65 // do fit but end in "..." as if they were trimmed.
66self.computed_right - ELLIPSIS_PASSING67 } else {
68self.computed_right
69 };
70right < line_len && self.computed_left + self.term_width < line_len71 }
7273fn compute(&mut self, max_line_len: usize) {
74// When there's a lot of whitespace (>20), we want to trim it as it is useless.
75self.computed_left = if self.whitespace_left > LONG_WHITESPACE {
76self.whitespace_left - (LONG_WHITESPACE - LONG_WHITESPACE_PADDING) // We want some padding.
77} else {
780
79};
80// We want to show as much as possible, max_line_len is the right-most boundary for the
81 // relevant code.
82self.computed_right = max(max_line_len, self.computed_left);
8384if self.computed_right - self.computed_left > self.term_width {
85// Trimming only whitespace isn't enough, let's get craftier.
86if self.label_right - self.whitespace_left <= self.term_width {
87// Attempt to fit the code window only trimming whitespace.
88self.computed_left = self.whitespace_left;
89self.computed_right = self.computed_left + self.term_width;
90 } else if self.label_right - self.span_left <= self.term_width {
91// Attempt to fit the code window considering only the spans and labels.
92let padding_left = (self.term_width - (self.label_right - self.span_left)) / 2;
93self.computed_left = self.span_left.saturating_sub(padding_left);
94self.computed_right = self.computed_left + self.term_width;
95 } else if self.span_right - self.span_left <= self.term_width {
96// Attempt to fit the code window considering the spans and labels plus padding.
97let padding_left = (self.term_width - (self.span_right - self.span_left)) / 5 * 2;
98self.computed_left = self.span_left.saturating_sub(padding_left);
99self.computed_right = self.computed_left + self.term_width;
100 } else {
101// Mostly give up but still don't show the full line.
102self.computed_left = self.span_left;
103self.computed_right = self.span_right;
104 }
105 }
106 }
107108pub(crate) fn left(&self, line_len: usize) -> usize {
109min(self.computed_left, line_len)
110 }
111112pub(crate) fn right(&self, line_len: usize) -> usize {
113if line_len.saturating_sub(self.computed_left) <= self.term_width {
114line_len115 } else {
116min(line_len, self.computed_right)
117 }
118 }
119}