зеркало из
https://github.com/glebtv/tui-textarea.git
synced 2026-09-07 16:05:50 +03:00
move Edit and EditKind into history.rs
since they are used only for undo/redo
Этот коммит содержится в:
91
src/edit.rs
91
src/edit.rs
@@ -1,91 +0,0 @@
|
|||||||
#[derive(Clone)]
|
|
||||||
pub enum EditKind {
|
|
||||||
InsertChar(char, usize),
|
|
||||||
DeleteChar(char, usize),
|
|
||||||
InsertNewline(usize),
|
|
||||||
DeleteNewline(usize),
|
|
||||||
Insert(String, usize),
|
|
||||||
Remove(String, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl EditKind {
|
|
||||||
fn apply(&self, row: usize, lines: &mut Vec<String>) {
|
|
||||||
match self {
|
|
||||||
EditKind::InsertChar(c, i) => {
|
|
||||||
lines[row].insert(*i, *c);
|
|
||||||
}
|
|
||||||
EditKind::DeleteChar(_, i) => {
|
|
||||||
lines[row].remove(*i);
|
|
||||||
}
|
|
||||||
EditKind::InsertNewline(i) => {
|
|
||||||
let line = &mut lines[row];
|
|
||||||
let next_line = line[*i..].to_string();
|
|
||||||
line.truncate(*i);
|
|
||||||
lines.insert(row + 1, next_line);
|
|
||||||
}
|
|
||||||
EditKind::DeleteNewline(_) => {
|
|
||||||
if row > 0 {
|
|
||||||
let line = lines.remove(row);
|
|
||||||
lines[row - 1].push_str(&line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EditKind::Insert(s, i) => {
|
|
||||||
lines[row].insert_str(*i, s.as_str());
|
|
||||||
}
|
|
||||||
EditKind::Remove(s, i) => {
|
|
||||||
let end = *i + s.len();
|
|
||||||
lines[row].replace_range(*i..end, "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn invert(&self) -> Self {
|
|
||||||
use EditKind::*;
|
|
||||||
match self.clone() {
|
|
||||||
InsertChar(c, i) => DeleteChar(c, i),
|
|
||||||
DeleteChar(c, i) => InsertChar(c, i),
|
|
||||||
InsertNewline(i) => DeleteNewline(i),
|
|
||||||
DeleteNewline(i) => InsertNewline(i),
|
|
||||||
Insert(s, i) => Remove(s, i),
|
|
||||||
Remove(s, i) => Insert(s, i),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Edit {
|
|
||||||
kind: EditKind,
|
|
||||||
cursor_before: (usize, usize),
|
|
||||||
cursor_after: (usize, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Edit {
|
|
||||||
pub fn new(
|
|
||||||
kind: EditKind,
|
|
||||||
cursor_before: (usize, usize),
|
|
||||||
cursor_after: (usize, usize),
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
kind,
|
|
||||||
cursor_before,
|
|
||||||
cursor_after,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn redo(&self, lines: &mut Vec<String>) {
|
|
||||||
let (row, _) = self.cursor_before;
|
|
||||||
self.kind.apply(row, lines);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn undo(&self, lines: &mut Vec<String>) {
|
|
||||||
let (row, _) = self.cursor_after;
|
|
||||||
self.kind.invert().apply(row, lines); // Undo is redo of inverted edit
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cursor_before(&self) -> (usize, usize) {
|
|
||||||
self.cursor_before
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cursor_after(&self) -> (usize, usize) {
|
|
||||||
self.cursor_after
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,104 @@
|
|||||||
use crate::edit::Edit;
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
pub struct EditHistory {
|
#[derive(Clone)]
|
||||||
|
pub enum EditKind {
|
||||||
|
InsertChar(char, usize),
|
||||||
|
DeleteChar(char, usize),
|
||||||
|
InsertNewline(usize),
|
||||||
|
DeleteNewline(usize),
|
||||||
|
Insert(String, usize),
|
||||||
|
Remove(String, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EditKind {
|
||||||
|
fn apply(&self, row: usize, lines: &mut Vec<String>) {
|
||||||
|
match self {
|
||||||
|
EditKind::InsertChar(c, i) => {
|
||||||
|
lines[row].insert(*i, *c);
|
||||||
|
}
|
||||||
|
EditKind::DeleteChar(_, i) => {
|
||||||
|
lines[row].remove(*i);
|
||||||
|
}
|
||||||
|
EditKind::InsertNewline(i) => {
|
||||||
|
let line = &mut lines[row];
|
||||||
|
let next_line = line[*i..].to_string();
|
||||||
|
line.truncate(*i);
|
||||||
|
lines.insert(row + 1, next_line);
|
||||||
|
}
|
||||||
|
EditKind::DeleteNewline(_) => {
|
||||||
|
if row > 0 {
|
||||||
|
let line = lines.remove(row);
|
||||||
|
lines[row - 1].push_str(&line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EditKind::Insert(s, i) => {
|
||||||
|
lines[row].insert_str(*i, s.as_str());
|
||||||
|
}
|
||||||
|
EditKind::Remove(s, i) => {
|
||||||
|
let end = *i + s.len();
|
||||||
|
lines[row].replace_range(*i..end, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invert(&self) -> Self {
|
||||||
|
use EditKind::*;
|
||||||
|
match self.clone() {
|
||||||
|
InsertChar(c, i) => DeleteChar(c, i),
|
||||||
|
DeleteChar(c, i) => InsertChar(c, i),
|
||||||
|
InsertNewline(i) => DeleteNewline(i),
|
||||||
|
DeleteNewline(i) => InsertNewline(i),
|
||||||
|
Insert(s, i) => Remove(s, i),
|
||||||
|
Remove(s, i) => Insert(s, i),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Edit {
|
||||||
|
kind: EditKind,
|
||||||
|
cursor_before: (usize, usize),
|
||||||
|
cursor_after: (usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Edit {
|
||||||
|
pub fn new(
|
||||||
|
kind: EditKind,
|
||||||
|
cursor_before: (usize, usize),
|
||||||
|
cursor_after: (usize, usize),
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
kind,
|
||||||
|
cursor_before,
|
||||||
|
cursor_after,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn redo(&self, lines: &mut Vec<String>) {
|
||||||
|
let (row, _) = self.cursor_before;
|
||||||
|
self.kind.apply(row, lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn undo(&self, lines: &mut Vec<String>) {
|
||||||
|
let (row, _) = self.cursor_after;
|
||||||
|
self.kind.invert().apply(row, lines); // Undo is redo of inverted edit
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor_before(&self) -> (usize, usize) {
|
||||||
|
self.cursor_before
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cursor_after(&self) -> (usize, usize) {
|
||||||
|
self.cursor_after
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct History {
|
||||||
index: usize,
|
index: usize,
|
||||||
max_items: usize,
|
max_items: usize,
|
||||||
edits: VecDeque<Edit>,
|
edits: VecDeque<Edit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EditHistory {
|
impl History {
|
||||||
pub fn new(max_items: usize) -> Self {
|
pub fn new(max_items: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
index: 0,
|
index: 0,
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
mod cursor;
|
mod cursor;
|
||||||
mod edit;
|
|
||||||
mod history;
|
mod history;
|
||||||
mod input;
|
mod input;
|
||||||
mod textarea;
|
mod textarea;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::cursor::CursorMove;
|
use crate::cursor::CursorMove;
|
||||||
use crate::edit::{Edit, EditKind};
|
use crate::history::{Edit, EditKind, History};
|
||||||
use crate::history::EditHistory;
|
|
||||||
use crate::input::{Input, Key};
|
use crate::input::{Input, Key};
|
||||||
use std::sync::atomic::{AtomicU16, Ordering};
|
use std::sync::atomic::{AtomicU16, Ordering};
|
||||||
use tui::buffer::Buffer;
|
use tui::buffer::Buffer;
|
||||||
@@ -15,7 +14,7 @@ pub struct TextArea<'a> {
|
|||||||
style: Style,
|
style: Style,
|
||||||
cursor: (usize, usize), // 0-base
|
cursor: (usize, usize), // 0-base
|
||||||
tab: &'a str,
|
tab: &'a str,
|
||||||
history: EditHistory,
|
history: History,
|
||||||
cursor_line_style: Style,
|
cursor_line_style: Style,
|
||||||
scroll_top: (AtomicU16, AtomicU16),
|
scroll_top: (AtomicU16, AtomicU16),
|
||||||
}
|
}
|
||||||
@@ -47,7 +46,7 @@ impl<'a> TextArea<'a> {
|
|||||||
style: Style::default(),
|
style: Style::default(),
|
||||||
cursor: (0, 0),
|
cursor: (0, 0),
|
||||||
tab: " ",
|
tab: " ",
|
||||||
history: EditHistory::new(50),
|
history: History::new(50),
|
||||||
cursor_line_style: Style::default().add_modifier(Modifier::UNDERLINED),
|
cursor_line_style: Style::default().add_modifier(Modifier::UNDERLINED),
|
||||||
scroll_top: (AtomicU16::new(0), AtomicU16::new(0)),
|
scroll_top: (AtomicU16::new(0), AtomicU16::new(0)),
|
||||||
}
|
}
|
||||||
@@ -453,7 +452,7 @@ impl<'a> TextArea<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_max_histories(&mut self, max: usize) {
|
pub fn set_max_histories(&mut self, max: usize) {
|
||||||
self.history = EditHistory::new(max);
|
self.history = History::new(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cursor_line_style(&mut self, style: Style) {
|
pub fn set_cursor_line_style(&mut self, style: Style) {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user