1use std::sync::Arc;
4
5use super::renderer::{Renderer, StatusFields, Table, Writer};
6use super::{Printer, Role};
7
8pub struct SectionGuard<'p> {
13 pub(crate) printer: &'p Printer,
14 pub(crate) renderer: Arc<Renderer>,
15 pub(crate) sink: Arc<dyn Writer>,
16 pub(crate) depth: usize,
17}
18
19impl<'p> SectionGuard<'p> {
20 pub fn bullet(&self, text: impl Into<String>) -> &Self {
21 self.renderer
22 .render_bullet(self.sink.as_ref(), self.depth, &text.into());
23 self
24 }
25
26 pub fn kv(&self, key: impl Into<String>, value: impl Into<String>) -> &Self {
27 self.renderer.render_kv(&key.into(), &value.into());
29 self
30 }
31
32 pub fn kv_block<I, K, V>(&self, pairs: I) -> &Self
33 where
34 I: IntoIterator<Item = (K, V)>,
35 K: Into<String>,
36 V: Into<String>,
37 {
38 let pairs: Vec<(String, String)> = pairs
39 .into_iter()
40 .map(|(k, v)| (k.into(), v.into()))
41 .collect();
42 self.renderer
43 .render_kv_block(self.sink.as_ref(), self.depth, &pairs);
44 self
45 }
46
47 pub fn hint(&self, text: impl Into<String>) -> &Self {
48 self.renderer
49 .render_hint(self.sink.as_ref(), self.depth, &text.into());
50 self
51 }
52
53 pub fn note(&self, text: impl Into<String>) -> &Self {
54 self.renderer
55 .render_note(self.sink.as_ref(), self.depth, &text.into());
56 self
57 }
58
59 pub fn table(&self, table: Table) -> &Self {
60 self.renderer
61 .render_table(self.sink.as_ref(), self.depth, &table);
62 self
63 }
64
65 pub fn empty_state(&self, text: impl Into<String>) -> &Self {
69 self.renderer.render_section_empty_state(&text.into());
70 self
71 }
72
73 pub fn status_simple(&self, role: Role, subject: impl Into<String>) -> &Self {
76 let subject = subject.into();
77 self.renderer.render_status(
78 self.sink.as_ref(),
79 self.depth,
80 &StatusFields {
81 role,
82 subject: &subject,
83 detail: None,
84 duration: None,
85 target: None,
86 },
87 );
88 self
89 }
90
91 pub fn status(
93 &self,
94 role: Role,
95 subject: impl Into<String>,
96 ) -> super::status_builder::StatusBuilder<'_> {
97 super::status_builder::StatusBuilder::new(
98 self.renderer.clone(),
99 self.sink.clone(),
100 self.depth,
101 role,
102 subject,
103 )
104 }
105
106 #[must_use = "section closes when SectionGuard is dropped; bind it"]
109 pub fn section(&self, name: impl Into<String>) -> SectionGuard<'_> {
110 self.renderer
111 .render_section_open(&name.into(), true);
112 SectionGuard {
113 printer: self.printer,
114 renderer: self.renderer.clone(),
115 sink: self.sink.clone(),
116 depth: self.depth + 1,
117 }
118 }
119
120 #[must_use = "section closes when SectionGuard is dropped; bind it"]
121 pub fn section_or_collapse(&self, name: impl Into<String>) -> SectionGuard<'_> {
122 self.renderer
123 .render_section_open(&name.into(), false);
124 SectionGuard {
125 printer: self.printer,
126 renderer: self.renderer.clone(),
127 sink: self.sink.clone(),
128 depth: self.depth + 1,
129 }
130 }
131
132 #[must_use]
135 pub fn spinner(&self, message: impl Into<String>) -> super::spinner::Spinner<'_> {
136 let message = message.into();
137 let bar = super::spinner::make_spinner_bar(
138 &self.printer.multi_progress,
139 &self.renderer,
140 self.printer.verbosity(),
141 &message,
142 );
143 super::spinner::Spinner {
144 renderer: self.renderer.clone(),
145 sink: self.sink.clone(),
146 depth: self.depth,
147 bar,
148 message,
149 finished: false,
150 _phantom: std::marker::PhantomData,
151 }
152 }
153
154 #[must_use]
156 pub fn progress_bar(
157 &self,
158 total: u64,
159 message: impl Into<String>,
160 ) -> super::spinner::ProgressBar<'_> {
161 let bar = super::spinner::make_progress_bar(
162 &self.printer.multi_progress,
163 total,
164 self.printer.verbosity(),
165 &message.into(),
166 );
167 super::spinner::ProgressBar {
168 bar,
169 _phantom: std::marker::PhantomData,
170 }
171 }
172
173 pub fn run(
177 &self,
178 cmd: &mut std::process::Command,
179 label: impl Into<String>,
180 ) -> std::io::Result<super::process::CommandOutput> {
181 super::process::run_command(
182 &self.renderer,
183 self.sink.as_ref(),
184 &self.printer.multi_progress,
185 self.depth,
186 cmd,
187 &label.into(),
188 )
189 }
190
191 pub fn close(self) { }
195}
196
197impl Drop for SectionGuard<'_> {
198 fn drop(&mut self) {
199 self.renderer.render_section_close(self.sink.as_ref());
200 }
201}