зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-08-28 11:36:17 +03:00
329 строки
8.4 KiB
Rust
329 строки
8.4 KiB
Rust
use tui_textarea::{CursorMove, TextArea};
|
|
|
|
const BOTTOM_RIGHT: CursorMove = CursorMove::Jump(u16::MAX, u16::MAX);
|
|
|
|
#[test]
|
|
fn empty_textarea() {
|
|
use CursorMove::*;
|
|
|
|
let mut t = TextArea::default();
|
|
for m in [
|
|
Forward,
|
|
Back,
|
|
Up,
|
|
Down,
|
|
Head,
|
|
End,
|
|
Top,
|
|
Bottom,
|
|
WordForward,
|
|
WordEnd,
|
|
WordBack,
|
|
ParagraphForward,
|
|
ParagraphBack,
|
|
Jump(0, 0),
|
|
Jump(u16::MAX, u16::MAX),
|
|
] {
|
|
t.move_cursor(m);
|
|
assert_eq!(t.cursor(), (0, 0), "{m:?}");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn forward() {
|
|
for (text, positions) in [
|
|
(
|
|
["abc", "def"],
|
|
[
|
|
(0, 1),
|
|
(0, 2),
|
|
(0, 3),
|
|
(1, 0),
|
|
(1, 1),
|
|
(1, 2),
|
|
(1, 3),
|
|
(1, 3),
|
|
],
|
|
),
|
|
(
|
|
["あいう", "🐶🐱👪"],
|
|
[
|
|
(0, 1),
|
|
(0, 2),
|
|
(0, 3),
|
|
(1, 0),
|
|
(1, 1),
|
|
(1, 2),
|
|
(1, 3),
|
|
(1, 3),
|
|
],
|
|
),
|
|
] {
|
|
let mut t = TextArea::from(text);
|
|
|
|
for pos in positions {
|
|
t.move_cursor(CursorMove::Forward);
|
|
assert_eq!(t.cursor(), pos, "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn back() {
|
|
for (text, positions) in [
|
|
(
|
|
["abc", "def"],
|
|
[
|
|
(1, 2),
|
|
(1, 1),
|
|
(1, 0),
|
|
(0, 3),
|
|
(0, 2),
|
|
(0, 1),
|
|
(0, 0),
|
|
(0, 0),
|
|
],
|
|
),
|
|
(
|
|
["あいう", "🐶🐱👪"],
|
|
[
|
|
(1, 2),
|
|
(1, 1),
|
|
(1, 0),
|
|
(0, 3),
|
|
(0, 2),
|
|
(0, 1),
|
|
(0, 0),
|
|
(0, 0),
|
|
],
|
|
),
|
|
] {
|
|
let mut t = TextArea::from(text);
|
|
t.move_cursor(BOTTOM_RIGHT);
|
|
|
|
for pos in positions {
|
|
t.move_cursor(CursorMove::Back);
|
|
assert_eq!(t.cursor(), pos, "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn up() {
|
|
for text in [["abc", "def", "ghi"], ["あいう", "🐶🐱🐰", "👪🤟🏿👩🏻❤️💋👨🏾"]]
|
|
{
|
|
let mut t = TextArea::from(text);
|
|
|
|
for col in 0..=3 {
|
|
let mut row = 2;
|
|
|
|
t.move_cursor(CursorMove::Jump(2, col as u16));
|
|
assert_eq!(t.cursor(), (row, col), "{:?}", t.lines());
|
|
|
|
while row > 0 {
|
|
t.move_cursor(CursorMove::Up);
|
|
row -= 1;
|
|
assert_eq!(t.cursor(), (row, col), "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn up_trim() {
|
|
for text in [["", "a", "bcd", "efgh"], ["", "👪", "🐶!🐱", "あ?い!"]] {
|
|
let mut t = TextArea::from(text);
|
|
t.move_cursor(CursorMove::Jump(3, 3));
|
|
|
|
for expected in [(2, 3), (1, 1), (0, 0)] {
|
|
t.move_cursor(CursorMove::Up);
|
|
assert_eq!(t.cursor(), expected, "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn down() {
|
|
for text in [["abc", "def", "ghi"], ["あいう", "🐶🐱🐰", "👪🤟🏿👩🏻❤️💋👨🏾"]]
|
|
{
|
|
let mut t = TextArea::from(text);
|
|
|
|
for col in 0..=3 {
|
|
let mut row = 0;
|
|
|
|
t.move_cursor(CursorMove::Jump(0, col as u16));
|
|
assert_eq!(t.cursor(), (row, col), "{:?}", t.lines());
|
|
|
|
while row < 2 {
|
|
t.move_cursor(CursorMove::Down);
|
|
row += 1;
|
|
assert_eq!(t.cursor(), (row, col), "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn down_trim() {
|
|
for text in [["abcd", "efg", "h", ""], ["あ?い!", "🐶!🐱", "👪", ""]] {
|
|
let mut t = TextArea::from(text);
|
|
t.move_cursor(CursorMove::Jump(0, 3));
|
|
|
|
for expected in [(1, 3), (2, 1), (3, 0)] {
|
|
t.move_cursor(CursorMove::Down);
|
|
assert_eq!(t.cursor(), expected, "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn head() {
|
|
for text in [["efg", "h", ""], ["あいう", "👪", ""]] {
|
|
let mut t = TextArea::from(text);
|
|
for row in 0..t.lines().len() {
|
|
let len = t.lines()[row].len();
|
|
for col in [0, len / 2, len] {
|
|
t.move_cursor(CursorMove::Jump(row as u16, col as u16));
|
|
t.move_cursor(CursorMove::Head);
|
|
assert_eq!(t.cursor(), (row, 0), "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn end() {
|
|
for text in [["efg", "h", ""], ["あいう", "👪", ""]] {
|
|
let mut t = TextArea::from(text);
|
|
for row in 0..t.lines().len() {
|
|
let len = match row {
|
|
0 => 3,
|
|
1 => 1,
|
|
2 => 0,
|
|
_ => unreachable!(),
|
|
};
|
|
for col in [0, len / 2, len] {
|
|
t.move_cursor(CursorMove::Jump(row as u16, col as u16));
|
|
t.move_cursor(CursorMove::End);
|
|
assert_eq!(t.cursor(), (row, len), "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn top() {
|
|
for text in [["abc", "def", "ghi"], ["あいう", "🐶🐱🐰", "👪🤟🏿👩🏻❤️💋👨🏾"]]
|
|
{
|
|
let mut t = TextArea::from(text);
|
|
for row in 0..=2 {
|
|
for col in 0..=3 {
|
|
t.move_cursor(CursorMove::Jump(row, col));
|
|
t.move_cursor(CursorMove::Top);
|
|
assert_eq!(t.cursor(), (0, col as usize), "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn top_trim() {
|
|
for lines in [
|
|
&["a", "bc"][..],
|
|
&["あ", "🐶🐱"][..],
|
|
&["a", "bcd", "ef"][..],
|
|
&["", "犬"][..],
|
|
] {
|
|
let mut t: TextArea = lines.iter().cloned().collect();
|
|
t.move_cursor(CursorMove::Jump(u16::MAX, u16::MAX));
|
|
t.move_cursor(CursorMove::Top);
|
|
let col = t.lines()[0].chars().count();
|
|
assert_eq!(t.cursor(), (0, col), "{:?}", t.lines());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn bottom() {
|
|
for text in [["abc", "def", "ghi"], ["あいう", "🐶🐱🐰", "👪🤟🏿👩🏻❤️💋👨🏾"]]
|
|
{
|
|
let mut t = TextArea::from(text);
|
|
for row in 0..=2 {
|
|
for col in 0..=3 {
|
|
t.move_cursor(CursorMove::Jump(row, col));
|
|
t.move_cursor(CursorMove::Bottom);
|
|
assert_eq!(t.cursor(), (2, col as usize), "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn bottom_trim() {
|
|
for lines in [
|
|
&["bc", "a"][..],
|
|
&["🐶🐱", "🐰"][..],
|
|
&["ef", "bcd", "a"][..],
|
|
&["犬", ""][..],
|
|
] {
|
|
let mut t: TextArea = lines.iter().cloned().collect();
|
|
t.move_cursor(CursorMove::Jump(0, u16::MAX));
|
|
t.move_cursor(CursorMove::Bottom);
|
|
let col = t.lines().last().unwrap().chars().count();
|
|
assert_eq!(t.cursor(), (t.lines().len() - 1, col), "{:?}", t.lines());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn word_end() {
|
|
for (lines, positions) in [
|
|
(
|
|
&[
|
|
"aaa !!! bbb", // Consecutive punctuations are a word
|
|
][..],
|
|
&[(0, 2), (0, 6), (0, 10)][..],
|
|
),
|
|
(
|
|
&[
|
|
"aaa!!!bbb", // Word boundaries without spaces
|
|
][..],
|
|
&[(0, 2), (0, 5), (0, 8)][..],
|
|
),
|
|
(
|
|
&[
|
|
"aaa", "", "", "bbb", // Go across multiple empty lines (regression of #75)
|
|
][..],
|
|
&[(0, 2), (3, 2)][..],
|
|
),
|
|
(
|
|
&[
|
|
"aaa", " ", " ", "bbb", // Go across multiple blank lines
|
|
][..],
|
|
&[(0, 2), (3, 2)][..],
|
|
),
|
|
(
|
|
&[
|
|
" aaa", " bbb", // Ignore the spaces at the head of line
|
|
][..],
|
|
&[(0, 5), (1, 5)][..],
|
|
),
|
|
(
|
|
&[
|
|
"aaa ", "bbb ", // Ignore the spaces at the end of line
|
|
][..],
|
|
&[(0, 2), (1, 2), (1, 6)][..],
|
|
),
|
|
(
|
|
&[
|
|
"a aa", "b!!!", // Accept the head of line (regression of #75)
|
|
][..],
|
|
&[(0, 3), (1, 0), (1, 3)][..],
|
|
),
|
|
] {
|
|
let mut t: TextArea = lines.iter().cloned().collect();
|
|
for pos in positions {
|
|
t.move_cursor(CursorMove::WordEnd);
|
|
assert_eq!(t.cursor(), *pos, "{:?}", t.lines());
|
|
}
|
|
}
|
|
}
|