From 9e3df38b548eca800d87d15e824b70e45ea7be85 Mon Sep 17 00:00:00 2001 From: rhysd Date: Sun, 19 Nov 2023 22:08:25 +0900 Subject: [PATCH] fix `inser_str` doesn't handle `\r\n` and ignores newline at end of input --- src/textarea.rs | 7 ++++- tests/textarea.rs | 70 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/src/textarea.rs b/src/textarea.rs index d2822a6..230ba1c 100644 --- a/src/textarea.rs +++ b/src/textarea.rs @@ -748,6 +748,7 @@ impl<'a> TextArea<'a> { } /// Insert a string at current cursor position. This method returns if some text was inserted or not in the textarea. + /// Both `\n` and `\r\n` are recognized as newlines but `\r` isn't. /// ``` /// use tui_textarea::TextArea; /// @@ -761,7 +762,11 @@ impl<'a> TextArea<'a> { /// ``` pub fn insert_str>(&mut self, s: S) -> bool { let modified = self.delete_selection(false); - let mut lines: Vec<_> = s.as_ref().lines().map(ToString::to_string).collect(); + let mut lines: Vec<_> = s + .as_ref() + .split('\n') + .map(|s| s.strip_suffix('\r').unwrap_or(s).to_string()) + .collect(); match lines.len() { 0 => modified, 1 => self.insert_piece(lines.remove(0)), diff --git a/tests/textarea.rs b/tests/textarea.rs index 868ca3f..52d9d90 100644 --- a/tests/textarea.rs +++ b/tests/textarea.rs @@ -301,6 +301,24 @@ fn test_insert_str_multiple_lines() { "ef", ][..], ), + // Newline at end of line + ( + &[ + "ab", + "cd", + "ef", + ][..], + (1, 1), + "x\ny\n", + (3, 0), + &[ + "ab", + "cx", + "y", + "d", + "ef", + ][..], + ), // Empty lines ( &[ @@ -376,8 +394,9 @@ fn test_insert_str_multiple_lines() { ][..], (0, 0), "\n\n\n", - (2, 0), + (3, 0), &[ + "", "", "", "ab", @@ -393,11 +412,12 @@ fn test_insert_str_multiple_lines() { ][..], (1, 0), "\n\n\n", - (3, 0), + (4, 0), &[ "ab", "", "", + "", "cd", "ef", ][..], @@ -410,11 +430,12 @@ fn test_insert_str_multiple_lines() { ][..], (1, 1), "\n\n\n", - (3, 0), + (4, 0), &[ "ab", "c", "", + "", "d", "ef", ][..], @@ -427,12 +448,13 @@ fn test_insert_str_multiple_lines() { ][..], (1, 2), "\n\n\n", - (3, 0), + (4, 0), &[ "ab", "cd", "", "", + "", "ef", ][..], ), @@ -444,13 +466,14 @@ fn test_insert_str_multiple_lines() { ][..], (2, 2), "\n\n\n", - (4, 0), + (5, 0), &[ "ab", "cd", "ef", "", "", + "", ][..], ), // Multi-byte characters @@ -539,6 +562,41 @@ fn test_insert_str_multiple_lines() { "🐴", ][..], ), + // Handle \r\n as newlines + ( + &[ + "ab", + "cd", + "ef", + ][..], + (1, 1), + "x\r\ny\r\nz", + (3, 1), + &[ + "ab", + "cx", + "y", + "zd", + "ef", + ][..], + ), + ( + &[ + "ab", + "cd", + "ef", + ][..], + (1, 1), + "x\ny\r\nz", + (3, 1), + &[ + "ab", + "cx", + "y", + "zd", + "ef", + ][..], + ), ]; for test in tests { @@ -549,8 +607,8 @@ fn test_insert_str_multiple_lines() { t.move_cursor(CursorMove::Jump(row as _, col as _)); assert!(t.insert_str(input), "{test:?}"); - assert_eq!(t.cursor(), after_pos, "{test:?}"); assert_eq!(t.lines(), expected, "{test:?}"); + assert_eq!(t.cursor(), after_pos, "{test:?}"); assert_undo_redo(before_pos, before, expected, &mut t, test); }