Skip to content

Commit

Permalink
fix: unicode truncation bug (#1089)
Browse files Browse the repository at this point in the history
- Rewrote the line / span rendering code to take into account how
multi-byte / wide emoji characters are truncated when rendering into
areas that cannot accommodate them in the available space
- Added comprehensive coverage over the edge cases
- Adds a benchmark to ensure perf

Fixes: #1032
Co-authored-by: EdJoPaTo <rfc-conform-git-commit-email@funny-long-domain-label-everyone-hates-as-it-is-too-long.edjopato.de>
Co-authored-by: EdJoPaTo <[email protected]>
  • Loading branch information
3 people committed May 12, 2024
1 parent 3cc29bd commit 699c2d7
Show file tree
Hide file tree
Showing 4 changed files with 399 additions and 112 deletions.
22 changes: 13 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,24 +25,24 @@ rust-version = "1.74.0"
[badges]

[dependencies]
crossterm = { version = "0.27", optional = true }
termion = { version = "3.0", optional = true }
termwiz = { version = "0.22.0", optional = true }

serde = { version = "1", optional = true, features = ["derive"] }
bitflags = "2.3"
cassowary = "0.3"
compact_str = "0.7.1"
crossterm = { version = "0.27", optional = true }
document-features = { version = "0.2.7", optional = true }
indoc = "2.0"
itertools = "0.12"
lru = "0.12.0"
paste = "1.0.2"
serde = { version = "1", optional = true, features = ["derive"] }
stability = "0.2.0"
strum = { version = "0.26", features = ["derive"] }
time = { version = "0.3.11", optional = true, features = ["local-offset"] }
termion = { version = "3.0", optional = true }
termwiz = { version = "0.22.0", optional = true }
unicode-segmentation = "1.10"
unicode-truncate = "1"
unicode-width = "0.1"
document-features = { version = "0.2.7", optional = true }
lru = "0.12.0"
stability = "0.2.0"
compact_str = "0.7.1"

[dev-dependencies]
anyhow = "1.0.71"
Expand Down Expand Up @@ -163,6 +163,10 @@ harness = false
name = "block"
harness = false

[[bench]]
name = "line"
harness = false

[[bench]]
name = "list"
harness = false
Expand Down
39 changes: 39 additions & 0 deletions benches/line.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::hint::black_box;

use criterion::{criterion_group, criterion_main, Criterion};
use ratatui::{
buffer::Buffer,
layout::{Alignment, Rect},
style::Stylize,
text::Line,
widgets::Widget,
};

fn line_render(criterion: &mut Criterion) {
for alignment in [Alignment::Left, Alignment::Center, Alignment::Right] {
let mut group = criterion.benchmark_group(format!("line_render/{alignment}"));
group.sample_size(1000);

let line = &Line::from(vec![
"This".red(),
" ".green(),
"is".italic(),
" ".blue(),
"SPARTA!!".bold(),
])
.alignment(alignment);

for width in [0, 3, 4, 6, 7, 10, 42] {
let area = Rect::new(0, 0, width, 1);

group.bench_function(width.to_string(), |bencher| {
let mut buffer = Buffer::empty(area);
bencher.iter(|| black_box(line).render(area, &mut buffer));
});
}
group.finish();
}
}

criterion_group!(benches, line_render);
criterion_main!(benches);
12 changes: 12 additions & 0 deletions src/layout/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,18 @@ impl Rect {
height: self.height,
}
}

/// indents the x value of the `Rect` by a given `offset`
///
/// This is pub(crate) for now as we need to stabilize the naming / design of this API.
#[must_use]
pub(crate) const fn indent_x(self, offset: u16) -> Self {
Self {
x: self.x.saturating_add(offset),
width: self.width.saturating_sub(offset),
..self
}
}
}

impl From<(Position, Size)> for Rect {
Expand Down

0 comments on commit 699c2d7

Please sign in to comment.