1use crate::core::output::{ColorMode, OutputFormat, RenderMode, UnicodeMode};
12use crate::core::output_model::OutputResult;
13use crate::ui::chrome::{RuledSectionPolicy, SectionFrameStyle};
14use crate::ui::theme;
15use crate::ui::{
16 HelpChromeSettings, RenderBackend, RenderSettings, StyleOverrides, TableBorderStyle,
17 TableOverflow, ThemeDefinition,
18};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct ResolvedRenderSettings {
23 pub backend: RenderBackend,
25 pub color: bool,
27 pub unicode: bool,
29 pub width: Option<usize>,
31 pub margin: usize,
33 pub indent_size: usize,
35 pub short_list_max: usize,
37 pub medium_list_max: usize,
39 pub grid_padding: usize,
41 pub grid_columns: Option<usize>,
43 pub column_weight: usize,
45 pub table_overflow: TableOverflow,
47 pub table_border: TableBorderStyle,
49 pub help_table_border: TableBorderStyle,
51 pub theme_name: String,
53 pub theme: ThemeDefinition,
55 pub style_overrides: StyleOverrides,
57 pub chrome_frame: SectionFrameStyle,
59}
60
61#[derive(Debug, Clone, PartialEq, Eq)]
67pub(crate) struct ResolvedRenderPlan {
68 pub(crate) format: OutputFormat,
70 pub(crate) render: ResolvedRenderSettings,
72 pub(crate) guide: ResolvedGuideRenderSettings,
74 pub(crate) mreg: ResolvedMregBuildSettings,
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub(crate) struct ResolvedHelpChromeSettings {
80 pub(crate) table_border: TableBorderStyle,
81 pub(crate) entry_indent: Option<usize>,
82 pub(crate) entry_gap: Option<usize>,
83 pub(crate) section_spacing: Option<usize>,
84}
85
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87pub(crate) struct ResolvedGuideRenderSettings {
88 pub(crate) frame_style: SectionFrameStyle,
89 pub(crate) ruled_section_policy: RuledSectionPolicy,
90 pub(crate) help_chrome: ResolvedHelpChromeSettings,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub(crate) struct ResolvedMregBuildSettings {
95 pub(crate) short_list_max: usize,
96 pub(crate) medium_list_max: usize,
97 pub(crate) indent_size: usize,
98 pub(crate) stack_min_col_width: usize,
99 pub(crate) stack_overflow_ratio: usize,
100}
101
102impl RenderSettings {
103 pub(crate) fn resolve_guide_render_settings(&self) -> ResolvedGuideRenderSettings {
104 ResolvedGuideRenderSettings {
105 frame_style: self.chrome_frame,
106 ruled_section_policy: self.ruled_section_policy,
107 help_chrome: self.help_chrome.resolve(self.table_border),
108 }
109 }
110
111 pub(crate) fn resolve_mreg_build_settings(&self) -> ResolvedMregBuildSettings {
112 ResolvedMregBuildSettings {
113 short_list_max: self.short_list_max.max(1),
114 medium_list_max: self.medium_list_max.max(self.short_list_max.max(1) + 1),
115 indent_size: self.indent_size.max(1),
116 stack_min_col_width: self.mreg_stack_min_col_width.max(1),
117 stack_overflow_ratio: self.mreg_stack_overflow_ratio.max(100),
118 }
119 }
120
121 fn resolve_color_mode(&self) -> bool {
122 match self.color {
123 ColorMode::Always => true,
124 ColorMode::Never => false,
125 ColorMode::Auto => !self.runtime.no_color && self.runtime.stdout_is_tty,
126 }
127 }
128
129 fn resolve_unicode_mode(&self) -> bool {
130 match self.unicode {
131 UnicodeMode::Always => true,
132 UnicodeMode::Never => false,
133 UnicodeMode::Auto => {
134 if !self.runtime.stdout_is_tty {
135 return false;
136 }
137 if matches!(self.runtime.terminal.as_deref(), Some("dumb")) {
138 return false;
139 }
140 match self.runtime.locale_utf8 {
141 Some(true) => true,
142 Some(false) => false,
143 None => true,
144 }
145 }
146 }
147 }
148
149 pub fn resolve_render_settings(&self) -> ResolvedRenderSettings {
173 let backend = match self.mode {
174 RenderMode::Plain => RenderBackend::Plain,
175 RenderMode::Rich => RenderBackend::Rich,
176 RenderMode::Auto => {
177 if matches!(self.color, ColorMode::Always)
178 || matches!(self.unicode, UnicodeMode::Always)
179 {
180 RenderBackend::Rich
181 } else if !self.runtime.stdout_is_tty
182 || matches!(self.runtime.terminal.as_deref(), Some("dumb"))
183 {
184 RenderBackend::Plain
185 } else {
186 RenderBackend::Rich
187 }
188 }
189 };
190
191 let theme = self
192 .theme
193 .clone()
194 .unwrap_or_else(|| theme::resolve_theme(&self.theme_name));
195 let theme_name = theme::normalize_theme_name(&theme.id);
196
197 match backend {
198 RenderBackend::Plain => ResolvedRenderSettings {
199 backend,
200 color: false,
201 unicode: false,
202 width: self.resolve_width(),
203 margin: self.margin,
204 indent_size: self.indent_size.max(1),
205 short_list_max: self.short_list_max.max(1),
206 medium_list_max: self.medium_list_max.max(self.short_list_max.max(1) + 1),
207 grid_padding: self.grid_padding.max(1),
208 grid_columns: self.grid_columns.filter(|value| *value > 0),
209 column_weight: self.column_weight.max(1),
210 table_overflow: self.table_overflow,
211 table_border: self.table_border,
212 help_table_border: self.help_chrome.table_chrome.resolve(self.table_border),
213 theme_name,
214 theme: theme.clone(),
215 style_overrides: self.style_overrides.clone(),
216 chrome_frame: self.chrome_frame,
217 },
218 RenderBackend::Rich => ResolvedRenderSettings {
219 backend,
220 color: self.resolve_color_mode(),
221 unicode: self.resolve_unicode_mode(),
222 width: self.resolve_width(),
223 margin: self.margin,
224 indent_size: self.indent_size.max(1),
225 short_list_max: self.short_list_max.max(1),
226 medium_list_max: self.medium_list_max.max(self.short_list_max.max(1) + 1),
227 grid_padding: self.grid_padding.max(1),
228 grid_columns: self.grid_columns.filter(|value| *value > 0),
229 column_weight: self.column_weight.max(1),
230 table_overflow: self.table_overflow,
231 table_border: self.table_border,
232 help_table_border: self.help_chrome.table_chrome.resolve(self.table_border),
233 theme_name,
234 theme,
235 style_overrides: self.style_overrides.clone(),
236 chrome_frame: self.chrome_frame,
237 },
238 }
239 }
240
241 pub(crate) fn resolve_render_plan(&self, output: &OutputResult) -> ResolvedRenderPlan {
243 ResolvedRenderPlan {
244 format: crate::ui::format::resolve_output_format(output, self),
245 render: self.resolve_render_settings(),
246 guide: self.resolve_guide_render_settings(),
247 mreg: self.resolve_mreg_build_settings(),
248 }
249 }
250
251 fn resolve_width(&self) -> Option<usize> {
252 if let Some(width) = self.width {
253 return (width > 0).then_some(width);
254 }
255 self.runtime.width.filter(|width| *width > 0)
256 }
257
258 pub(crate) fn plain_copy_settings(&self) -> Self {
259 Self {
260 format: self.format,
261 format_explicit: self.format_explicit,
262 mode: RenderMode::Plain,
263 color: ColorMode::Never,
264 unicode: UnicodeMode::Never,
265 width: self.width,
266 margin: self.margin,
267 indent_size: self.indent_size,
268 short_list_max: self.short_list_max,
269 medium_list_max: self.medium_list_max,
270 grid_padding: self.grid_padding,
271 grid_columns: self.grid_columns,
272 column_weight: self.column_weight,
273 table_overflow: self.table_overflow,
274 table_border: self.table_border,
275 help_chrome: self.help_chrome,
276 mreg_stack_min_col_width: self.mreg_stack_min_col_width,
277 mreg_stack_overflow_ratio: self.mreg_stack_overflow_ratio,
278 theme_name: self.theme_name.clone(),
279 theme: self.theme.clone(),
280 style_overrides: self.style_overrides.clone(),
281 chrome_frame: self.chrome_frame,
282 ruled_section_policy: self.ruled_section_policy,
283 guide_default_format: self.guide_default_format,
284 runtime: self.runtime.clone(),
285 }
286 }
287}
288
289impl HelpChromeSettings {
290 pub(crate) fn resolve(self, table_border: TableBorderStyle) -> ResolvedHelpChromeSettings {
291 ResolvedHelpChromeSettings {
292 table_border: self.table_chrome.resolve(table_border),
293 entry_indent: self.entry_indent,
294 entry_gap: self.entry_gap,
295 section_spacing: self.section_spacing,
296 }
297 }
298}
299
300impl ResolvedGuideRenderSettings {
301 #[cfg(test)]
302 pub(crate) fn plain_help(
303 frame_style: SectionFrameStyle,
304 table_border: TableBorderStyle,
305 ) -> Self {
306 Self {
307 frame_style,
308 ruled_section_policy: RuledSectionPolicy::PerSection,
309 help_chrome: HelpChromeSettings {
310 table_chrome: match table_border {
311 TableBorderStyle::None => crate::ui::HelpTableChrome::None,
312 TableBorderStyle::Square => crate::ui::HelpTableChrome::Square,
313 TableBorderStyle::Round => crate::ui::HelpTableChrome::Round,
314 },
315 ..HelpChromeSettings::default()
316 }
317 .resolve(table_border),
318 }
319 }
320}