From 97e8cae431a8ae4e6baca51b1b1dc837f49d55d4 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 30 Nov 2025 11:08:32 -0800 Subject: [PATCH] work --- rust/pspp/src/output.rs | 63 ++++++++++++++++++++++++++++ rust/pspp/src/output/drivers/text.rs | 31 +++++++------- 2 files changed, 80 insertions(+), 14 deletions(-) diff --git a/rust/pspp/src/output.rs b/rust/pspp/src/output.rs index a794de3d37..a90ef6e198 100644 --- a/rust/pspp/src/output.rs +++ b/rust/pspp/src/output.rs @@ -132,6 +132,14 @@ impl Item { ..self } } + + /// Should the item be shown? + /// + /// This always returns true for headings because their contents are always + /// shown (although headings can be collapsed in an outline view). + pub fn is_shown(&self) -> bool { + self.details.kind() == ItemKind::Heading || self.show + } } impl From for Item @@ -161,6 +169,12 @@ impl PivotTable { } } +/// A group of output items. +/// +/// The name "heading" is used in SPV files. There is only a visible +/// heading if the output items inside the heading include a [Text] item. +/// The grouping itself is only visible in the outline pane in a viewer +/// window. #[derive(Clone, Debug, Default, Serialize)] pub struct Heading(pub Vec>); @@ -474,16 +488,65 @@ impl TextType { } } +pub struct ItemRefIterator<'a> { + next: Option<&'a Item>, + stack: Vec<(&'a Item, usize)>, +} + +impl<'a> ItemRefIterator<'a> { + pub fn without_hidden(start: &'a Item) -> impl Iterator { + Self::with_hidden(start).filter(|item| item.is_shown()) + } + + pub fn with_hidden(start: &'a Item) -> Self { + Self { + next: Some(start), + stack: Vec::new(), + } + } +} + +impl<'a> Iterator for ItemRefIterator<'a> { + type Item = &'a Item; + + fn next(&mut self) -> Option { + let cur = self.next.take()?; + if let Some(first_child) = cur.details.children().first() { + self.next = Some(&*first_child); + self.stack.push((cur, 1)); + } else { + while let Some((item, index)) = self.stack.pop() { + if let Some(child) = item.details.children().get(index) { + self.next = Some(&*child); + self.stack.push((item, index + 1)); + return Some(cur); + } + } + } + Some(cur) + } +} + pub struct ItemCursor { cur: Option>, stack: Vec<(Arc, usize)>, + include_hidden: bool, } impl ItemCursor { pub fn new(start: Arc) -> Self { + Self { + cur: start.is_shown().then_some(start), + stack: Vec::new(), + include_hidden: false, + } + } + + pub fn with_hidden(start: Arc) -> Self { Self { cur: Some(start), stack: Vec::new(), + include_hidden: true, } } diff --git a/rust/pspp/src/output/drivers/text.rs b/rust/pspp/src/output/drivers/text.rs index 42b0eacdeb..181a6c2ddb 100644 --- a/rust/pspp/src/output/drivers/text.rs +++ b/rust/pspp/src/output/drivers/text.rs @@ -29,7 +29,7 @@ use serde::{Deserialize, Serialize}; use unicode_linebreak::{BreakOpportunity, linebreaks}; use unicode_width::UnicodeWidthStr; -use crate::output::{render::Extreme, table::DrawCell}; +use crate::output::{ItemRefIterator, render::Extreme, table::DrawCell}; use crate::output::{ Details, Item, @@ -381,22 +381,25 @@ impl TextRenderer { where W: FmtWrite, { - match &item.details { - Details::Chart | Details::Image(_) => todo!(), - Details::Heading(children) => { - for (index, child) in children.0.iter().enumerate() { - if index > 0 { - writeln!(writer)?; - } - self.render(child, writer)?; + for (index, item) in ItemRefIterator::without_hidden(item) + .filter(|item| !item.details.is_heading()) + .enumerate() + { + if index > 0 { + writeln!(writer)?; + } + match &item.details { + Details::Chart | Details::Image(_) => todo!(), + Details::Heading(_) => unreachable!(), + Details::Message(_diagnostic) => todo!(), + Details::PageBreak => (), + Details::Table(pivot_table) => self.render_table(pivot_table, writer)?, + Details::Text(text) => { + self.render_table(&PivotTable::from((**text).clone()), writer)? } - Ok(()) } - Details::Message(_diagnostic) => todo!(), - Details::PageBreak => Ok(()), - Details::Table(pivot_table) => self.render_table(pivot_table, writer), - Details::Text(text) => self.render_table(&PivotTable::from((**text).clone()), writer), } + Ok(()) } fn render_table(&mut self, table: &PivotTable, writer: &mut W) -> FmtResult -- 2.30.2