borrow::Cow,
fs::File,
io::{BufWriter, Write},
- ops::Range,
+ ops::{Index, Range},
sync::{Arc, LazyLock},
};
self.0[Lines { r, b, l, t }] = c;
}
}
- fn get(&self, lines: Lines) -> char {
- self.0[lines]
+}
+
+impl Index<Lines> for BoxChars {
+ type Output = char;
+
+ fn index(&self, lines: Lines) -> &Self::Output {
+ &self.0[lines]
}
}
.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;
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]
}
}
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!(),
}
}
}
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<Axis2, [BorderStyle; 2]>) {
- 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(
_alternate_row: bool,
bb: &Rect2,
valign_offset: usize,
- spill: EnumMap<Axis2, [usize; 2]>,
+ _spill: EnumMap<Axis2, [usize; 2]>,
clip: &Rect2,
) {
let display = Self::display_cell(cell);
.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) {
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!()
}
}
self.width = x;
}
- pub fn put(&mut self, x0: usize, s: &str) {
- let w = Widths::new(s).sum::<usize>();
+ fn put_closure<F>(&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);
// 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);