codespan_reporting/term/
mod.rs

1//! Terminal back-end for emitting diagnostics.
2
3use crate::diagnostic::Diagnostic;
4use crate::files::Files;
5
6mod config;
7mod renderer;
8mod views;
9
10#[cfg(not(feature = "std"))]
11use alloc::string::String;
12
13pub use config::{Chars, Config, DisplayStyle};
14
15// re-export
16#[cfg(feature = "termcolor")]
17pub use config::styles::{termcolor, Styles, StylesWriter};
18
19pub use renderer::{GeneralWrite, GeneralWriteResult, Renderer, WriteStyle};
20pub use views::{RichDiagnostic, ShortDiagnostic};
21
22pub fn emit_into_string<'files, F: Files<'files> + ?Sized>(
23    config: &Config,
24    files: &'files F,
25    diagnostic: &Diagnostic<F::FileId>,
26) -> Result<String, super::files::Error> {
27    let mut writer = String::new();
28    emit_to_string(&mut writer, config, files, diagnostic)?;
29    Ok(writer)
30}
31
32pub fn emit_to_string<'files, F: Files<'files> + ?Sized>(
33    writer: &mut String,
34    config: &Config,
35    files: &'files F,
36    diagnostic: &Diagnostic<F::FileId>,
37) -> Result<(), super::files::Error> {
38    // std::io::Write used under `feature = "std"`
39    #[cfg(feature = "std")]
40    {
41        let mut buffer = Vec::new();
42        emit_with_style(
43            renderer::PlainWriter::new(&mut buffer),
44            config,
45            files,
46            diagnostic,
47        )?;
48        let buffer_str: &str = core::str::from_utf8(&buffer).expect("buffer not utf8");
49        writer.push_str(buffer_str);
50        Ok(())
51    }
52
53    // core::fmt::Write used not `not(feature = "std")`
54    #[cfg(not(feature = "std"))]
55    {
56        emit_with_style(
57            renderer::PlainWriter::new(writer),
58            config,
59            files,
60            diagnostic,
61        )
62    }
63}
64
65#[cfg(feature = "std")]
66pub fn emit_to_io_write<'files, F: Files<'files> + ?Sized, W: std::io::Write + ?Sized>(
67    writer: &mut W,
68    config: &Config,
69    files: &'files F,
70    diagnostic: &Diagnostic<F::FileId>,
71) -> Result<(), super::files::Error> {
72    emit_with_style(
73        renderer::PlainWriter::new(writer),
74        config,
75        files,
76        diagnostic,
77    )
78}
79
80pub fn emit_to_write_style<'files, F: Files<'files> + ?Sized, W: WriteStyle + ?Sized>(
81    writer: &mut W,
82    config: &Config,
83    files: &'files F,
84    diagnostic: &Diagnostic<F::FileId>,
85) -> Result<(), super::files::Error> {
86    emit_with_style(
87        renderer::WriteStyleByRef::new(writer),
88        config,
89        files,
90        diagnostic,
91    )
92}
93
94#[deprecated(
95    since = "0.13.0",
96    note = "Use `emit_to_write_style` instead or depending on the writer use `emit_to_io_write` or `emit_to_string`"
97)]
98/// Emit a diagnostic using the given writer, context, config, and files.
99///
100/// The return value covers all error cases. These error case can arise if:
101/// * a file was removed from the file database.
102/// * a file was changed so that it is too small to have an index
103/// * IO fails
104pub fn emit<'files, F: Files<'files> + ?Sized, W: renderer::GeneralWrite + ?Sized>(
105    writer: &mut W,
106    config: &Config,
107    files: &'files F,
108    diagnostic: &Diagnostic<F::FileId>,
109) -> Result<(), super::files::Error> {
110    emit_with_style(
111        renderer::PlainWriter::new(writer),
112        config,
113        files,
114        diagnostic,
115    )
116}
117
118fn emit_with_style<'files, F: Files<'files> + ?Sized, W: WriteStyle>(
119    mut writer: W,
120    config: &Config,
121    files: &'files F,
122    diagnostic: &Diagnostic<F::FileId>,
123) -> Result<(), super::files::Error> {
124    let mut renderer = Renderer::new(&mut writer, config);
125    match config.display_style {
126        DisplayStyle::Rich => RichDiagnostic::new(diagnostic, config).render(files, &mut renderer),
127        DisplayStyle::Medium => ShortDiagnostic::new(diagnostic, true).render(files, &mut renderer),
128        DisplayStyle::Short => ShortDiagnostic::new(diagnostic, false).render(files, &mut renderer),
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use alloc::vec::Vec;
135
136    use super::*;
137
138    use crate::diagnostic::Label;
139    use crate::files::SimpleFiles;
140
141    /// Test range of 0 to 0 and check does not crash
142    #[test]
143    fn unsized_emit() {
144        let mut files = SimpleFiles::new();
145
146        let id = files.add("test", "");
147        let zero_range = 0..0;
148        let diagnostic = Diagnostic::bug().with_label(Label::primary(id, zero_range));
149        emit_into_string(&Config::default(), &files, &diagnostic).unwrap();
150    }
151}