termfmt/
fmt.rs

1use std::fmt::Display;
2use std::io::stdout;
3
4use serde::Serialize;
5
6pub enum TermFmt<Bundle> {
7    Direct(DirectTermFmt),
8    Bundled(BundledTermFmt, Bundle),
9}
10
11pub enum DirectTermFmt {
12    Plain,
13    Interactive,
14}
15
16pub enum BundledTermFmt {
17    Json,
18}
19
20pub trait BundleFmt: Serialize + Sized {
21    type Config;
22
23    fn new(config: Self::Config) -> Self;
24
25    fn clear(&mut self);
26}
27
28impl<Bundle> TermFmt<Bundle>
29where
30    Bundle: Serialize,
31    Bundle: BundleFmt,
32{
33    pub fn new_plain() -> Self {
34        Self::Direct(DirectTermFmt::Plain)
35    }
36
37    pub fn new_interactive() -> Self {
38        Self::Direct(DirectTermFmt::Interactive)
39    }
40
41    pub fn new_json(bundle: Bundle) -> Self {
42        Self::Bundled(BundledTermFmt::Json, bundle)
43    }
44
45    pub fn bundle(&mut self, modify: impl Fn(&mut Bundle)) {
46        let TermFmt::Bundled(_, bundle) = self else {
47            return;
48        };
49        modify(bundle);
50    }
51
52    pub fn plain(&self, value: impl Display) {
53        if self.is_plain() {
54            println!("{}", value);
55        }
56    }
57
58    pub fn is_plain(&self) -> bool {
59        matches!(self, Self::Direct(DirectTermFmt::Plain))
60    }
61
62    pub fn is_interactive(&self) -> bool {
63        matches!(self, Self::Direct(DirectTermFmt::Interactive))
64    }
65
66    pub fn flush(&mut self) -> eyre::Result<()> {
67        let TermFmt::Bundled(fmt, bundle) = self else {
68            return Ok(());
69        };
70        match fmt {
71            BundledTermFmt::Json => serde_json::to_writer(stdout(), bundle)?,
72        }
73        bundle.clear();
74        Ok(())
75    }
76}