From: Ben Pfaff Date: Sat, 8 Mar 2025 20:52:24 +0000 (-0800) Subject: text driver is finished? X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2caf5f1525c79d16a3e16338cc94c8068049f8b2;p=pspp text driver is finished? --- diff --git a/rust/pspp/src/output/text.rs b/rust/pspp/src/output/text.rs index 778f49292d..1a70a9769e 100644 --- a/rust/pspp/src/output/text.rs +++ b/rust/pspp/src/output/text.rs @@ -2,7 +2,7 @@ use std::{ borrow::Cow, fs::File, io::{BufWriter, Write}, - ops::Range, + ops::{Index, Range}, sync::{Arc, LazyLock}, }; @@ -78,8 +78,13 @@ impl BoxChars { self.0[Lines { r, b, l, t }] = c; } } - fn get(&self, lines: Lines) -> char { - self.0[lines] +} + +impl Index for BoxChars { + type Output = char; + + fn index(&self, lines: Lines) -> &Self::Output { + &self.0[lines] } } @@ -275,15 +280,15 @@ impl TextDriver { .with_footnotes(cell.footnotes) } - fn layout_cell(&self, cell: &DrawCell, mut text: &str, bb: Rect2, clip: Rect2) -> Coord2 { + fn layout_cell(&self, text: &str, bb: Rect2) -> Coord2 { if text.is_empty() { return Coord2::default(); } use Axis2::*; - let mut breaks = new_line_breaks(text, bb[X].len()); + let breaks = new_line_breaks(text, bb[X].len()); let mut size = Coord2::new(0, 0); - for (text, _y) in breaks.zip(bb[Y].clone()) { + for text in breaks.take(bb[Y].len()) { let width = text.width(); if width > size[X] { size[X] = width; @@ -293,10 +298,11 @@ impl TextDriver { size } - fn reserve(&mut self, y: usize) { + fn get_line(&mut self, y: usize) -> &mut TextLine { if y >= self.lines.len() { self.lines.resize(y + 1, TextLine::new()); } + &mut self.lines[y] } } @@ -438,10 +444,10 @@ impl Driver for TextDriver { Details::Chart => todo!(), Details::Image => todo!(), Details::Group(_) => todo!(), - Details::Message(diagnostic) => todo!(), + Details::Message(_diagnostic) => todo!(), Details::PageBreak => (), Details::Table(pivot_table) => self.output_table(pivot_table), - Details::Text(text) => todo!(), + Details::Text(_text) => todo!(), } } } @@ -453,38 +459,39 @@ impl Device for TextDriver { fn measure_cell_width(&self, cell: &DrawCell) -> [usize; 2] { let text = Self::display_cell(cell).to_string(); - let max_width = self.layout_cell( - cell, - &text, - Rect2::new(0..usize::MAX, 0..usize::MAX), - Rect2::default(), - ); - let min_width = self.layout_cell( - cell, - &text, - Rect2::new(0..1, 0..usize::MAX), - Rect2::default(), - ); + let max_width = self.layout_cell(&text, Rect2::new(0..usize::MAX, 0..usize::MAX)); + let min_width = self.layout_cell(&text, Rect2::new(0..1, 0..usize::MAX)); [min_width.x(), max_width.x()] } fn measure_cell_height(&self, cell: &DrawCell, width: usize) -> usize { let text = Self::display_cell(cell).to_string(); - self.layout_cell( - cell, - &text, - Rect2::new(0..width, 0..usize::MAX), - Rect2::default(), - ) - .y() + self.layout_cell(&text, Rect2::new(0..width, 0..usize::MAX)) + .y() } - fn adjust_break(&self, cell: &Content, size: Coord2) -> usize { + fn adjust_break(&self, _cell: &Content, _size: Coord2) -> usize { unreachable!() } fn draw_line(&mut self, bb: Rect2, styles: EnumMap) { - todo!() + use Axis2::*; + let x = bb[X].start.max(0)..bb[X].end.min(self.width); + let y = bb[Y].start.max(0)..bb[Y].end; + if x.is_empty() || x.end >= self.width { + return; + } + + 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(), + }; + let c = self.box_chars[lines]; + for y in y { + self.get_line(y).put_multiple(x.start, c, x.len()); + } } fn draw_cell( @@ -493,7 +500,7 @@ impl Device for TextDriver { _alternate_row: bool, bb: &Rect2, valign_offset: usize, - spill: EnumMap, + _spill: EnumMap, clip: &Rect2, ) { let display = Self::display_cell(cell); @@ -505,7 +512,7 @@ impl Device for TextDriver { .unwrap_or_else(|| HorzAlign::for_mixed(display.var_type())); use Axis2::*; - let mut breaks = new_line_breaks(&text, bb[X].len()); + let breaks = new_line_breaks(&text, bb[X].len()); for (text, y) in breaks.zip(bb[Y].start + valign_offset..bb[Y].end) { let width = text.width(); if !clip[Y].contains(&y) { @@ -521,12 +528,11 @@ impl Device for TextDriver { continue; }; - self.reserve(y); - self.lines[y].put(x, text); + self.get_line(y).put(x, text); } } - fn scale(&mut self, factor: f64) { - todo!() + fn scale(&mut self, _factor: f64) { + unimplemented!() } } diff --git a/rust/pspp/src/output/text_line.rs b/rust/pspp/src/output/text_line.rs index 21e9e9a395..b861da2df3 100644 --- a/rust/pspp/src/output/text_line.rs +++ b/rust/pspp/src/output/text_line.rs @@ -43,15 +43,17 @@ impl TextLine { self.width = x; } - pub fn put(&mut self, x0: usize, s: &str) { - let w = Widths::new(s).sum::(); + fn put_closure(&mut self, x0: usize, w: usize, push_str: F) + where + F: FnOnce(&mut String), + { let x1 = x0 + w; if w == 0 { // Nothing to do. } else if x0 >= self.width { // The common case: adding new characters at the end of a line. self.string.extend((self.width..x0).map(|_| ' ')); - self.string.push_str(s); + push_str(&mut self.string); self.width = x1; } else if x1 >= self.width { let p0 = self.find_pos(x0); @@ -60,23 +62,31 @@ impl TextLine { // replace its first character width by `?`. self.string.truncate(p0.offsets.start); self.string.extend((p0.columns.start..x0).map(|_| '?')); - self.string.push_str(s); + push_str(&mut self.string); self.width = x1; } else { let span = self.find_span(x0, x1); - if span.columns.start < x0 || span.columns.end > x1 { - let tail = self.string.split_off(span.offsets.end); - self.string.truncate(span.offsets.start); - self.string.extend((span.columns.start..x0).map(|_| '?')); - self.string.push_str(s); - self.string.extend((x1..span.columns.end).map(|_| '?')); - self.string.push_str(&tail); - } else { - self.string.replace_range(span.offsets, s); - } + let tail = self.string.split_off(span.offsets.end); + self.string.truncate(span.offsets.start); + self.string.extend((span.columns.start..x0).map(|_| '?')); + push_str(&mut self.string); + self.string.extend((x1..span.columns.end).map(|_| '?')); + self.string.push_str(&tail); } } + pub fn put(&mut self, x0: usize, s: &str) { + self.string.reserve(s.len()); + self.put_closure(x0, Widths::new(s).sum(), |dst| dst.push_str(s)); + } + + pub fn put_multiple(&mut self, x0: usize, c: char, n: usize) { + self.string.reserve(c.len_utf8() * n); + self.put_closure(x0, c.width().unwrap() * n, |dst| { + (0..n).for_each(|_| dst.push(c)) + }); + } + fn find_span(&self, x0: usize, x1: usize) -> Position { debug_assert!(x1 > x0); let p0 = self.find_pos(x0);