core: Add string_utils char boundary functions
This commit is contained in:
parent
b81cb1a3eb
commit
beed570475
|
@ -10,6 +10,7 @@ use crate::font::{round_down_to_pixel, Glyph};
|
||||||
use crate::html::{BoxBounds, FormatSpans, LayoutBox, LayoutContent, TextFormat};
|
use crate::html::{BoxBounds, FormatSpans, LayoutBox, LayoutContent, TextFormat};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::shape_utils::DrawCommand;
|
use crate::shape_utils::DrawCommand;
|
||||||
|
use crate::string_utils;
|
||||||
use crate::tag_utils::SwfMovie;
|
use crate::tag_utils::SwfMovie;
|
||||||
use crate::transform::Transform;
|
use crate::transform::Transform;
|
||||||
use crate::types::{Degrees, Percent};
|
use crate::types::{Degrees, Percent};
|
||||||
|
@ -1023,11 +1024,7 @@ impl<'gc> EditText<'gc> {
|
||||||
&& local_position.1 <= params.height()
|
&& local_position.1 <= params.height()
|
||||||
{
|
{
|
||||||
if local_position.0 >= x + (advance / 2) {
|
if local_position.0 >= x + (advance / 2) {
|
||||||
let mut idx = pos + 1;
|
result = Some(string_utils::next_char_boundary(text, pos));
|
||||||
while !text.is_char_boundary(idx) {
|
|
||||||
idx += 1;
|
|
||||||
}
|
|
||||||
result = Some(idx);
|
|
||||||
} else {
|
} else {
|
||||||
result = Some(pos);
|
result = Some(pos);
|
||||||
}
|
}
|
||||||
|
@ -1065,10 +1062,7 @@ impl<'gc> EditText<'gc> {
|
||||||
if selection.start() > 0 {
|
if selection.start() > 0 {
|
||||||
// Delete previous character
|
// Delete previous character
|
||||||
let text = self.text();
|
let text = self.text();
|
||||||
let mut start = selection.start() - 1;
|
let start = string_utils::prev_char_boundary(&text, selection.start());
|
||||||
while !text.is_char_boundary(start) {
|
|
||||||
start -= 1;
|
|
||||||
}
|
|
||||||
self.replace_text(start, selection.start(), "", context);
|
self.replace_text(start, selection.start(), "", context);
|
||||||
self.set_selection(
|
self.set_selection(
|
||||||
Some(TextSelection::for_position(start)),
|
Some(TextSelection::for_position(start)),
|
||||||
|
@ -1082,10 +1076,7 @@ impl<'gc> EditText<'gc> {
|
||||||
if selection.end() < self.text_length() {
|
if selection.end() < self.text_length() {
|
||||||
// Delete next character
|
// Delete next character
|
||||||
let text = self.text();
|
let text = self.text();
|
||||||
let mut end = selection.start() + 1;
|
let end = string_utils::next_char_boundary(&text, selection.start());
|
||||||
while !text.is_char_boundary(end) {
|
|
||||||
end += 1;
|
|
||||||
}
|
|
||||||
self.replace_text(selection.start(), end, "", context);
|
self.replace_text(selection.start(), end, "", context);
|
||||||
// No need to change selection
|
// No need to change selection
|
||||||
changed = true;
|
changed = true;
|
||||||
|
@ -1450,19 +1441,13 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
|
||||||
let length = text.len();
|
let length = text.len();
|
||||||
match key_code {
|
match key_code {
|
||||||
ButtonKeyCode::Left if selection.to > 0 => {
|
ButtonKeyCode::Left if selection.to > 0 => {
|
||||||
selection.to -= 1;
|
selection.to = string_utils::prev_char_boundary(text, selection.to);
|
||||||
while !text.is_char_boundary(selection.to) {
|
|
||||||
selection.to -= 1;
|
|
||||||
}
|
|
||||||
if !context.input.is_key_down(KeyCode::Shift) {
|
if !context.input.is_key_down(KeyCode::Shift) {
|
||||||
selection.from = selection.to;
|
selection.from = selection.to;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ButtonKeyCode::Right if selection.to < length => {
|
ButtonKeyCode::Right if selection.to < length => {
|
||||||
selection.to += 1;
|
selection.to = string_utils::next_char_boundary(text, selection.to);
|
||||||
while !text.is_char_boundary(selection.to) {
|
|
||||||
selection.to += 1;
|
|
||||||
}
|
|
||||||
if !context.input.is_key_down(KeyCode::Shift) {
|
if !context.input.is_key_down(KeyCode::Shift) {
|
||||||
selection.from = selection.to;
|
selection.from = selection.to;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::font::{EvalParameters, Font};
|
||||||
use crate::html::dimensions::{BoxBounds, Position, Size};
|
use crate::html::dimensions::{BoxBounds, Position, Size};
|
||||||
use crate::html::text_format::{FormatSpans, TextFormat, TextSpan};
|
use crate::html::text_format::{FormatSpans, TextFormat, TextSpan};
|
||||||
use crate::shape_utils::DrawCommand;
|
use crate::shape_utils::DrawCommand;
|
||||||
|
use crate::string_utils;
|
||||||
use crate::tag_utils::SwfMovie;
|
use crate::tag_utils::SwfMovie;
|
||||||
use gc_arena::{Collect, GcCell, MutationContext};
|
use gc_arena::{Collect, GcCell, MutationContext};
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
|
@ -720,16 +721,10 @@ impl<'gc> LayoutBox<'gc> {
|
||||||
|
|
||||||
// This ensures that the space causing the line break
|
// This ensures that the space causing the line break
|
||||||
// is included in the line it broke.
|
// is included in the line it broke.
|
||||||
let next_breakpoint = if last_breakpoint + breakpoint + 1 >= text.len()
|
let next_breakpoint = string_utils::next_char_boundary(
|
||||||
{
|
text,
|
||||||
text.len()
|
last_breakpoint + breakpoint,
|
||||||
} else {
|
);
|
||||||
let mut nb = last_breakpoint + breakpoint + 1;
|
|
||||||
while !text.is_char_boundary(nb) {
|
|
||||||
nb += 1;
|
|
||||||
}
|
|
||||||
nb
|
|
||||||
};
|
|
||||||
|
|
||||||
layout_context.append_text(
|
layout_context.append_text(
|
||||||
&text[last_breakpoint..next_breakpoint],
|
&text[last_breakpoint..next_breakpoint],
|
||||||
|
|
|
@ -1,5 +1,29 @@
|
||||||
///! Utilities for operating on strings in SWF files.
|
///! Utilities for operating on strings in SWF files.
|
||||||
|
|
||||||
|
/// Gets the position of the previous char
|
||||||
|
/// `pos` must already lie on a char boundary
|
||||||
|
pub fn prev_char_boundary(slice: &str, pos: usize) -> usize {
|
||||||
|
if pos == 0 {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut idx = pos - 1;
|
||||||
|
while !slice.is_char_boundary(idx) {
|
||||||
|
idx -= 1;
|
||||||
|
}
|
||||||
|
idx
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the byte position of the next char
|
||||||
|
/// `pos` must already lie on a char boundary
|
||||||
|
pub fn next_char_boundary(slice: &str, pos: usize) -> usize {
|
||||||
|
if let Some(c) = slice[pos..].chars().next() {
|
||||||
|
pos + c.len_utf8()
|
||||||
|
} else {
|
||||||
|
slice.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a `String` from an iterator of UTF-16 code units.
|
/// Creates a `String` from an iterator of UTF-16 code units.
|
||||||
/// TODO: Unpaired surrogates will get replaced with the Unicode replacement character.
|
/// TODO: Unpaired surrogates will get replaced with the Unicode replacement character.
|
||||||
pub fn utf16_iter_to_string<I: Iterator<Item = u16>>(it: I) -> String {
|
pub fn utf16_iter_to_string<I: Iterator<Item = u16>>(it: I) -> String {
|
||||||
|
|
Loading…
Reference in New Issue