mirror of https://github.com/andrewkdinh/via.git
Add partial support for undo
This commit is contained in:
parent
3f9db644b8
commit
42de36bdde
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||||
Cargo.lock
|
#Cargo.lock
|
||||||
|
|
||||||
# These are backup files generated by rustfmt
|
# These are backup files generated by rustfmt
|
||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
[[package]]
|
||||||
|
name = "via"
|
||||||
|
version = "0.1.0"
|
|
@ -1,5 +1,7 @@
|
||||||
# via
|
# via
|
||||||
|
|
||||||
An efficient text editor
|
An efficient text editor
|
||||||
|
|
||||||
**This software is in alpha. Don't use it for anything important**
|
**This software is in alpha. Don't use it for anything important**
|
||||||
|
|
||||||
|
Mirrors: [GitHub](https://github.com/andrewkdinh/via) (main), [GitLab](https://gitlab.com/andrewkdinh/via), [Gitea](https://gitea.andrewkdinh.com/andrewkdinh/via)
|
83
src/main.rs
83
src/main.rs
|
@ -4,13 +4,14 @@
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
// use std::io;
|
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// The overarching editor class
|
/// The overarching editor class
|
||||||
struct Editor {
|
struct Editor {
|
||||||
|
/// The piece table
|
||||||
piece_table: PieceTable,
|
piece_table: PieceTable,
|
||||||
|
/// Reader of the file
|
||||||
reader: BufReader<File>,
|
reader: BufReader<File>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,17 +25,26 @@ impl Editor {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// The main structure for storing text
|
/// The main structure for storing text
|
||||||
struct PieceTable {
|
struct PieceTable {
|
||||||
|
/// The main table, contains `TableEntry`'s
|
||||||
table: Vec<TableEntry>,
|
table: Vec<TableEntry>,
|
||||||
|
/// Original buffer
|
||||||
original_buffer: Buffer,
|
original_buffer: Buffer,
|
||||||
|
/// Add buffer
|
||||||
add_buffer: Buffer,
|
add_buffer: Buffer,
|
||||||
|
/// All active text. Only to be used when `text_up_to_date == true`
|
||||||
text: String,
|
text: String,
|
||||||
|
/// Whether `text` is up to date
|
||||||
text_up_to_date: bool,
|
text_up_to_date: bool,
|
||||||
|
/// List of table entries that have had actions.
|
||||||
|
actions: Vec<TableEntry>,
|
||||||
|
/// Where in `self.actions` we are currently at
|
||||||
|
actions_index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PieceTable {
|
impl PieceTable {
|
||||||
/// Initializes a piece table with the original buffer set
|
/// Initializes a piece table with the original buffer set
|
||||||
fn new(original_buffer: Buffer) -> PieceTable {
|
fn new(original_buffer: Buffer) -> PieceTable {
|
||||||
PieceTable {table: Vec::new(), original_buffer: original_buffer, add_buffer: Buffer::new(), text_up_to_date: true, text: String::new()}
|
PieceTable {table: Vec::new(), original_buffer: original_buffer, add_buffer: Buffer::new(), text: String::new(), text_up_to_date: true, actions: Vec::new(), actions_index: 0}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add text at a certain index
|
/// Add text at a certain index
|
||||||
|
@ -44,9 +54,13 @@ impl PieceTable {
|
||||||
if cursor > text_len {
|
if cursor > text_len {
|
||||||
panic!("cursor ({}) is a greater value than text len ({})", cursor, text_len);
|
panic!("cursor ({}) is a greater value than text len ({})", cursor, text_len);
|
||||||
} else if cursor == 0 {
|
} else if cursor == 0 {
|
||||||
self.table.insert(0, TableEntry::new(true, add_buffer_len, add_buffer_len + text.len()));
|
let new_table_entry = TableEntry::new(true, add_buffer_len, add_buffer_len + text.len());
|
||||||
|
self.add_action(&new_table_entry);
|
||||||
|
self.table.insert(0, new_table_entry);
|
||||||
} else if cursor == text_len {
|
} else if cursor == text_len {
|
||||||
self.table.push(TableEntry::new(true, add_buffer_len, add_buffer_len + text.len()));
|
let new_table_entry = TableEntry::new(true, add_buffer_len, add_buffer_len + text.len());
|
||||||
|
self.add_action(&new_table_entry);
|
||||||
|
self.table.push(new_table_entry);
|
||||||
} else {
|
} else {
|
||||||
let mut table_entry_count = 0;
|
let mut table_entry_count = 0;
|
||||||
let mut curr_pos = 0;
|
let mut curr_pos = 0;
|
||||||
|
@ -62,10 +76,13 @@ impl PieceTable {
|
||||||
self.table.insert(table_entry_count + 1, last_table_entry);
|
self.table.insert(table_entry_count + 1, last_table_entry);
|
||||||
|
|
||||||
let middle_table_entry = TableEntry::new(true, add_buffer_len, add_buffer_len + text.len());
|
let middle_table_entry = TableEntry::new(true, add_buffer_len, add_buffer_len + text.len());
|
||||||
|
self.add_action(&middle_table_entry);
|
||||||
self.table.insert(table_entry_count + 1, middle_table_entry);
|
self.table.insert(table_entry_count + 1, middle_table_entry);
|
||||||
break
|
break
|
||||||
} else if curr_pos == cursor {
|
} else if curr_pos == cursor {
|
||||||
self.table.insert(table_entry_count, TableEntry::new(true, add_buffer_len, add_buffer_len + text.len()));
|
let new_table_entry = TableEntry::new(true, add_buffer_len, add_buffer_len + text.len());
|
||||||
|
self.add_action(&new_table_entry);
|
||||||
|
self.table.insert(table_entry_count, new_table_entry);
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
curr_pos += len;
|
curr_pos += len;
|
||||||
|
@ -89,7 +106,7 @@ impl PieceTable {
|
||||||
let mut temp_table_entry = TableEntry::new(true, 0, 0);
|
let mut temp_table_entry = TableEntry::new(true, 0, 0);
|
||||||
let mut temp_table_set = false;
|
let mut temp_table_set = false;
|
||||||
let mut temp_table_index = 0;
|
let mut temp_table_index = 0;
|
||||||
for table_entry in &mut self.table {
|
for table_entry in self.table.iter_mut() {
|
||||||
if curr_pos == end {
|
if curr_pos == end {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -126,6 +143,42 @@ impl PieceTable {
|
||||||
self.text_up_to_date = false;
|
self.text_up_to_date = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Add a table entry to actions
|
||||||
|
fn add_action(&mut self, table_entry: &TableEntry) {
|
||||||
|
// Remove actions after current index
|
||||||
|
self.actions = self.actions[..self.actions_index].to_vec();
|
||||||
|
self.actions.push(*table_entry);
|
||||||
|
self.actions_index += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Undo an action. Errors if no actions to undo
|
||||||
|
fn undo(&mut self) {
|
||||||
|
// TODO: Need to support undoing delete's, which can span multiple table entries
|
||||||
|
if self.actions.is_empty() {
|
||||||
|
panic!("Unable to undo");
|
||||||
|
}
|
||||||
|
let table_entry_copy : &TableEntry = match self.actions.get(self.actions_index - 1) {
|
||||||
|
Some(table_entry) => table_entry,
|
||||||
|
None => panic!("Unable to get last action"),
|
||||||
|
};
|
||||||
|
for table_entry in self.table.iter_mut() {
|
||||||
|
if table_entry.is_add_buffer == table_entry_copy.is_add_buffer
|
||||||
|
&& table_entry.start_index == table_entry_copy.start_index
|
||||||
|
&& table_entry.end_index == table_entry_copy.end_index {
|
||||||
|
table_entry.switch();
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.text_up_to_date = false;
|
||||||
|
self.actions_index -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Redo an action. Errors if no actions to redo
|
||||||
|
fn redo(&mut self) {
|
||||||
|
// TODO
|
||||||
|
self.text_up_to_date = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the text represented by a table entry.
|
/// Returns the text represented by a table entry.
|
||||||
///
|
///
|
||||||
/// Assumes buffer is up to date
|
/// Assumes buffer is up to date
|
||||||
|
@ -186,12 +239,17 @@ impl PieceTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)] // Needed for PieceTable.actions
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// An entry in PieceTable's table
|
/// An entry in PieceTable's table
|
||||||
struct TableEntry {
|
struct TableEntry {
|
||||||
|
/// Whether this table entry points to the add buffer
|
||||||
is_add_buffer: bool,
|
is_add_buffer: bool,
|
||||||
|
/// Start index
|
||||||
start_index: usize,
|
start_index: usize,
|
||||||
|
/// End index
|
||||||
end_index: usize,
|
end_index: usize,
|
||||||
|
/// Whether this table is visible
|
||||||
active: bool,
|
active: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,13 +258,21 @@ impl TableEntry {
|
||||||
fn new(is_add_buffer: bool, start_index: usize, end_index: usize) -> TableEntry {
|
fn new(is_add_buffer: bool, start_index: usize, end_index: usize) -> TableEntry {
|
||||||
TableEntry {is_add_buffer: is_add_buffer, start_index: start_index, end_index: end_index, active: true}
|
TableEntry {is_add_buffer: is_add_buffer, start_index: start_index, end_index: end_index, active: true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Change from active to deactivated and visa versa
|
||||||
|
fn switch(&mut self) {
|
||||||
|
self.active = !self.active;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// Immutable text (abstracted)
|
/// Immutable text (abstracted)
|
||||||
struct Buffer {
|
struct Buffer {
|
||||||
|
/// Text contained in this buffer. Only use when `text_up_to_date == true`
|
||||||
text: String,
|
text: String,
|
||||||
|
/// Whether `text` is up to date
|
||||||
text_up_to_date: bool,
|
text_up_to_date: bool,
|
||||||
|
/// Text pieces making up `text`
|
||||||
text_pieces: Vec<String>,
|
text_pieces: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,12 +336,17 @@ fn main() {
|
||||||
piece_table.add_text(String::from("b"), 1);
|
piece_table.add_text(String::from("b"), 1);
|
||||||
piece_table.add_text(String::from("de"), 3);
|
piece_table.add_text(String::from("de"), 3);
|
||||||
println!("New: {}", piece_table.text());
|
println!("New: {}", piece_table.text());
|
||||||
|
/*
|
||||||
piece_table.delete_text(0, 1);
|
piece_table.delete_text(0, 1);
|
||||||
println!("New: {}", piece_table.text());
|
println!("New: {}", piece_table.text());
|
||||||
piece_table.delete_text(4, 5);
|
piece_table.delete_text(4, 5);
|
||||||
println!("New: {}", piece_table.text());
|
println!("New: {}", piece_table.text());
|
||||||
piece_table.delete_text(4, 5);
|
piece_table.delete_text(4, 5);
|
||||||
println!("New: {}", piece_table.text());
|
println!("New: {}", piece_table.text());
|
||||||
|
*/
|
||||||
|
piece_table.undo();
|
||||||
|
piece_table.undo();
|
||||||
|
println!("New: {}", piece_table.text());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize(file_name: &String) -> Editor {
|
fn initialize(file_name: &String) -> Editor {
|
||||||
|
|
Loading…
Reference in New Issue