mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #15666 - clementmiao:keyboard_shortcuts, r=asajeffrey
added keyboard shortcuts for navigation inside text box PR to implement keyboard shortcuts per issue #12278, r? jdm Thanks for letting me help! --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #12278 (github issue number if applicable). <!-- Either: --> - [X] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15666) <!-- Reviewable:end -->
This commit is contained in:
commit
45f20f0bd6
5 changed files with 292 additions and 15 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2305,6 +2305,7 @@ dependencies = [
|
||||||
"style_traits 0.0.1",
|
"style_traits 0.0.1",
|
||||||
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tinyfiledialogs 2.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tinyfiledialogs 2.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"webrender_traits 0.31.0 (git+https://github.com/servo/webrender)",
|
"webrender_traits 0.31.0 (git+https://github.com/servo/webrender)",
|
||||||
|
|
|
@ -85,6 +85,7 @@ smallvec = "0.3"
|
||||||
style = {path = "../style"}
|
style = {path = "../style"}
|
||||||
style_traits = {path = "../style_traits"}
|
style_traits = {path = "../style_traits"}
|
||||||
time = "0.1.12"
|
time = "0.1.12"
|
||||||
|
unicode-segmentation = "1.1.0"
|
||||||
url = {version = "1.2", features = ["heap_size", "query_encoding"]}
|
url = {version = "1.2", features = ["heap_size", "query_encoding"]}
|
||||||
uuid = {version = "0.4", features = ["v4"]}
|
uuid = {version = "0.4", features = ["v4"]}
|
||||||
xml5ever = {version = "0.5", features = ["unstable"]}
|
xml5ever = {version = "0.5", features = ["unstable"]}
|
||||||
|
|
|
@ -97,6 +97,7 @@ extern crate style_traits;
|
||||||
extern crate time;
|
extern crate time;
|
||||||
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
#[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
|
||||||
extern crate tinyfiledialogs;
|
extern crate tinyfiledialogs;
|
||||||
|
extern crate unicode_segmentation;
|
||||||
extern crate url;
|
extern crate url;
|
||||||
extern crate uuid;
|
extern crate uuid;
|
||||||
extern crate webrender_traits;
|
extern crate webrender_traits;
|
||||||
|
|
|
@ -14,6 +14,7 @@ use std::cmp::{max, min};
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
use std::usize;
|
use std::usize;
|
||||||
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
pub enum Selection {
|
pub enum Selection {
|
||||||
|
@ -468,6 +469,111 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
self.selection_begin = None;
|
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.
|
/// Process a given `KeyboardEvent` and return an action for the caller to execute.
|
||||||
pub fn handle_keydown(&mut self, event: &KeyboardEvent) -> KeyReaction {
|
pub fn handle_keydown(&mut self, event: &KeyboardEvent) -> KeyReaction {
|
||||||
if let Some(key) = event.get_key() {
|
if let Some(key) = event.get_key() {
|
||||||
|
@ -483,6 +589,32 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
mods: KeyModifiers) -> KeyReaction {
|
mods: KeyModifiers) -> KeyReaction {
|
||||||
let maybe_select = if mods.contains(SHIFT) { Selection::Selected } else { Selection::NotSelected };
|
let maybe_select = if mods.contains(SHIFT) { Selection::Selected } else { Selection::NotSelected };
|
||||||
match (printable, key) {
|
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) => {
|
(Some('a'), _) if is_control_key(mods) => {
|
||||||
self.select_all();
|
self.select_all();
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
|
@ -501,49 +633,85 @@ impl<T: ClipboardProvider> TextInput<T> {
|
||||||
(Some(c), _) => {
|
(Some(c), _) => {
|
||||||
self.insert_char(c);
|
self.insert_char(c);
|
||||||
KeyReaction::DispatchInput
|
KeyReaction::DispatchInput
|
||||||
}
|
},
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
(None, Key::Home) => {
|
||||||
|
KeyReaction::RedrawSelection
|
||||||
|
},
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
(None, Key::End) => {
|
||||||
|
KeyReaction::RedrawSelection
|
||||||
|
},
|
||||||
(None, Key::Delete) => {
|
(None, Key::Delete) => {
|
||||||
self.delete_char(Direction::Forward);
|
self.delete_char(Direction::Forward);
|
||||||
KeyReaction::DispatchInput
|
KeyReaction::DispatchInput
|
||||||
}
|
},
|
||||||
(None, Key::Backspace) => {
|
(None, Key::Backspace) => {
|
||||||
self.delete_char(Direction::Backward);
|
self.delete_char(Direction::Backward);
|
||||||
KeyReaction::DispatchInput
|
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) => {
|
(None, Key::Left) => {
|
||||||
self.adjust_horizontal_by_one(Direction::Backward, maybe_select);
|
self.adjust_horizontal_by_one(Direction::Backward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
},
|
||||||
(None, Key::Right) => {
|
(None, Key::Right) => {
|
||||||
self.adjust_horizontal_by_one(Direction::Forward, maybe_select);
|
self.adjust_horizontal_by_one(Direction::Forward, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
},
|
||||||
(None, Key::Up) => {
|
(None, Key::Up) => {
|
||||||
self.adjust_vertical(-1, maybe_select);
|
self.adjust_vertical(-1, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
},
|
||||||
(None, Key::Down) => {
|
(None, Key::Down) => {
|
||||||
self.adjust_vertical(1, maybe_select);
|
self.adjust_vertical(1, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
},
|
||||||
(None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(),
|
(None, Key::Enter) | (None, Key::KpEnter) => self.handle_return(),
|
||||||
(None, Key::Home) => {
|
(None, Key::Home) => {
|
||||||
self.edit_point.index = 0;
|
self.edit_point.index = 0;
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
},
|
||||||
(None, Key::End) => {
|
(None, Key::End) => {
|
||||||
self.edit_point.index = self.current_line_length();
|
self.edit_point.index = self.current_line_length();
|
||||||
self.assert_ok_selection();
|
self.assert_ok_selection();
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
},
|
||||||
(None, Key::PageUp) => {
|
(None, Key::PageUp) => {
|
||||||
self.adjust_vertical(-28, maybe_select);
|
self.adjust_vertical(-28, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
},
|
||||||
(None, Key::PageDown) => {
|
(None, Key::PageDown) => {
|
||||||
self.adjust_vertical(28, maybe_select);
|
self.adjust_vertical(28, maybe_select);
|
||||||
KeyReaction::RedrawSelection
|
KeyReaction::RedrawSelection
|
||||||
}
|
},
|
||||||
_ => KeyReaction::Nothing,
|
_ => KeyReaction::Nothing,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,8 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use msg::constellation_msg::{ALT, CONTROL, SUPER};
|
||||||
use msg::constellation_msg::{Key, KeyModifiers};
|
use msg::constellation_msg::{Key, KeyModifiers};
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
use msg::constellation_msg::CONTROL;
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
use msg::constellation_msg::SUPER;
|
|
||||||
use script::clipboard_provider::DummyClipboardContext;
|
use script::clipboard_provider::DummyClipboardContext;
|
||||||
use script::test::DOMString;
|
use script::test::DOMString;
|
||||||
use script::textinput::{TextInput, TextPoint, Selection, Lines, Direction, SelectionDirection};
|
use script::textinput::{TextInput, TextPoint, Selection, Lines, Direction, SelectionDirection};
|
||||||
|
@ -349,6 +346,115 @@ fn test_textinput_adjust_horizontal() {
|
||||||
assert_eq!(textinput.edit_point.index, 2);
|
assert_eq!(textinput.edit_point.index, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_textinput_adjust_horizontal_by_word() {
|
||||||
|
// Test basic case of movement word by word based on UAX#29 rules
|
||||||
|
let mut textinput = text_input(Lines::Single, "abc def");
|
||||||
|
textinput.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||||
|
textinput.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput.edit_point.index, 7);
|
||||||
|
textinput.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput.edit_point.index, 4);
|
||||||
|
textinput.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput.edit_point.index, 0);
|
||||||
|
|
||||||
|
// Test new line case of movement word by word based on UAX#29 rules
|
||||||
|
let mut textinput_2 = text_input(Lines::Multiple, "abc\ndef");
|
||||||
|
textinput_2.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||||
|
textinput_2.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_2.edit_point.line, 1);
|
||||||
|
assert_eq!(textinput_2.edit_point.index, 3);
|
||||||
|
textinput_2.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_2.edit_point.line, 1);
|
||||||
|
assert_eq!(textinput_2.edit_point.index, 0);
|
||||||
|
textinput_2.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_2.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_2.edit_point.index, 0);
|
||||||
|
|
||||||
|
// Test non-standard sized characters case of movement word by word based on UAX#29 rules
|
||||||
|
let mut textinput_3 = text_input(Lines::Single, "áéc d🌠bc");
|
||||||
|
textinput_3.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_3.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_3.edit_point.index, 5);
|
||||||
|
textinput_3.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_3.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_3.edit_point.index, 7);
|
||||||
|
textinput_3.adjust_horizontal_by_word(Direction::Forward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_3.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_3.edit_point.index, 13);
|
||||||
|
textinput_3.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_3.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_3.edit_point.index, 11);
|
||||||
|
textinput_3.adjust_horizontal_by_word(Direction::Backward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_3.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_3.edit_point.index, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_textinput_adjust_horizontal_to_line_end() {
|
||||||
|
// Test standard case of movement to end based on UAX#29 rules
|
||||||
|
let mut textinput = text_input(Lines::Single, "abc def");
|
||||||
|
textinput.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput.edit_point.index, 7);
|
||||||
|
|
||||||
|
// Test new line case of movement to end based on UAX#29 rules
|
||||||
|
let mut textinput_2 = text_input(Lines::Multiple, "abc\ndef");
|
||||||
|
textinput_2.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_2.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_2.edit_point.index, 3);
|
||||||
|
textinput_2.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_2.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_2.edit_point.index, 3);
|
||||||
|
textinput_2.adjust_horizontal_to_line_end(Direction::Backward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_2.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_2.edit_point.index, 0);
|
||||||
|
|
||||||
|
// Test non-standard sized characters case of movement to end based on UAX#29 rules
|
||||||
|
let mut textinput_3 = text_input(Lines::Single, "áéc d🌠bc");
|
||||||
|
textinput_3.adjust_horizontal_to_line_end(Direction::Forward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_3.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_3.edit_point.index, 13);
|
||||||
|
textinput_3.adjust_horizontal_to_line_end(Direction::Backward, Selection::NotSelected);
|
||||||
|
assert_eq!(textinput_3.edit_point.line, 0);
|
||||||
|
assert_eq!(textinput_3.edit_point.index, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn test_navigation_keyboard_shortcuts() {
|
||||||
|
let mut textinput = text_input(Lines::Multiple, "hello áéc");
|
||||||
|
|
||||||
|
// Test that CMD + Right moves to the end of the current line.
|
||||||
|
textinput.handle_keydown_aux(None, Key::Right, SUPER);
|
||||||
|
assert_eq!(textinput.edit_point.index, 11);
|
||||||
|
// Test that CMD + Right moves to the beginning of the current line.
|
||||||
|
textinput.handle_keydown_aux(None, Key::Left, SUPER);
|
||||||
|
assert_eq!(textinput.edit_point.index, 0);
|
||||||
|
// Test that CTRL + ALT + E moves to the end of the current line also.
|
||||||
|
textinput.handle_keydown_aux(None, Key::E, CONTROL | ALT);
|
||||||
|
assert_eq!(textinput.edit_point.index, 11);
|
||||||
|
// Test that CTRL + ALT + A moves to the beginning of the current line also.
|
||||||
|
textinput.handle_keydown_aux(None, Key::A, CONTROL | ALT);
|
||||||
|
assert_eq!(textinput.edit_point.index, 0);
|
||||||
|
|
||||||
|
// Test that ALT + Right moves to the end of the word.
|
||||||
|
textinput.handle_keydown_aux(None, Key::Right, ALT);
|
||||||
|
assert_eq!(textinput.edit_point.index, 5);
|
||||||
|
// Test that CTRL + ALT + F moves to the end of the word also.
|
||||||
|
textinput.handle_keydown_aux(None, Key::F, CONTROL | ALT);
|
||||||
|
assert_eq!(textinput.edit_point.index, 11);
|
||||||
|
// Test that ALT + Left moves to the end of the word.
|
||||||
|
textinput.handle_keydown_aux(None, Key::Left, ALT);
|
||||||
|
assert_eq!(textinput.edit_point.index, 6);
|
||||||
|
// Test that CTRL + ALT + B moves to the end of the word also.
|
||||||
|
textinput.handle_keydown_aux(None, Key::B, CONTROL | ALT);
|
||||||
|
assert_eq!(textinput.edit_point.index, 0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_textinput_handle_return() {
|
fn test_textinput_handle_return() {
|
||||||
let mut single_line_textinput = text_input(Lines::Single, "abcdef");
|
let mut single_line_textinput = text_input(Lines::Single, "abcdef");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue