]> git.proxmox.com Git - rustc.git/blob - vendor/codespan-reporting/src/term/views/source_snippet/underline.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / vendor / codespan-reporting / src / term / views / source_snippet / underline.rs
1 use std::io;
2 use termcolor::{ColorSpec, WriteColor};
3
4 use crate::diagnostic::Severity;
5 use crate::term::Config;
6
7 #[derive(Copy, Clone)]
8 pub enum MarkStyle {
9 Primary(Severity),
10 Secondary,
11 }
12
13 impl MarkStyle {
14 pub fn label_style<'config>(self, config: &'config Config) -> &'config ColorSpec {
15 match self {
16 MarkStyle::Primary(severity) => config.styles.primary_label(severity),
17 MarkStyle::Secondary => &config.styles.secondary_label,
18 }
19 }
20
21 pub fn caret_char(self, config: &Config) -> char {
22 match self {
23 MarkStyle::Primary(_) => config.chars.primary_caret,
24 MarkStyle::Secondary => config.chars.secondary_caret,
25 }
26 }
27
28 pub fn multiline_caret_char(self, config: &Config) -> char {
29 match self {
30 MarkStyle::Primary(_) => config.chars.multiline_primary_caret,
31 MarkStyle::Secondary => config.chars.multiline_secondary_caret,
32 }
33 }
34 }
35
36 /// The underline of a single source line.
37 ///
38 /// ```text
39 /// ^^ expected `Int` but found `String`
40 /// ```
41 pub struct Underline<'a> {
42 mark_style: MarkStyle,
43 prefix_source: &'a str,
44 highlighted_source: &'a str,
45 message: &'a str,
46 }
47
48 impl<'a> Underline<'a> {
49 pub fn new(
50 mark_style: MarkStyle,
51 prefix_source: &'a str,
52 highlighted_source: &'a str,
53 message: &'a str,
54 ) -> Underline<'a> {
55 Underline {
56 mark_style,
57 prefix_source,
58 highlighted_source,
59 message,
60 }
61 }
62
63 pub fn emit(&self, writer: &mut impl WriteColor, config: &Config) -> io::Result<()> {
64 let prefix_len = config.width(self.prefix_source);
65 write!(writer, " {space: >width$}", space = "", width = prefix_len)?;
66
67 writer.set_color(self.mark_style.label_style(config))?;
68 // We use `usize::max` here to ensure that we print at least one
69 // underline character - even when we have a zero-length span.
70 let underline_len = usize::max(config.width(self.highlighted_source), 1);
71 for _ in 0..underline_len {
72 write!(writer, "{}", self.mark_style.caret_char(config))?;
73 }
74 if !self.message.is_empty() {
75 write!(writer, " {}", self.message)?;
76 }
77 writer.reset()?;
78
79 Ok(())
80 }
81 }
82
83 /// The top-left of a multi-line underline.
84 ///
85 /// ```text
86 /// ╭
87 /// ```
88 pub struct UnderlineTopLeft {
89 mark_style: MarkStyle,
90 }
91
92 impl UnderlineTopLeft {
93 pub fn new(mark_style: MarkStyle) -> UnderlineTopLeft {
94 UnderlineTopLeft { mark_style }
95 }
96
97 pub fn emit(&self, writer: &mut impl WriteColor, config: &Config) -> io::Result<()> {
98 write!(writer, " ")?;
99
100 writer.set_color(self.mark_style.label_style(config))?;
101 write!(writer, "{}", config.chars.multiline_top_left)?;
102 writer.reset()?;
103
104 Ok(())
105 }
106 }
107
108 /// The top of a multi-line underline.
109 ///
110 /// ```text
111 /// ╭─────────────^
112 /// ```
113 pub struct UnderlineTop<'a> {
114 mark_style: MarkStyle,
115 prefix_source: &'a str,
116 }
117
118 impl<'a> UnderlineTop<'a> {
119 pub fn new(mark_style: MarkStyle, prefix_source: &'a str) -> UnderlineTop<'a> {
120 UnderlineTop {
121 mark_style,
122 prefix_source,
123 }
124 }
125
126 pub fn emit(&self, writer: &mut impl WriteColor, config: &Config) -> io::Result<()> {
127 write!(writer, " ")?;
128
129 writer.set_color(self.mark_style.label_style(config))?;
130 write!(writer, "{}", config.chars.multiline_top_left)?;
131 let underline_len = config.width(self.prefix_source) + 1;
132 for _ in 0..underline_len {
133 write!(writer, "{}", config.chars.multiline_top)?;
134 }
135 write!(writer, "{}", self.mark_style.multiline_caret_char(config))?;
136 writer.reset()?;
137
138 Ok(())
139 }
140 }
141
142 /// The left of a multi-line underline.
143 pub struct UnderlineLeft {
144 mark_style: MarkStyle,
145 }
146
147 impl UnderlineLeft {
148 pub fn new(mark_style: MarkStyle) -> UnderlineLeft {
149 UnderlineLeft { mark_style }
150 }
151
152 pub fn emit(&self, writer: &mut impl WriteColor, config: &Config) -> io::Result<()> {
153 write!(writer, " ")?;
154 writer.set_color(self.mark_style.label_style(config))?;
155 write!(writer, "{}", config.chars.multiline_left)?;
156 writer.reset()?;
157
158 Ok(())
159 }
160 }
161
162 /// The bottom of a multi-line underline.
163 ///
164 /// ```text
165 /// ╰──────────────^ `case` clauses have incompatible types
166 /// ```
167 pub struct UnderlineBottom<'a> {
168 mark_style: MarkStyle,
169 highlighted_source: &'a str,
170 message: &'a str,
171 }
172
173 impl<'a> UnderlineBottom<'a> {
174 pub fn new(
175 mark_style: MarkStyle,
176 highlighted_source: &'a str,
177 message: &'a str,
178 ) -> UnderlineBottom<'a> {
179 UnderlineBottom {
180 mark_style,
181 highlighted_source,
182 message,
183 }
184 }
185
186 pub fn emit(&self, writer: &mut impl WriteColor, config: &Config) -> io::Result<()> {
187 write!(writer, " ")?;
188
189 writer.set_color(self.mark_style.label_style(config))?;
190 write!(writer, "{}", config.chars.multiline_bottom_left)?;
191 let width = config.width(self.highlighted_source);
192 for _ in 0..width {
193 write!(writer, "{}", config.chars.multiline_bottom)?;
194 }
195 write!(writer, "{}", self.mark_style.multiline_caret_char(config))?;
196 if !self.message.is_empty() {
197 write!(writer, " {}", self.message)?;
198 }
199 writer.reset()?;
200
201 Ok(())
202 }
203 }