From: Ben Pfaff Date: Tue, 9 Dec 2025 20:10:10 +0000 (-0800) Subject: work X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b573acf14140518523bf5dc3b4cdc77f3da10fe4;p=pspp work --- diff --git a/rust/pspp/src/output/drivers/text.rs b/rust/pspp/src/output/drivers/text.rs index cc6cad0432..423664dd02 100644 --- a/rust/pspp/src/output/drivers/text.rs +++ b/rust/pspp/src/output/drivers/text.rs @@ -392,7 +392,8 @@ impl TextRenderer { writeln!(writer)?; } match &item.details { - Details::Chart | Details::Image(_) => todo!(), + Details::Chart => writeln!(writer, "Omitting chart from text output")?, + Details::Image(_) => writeln!(writer, "Omitting image from text output")?, Details::Heading(_) => unreachable!(), Details::Message(_diagnostic) => todo!(), Details::PageBreak => (), diff --git a/rust/pspp/src/output/pivot.rs b/rust/pspp/src/output/pivot.rs index 448e95f92c..4bbcf2dab9 100644 --- a/rust/pspp/src/output/pivot.rs +++ b/rust/pspp/src/output/pivot.rs @@ -44,7 +44,7 @@ use std::{ collections::HashMap, - fmt::{Debug, Display}, + fmt::{Debug, Display, Write}, io::Read, iter::{FusedIterator, once, repeat, repeat_n}, ops::{Index, IndexMut, Not, Range, RangeInclusive}, @@ -2773,9 +2773,7 @@ impl Display for DisplayValue<'_> { ValueInner::Markup(markup) => write!(f, "{markup}"), - ValueInner::Text(TextValue { - localized: local, .. - }) => f.write_str(local), + ValueInner::Text(text_value) => write!(f, "{text_value}"), ValueInner::Template(template_value) => template_value.display(self, f), @@ -2829,14 +2827,32 @@ impl Debug for Value { } } +/// A numeric value and how to display it. #[derive(Clone, Debug, PartialEq)] pub struct NumberValue { /// The numerical value, or `None` if it is a missing value. pub value: Option, + + /// The display format (usually [F] or [Pct]). + /// + /// [F]: crate::format::Type::F + /// [Pct]: crate::format::Type::Pct pub format: Format, + + /// Whether to show `value` or `value_label` or both. + /// + /// If this is unset, then a higher-level default is used. pub show: Option, + + /// If true, then numbers smaller than a threshold will be displayed in + /// scientific notation. Otherwise, all numbers will be displayed with + /// `format`. pub honor_small: bool, + + /// The name of the variable that `value` came from, if any. pub variable: Option, + + /// The value label associated with `value`, if any. pub value_label: Option, } @@ -2920,6 +2936,7 @@ pub struct BareNumberValue<'a>( #[serde(serialize_with = "NumberValue::serialize_bare")] pub &'a NumberValue, ); +/// A string value and how to display it. #[derive(Clone, Debug, Serialize, PartialEq)] pub struct StringValue { /// The string value. @@ -2931,27 +2948,56 @@ pub struct StringValue { /// True if `s` is hex digits. pub hex: bool, + /// Whether to show `s` or `value_label` or both. + /// + /// If this is unset, then a higher-level default is used. pub show: Option, + /// The name of the variable that `s` came from, if any. pub var_name: Option, + + /// The value label associated with `s`, if any. pub value_label: Option, } #[derive(Clone, Debug, Serialize, PartialEq)] pub struct VariableValue { + /// Whether to show `var_name` or `variable_label` or both. + /// + /// If this is unset, then a higher-level default is used. pub show: Option, pub var_name: String, pub variable_label: Option, } +/// A text string. +/// +/// Whereas a [StringValue] is usually related to data, a `TextValue` is used +/// for other text within a table, such as a title, a column or row heading, or +/// a footnote. #[derive(Clone, Debug, PartialEq)] pub struct TextValue { + /// Whether the text came from the user. + /// + /// PSPP can localize text that it writes itself, but not text provided by + /// the user. pub user_provided: bool, + /// Localized. + /// + /// This is the main output string. pub localized: String, - /// English. + + /// English version of the string. + /// + /// Only for strings that are not user-provided, and only if it is different + /// from `localized`. pub c: Option, + /// Identifier. + /// + /// Only for strings that are not user-provided, and only if it is different + /// from `localized`. pub id: Option, } @@ -2980,6 +3026,12 @@ impl Serialize for TextValue { } } +impl Display for TextValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.localized) + } +} + impl TextValue { pub fn localized(&self) -> &str { self.localized.as_str() @@ -3020,19 +3072,22 @@ impl TemplateValue { while let Some(c) = iter.next() { match c { '\\' => { - let c = iter.next().unwrap_or('\\') as char; - let c = if c == 'n' { '\n' } else { c }; - write!(f, "{c}")?; + let c = match iter.next() { + None => '\\', + Some('n') => '\n', + Some(c) => c, + }; + f.write_char(c)?; } '^' => { let (index, rest) = Self::consume_int(iter.as_str()); - iter = rest.chars(); - let Some(arg) = self.args.get(index.wrapping_sub(1)) else { - continue; - }; - if let Some(arg) = arg.first() { - write!(f, "{}", arg.display(display.options))?; + if let Some(index) = index.checked_sub(1) + && let Some(arg) = self.args.get(index) + && let Some(arg) = arg.first() + { + arg.display(display.options).fmt(f)?; } + iter = rest.chars(); } '[' => { let (a, rest) = extract_inner_template(iter.as_str()); @@ -3041,28 +3096,24 @@ impl TemplateValue { let (index, rest) = Self::consume_int(rest); iter = rest.chars(); - dbg!((a, b, index)); - let Some(mut args) = self - .args - .get(index.wrapping_sub(1)) - .map(|vec| vec.as_slice()) - else { - continue; - }; - let (mut template, mut escape) = - if !a.is_empty() { (a, '%') } else { (b, '^') }; - while !args.is_empty() { - let n_consumed = self.inner_template(display, f, template, escape, args)?; - if n_consumed == 0 { - break; + if let Some(index) = index.checked_sub(1) + && let Some(args) = self.args.get(index) + { + let mut args = args.as_slice(); + let (mut template, mut escape) = + if !a.is_empty() { (a, '%') } else { (b, '^') }; + while !args.is_empty() + && let n_consumed = + self.inner_template(display, f, template, escape, args)? + && n_consumed > 0 + { + args = &args[n_consumed..]; + template = b; + escape = '^'; } - args = &args[n_consumed..]; - - template = b; - escape = '^'; } } - c => write!(f, "{c}")?, + c => f.write_char(c)?, } } Ok(()) @@ -3088,11 +3139,12 @@ impl TemplateValue { c if c == escape => { let (index, rest) = Self::consume_int(iter.as_str()); iter = rest.chars(); - let Some(arg) = args.get(index.wrapping_sub(1)) else { - continue; - }; - args_consumed = args_consumed.max(index); - write!(f, "{}", arg.display(display.options))?; + if let Some(index) = index.checked_sub(1) + && let Some(arg) = args.get(index) + { + args_consumed = args_consumed.max(index); + write!(f, "{}", arg.display(display.options))?; + } } c => write!(f, "{c}")?, }