diff options
| -rw-r--r-- | rprt-engine/src/buffer.rs | 35 | ||||
| -rw-r--r-- | rprt-engine/src/explainer.rs | 10 | ||||
| -rw-r--r-- | rprt-engine/src/lib.rs | 1 | ||||
| -rw-r--r-- | rprt-engine/src/state.rs | 153 |
4 files changed, 194 insertions, 5 deletions
diff --git a/rprt-engine/src/buffer.rs b/rprt-engine/src/buffer.rs index f2c6e0f..ab97c44 100644 --- a/rprt-engine/src/buffer.rs +++ b/rprt-engine/src/buffer.rs @@ -4,14 +4,39 @@ use std::process::Command; use std::time::{SystemTime, UNIX_EPOCH}; pub type BufferID = usize; + +#[derive(Debug)] +pub enum BufferState { + Modified, + Unmodified, +} + +#[derive(Debug)] pub struct Buffer { pub content: String, pub name: String, + pub state: BufferState, + pub read_only: bool, + pub ephemeral: bool, } impl Buffer { pub fn new(name: String, content: String) -> Self { - Self { name, content } + Self { + name, + content, + state: BufferState::Unmodified, + read_only: false, + ephemeral: false, + } + } + + pub fn max_pos(&self) -> usize { + self.content.len() + } + + pub fn valid_pos(&self, pos: usize) -> bool { + pos <= self.max_pos() } fn generate_shell_name(command: &str) -> String { @@ -40,6 +65,12 @@ impl Buffer { Err(e) => format!("Command failed: {}", e), }; - Self { name, content } + Self { + name, + content, + read_only: true, + state: BufferState::Unmodified, + ephemeral: true, + } } } diff --git a/rprt-engine/src/explainer.rs b/rprt-engine/src/explainer.rs index 9770c72..e3e99fb 100644 --- a/rprt-engine/src/explainer.rs +++ b/rprt-engine/src/explainer.rs @@ -118,11 +118,15 @@ fn generate_tree(formatted: &str, expr: &Composite) -> String { if let Some(node) = node_at_pos { match node.node_kind { - NodeKind::Hook(hook_kind) => line[i] = hook_kind.to_string().chars().next().unwrap(), + NodeKind::Hook(hook_kind) => { + line[i] = hook_kind.to_string().chars().next().unwrap() + } NodeKind::Train(arity) => line[i] = char::from_digit(arity as u32, 10).unwrap(), NodeKind::Group => line[i] = '+', - NodeKind::Plain => if up || down || in_span { - line[i] = box_char(up, down, left, right); + NodeKind::Plain => { + if up || down || in_span { + line[i] = box_char(up, down, left, right); + } } } } else if up || down || in_span { diff --git a/rprt-engine/src/lib.rs b/rprt-engine/src/lib.rs index 4d9e07a..3ef4ac1 100644 --- a/rprt-engine/src/lib.rs +++ b/rprt-engine/src/lib.rs @@ -4,4 +4,5 @@ pub mod buffer; pub mod expression; pub mod parser; pub mod selection; +pub mod state; pub mod token; diff --git a/rprt-engine/src/state.rs b/rprt-engine/src/state.rs new file mode 100644 index 0000000..7964876 --- /dev/null +++ b/rprt-engine/src/state.rs @@ -0,0 +1,153 @@ +use crate::buffer::{Buffer, BufferID}; +use crate::selection::Selection; +use std::collections::HashMap; +use std::path::PathBuf; + +#[derive(Debug, Clone)] +pub enum StateChange { + SetCurrentSelection { + old_selection: Selection, + new_selection: Selection, + }, + SetCurrentBuffer { + old_buffer: BufferID, + new_buffer: BufferID, + }, + ModifyBuffer { + buffer: BufferID, + old_start: usize, + old_end: usize, + old_content: String, + new_content: String, + }, + CreateBuffer { + buffer: BufferID, + file: Option<PathBuf>, + }, + DeleteBuffer { + buffer: BufferID, + }, +} + +impl StateChange { + pub fn invert(&self) -> Option<Self> { + match self { + StateChange::SetCurrentSelection { + old_selection, + new_selection, + } => Some(StateChange::SetCurrentSelection { + old_selection: new_selection.clone(), + new_selection: old_selection.clone(), + }), + StateChange::SetCurrentBuffer { + old_buffer, + new_buffer, + } => Some(StateChange::SetCurrentBuffer { + old_buffer: *new_buffer, + new_buffer: *old_buffer, + }), + StateChange::ModifyBuffer { .. } => None, // TODO: implement, irritating coordinate stuff + // TODO: Not supported? + StateChange::CreateBuffer { .. } => None, + StateChange::DeleteBuffer { .. } => None, + } + } +} + +#[derive(Debug)] +pub struct EditorState { + current_buffer: BufferID, + current_selection: Selection, + buffers: HashMap<BufferID, Buffer>, + buffer_to_file: HashMap<BufferID, Option<PathBuf>>, + history: Vec<StateChange>, + next_buffer_id: BufferID, +} + +impl EditorState { + pub fn new() -> Self { + Self { + current_buffer: 0, + current_selection: Selection::empty(), + buffers: HashMap::new(), + buffer_to_file: HashMap::new(), + history: Vec::new(), + next_buffer_id: 0, + } + } + + pub fn create_buffer( + &mut self, + name: String, + content: String, + file: Option<PathBuf>, + ) -> BufferID { + let buffer_id = self.next_buffer_id; + self.next_buffer_id += 1; + + let buffer = Buffer::new(name, content); + self.buffers.insert(buffer_id, buffer); + self.buffer_to_file.insert(buffer_id, file.clone()); + + self.history.push(StateChange::CreateBuffer { + buffer: buffer_id, + file, + }); + + buffer_id + } + + pub fn get_buffer(&self, buffer_id: BufferID) -> Option<&Buffer> { + self.buffers.get(&buffer_id) + } + + pub fn get_buffer_mut(&mut self, buffer_id: BufferID) -> Option<&mut Buffer> { + self.buffers.get_mut(&buffer_id) + } + + pub fn commit(&mut self, change: StateChange) { + match &change { + StateChange::SetCurrentSelection { new_selection, .. } => { + self.current_selection = new_selection.clone(); + } + StateChange::SetCurrentBuffer { new_buffer, .. } => { + self.current_buffer = *new_buffer; + } + StateChange::ModifyBuffer { + buffer, + old_start, + old_end, + new_content, + .. + } => { + if let Some(buf) = self.buffers.get_mut(buffer) { + buf.content = format!( + "{}{}{}", + &buf.content[..*old_start], + new_content, + &buf.content[*old_end..] + ); + } + } + StateChange::CreateBuffer { buffer, file } => { + // TODO: do we want this? + if !self.buffer_to_file.contains_key(buffer) { + self.buffer_to_file.insert(*buffer, file.clone()); + } + } + StateChange::DeleteBuffer { buffer } => { + self.buffers.remove(buffer); + self.buffer_to_file.remove(buffer); + } + } + self.history.push(change); + } + + pub fn commit_changes(&mut self, changes: Vec<StateChange>) { + for change in changes { + self.commit(change); + } + } +} + +pub type EvaluationResult = (Selection, Vec<StateChange>); |
