aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoralex-ds13 <145657253+alex-ds13@users.noreply.github.com>2025-11-25 18:43:51 +0000
committerPolesznyák Márk <contact@pml68.dev>2025-12-29 23:23:41 +0100
commit99ee469c86c8c187d874253ad8f0e3274cf97943 (patch)
tree30e27d835a2e942bfa1aa9365d121bec3084b704 /src
parentfix: outbounds selecting when inside a scrollable (diff)
downloadiced_selection-99ee469c86c8c187d874253ad8f0e3274cf97943.tar.gz
fix: select graphemes with multi codepoints properly
- We continue to use the graphemes index for the selection ends, however when calculating the selection rectangles we now check if the visual line had any glyph with `start` and `end` index bigger than 1 before or within the range and update the range accordingly. This way all the code that checks for word boundaries when selecting by words still functions properly.
Diffstat (limited to 'src')
-rw-r--r--src/text.rs38
-rw-r--r--src/text/rich.rs38
2 files changed, 48 insertions, 28 deletions
diff --git a/src/text.rs b/src/text.rs
index ac51395..143a78d 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -831,7 +831,7 @@ fn highlight_line(
.map(|glyph| glyph.end)
.unwrap_or(0);
- let range = start.max(from)..end.min(to);
+ let mut range = start.max(from)..end.min(to);
let x_offset = visual_line
.glyphs
@@ -844,21 +844,31 @@ fn highlight_line(
} else if range.start == start && range.end == end {
(x_offset, visual_line.w)
} else {
- let first_glyph = visual_line
- .glyphs
- .iter()
- .position(|glyph| range.start <= glyph.start)
- .unwrap_or(0);
-
- let mut glyphs = visual_line.glyphs.iter();
+ let mut x = 0.0;
+ let mut width = 0.0;
+ for glyph in &visual_line.glyphs {
+ let glyph_count = glyph.start.abs_diff(glyph.end);
+
+ // Check for multi codepoint glyphs before or within the range
+ if glyph_count > 1 {
+ if range.start > glyph.start {
+ range.start += glyph_count - 1;
+ range.end += glyph_count - 1;
+ } else if range.end > glyph.start {
+ range.end += glyph_count - 1;
+ }
+ }
- let x: f32 =
- glyphs.by_ref().take(first_glyph).map(|glyph| glyph.w).sum();
+ if range.start > glyph.start {
+ x += glyph.w;
+ }
- let width: f32 = glyphs
- .take_while(|glyph| range.end > glyph.start)
- .map(|glyph| glyph.w)
- .sum();
+ if range.start <= glyph.start && range.end > glyph.start {
+ width += glyph.w;
+ } else if range.end <= glyph.start {
+ break;
+ }
+ }
(x_offset + x, width)
}
diff --git a/src/text/rich.rs b/src/text/rich.rs
index 9f53387..597fa26 100644
--- a/src/text/rich.rs
+++ b/src/text/rich.rs
@@ -983,7 +983,7 @@ fn highlight_line(
.map(|glyph| glyph.end)
.unwrap_or(0);
- let range = start.max(from)..end.min(to);
+ let mut range = start.max(from)..end.min(to);
let x_offset = visual_line
.glyphs
@@ -996,21 +996,31 @@ fn highlight_line(
} else if range.start == start && range.end == end {
(x_offset, visual_line.w)
} else {
- let first_glyph = visual_line
- .glyphs
- .iter()
- .position(|glyph| range.start <= glyph.start)
- .unwrap_or(0);
-
- let mut glyphs = visual_line.glyphs.iter();
+ let mut x = 0.0;
+ let mut width = 0.0;
+ for glyph in &visual_line.glyphs {
+ let glyph_count = glyph.start.abs_diff(glyph.end);
+
+ // Check for multi codepoint glyphs before or within the range
+ if glyph_count > 1 {
+ if range.start > glyph.start {
+ range.start += glyph_count - 1;
+ range.end += glyph_count - 1;
+ } else if range.end > glyph.start {
+ range.end += glyph_count - 1;
+ }
+ }
- let x: f32 =
- glyphs.by_ref().take(first_glyph).map(|glyph| glyph.w).sum();
+ if range.start > glyph.start {
+ x += glyph.w;
+ }
- let width: f32 = glyphs
- .take_while(|glyph| range.end > glyph.start)
- .map(|glyph| glyph.w)
- .sum();
+ if range.start <= glyph.start && range.end > glyph.start {
+ width += glyph.w;
+ } else if range.end <= glyph.start {
+ break;
+ }
+ }
(x_offset + x, width)
}