aboutsummaryrefslogtreecommitdiff
path: root/rprt-engine/src
diff options
context:
space:
mode:
Diffstat (limited to 'rprt-engine/src')
-rw-r--r--rprt-engine/src/buffer.rs35
-rw-r--r--rprt-engine/src/explainer.rs10
-rw-r--r--rprt-engine/src/lib.rs1
-rw-r--r--rprt-engine/src/state.rs153
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>);