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}