diff --git a/benches/layout.rs b/benches/layout.rs index e5023de..a5dacfe 100644 --- a/benches/layout.rs +++ b/benches/layout.rs @@ -10,7 +10,7 @@ fn load_font_system(c: &mut Criterion) { fn layout(c: &mut Criterion) { let mut fs = ct::FontSystem::new(); let mut buffer = ct::Buffer::new(&mut fs, ct::Metrics::new(10.0, 10.0)); - buffer.set_size(&mut fs, 80.0, f32::MAX); + buffer.set_size(&mut fs, Some(80.0), None); for (wrap_name, wrap) in &[ ("None", ct::Wrap::None), diff --git a/examples/editor-test/src/main.rs b/examples/editor-test/src/main.rs index 0c4f46f..85bae2b 100644 --- a/examples/editor-test/src/main.rs +++ b/examples/editor-test/src/main.rs @@ -74,7 +74,7 @@ fn main() { let mut buffer = Buffer::new(&mut font_system, font_sizes[font_size_default]); buffer .borrow_with(&mut font_system) - .set_size(window.width() as f32, window.height() as f32); + .set_size(Some(window.width() as f32), Some(window.height() as f32)); let mut editor = Editor::new(buffer); diff --git a/examples/editor/src/main.rs b/examples/editor/src/main.rs index e0477bc..1ce0758 100644 --- a/examples/editor/src/main.rs +++ b/examples/editor/src/main.rs @@ -110,8 +110,8 @@ fn main() { editor.with_buffer_mut(|buffer| { buffer.set_size( - width as f32 - scrollbar_width * display_scale, - height as f32, + Some(width as f32 - scrollbar_width * display_scale), + Some(height as f32), ) }); diff --git a/examples/multiview/src/main.rs b/examples/multiview/src/main.rs index d95c588..5e14298 100644 --- a/examples/multiview/src/main.rs +++ b/examples/multiview/src/main.rs @@ -102,7 +102,7 @@ fn main() { // Set scroll to view scroll buffer.set_scroll(*scroll); // Set size, will relayout and shape until scroll if changed - buffer.set_size(width as f32, height as f32); + buffer.set_size(Some(width as f32), Some(height as f32)); // Shape until scroll, ensures scroll is clamped //TODO: ability to prune with multiple views? buffer.shape_until_scroll(true); @@ -154,10 +154,10 @@ fn main() { scroll.vertical -= buffer.metrics().line_height; } Key::Named(NamedKey::PageDown) => { - scroll.vertical += buffer.size().1; + scroll.vertical += buffer.size().1.unwrap_or(0.0); } Key::Named(NamedKey::PageUp) => { - scroll.vertical -= buffer.size().1; + scroll.vertical -= buffer.size().1.unwrap_or(0.0); } _ => {} } diff --git a/examples/rich-text/src/main.rs b/examples/rich-text/src/main.rs index 1044ea8..8a2f858 100644 --- a/examples/rich-text/src/main.rs +++ b/examples/rich-text/src/main.rs @@ -122,8 +122,8 @@ fn main() { let mut editor = editor.borrow_with(&mut font_system); editor.with_buffer_mut(|buffer| { buffer.set_size( - window.inner_size().width as f32, - window.inner_size().height as f32, + Some(window.inner_size().width as f32), + Some(window.inner_size().height as f32), ) }); editor.with_buffer_mut(|buffer| set_buffer_text(buffer)); @@ -182,7 +182,7 @@ fn main() { pixmap.fill(bg_color); editor.with_buffer_mut(|buffer| { - buffer.set_size(width as f32, height as f32) + buffer.set_size(Some(width as f32), Some(height as f32)) }); let mut paint = Paint::default(); diff --git a/examples/terminal/src/main.rs b/examples/terminal/src/main.rs index 1da762d..7e4bfbb 100644 --- a/examples/terminal/src/main.rs +++ b/examples/terminal/src/main.rs @@ -26,8 +26,8 @@ fn main() { // Set a size for the text buffer, in pixels let width = 80.0; - let height = f32::MAX; // The height is unbounded - buffer.set_size(width, height); + // The height is unbounded + buffer.set_size(Some(width), None); // Attributes indicate what font to choose let attrs = Attrs::new(); @@ -45,7 +45,6 @@ fn main() { const TEXT_COLOR: Color = Color::rgb(0xFF, 0xFF, 0xFF); // Set up the canvas - let width = buffer.size().0; let height = LINE_HEIGHT * buffer.layout_runs().count() as f32; let mut canvas = vec![vec![None; width as usize]; height as usize]; diff --git a/src/buffer.rs b/src/buffer.rs index 09befd3..175c135 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -129,8 +129,10 @@ impl<'b> Iterator for LayoutRunIter<'b> { let glyph_height = layout_line.max_ascent + layout_line.max_descent; let centering_offset = (line_height - glyph_height) / 2.0; let line_y = line_top + centering_offset + layout_line.max_ascent; - if line_top + centering_offset > self.buffer.height { - return None; + if let Some(height) = self.buffer.height_opt { + if line_top + centering_offset > height { + return None; + } } self.line_top += line_height; if line_y < 0.0 { @@ -203,8 +205,8 @@ pub struct Buffer { /// [BufferLine]s (or paragraphs) of text in the buffer pub lines: Vec, metrics: Metrics, - width: f32, - height: f32, + width_opt: Option, + height_opt: Option, scroll: Scroll, /// True if a redraw is requires. Set to false after processing redraw: bool, @@ -221,8 +223,8 @@ impl Clone for Buffer { Self { lines: self.lines.clone(), metrics: self.metrics, - width: self.width, - height: self.height, + width_opt: self.width_opt, + height_opt: self.height_opt, scroll: self.scroll, redraw: self.redraw, wrap: self.wrap, @@ -250,8 +252,8 @@ impl Buffer { Self { lines: Vec::new(), metrics, - width: 0.0, - height: 0.0, + width_opt: None, + height_opt: None, scroll: Scroll::default(), redraw: false, wrap: Wrap::WordOrGlyph, @@ -294,7 +296,7 @@ impl Buffer { &mut self.scratch, font_system, self.metrics.font_size, - Some(self.width), + self.width_opt, self.wrap, self.monospace_width, self.tab_width, @@ -315,7 +317,6 @@ impl Buffer { cursor: Cursor, prune: bool, ) { - let height = self.height; let metrics = self.metrics; let old_scroll = self.scroll; @@ -345,7 +346,7 @@ impl Buffer { // Adjust scroll backwards if cursor is before it self.scroll.line = layout_cursor.line; self.scroll.vertical = layout_y; - } else { + } else if let Some(height) = self.height_opt { // Adjust scroll forwards if cursor is after it let mut line_i = layout_cursor.line; while line_i > self.scroll.line { @@ -389,9 +390,11 @@ impl Buffer { self.scroll.horizontal = x_min; self.redraw = true; } - if x_max > self.scroll.horizontal + self.width { - self.scroll.horizontal = x_max - self.width; - self.redraw = true; + if let Some(width) = self.width_opt { + if x_max > self.scroll.horizontal + width { + self.scroll.horizontal = x_max - width; + self.redraw = true; + } } } } @@ -424,7 +427,7 @@ impl Buffer { } let scroll_start = self.scroll.vertical; - let scroll_end = scroll_start + self.height; + let scroll_end = scroll_start + self.height_opt.unwrap_or(f32::INFINITY); let mut total_height = 0.0; for line_i in 0..self.lines.len() { @@ -528,7 +531,7 @@ impl Buffer { &mut self.scratch, font_system, self.metrics.font_size, - Some(self.width), + self.width_opt, self.wrap, self.monospace_width, self.tab_width, @@ -546,7 +549,7 @@ impl Buffer { /// /// Will panic if `metrics.font_size` is zero. pub fn set_metrics(&mut self, font_system: &mut FontSystem, metrics: Metrics) { - self.set_metrics_and_size(font_system, metrics, self.width, self.height); + self.set_metrics_and_size(font_system, metrics, self.width_opt, self.height_opt); } /// Get the current [`Wrap`] @@ -608,13 +611,18 @@ impl Buffer { } /// Get the current buffer dimensions (width, height) - pub fn size(&self) -> (f32, f32) { - (self.width, self.height) + pub fn size(&self) -> (Option, Option) { + (self.width_opt, self.height_opt) } /// Set the current buffer dimensions - pub fn set_size(&mut self, font_system: &mut FontSystem, width: f32, height: f32) { - self.set_metrics_and_size(font_system, self.metrics, width, height); + pub fn set_size( + &mut self, + font_system: &mut FontSystem, + width_opt: Option, + height_opt: Option, + ) { + self.set_metrics_and_size(font_system, self.metrics, width_opt, height_opt); } /// Set the current [`Metrics`] and buffer dimensions at the same time @@ -626,17 +634,20 @@ impl Buffer { &mut self, font_system: &mut FontSystem, metrics: Metrics, - width: f32, - height: f32, + width_opt: Option, + height_opt: Option, ) { - let clamped_width = width.max(0.0); - let clamped_height = height.max(0.0); + let clamped_width_opt = width_opt.map(|width| width.max(0.0)); + let clamped_height_opt = height_opt.map(|height| height.max(0.0)); - if metrics != self.metrics || clamped_width != self.width || clamped_height != self.height { + if metrics != self.metrics + || clamped_width_opt != self.width_opt + || clamped_height_opt != self.height_opt + { assert_ne!(metrics.font_size, 0.0, "font size cannot be 0"); self.metrics = metrics; - self.width = clamped_width; - self.height = clamped_height; + self.width_opt = clamped_width_opt; + self.height_opt = clamped_height_opt; self.relayout(font_system); self.shape_until_scroll(font_system, false); } @@ -1128,20 +1139,24 @@ impl Buffer { cursor_x_opt = None; } Motion::PageUp => { - (cursor, cursor_x_opt) = self.cursor_motion( - font_system, - cursor, - cursor_x_opt, - Motion::Vertical(-self.size().1 as i32), - )?; + if let Some(height) = self.height_opt { + (cursor, cursor_x_opt) = self.cursor_motion( + font_system, + cursor, + cursor_x_opt, + Motion::Vertical(-height as i32), + )?; + } } Motion::PageDown => { - (cursor, cursor_x_opt) = self.cursor_motion( - font_system, - cursor, - cursor_x_opt, - Motion::Vertical(self.size().1 as i32), - )?; + if let Some(height) = self.height_opt { + (cursor, cursor_x_opt) = self.cursor_motion( + font_system, + cursor, + cursor_x_opt, + Motion::Vertical(height as i32), + )?; + } } Motion::Vertical(px) => { // TODO more efficient, use layout run line height @@ -1341,8 +1356,8 @@ impl<'a> BorrowedWithFontSystem<'a, Buffer> { } /// Set the current buffer dimensions - pub fn set_size(&mut self, width: f32, height: f32) { - self.inner.set_size(self.font_system, width, height); + pub fn set_size(&mut self, width_opt: Option, height_opt: Option) { + self.inner.set_size(self.font_system, width_opt, height_opt); } /// Set the current [`Metrics`] and buffer dimensions at the same time @@ -1350,9 +1365,14 @@ impl<'a> BorrowedWithFontSystem<'a, Buffer> { /// # Panics /// /// Will panic if `metrics.font_size` is zero. - pub fn set_metrics_and_size(&mut self, metrics: Metrics, width: f32, height: f32) { + pub fn set_metrics_and_size( + &mut self, + metrics: Metrics, + width_opt: Option, + height_opt: Option, + ) { self.inner - .set_metrics_and_size(self.font_system, metrics, width, height); + .set_metrics_and_size(self.font_system, metrics, width_opt, height_opt); } /// Set text of buffer, using provided attributes for each line by default diff --git a/src/edit/editor.rs b/src/edit/editor.rs index dd1bfff..eaf02cd 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -167,7 +167,7 @@ impl<'buffer> Editor<'buffer> { if run.glyphs.is_empty() && end.line > line_i { // Highlight all of internal empty lines - range_opt = Some((0, buffer.size().0 as i32)); + range_opt = Some((0, buffer.size().0.unwrap_or(0.0) as i32)); } if let Some((mut min, mut max)) = range_opt.take() { @@ -176,7 +176,7 @@ impl<'buffer> Editor<'buffer> { if run.rtl { min = 0; } else { - max = buffer.size().0 as i32; + max = buffer.size().0.unwrap_or(0.0) as i32; } } f( diff --git a/src/edit/syntect.rs b/src/edit/syntect.rs index ebd0b88..28f367f 100644 --- a/src/edit/syntect.rs +++ b/src/edit/syntect.rs @@ -201,7 +201,11 @@ impl<'syntax_system, 'buffer> SyntaxEditor<'syntax_system, 'buffer> { F: FnMut(i32, i32, u32, u32, Color), { let size = self.with_buffer(|buffer| buffer.size()); - f(0, 0, size.0 as u32, size.1 as u32, self.background_color()); + if let Some(width) = size.0 { + if let Some(height) = size.1 { + f(0, 0, width as u32, height as u32, self.background_color()); + } + } self.editor.draw( font_system, cache, @@ -263,7 +267,7 @@ impl<'syntax_system, 'buffer> Edit<'buffer> for SyntaxEditor<'syntax_system, 'bu self.editor.with_buffer_mut(|buffer| { let metrics = buffer.metrics(); let scroll = buffer.scroll(); - let scroll_end = scroll.vertical + buffer.size().1; + let scroll_end = scroll.vertical + buffer.size().1.unwrap_or(f32::INFINITY); let mut total_height = 0.0; let mut highlighted = 0; for line_i in 0..buffer.lines.len() { diff --git a/src/edit/vi.rs b/src/edit/vi.rs index 641a028..08dfd48 100644 --- a/src/edit/vi.rs +++ b/src/edit/vi.rs @@ -310,7 +310,11 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> { let selection_color = self.selection_color(); self.with_buffer(|buffer| { let size = buffer.size(); - f(0, 0, size.0 as u32, size.1 as u32, background_color); + if let Some(width) = size.0 { + if let Some(height) = size.1 { + f(0, 0, width as u32, height as u32, background_color); + } + } let font_size = buffer.metrics().font_size; for run in buffer.layout_runs() { let line_i = run.line_i; @@ -393,7 +397,7 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> { if run.glyphs.is_empty() && end.line > line_i { // Highlight all of internal empty lines - range_opt = Some((0, buffer.size().0 as i32)); + range_opt = Some((0, buffer.size().0.unwrap_or(0.0) as i32)); } if let Some((mut min, mut max)) = range_opt.take() { @@ -402,7 +406,7 @@ impl<'syntax_system, 'buffer> ViEditor<'syntax_system, 'buffer> { if run.rtl { min = 0; } else { - max = buffer.size().0 as i32; + max = buffer.size().0.unwrap_or(0.0) as i32; } } f( diff --git a/src/lib.rs b/src/lib.rs index b34f6a5..0efcc8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ //! let mut buffer = buffer.borrow_with(&mut font_system); //! //! // Set a size for the text buffer, in pixels -//! buffer.set_size(80.0, 25.0); +//! buffer.set_size(Some(80.0), Some(25.0)); //! //! // Attributes indicate what font to choose //! let attrs = Attrs::new(); diff --git a/src/shape.rs b/src/shape.rs index 251931b..3d7e61e 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -852,7 +852,7 @@ impl ShapeLine { for span in spans.iter_mut() { for word in span.words.iter_mut() { for glyph in word.glyphs.iter_mut() { - if &line[glyph.start..glyph.end] == "\t" { + if line.get(glyph.start..glyph.end) == Some("\t") { //TODO: better fallback for width let space_x_advance = glyph.font_monospace_em_width.unwrap_or(glyph.x_advance); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 20617d6..c290f2b 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -89,8 +89,8 @@ impl DrawTestCfg { let mut buffer = buffer.borrow_with(&mut font_system); let margins = 5; buffer.set_size( - (self.canvas_width - margins * 2) as f32, - (self.canvas_height - margins * 2) as f32, + Some((self.canvas_width - margins * 2) as f32), + Some((self.canvas_height - margins * 2) as f32), ); buffer.set_text(&self.text, self.font.as_attrs(), Shaping::Advanced); buffer.shape_until_scroll(true); diff --git a/tests/wrap_stability.rs b/tests/wrap_stability.rs index be48ada..11188fc 100644 --- a/tests/wrap_stability.rs +++ b/tests/wrap_stability.rs @@ -108,7 +108,7 @@ fn wrap_extra_line() { buffer.set_text("Lorem ipsum dolor sit amet, qui minim labore adipisicing\n\nweeewoooo minim sint cillum sint consectetur cupidatat.", Attrs::new().family(cosmic_text::Family::Name("Inter")), Shaping::Advanced); // Set a size for the text buffer, in pixels - buffer.set_size(50.0, 1000.0); + buffer.set_size(Some(50.0), Some(1000.0)); // Perform shaping as desired buffer.shape_until_scroll(false); diff --git a/tests/wrap_word_fallback.rs b/tests/wrap_word_fallback.rs index b613fe2..3a2b474 100644 --- a/tests/wrap_word_fallback.rs +++ b/tests/wrap_word_fallback.rs @@ -16,17 +16,17 @@ fn wrap_word_fallback() { buffer.set_wrap(Wrap::WordOrGlyph); buffer.set_text("Lorem ipsum dolor sit amet, qui minim labore adipisicing minim sint cillum sint consectetur cupidatat.", Attrs::new().family(cosmic_text::Family::Name("Inter")), Shaping::Advanced); - buffer.set_size(50.0, 1000.0); + buffer.set_size(Some(50.0), Some(1000.0)); buffer.shape_until_scroll(false); let measured_size = measure(&buffer); assert!( - measured_size <= buffer.size().0, + measured_size <= buffer.size().0.unwrap_or(0.0), "Measured width is larger than buffer width\n{} <= {}", measured_size, - buffer.size().0 + buffer.size().0.unwrap_or(0.0) ); }