Skip to main content

sel/format/
mod.rs

1//! Output formatting.
2
3pub mod ansi;
4pub mod fragment;
5pub mod plain;
6
7pub use fragment::FragmentFormatter;
8pub use plain::PlainFormatter;
9
10use crate::Emit;
11use std::io;
12
13/// A formatter serializes one `Emit` into bytes.
14pub trait Formatter {
15    fn write(&mut self, sink: &mut dyn io::Write, emit: &Emit) -> io::Result<()>;
16}
17
18/// Common configuration shared by plain and fragment formatters.
19#[derive(Debug, Clone)]
20pub struct FormatOpts {
21    pub show_line_numbers: bool,
22    pub show_filename: bool,
23    pub filename: Option<String>,
24    pub color: bool,
25    /// Prepend `"> "` (colorized green) before target lines.
26    /// Set `true` only when mixing target and context lines (i.e. `-c N`).
27    pub target_marker: bool,
28    pub line_number_width: usize,
29}
30
31impl FormatOpts {
32    pub fn widen_for_line(&mut self, line_no: u64) {
33        self.line_number_width = self.line_number_width.max(digits(line_no));
34    }
35
36    pub fn prefix(&self, line_no: u64) -> String {
37        let mut p = String::new();
38        if self.show_filename
39            && let Some(f) = &self.filename
40        {
41            p.push_str(f);
42            p.push(':');
43        }
44        if self.show_line_numbers {
45            p.push_str(&format!(
46                "{line_no:>width$}: ",
47                width = self.line_number_width
48            ));
49        }
50        p
51    }
52}
53
54pub fn digits(n: u64) -> usize {
55    n.to_string().len()
56}
57
58fn push_lossy(out: &mut String, bytes: &[u8]) {
59    out.push_str(&String::from_utf8_lossy(bytes));
60}