aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/textinput.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/textinput.rs')
-rw-r--r--components/script/textinput.rs208
1 files changed, 191 insertions, 17 deletions
diff --git a/components/script/textinput.rs b/components/script/textinput.rs
index 5f04b5b187e..144be9dbd78 100644
--- a/components/script/textinput.rs
+++ b/components/script/textinput.rs
@@ -14,6 +14,7 @@ use std::cmp::{max, min};
use std::default::Default;
use std::ops::Range;
use std::usize;
+use unicode_segmentation::UnicodeSegmentation;
#[derive(Copy, Clone, PartialEq)]
pub enum Selection {
@@ -376,18 +377,16 @@ impl<T: ClipboardProvider> TextInput<T> {
}
let adjust = {
let current_line = &self.lines[self.edit_point.line];
- // FIXME: We adjust by one code point, but it proably should be one grapheme cluster
- // https://github.com/unicode-rs/unicode-segmentation
match direction {
Direction::Forward => {
- match current_line[self.edit_point.index..].chars().next() {
- Some(c) => c.len_utf8() as isize,
+ match current_line[self.edit_point.index..].graphemes(true).next() {
+ Some(c) => c.len() as isize,
None => 1, // Going to the next line is a "one byte" offset
}
}
Direction::Backward => {
- match current_line[..self.edit_point.index].chars().next_back() {
- Some(c) => -(c.len_utf8() as isize),
+ match current_line[..self.edit_point.index].graphemes(true).next_back() {
+ Some(c) => -(c.len() as isize),
None => -1, // Going to the previous line is a "one byte" offset
}
}
@@ -468,6 +467,111 @@ impl<T: ClipboardProvider> TextInput<T> {
self.selection_begin = None;
}
+ pub fn adjust_horizontal_by_word(&mut self, direction: Direction, select: Selection) {
+ if self.adjust_selection_for_horizontal_change(direction, select) {
+ return
+ }
+ let shift_increment: isize = {
+ let input: &str;
+ match direction {
+ Direction::Backward => {
+ let remaining = self.edit_point.index;
+ let current_line = self.edit_point.line;
+ let mut newline_adjustment = 0;
+ if remaining == 0 && current_line > 0 {
+ input = &self
+ .lines[current_line-1];
+ newline_adjustment = 1;
+ } else {
+ input = &self
+ .lines[current_line]
+ [..remaining];
+ }
+
+ let mut iter = input.split_word_bounds().rev();
+ let mut shift_temp: isize = 0;
+ loop {
+ match iter.next() {
+ None => break,
+ Some(x) => {
+ shift_temp += - (x.len() as isize);
+ if x.chars().any(|x| x.is_alphabetic() || x.is_numeric()) {
+ break;
+ }
+ }
+ }
+ }
+ shift_temp - newline_adjustment
+ }
+ Direction::Forward => {
+ let remaining = self.current_line_length() - self.edit_point.index;
+ let current_line = self.edit_point.line;
+ let mut newline_adjustment = 0;
+ if remaining == 0 && self.lines.len() > self.edit_point.line + 1 {
+ input = &self
+ .lines[current_line + 1];
+ newline_adjustment = 1;
+ } else {
+ input = &self
+ .lines[current_line]
+ [self.edit_point.index..];
+ }
+
+ let mut iter = input.split_word_bounds();
+ let mut shift_temp: isize = 0;
+ loop {
+ match iter.next() {
+ None => break,
+ Some(x) => {
+ shift_temp += x.len() as isize;
+ if x.chars().any(|x| x.is_alphabetic() || x.is_numeric()) {
+ break;
+ }
+ }
+ }
+ }
+ shift_temp + newline_adjustment
+ }
+ }
+ };
+
+ self.adjust_horizontal(shift_increment, select);
+ }
+
+ pub fn adjust_horizontal_to_line_end(&mut self, direction: Direction, select: Selection) {
+ if self.adjust_selection_for_horizontal_change(direction, select) {
+ return
+ }
+ let shift: isize = {
+ let current_line = &self.lines[self.edit_point.line];
+ match direction {
+ Direction::Backward => {
+ - (current_line[..self.edit_point.index].len() as isize)
+ },
+ Direction::Forward => {
+ current_line[self.edit_point.index..].len() as isize
+ }
+ }
+ };
+ self.perform_horizontal_adjustment(shift, select);
+ }
+
+ pub fn adjust_horizontal_to_limit(&mut self, direction: Direction, select: Selection) {
+ if self.adjust_selection_for_horizontal_change(direction, select) {
+ return
+ }
+ match direction {
+ Direction::Backward => {
+ self.edit_point.line = 0;
+ self.edit_point.index = 0;
+ },
+ Direction::Forward => {
+ self.edit_point.line = &self.lines.len() - 1;
+ self.edit_point.index = (&self.lines[&self.lines.len() - 1]).len();
+ }
+ }
+ }
+
/// Process a given `KeyboardEvent` and return an action for the caller to execute.
pub fn handle_keydown(&mut self, event: &KeyboardEvent) -> KeyReaction {
if let Some(key) = event.get_key() {
@@ -483,6 +587,32 @@ impl<T: ClipboardProvider> TextInput<T> {
mods: KeyModifiers) -> KeyReaction {
let maybe_select = if mods.contains(SHIFT) { Selection::Selected } else { Selection::NotSelected };
match (printable, key) {
+ (_, Key::B) if mods.contains(CONTROL | ALT) => {
+ self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ (_, Key::F) if mods.contains(CONTROL | ALT) => {
+ self.adjust_horizontal_by_word(Direction::Forward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ (_, Key::A) if mods.contains(CONTROL | ALT) => {
+ self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ (_, Key::E) if mods.contains(CONTROL | ALT) => {
+ self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ #[cfg(target_os = "macos")]
+ (None, Key::A) if mods == CONTROL => {
+ self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ #[cfg(target_os = "macos")]
+ (None, Key::E) if mods == CONTROL => {
+ self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
(Some('a'), _) if is_control_key(mods) => {
self.select_all();
KeyReaction::RedrawSelection
@@ -501,49 +631,85 @@ impl<T: ClipboardProvider> TextInput<T> {
(Some(c), _) => {
self.insert_char(c);
KeyReaction::DispatchInput
- }
+ },
+ #[cfg(target_os = "macos")]
+ (None, Key::Home) => {
+ KeyReaction::RedrawSelection
+ },
+ #[cfg(target_os = "macos")]
+ (None, Key::End) => {
+ KeyReaction::RedrawSelection
+ },
(None, Key::Delete) => {
self.delete_char(Direction::Forward);
KeyReaction::DispatchInput
- }
+ },
(None, Key::Backspace) => {
self.delete_char(Direction::Backward);
KeyReaction::DispatchInput
- }
+ },
+ #[cfg(target_os = "macos")]
+ (None, Key::Left) if mods.contains(SUPER) => {
+ self.adjust_horizontal_to_line_end(Direction::Backward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ #[cfg(target_os = "macos")]
+ (None, Key::Right) if mods.contains(SUPER) => {
+ self.adjust_horizontal_to_line_end(Direction::Forward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ #[cfg(target_os = "macos")]
+ (None, Key::Up) if mods.contains(SUPER) => {
+ self.adjust_horizontal_to_limit(Direction::Backward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ #[cfg(target_os = "macos")]
+ (None, Key::Down) if mods.contains(SUPER) => {
+ self.adjust_horizontal_to_limit(Direction::Forward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ (None, Key::Left) if mods.contains(ALT) => {
+ self.adjust_horizontal_by_word(Direction::Backward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
+ (None, Key::Right) if mods.contains(ALT) => {
+ self.adjust_horizontal_by_word(Direction::Forward, maybe_select);
+ KeyReaction::RedrawSelection
+ },
(None, Key::Left) => {
self.adjust_horizontal_by_one(Direction::Backward, maybe_select);
KeyReaction::RedrawSelection
- }
+ },
(None, Key::Right) => {
self.adjust_horizontal_by_one(Direction::Forward, maybe_select);
KeyReaction::RedrawSelection
- }
+ },
(None, Key::Up) => {
self.adjust_vertical(-1, maybe_select);
KeyReaction::RedrawSelection
- }
+ },
(None, Key::Down) => {
self.adjust_vertical(1, maybe_select);
KeyReaction::RedrawSelection
- }
+ },
(None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(),
(None, Key::Home) => {
self.edit_point.index = 0;
KeyReaction::RedrawSelection
- }
+ },
(None, Key::End) => {
self.edit_point.index = self.current_line_length();
self.assert_ok_selection();
KeyReaction::RedrawSelection
- }
+ },
(None, Key::PageUp) => {
self.adjust_vertical(-28, maybe_select);
KeyReaction::RedrawSelection
- }
+ },
(None, Key::PageDown) => {
self.adjust_vertical(28, maybe_select);
KeyReaction::RedrawSelection
- }
+ },
_ => KeyReaction::Nothing,
}
}
@@ -677,4 +843,12 @@ impl<T: ClipboardProvider> TextInput<T> {
selection_start as u32
}
+
+ pub fn set_edit_point_index(&mut self, index: usize) {
+ let byte_size = self.lines[self.edit_point.line]
+ .graphemes(true)
+ .take(index)
+ .fold(0, |acc, x| acc + x.len());
+ self.edit_point.index = byte_size;
+ }
}