1use std::{io, io::IsTerminal, str::FromStr};
2
3use crate::{diagnostics::ShearAnalysis, output::miette::MietteRenderer};
4
5pub mod github;
6pub mod json;
7pub mod miette;
8
9#[derive(Debug, Clone, Copy, Default)]
11#[non_exhaustive]
12pub enum OutputFormat {
13 #[default]
15 Auto,
16
17 Json,
19
20 GitHub,
22}
23
24impl OutputFormat {
25 #[must_use]
31 pub fn resolve(self) -> Self {
32 if matches!(self, Self::Auto) && std::env::var_os("GITHUB_ACTIONS").is_some() {
33 Self::GitHub
34 } else {
35 self
36 }
37 }
38}
39
40impl FromStr for OutputFormat {
41 type Err = String;
42
43 fn from_str(s: &str) -> Result<Self, Self::Err> {
44 match s.to_lowercase().as_str() {
45 "auto" => Ok(Self::Auto),
46 "json" => Ok(Self::Json),
47 "github" => Ok(Self::GitHub),
48 _ => Err(format!("unknown format: {s}, expected: auto, json, github")),
49 }
50 }
51}
52
53#[derive(Debug, Clone, Copy, Default)]
55#[non_exhaustive]
56pub enum ColorMode {
57 #[default]
59 Auto,
60
61 Always,
63
64 Never,
66}
67
68impl ColorMode {
69 #[must_use]
71 pub fn enabled(self) -> bool {
72 match self {
73 Self::Always => true,
74 Self::Never => false,
75 Self::Auto => {
76 if std::env::var_os("NO_COLOR").is_some() {
77 return false;
78 }
79
80 std::io::stdout().is_terminal()
81 }
82 }
83 }
84}
85
86impl FromStr for ColorMode {
87 type Err = String;
88
89 fn from_str(s: &str) -> Result<Self, Self::Err> {
90 match s.to_lowercase().as_str() {
91 "auto" => Ok(Self::Auto),
92 "always" => Ok(Self::Always),
93 "never" => Ok(Self::Never),
94 _ => Err(format!("unknown color option: {s}, expected one of: auto, always, never")),
95 }
96 }
97}
98
99pub struct Renderer<W> {
100 writer: W,
101 format: OutputFormat,
102 color: bool,
103}
104
105impl<W: io::Write> Renderer<W> {
106 pub const fn new(writer: W, format: OutputFormat, color: bool) -> Self {
107 Self { writer, format, color }
108 }
109
110 pub fn render(&mut self, analysis: &ShearAnalysis) -> io::Result<()> {
111 match self.format {
112 OutputFormat::Auto => {
113 let mut renderer = MietteRenderer::new(&mut self.writer, self.color);
114 renderer.render(analysis)
115 }
116 OutputFormat::Json => {
117 let mut renderer = json::JsonRenderer::new(&mut self.writer);
118 renderer.render(analysis)
119 }
120 OutputFormat::GitHub => {
121 let mut renderer = github::GitHubRenderer::new(&mut self.writer);
122 renderer.render(analysis)
123 }
124 }
125 }
126}