"parking_lot_core",
]
+[[package]]
+name = "derive_more"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.87",
+ "unicode-xid",
+]
+
[[package]]
name = "diff"
version = "0.1.13"
"chrono",
"clap",
"color",
+ "derive_more",
"diff",
"either",
"encoding_rs",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
[[package]]
name = "url"
version = "2.5.2"
color = { version = "0.2.3", features = ["serde"] }
binrw = "0.14.1"
ndarray = "0.16.1"
+derive_more = { version = "2.0.1", features = ["debug"] }
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.48.0", features = ["Win32_Globalization"] }
///
/// 5. A template. PSPP doesn't create these itself yet, but it can read and
/// interpret those created by SPSS.
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Default)]
pub struct Value {
pub inner: ValueInner,
pub styling: Option<Box<ValueStyle>>,
}
}
+impl Debug for Value {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{:?}", self.display(()).to_string())
+ }
+}
+
#[derive(Clone, Debug, Default)]
pub enum ValueInner {
Number {
self.output_footnotes(&self.collect_footnotes(tables.into_iter().flatten()));
OutputTables {
- title,
- layers,
+ title: None,
+ layers: None,
body,
- caption,
- footnotes,
+ caption: None,
+ footnotes: None,
}
}
fn new(table: Arc<Table>, device: &dyn Device, min_width: usize, look: &Look) -> Self {
use Axis2::*;
- println!("{table:#?}");
+ dbg!(&table);
let n = table.n.clone();
// Figure out rule widths.
+ //
+ // `rules[X]` is vertical rules.
+ // `rules[Y]` is horizontal rules.
let rules = EnumMap::from_fn(|axis| {
(0..=n[axis])
.map(|z| measure_rule(&*device, &*table, axis, z))
.collect::<Vec<_>>()
});
+ dbg!(&rules);
let px_size = device.params().px_size.unwrap_or_default();
let heading_widths = look
}
}
}
+ dbg!(&unspanned_columns);
// Distribute widths of spanned columns.
let mut columns = unspanned_columns.clone();
columns[1][i] = columns[0][i];
}
}
+ dbg!(&columns);
// Decide final column widths.
let rule_widths = rules[X].iter().copied().sum::<usize>();
.iter()
.map(|row| row.iter().sum::<usize>() + rule_widths)
.collect::<SmallVec<[usize; 2]>>();
+ dbg!(&table_widths);
let cp_x = if table_widths[1] <= device.params().size[X] {
// Fits even with maximum widths. Use them.
// later we can break it horizontally into multiple pages.
Self::use_row_widths(&columns[0], &rules[X])
};
+ dbg!(&cp_x);
// Calculate heights of cells that do not span multiple rows.
let mut unspanned_rows = vec![0; n[Y]];
}
}
- fn accumulate_vec(mut vec: Vec<usize>) -> Vec<usize> {
+ fn use_row_widths(rows: &[usize], rules: &[usize]) -> Vec<usize> {
+ let mut vec = once(0)
+ .chain(interleave(rules, rows).copied())
+ .collect::<Vec<_>>();
for i in 1..vec.len() {
vec[i] += vec[i - 1]
}
vec
}
- fn use_row_widths(rows: &[usize], rules: &[usize]) -> Vec<usize> {
- once(0).chain(interleave(rules, rows).copied()).collect()
- }
-
fn interpolate_row_widths(
params: &Params,
rows_min: &[usize],
let mut x = cells[X].start;
while x < cells[X].end {
if !is_rule(x) && !is_rule(y) {
- let cell = self.get_cell(Coord2::new(x, y));
+ let cell = self.get_cell(Coord2::new(x / 2, y / 2));
self.draw_cell(device, ofs, &cell);
x = rule_ofs(cell.rect[X].end);
} else {
for y in cells[Y].clone() {
for x in cells[X].clone() {
- if is_rule(x) && is_rule(y) {
+ if is_rule(x) || is_rule(y) {
self.draw_rule(device, ofs, Coord2::new(x, y));
}
}
self.cp[a][cell.rect[a].start * 2 + 1]..self.cp[a][cell.rect[a].end * 2]
})
.translate(ofs);
- let spill = EnumMap::from_fn(|a| {
- [
- self.rule_width(a, cell.rect[a].start) / 2,
- self.rule_width(a, cell.rect[a].end) / 2,
- ]
- });
+ /*
+ let spill = EnumMap::from_fn(|a| {
+ [
+ self.rule_width(a, cell.rect[a].start) / 2,
+ self.rule_width(a, cell.rect[a].end) / 2,
+ ]
+ });*/
+ let spill = EnumMap::from_fn(|_| [0, 0]);
let clip = if let Some(overflow) = self.overflows.get(&cell.rect.top_left()) {
Rect2::from_fn(|a| {
spanned: &mut [usize],
rules: &[usize],
) {
- println!("{unspanned:?}");
- println!("{spanned:?}");
- println!("{rules:?}");
let n = unspanned.len();
debug_assert!(n >= 1);
debug_assert_eq!(spanned.len(), n);
debug_assert_eq!(rules.len(), n + 1);
- let total_unspanned =
- unspanned.iter().sum::<usize>() + (&rules[1..n - 1]).iter().copied().sum::<usize>();
+ let total_unspanned = unspanned.iter().sum::<usize>()
+ + rules
+ .get(1..n - 1)
+ .map_or(0, |rules| rules.iter().copied().sum::<usize>());
if total_unspanned >= width {
return;
}
}
fn find_breakpoint(&mut self, device: &dyn Device, size: usize) -> Option<(usize, usize)> {
- println!("{:?} {:?}", self.axis, self.z..self.page.n[self.axis]);
+ dbg!(self.axis, self.z..self.page.n[self.axis]);
for z in self.z..self.page.n[self.axis] {
let needed = self.needed_size(z + 1);
if needed > size {
layer_indexes.unwrap_or(&pivot_table.current_layer),
device.params().printing,
);
- println!("{:#?}", pivot_table);
- println!("{:#?}", output.body);
// Figure out the width of the body of the table. Use this to determine
// the base scale.
/// True if there's content left to rnder.
pub fn has_next(&mut self, device: &dyn Device) -> bool {
+ return !self.pages.is_empty();
while self
.y_break
.as_mut()
pub fn draw_next(&mut self, device: &mut dyn Device, mut space: usize) -> usize {
use Axis2::*;
+ let page = self.pages.pop().unwrap();
+ page.draw(device, Coord2::new(0, 0));
+ return page.total_size(Y);
+
if self.scale != 1.0 {
device.scale(self.scale);
space = (space as f64 / self.scale) as usize;
}
/// A table.
-#[derive(Debug)]
+#[derive(derive_more::Debug)]
pub struct Table {
/// Number of rows and columns.
pub n: Coord2,
pub contents: Array2<Content>,
/// Styles for areas of the table.
+ #[debug(skip)]
pub areas: EnumMap<Area, AreaStyle>,
/// Styles for borders in the table.
+ #[debug(skip)]
pub borders: EnumMap<Border, BorderStyle>,
- /// Horizontal and vertical rules.
+ /// Horizontal ([Axis2::Y]) and vertical ([Axis2::X]) rules.
pub rules: EnumMap<Axis2, Array2<Border>>,
/// How to present values.
+ #[debug(skip)]
pub value_options: ValueOptions,
}
areas,
borders,
rules: enum_map! {
- Axis2::X => Array::from_elem((n.x(), n.y() + 1), Border::Title),
- Axis2::Y => Array::from_elem((n.x() + 1, n.y()), Border::Title),
+ Axis2::X => Array::from_elem((n.x() + 1, n.y()), Border::Title),
+ Axis2::Y => Array::from_elem((n.x(), n.y() + 1), Border::Title),
},
value_options,
}
debug_assert!(x.start <= x.end);
debug_assert!(x.end <= self.n.x());
for x in x {
- self.rules[Axis2::X][[x, y]] = border;
+ self.rules[Axis2::Y][[x, y]] = border;
}
}
debug_assert!(y.start <= y.end);
debug_assert!(y.end <= self.n.y());
for y in y {
- self.rules[Axis2::Y][[x, y]] = border;
+ self.rules[Axis2::X][[x, y]] = border;
}
}
}
self.n_objects += 1;
- pager.draw_next(self, usize::MAX);
+ let h = pager.draw_next(self, usize::MAX);
+
+ for (ln, line) in self.lines[..h].iter_mut().enumerate() {
+ println!("{ln}: {}", line);
+ line.clear();
+ }
}
}
}
} else {
postindex
};
- println!("index={index} {:?}", &self.text[index..]);
if index <= self.indexes.end {
dbg!();
continue;
let segment_width = self.text[self.indexes.end..index].width();
if self.width == 0 || self.width + segment_width <= self.max_width {
- dbg!();
// Add this segment to the current line.
self.width += segment_width;
self.indexes.end = index;
// If this was a new-line, we're done.
if opportunity == BreakOpportunity::Mandatory {
- dbg!();
let segment = self.text[self.indexes.clone()].trim_end_matches('\n');
self.indexes = postindex..postindex;
self.width = 0;
}
let lines = Lines {
- l: styles[X][0].stroke.into(),
- r: styles[X][1].stroke.into(),
- t: styles[Y][0].stroke.into(),
- b: styles[Y][1].stroke.into(),
+ l: styles[Y][0].stroke.into(),
+ r: styles[Y][1].stroke.into(),
+ t: styles[X][0].stroke.into(),
+ b: styles[X][1].stroke.into(),
};
let c = self.box_chars[lines];
for y in y {
) {
let display = Self::display_cell(cell);
let text = display.to_string();
+ println!("text={text:?} bb={bb:?}");
let horz_align = cell
.style
.cell_style
use enum_iterator::Sequence;
-use std::{borrow::Cow, fmt::Debug, ops::Range};
+use std::{
+ borrow::Cow,
+ fmt::{Debug, Display},
+ ops::Range,
+};
use unicode_width::UnicodeWidthChar;
}
}
- fn str(&self) -> &str {
+ pub fn str(&self) -> &str {
&self.string
}
}
+impl Display for TextLine {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_str(&self.string)
+ }
+}
+
/// Position of one or more characters within a [TextLine].
#[derive(Debug)]
struct Position {