Use unicode-segmentation for text_input::Value

This commit is contained in:
Héctor Ramón Jiménez 2019-12-06 04:46:53 +01:00
parent 114a759d2c
commit a56eef0fec
2 changed files with 34 additions and 18 deletions

View File

@ -11,3 +11,4 @@ repository = "https://github.com/hecrj/iced"
iced_core = { version = "0.1.0", path = "../core", features = ["command"] } iced_core = { version = "0.1.0", path = "../core", features = ["command"] }
twox-hash = "1.5" twox-hash = "1.5"
raw-window-handle = "0.3" raw-window-handle = "0.3"
unicode-segmentation = "1.6"

View File

@ -9,6 +9,7 @@ use crate::{
layout, Element, Event, Hasher, Layout, Length, Point, Rectangle, Size, layout, Element, Event, Hasher, Layout, Length, Point, Rectangle, Size,
Widget, Widget,
}; };
use unicode_segmentation::UnicodeSegmentation;
/// A field that can be filled with text. /// A field that can be filled with text.
/// ///
@ -441,23 +442,29 @@ impl State {
/// The value of a [`TextInput`]. /// The value of a [`TextInput`].
/// ///
/// [`TextInput`]: struct.TextInput.html /// [`TextInput`]: struct.TextInput.html
// TODO: Use `unicode-segmentation` // TODO: Reduce allocations, cache results (?)
#[derive(Debug)] #[derive(Debug)]
pub struct Value(Vec<char>); pub struct Value {
graphemes: Vec<String>,
}
impl Value { impl Value {
/// Creates a new [`Value`] from a string slice. /// Creates a new [`Value`] from a string slice.
/// ///
/// [`Value`]: struct.Value.html /// [`Value`]: struct.Value.html
pub fn new(string: &str) -> Self { pub fn new(string: &str) -> Self {
Self(string.chars().collect()) let graphemes = UnicodeSegmentation::graphemes(string, true)
.map(String::from)
.collect();
Self { graphemes }
} }
/// Returns the total amount of `char` in the [`Value`]. /// Returns the total amount of graphemes in the [`Value`].
/// ///
/// [`Value`]: struct.Value.html /// [`Value`]: struct.Value.html
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.0.len() self.graphemes.len()
} }
/// Returns the position of the previous start of a word from the given /// Returns the position of the previous start of a word from the given
@ -469,9 +476,9 @@ impl Value {
while index > 0 { while index > 0 {
if skip_space { if skip_space {
skip_space = self.0[index - 1] == ' '; skip_space = self.graphemes[index - 1] == " ";
} else { } else {
if self.0[index - 1] == ' ' { if self.graphemes[index - 1] == " " {
break; break;
} }
} }
@ -488,11 +495,11 @@ impl Value {
pub fn next_end_of_word(&self, mut index: usize) -> usize { pub fn next_end_of_word(&self, mut index: usize) -> usize {
let mut skip_space = true; let mut skip_space = true;
while index < self.0.len() { while index < self.graphemes.len() {
if skip_space { if skip_space {
skip_space = self.0[index] == ' '; skip_space = self.graphemes[index] == " ";
} else { } else {
if self.0[index] == ' ' { if self.graphemes[index] == " " {
break; break;
} }
} }
@ -503,33 +510,41 @@ impl Value {
index index
} }
/// Returns a new [`Value`] containing the `char` until the given `index`. /// Returns a new [`Value`] containing the graphemes until the given `index`.
/// ///
/// [`Value`]: struct.Value.html /// [`Value`]: struct.Value.html
pub fn until(&self, index: usize) -> Self { pub fn until(&self, index: usize) -> Self {
Self(self.0[..index.min(self.len())].to_vec()) let graphemes = self.graphemes[..index.min(self.len())].to_vec();
Self { graphemes }
} }
/// Converts the [`Value`] into a `String`. /// Converts the [`Value`] into a `String`.
/// ///
/// [`Value`]: struct.Value.html /// [`Value`]: struct.Value.html
pub fn to_string(&self) -> String { pub fn to_string(&self) -> String {
use std::iter::FromIterator; self.graphemes.concat()
String::from_iter(self.0.iter())
} }
/// Inserts a new `char` at the given `index`. /// Inserts a new `char` at the given grapheme `index`.
/// ///
/// [`Value`]: struct.Value.html /// [`Value`]: struct.Value.html
pub fn insert(&mut self, index: usize, c: char) { pub fn insert(&mut self, index: usize, c: char) {
self.0.insert(index, c); self.graphemes.insert(index, c.to_string());
self.graphemes = UnicodeSegmentation::graphemes(
self.graphemes.concat().as_ref() as &str,
true,
)
.map(String::from)
.collect();
} }
/// Removes the `char` at the given `index`. /// Removes the grapheme at the given `index`.
/// ///
/// [`Value`]: struct.Value.html /// [`Value`]: struct.Value.html
pub fn remove(&mut self, index: usize) { pub fn remove(&mut self, index: usize) {
let _ = self.0.remove(index); let _ = self.graphemes.remove(index);
} }
} }