зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-08 00:15:50 +03:00
keep yanked lines in Vec
Этот коммит содержится в:
@@ -17,6 +17,33 @@ use ratatui::text::Line;
|
|||||||
use tui::text::Spans as Line;
|
use tui::text::Spans as Line;
|
||||||
use unicode_width::UnicodeWidthChar as _;
|
use unicode_width::UnicodeWidthChar as _;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
enum YankText {
|
||||||
|
Piece(String),
|
||||||
|
Chunk(Vec<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for YankText {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Piece(String::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Into<String>> From<S> for YankText {
|
||||||
|
fn from(s: S) -> Self {
|
||||||
|
Self::Piece(s.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToString for YankText {
|
||||||
|
fn to_string(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Self::Piece(s) => s.clone(),
|
||||||
|
Self::Chunk(ss) => ss.join("\n"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A type to manage state of textarea.
|
/// A type to manage state of textarea.
|
||||||
///
|
///
|
||||||
/// [`TextArea::default`] creates an empty textarea. [`TextArea::new`] creates a textarea with given text lines.
|
/// [`TextArea::default`] creates an empty textarea. [`TextArea::new`] creates a textarea with given text lines.
|
||||||
@@ -50,7 +77,7 @@ pub struct TextArea<'a> {
|
|||||||
line_number_style: Option<Style>,
|
line_number_style: Option<Style>,
|
||||||
pub(crate) viewport: Viewport,
|
pub(crate) viewport: Viewport,
|
||||||
cursor_style: Style,
|
cursor_style: Style,
|
||||||
yank: String,
|
yank: YankText,
|
||||||
#[cfg(feature = "search")]
|
#[cfg(feature = "search")]
|
||||||
search: Search,
|
search: Search,
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
@@ -150,7 +177,7 @@ impl<'a> TextArea<'a> {
|
|||||||
line_number_style: None,
|
line_number_style: None,
|
||||||
viewport: Viewport::default(),
|
viewport: Viewport::default(),
|
||||||
cursor_style: Style::default().add_modifier(Modifier::REVERSED),
|
cursor_style: Style::default().add_modifier(Modifier::REVERSED),
|
||||||
yank: String::new(),
|
yank: YankText::default(),
|
||||||
#[cfg(feature = "search")]
|
#[cfg(feature = "search")]
|
||||||
search: Search::default(),
|
search: Search::default(),
|
||||||
alignment: Alignment::Left,
|
alignment: Alignment::Left,
|
||||||
@@ -736,7 +763,7 @@ impl<'a> TextArea<'a> {
|
|||||||
.drain(first_start..first_start + offset)
|
.drain(first_start..first_start + offset)
|
||||||
.as_str()
|
.as_str()
|
||||||
.to_string();
|
.to_string();
|
||||||
self.yank = removed.clone();
|
self.yank = removed.clone().into();
|
||||||
self.push_history(EditKind::DeleteStr(removed, first_start), self.cursor);
|
self.push_history(EditKind::DeleteStr(removed, first_start), self.cursor);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -762,7 +789,7 @@ impl<'a> TextArea<'a> {
|
|||||||
deleted.push(last_line);
|
deleted.push(last_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.yank = deleted.join("\n"); // TODO
|
self.yank = YankText::Chunk(deleted.clone());
|
||||||
|
|
||||||
let edit = if deleted.len() == 1 {
|
let edit = if deleted.len() == 1 {
|
||||||
EditKind::DeleteStr(deleted.remove(0), first_start)
|
EditKind::DeleteStr(deleted.remove(0), first_start)
|
||||||
@@ -793,7 +820,7 @@ impl<'a> TextArea<'a> {
|
|||||||
|
|
||||||
self.cursor = (row, col);
|
self.cursor = (row, col);
|
||||||
self.push_history(EditKind::DeleteStr(removed.clone(), i), cursor_before);
|
self.push_history(EditKind::DeleteStr(removed.clone(), i), cursor_before);
|
||||||
self.yank = removed;
|
self.yank = removed.into();
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
@@ -1597,7 +1624,8 @@ impl<'a> TextArea<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the yanked text. Text is automatically yanked when deleting strings by [`TextArea::delete_line_by_head`],
|
/// Get the yanked text. Text is automatically yanked when deleting strings by [`TextArea::delete_line_by_head`],
|
||||||
/// [`TextArea::delete_line_by_end`], [`TextArea::delete_word`], [`TextArea::delete_next_word`].
|
/// [`TextArea::delete_line_by_end`], [`TextArea::delete_word`], [`TextArea::delete_next_word`],
|
||||||
|
/// [`TextArea::delete_str`].
|
||||||
/// ```
|
/// ```
|
||||||
/// use tui_textarea::TextArea;
|
/// use tui_textarea::TextArea;
|
||||||
///
|
///
|
||||||
@@ -1606,8 +1634,8 @@ impl<'a> TextArea<'a> {
|
|||||||
/// textarea.delete_next_word();
|
/// textarea.delete_next_word();
|
||||||
/// assert_eq!(textarea.yank_text(), "abc");
|
/// assert_eq!(textarea.yank_text(), "abc");
|
||||||
/// ```
|
/// ```
|
||||||
pub fn yank_text(&'a self) -> &'a str {
|
pub fn yank_text(&self) -> String {
|
||||||
&self.yank
|
self.yank.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a yanked text. The text can be inserted by [`TextArea::paste`]. The string passed to method must not contain
|
/// Set a yanked text. The text can be inserted by [`TextArea::paste`]. The string passed to method must not contain
|
||||||
@@ -1622,7 +1650,7 @@ impl<'a> TextArea<'a> {
|
|||||||
/// assert_eq!(textarea.lines(), ["hello, world"]);
|
/// assert_eq!(textarea.lines(), ["hello, world"]);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn set_yank_text(&mut self, text: impl Into<String>) {
|
pub fn set_yank_text(&mut self, text: impl Into<String>) {
|
||||||
self.yank = text.into();
|
self.yank = text.into().into();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a regular expression pattern for text search. Setting an empty string stops the text search.
|
/// Set a regular expression pattern for text search. Setting an empty string stops the text search.
|
||||||
|
|||||||
@@ -396,7 +396,7 @@ fn test_insert_str_multiple_lines() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_str_delete_nothing() {
|
fn test_delete_str_nothing() {
|
||||||
for i in 0..="ab".len() {
|
for i in 0..="ab".len() {
|
||||||
let mut t = TextArea::from(["ab"]);
|
let mut t = TextArea::from(["ab"]);
|
||||||
assert!(!t.delete_str(0), "{}", i);
|
assert!(!t.delete_str(0), "{}", i);
|
||||||
@@ -406,7 +406,7 @@ fn test_delete_str_delete_nothing() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_str_delete_within_line() {
|
fn test_delete_str_within_line() {
|
||||||
for i in 0.."abc".len() {
|
for i in 0.."abc".len() {
|
||||||
for j in 1..="abc".len() - i {
|
for j in 1..="abc".len() - i {
|
||||||
let mut t = TextArea::from(["abc"]);
|
let mut t = TextArea::from(["abc"]);
|
||||||
@@ -422,7 +422,7 @@ fn test_delete_str_delete_within_line() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_str_delete_multiple_lines() {
|
fn test_delete_str_multiple_lines() {
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
let tests = [
|
let tests = [
|
||||||
// Length
|
// Length
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user