|
1 | | -use std::ops::ControlFlow; |
2 | 1 | use mlua::{Function, Lua, Table}; |
3 | 2 | use twox_hash::XxHash3_128; |
4 | 3 | use unicode_width::UnicodeWidthChar; |
@@ -26,32 +25,55 @@ impl Utils { |
26 | 25 | } |
27 | 26 |
|
28 | 27 | pub(super) fn truncate(lua: &Lua) -> mlua::Result<Function> { |
29 | | - fn truncate_impl(mut chars: impl Iterator<Item = char>, max: usize) -> Vec<char> { |
| 28 | + fn idx_and_width(it: impl Iterator<Item = (usize, char)>, max: usize) -> (usize, usize) { |
30 | 29 | let mut width = 0; |
31 | | - let flow = chars.try_fold(Vec::with_capacity(max), |mut v, c| { |
| 30 | + let idx = it |
| 31 | + .take_while(|(_, c)| { |
32 | 32 | width += c.width().unwrap_or(0); |
33 | | - if width < max { |
34 | | - v.push(c); |
35 | | - ControlFlow::Continue(v) |
36 | | - } else { |
37 | | - ControlFlow::Break(v) |
| 33 | + width <= max |
| 34 | + }) |
| 35 | + .map(|(i, _)| i) |
| 36 | + .last() |
| 37 | + .unwrap(); |
| 38 | + (idx, width) |
38 | 39 | } |
39 | | - }); |
40 | 40 |
|
41 | | - match flow { |
42 | | - ControlFlow::Break(v) => v, |
43 | | - ControlFlow::Continue(v) => v, |
| 41 | + lua.create_function(|lua, (s, t): (mlua::String, Table)| { |
| 42 | + let b = s.as_bytes(); |
| 43 | + if b.is_empty() { |
| 44 | + return Ok(s); |
44 | 45 | } |
| 46 | + |
| 47 | + let max = t.raw_get("max")?; |
| 48 | + if b.len() <= max { |
| 49 | + return Ok(s); |
| 50 | + } else if max < 1 { |
| 51 | + return lua.create_string(""); |
45 | 52 | } |
46 | 53 |
|
47 | | - lua.create_function(|_, (text, t): (mlua::String, Table)| { |
48 | | - let (max, text) = (t.raw_get("max")?, text.to_string_lossy()); |
| 54 | + let lossy = String::from_utf8_lossy(&b); |
| 55 | + let rtl = t.raw_get("rtl").unwrap_or(false); |
| 56 | + let (idx, width) = if rtl { |
| 57 | + idx_and_width(lossy.char_indices().rev(), max) |
| 58 | + } else { |
| 59 | + idx_and_width(lossy.char_indices(), max) |
| 60 | + }; |
| 61 | + |
| 62 | + if width <= max { |
| 63 | + return Ok(s); |
| 64 | + } else if rtl && idx == 0 { |
| 65 | + return Ok(s); |
| 66 | + } else if !rtl && lossy[idx..].chars().nth(1).is_none() { |
| 67 | + return Ok(s); |
| 68 | + } |
49 | 69 |
|
50 | | - Ok(if t.raw_get("rtl").unwrap_or(false) { |
51 | | - truncate_impl(text.chars().rev(), max).into_iter().rev().collect() |
| 70 | + let result: Vec<_> = if rtl { |
| 71 | + let i = lossy[idx..].char_indices().nth(1).map(|(i, _)| idx + i).unwrap_or(lossy.len()); |
| 72 | + "…".bytes().chain(lossy[i..].bytes()).collect() |
52 | 73 | } else { |
53 | | - truncate_impl(text.chars(), max).into_iter().collect::<String>() |
54 | | - }) |
| 74 | + lossy[..idx].bytes().chain("…".bytes()).collect() |
| 75 | + }; |
| 76 | + lua.create_string(result) |
55 | 77 | }) |
56 | 78 | } |
57 | 79 |
|
|
0 commit comments