1use alloc::string::String;
2
3#[derive(Clone, Debug)]
5pub struct Config {
6 pub display_style: DisplayStyle,
11 pub tab_width: usize,
14
15 pub chars: Chars,
17 pub start_context_lines: usize,
23 pub end_context_lines: usize,
29 pub before_label_lines: usize,
33 pub after_label_lines: usize,
37}
38
39impl Default for Config {
40 fn default() -> Config {
41 Config {
42 display_style: DisplayStyle::Rich,
43 tab_width: 4,
44 chars: Chars::default(),
45 start_context_lines: 3,
46 end_context_lines: 1,
47 before_label_lines: 0,
48 after_label_lines: 0,
49 }
50 }
51}
52
53#[derive(Clone, Debug)]
55pub enum DisplayStyle {
56 Rich,
72 Medium,
82 Short,
89}
90
91#[cfg(feature = "termcolor")]
92pub mod styles {
93 use super::super::renderer::{self, WriteStyle};
94
95 use crate::diagnostic::{LabelStyle, Severity};
96 use termcolor::{Color, ColorSpec, WriteColor};
97
98 pub use termcolor;
100
101 #[derive(Clone, Debug)]
103 pub struct Styles {
104 pub header_bug: ColorSpec,
107 pub header_error: ColorSpec,
110 pub header_warning: ColorSpec,
113 pub header_note: ColorSpec,
116 pub header_help: ColorSpec,
119 pub header_message: ColorSpec,
122
123 pub primary_label_bug: ColorSpec,
126 pub primary_label_error: ColorSpec,
129 pub primary_label_warning: ColorSpec,
132 pub primary_label_note: ColorSpec,
135 pub primary_label_help: ColorSpec,
138 pub secondary_label: ColorSpec,
141
142 pub line_number: ColorSpec,
145 pub source_border: ColorSpec,
148 pub note_bullet: ColorSpec,
151 }
152
153 impl Styles {
154 #[must_use]
156 pub fn header(&self, severity: Severity) -> &ColorSpec {
157 match severity {
158 Severity::Bug => &self.header_bug,
159 Severity::Error => &self.header_error,
160 Severity::Warning => &self.header_warning,
161 Severity::Note => &self.header_note,
162 Severity::Help => &self.header_help,
163 }
164 }
165
166 #[must_use]
167 pub fn header_message(&self) -> &ColorSpec {
168 &self.header_message
169 }
170
171 #[must_use]
172 pub fn line_number(&self) -> &ColorSpec {
173 &self.line_number
174 }
175
176 #[must_use]
177 pub fn note_bullet(&self) -> &ColorSpec {
178 &self.note_bullet
179 }
180
181 #[must_use]
182 pub fn source_border(&self) -> &ColorSpec {
183 &self.source_border
184 }
185
186 #[must_use]
188 pub fn label(&self, severity: Severity, label_style: LabelStyle) -> &ColorSpec {
189 match (label_style, severity) {
190 (LabelStyle::Primary, Severity::Bug) => &self.primary_label_bug,
191 (LabelStyle::Primary, Severity::Error) => &self.primary_label_error,
192 (LabelStyle::Primary, Severity::Warning) => &self.primary_label_warning,
193 (LabelStyle::Primary, Severity::Note) => &self.primary_label_note,
194 (LabelStyle::Primary, Severity::Help) => &self.primary_label_help,
195 (LabelStyle::Secondary, _) => &self.secondary_label,
196 }
197 }
198 }
199
200 impl Styles {
201 #[must_use]
202 pub fn no_color() -> Styles {
203 Styles {
204 header_bug: ColorSpec::new(),
205 header_error: ColorSpec::new(),
206 header_warning: ColorSpec::new(),
207 header_note: ColorSpec::new(),
208 header_help: ColorSpec::new(),
209 header_message: ColorSpec::new(),
210
211 primary_label_bug: ColorSpec::new(),
212 primary_label_error: ColorSpec::new(),
213 primary_label_warning: ColorSpec::new(),
214 primary_label_note: ColorSpec::new(),
215 primary_label_help: ColorSpec::new(),
216 secondary_label: ColorSpec::new(),
217
218 line_number: ColorSpec::new(),
219 source_border: ColorSpec::new(),
220 note_bullet: ColorSpec::new(),
221 }
222 }
223 }
224
225 impl Default for Styles {
226 fn default() -> Styles {
227 let header = ColorSpec::new().set_bold(true).set_intense(true).clone();
229
230 Styles {
231 header_bug: header.clone().set_fg(Some(Color::Red)).clone(),
232 header_error: header.clone().set_fg(Some(Color::Red)).clone(),
233 header_warning: header.clone().set_fg(Some(Color::Yellow)).clone(),
234 header_note: header.clone().set_fg(Some(Color::Green)).clone(),
235 header_help: header.clone().set_fg(Some(Color::Cyan)).clone(),
236 header_message: header,
237
238 primary_label_bug: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
239 primary_label_error: ColorSpec::new().set_fg(Some(Color::Red)).clone(),
240 primary_label_warning: ColorSpec::new().set_fg(Some(Color::Yellow)).clone(),
241 primary_label_note: ColorSpec::new().set_fg(Some(Color::Green)).clone(),
242 primary_label_help: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(),
243 secondary_label: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(),
244
245 line_number: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(),
246 source_border: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(),
247 note_bullet: ColorSpec::new().set_fg(Some(Color::Cyan)).clone(),
248 }
249 }
250 }
251
252 pub struct StylesWriter<'a, W> {
257 writer: W,
258 style: &'a Styles,
259 }
260
261 impl<'a, W> StylesWriter<'a, W> {
262 pub fn new(writer: W, style: &'a Styles) -> Self {
264 Self { writer, style }
265 }
266 }
267
268 impl<'a, W: WriteColor> std::io::Write for StylesWriter<'a, W> {
270 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
271 self.writer.write(buf)
272 }
273
274 fn flush(&mut self) -> std::io::Result<()> {
275 self.writer.flush()
276 }
277 }
278
279 impl<W: WriteColor> WriteStyle for StylesWriter<'_, W> {
280 fn set_header(&mut self, severity: Severity) -> renderer::GeneralWriteResult {
281 self.writer.set_color(self.style.header(severity))
282 }
283
284 fn set_header_message(&mut self) -> renderer::GeneralWriteResult {
285 self.writer.set_color(&self.style.header_message)
286 }
287
288 fn set_line_number(&mut self) -> renderer::GeneralWriteResult {
289 self.writer.set_color(&self.style.line_number)
290 }
291
292 fn set_note_bullet(&mut self) -> renderer::GeneralWriteResult {
293 self.writer.set_color(&self.style.note_bullet)
294 }
295
296 fn set_source_border(&mut self) -> renderer::GeneralWriteResult {
297 self.writer.set_color(&self.style.source_border)
298 }
299
300 fn set_label(
301 &mut self,
302 severity: Severity,
303 label_style: LabelStyle,
304 ) -> renderer::GeneralWriteResult {
305 let spec = self.style.label(severity, label_style);
306 self.writer.set_color(spec)
307 }
308
309 fn reset(&mut self) -> renderer::GeneralWriteResult {
310 self.writer.reset()
311 }
312 }
313}
314
315#[cfg(feature = "termcolor")]
316impl<T> super::renderer::WriteStyle for T
317where
318 T: termcolor::WriteColor + ?Sized,
319{
320 fn set_header(
321 &mut self,
322 severity: crate::diagnostic::Severity,
323 ) -> super::renderer::GeneralWriteResult {
324 self.set_color(styles::Styles::default().header(severity))
325 }
326
327 fn set_header_message(&mut self) -> super::renderer::GeneralWriteResult {
328 self.set_color(&styles::Styles::default().header_message)
329 }
330
331 fn set_line_number(&mut self) -> super::renderer::GeneralWriteResult {
332 self.set_color(&styles::Styles::default().line_number)
333 }
334
335 fn set_note_bullet(&mut self) -> super::renderer::GeneralWriteResult {
336 self.set_color(&styles::Styles::default().note_bullet)
337 }
338
339 fn set_source_border(&mut self) -> super::renderer::GeneralWriteResult {
340 self.set_color(&styles::Styles::default().source_border)
341 }
342
343 fn set_label(
344 &mut self,
345 severity: crate::diagnostic::Severity,
346 label_style: crate::diagnostic::LabelStyle,
347 ) -> super::renderer::GeneralWriteResult {
348 let styles = styles::Styles::default();
349 let spec = styles.label(severity, label_style);
350 self.set_color(spec)
351 }
352
353 fn reset(&mut self) -> super::renderer::GeneralWriteResult {
354 self.reset()
355 }
356}
357
358#[derive(Clone, Debug)]
363pub struct Chars {
364 pub snippet_start: String,
367 pub source_border_left: char,
370 pub source_border_left_break: char,
373
374 pub note_bullet: char,
377
378 pub single_primary_caret: char,
381 pub single_secondary_caret: char,
384
385 pub multi_primary_caret_start: char,
388 pub multi_primary_caret_end: char,
391 pub multi_secondary_caret_start: char,
394 pub multi_secondary_caret_end: char,
397 pub multi_top_left: char,
400 pub multi_top: char,
403 pub multi_bottom_left: char,
406 pub multi_bottom: char,
409 pub multi_left: char,
412
413 pub pointer_left: char,
416}
417
418impl Default for Chars {
419 fn default() -> Chars {
420 Chars::box_drawing()
421 }
422}
423
424impl Chars {
425 #[must_use]
427 pub fn box_drawing() -> Chars {
428 Chars {
429 snippet_start: "┌─".into(),
430 source_border_left: '│',
431 source_border_left_break: '·',
432
433 note_bullet: '=',
434
435 single_primary_caret: '^',
436 single_secondary_caret: '-',
437
438 multi_primary_caret_start: '^',
439 multi_primary_caret_end: '^',
440 multi_secondary_caret_start: '\'',
441 multi_secondary_caret_end: '\'',
442 multi_top_left: '╭',
443 multi_top: '─',
444 multi_bottom_left: '╰',
445 multi_bottom: '─',
446 multi_left: '│',
447
448 pointer_left: '│',
449 }
450 }
451
452 #[must_use]
458 pub fn ascii() -> Chars {
459 Chars {
460 snippet_start: "-->".into(),
461 source_border_left: '|',
462 source_border_left_break: '.',
463
464 note_bullet: '=',
465
466 single_primary_caret: '^',
467 single_secondary_caret: '-',
468
469 multi_primary_caret_start: '^',
470 multi_primary_caret_end: '^',
471 multi_secondary_caret_start: '\'',
472 multi_secondary_caret_end: '\'',
473 multi_top_left: '/',
474 multi_top: '-',
475 multi_bottom_left: '\\',
476 multi_bottom: '-',
477 multi_left: '|',
478
479 pointer_left: '|',
480 }
481 }
482}