use crate::{Cell, Executor, SessionState, Store};
use anyhow::{Context, Result};
use std::collections::HashMap;
pub struct Session {
executor: Box<dyn Executor>,
store: Box<dyn Store>,
defs_text: String,
snapshots: HashMap<usize, Vec<Cell>>,
line_no: usize,
}
impl Session {
pub fn new(executor: Box<dyn Executor>, store: Box<dyn Store>) -> Session {
let state = store.load().unwrap_or_default();
let line_no = state.line_no.max(1);
Session {
executor,
store,
defs_text: state.defs_text,
snapshots: HashMap::new(),
line_no,
}
}
pub fn seed_defs(&mut self, text: &str) -> Result<()> {
quarb::parse_defs(text).context("parsing --defs")?;
self.defs_text = format!("{text}\n");
self.persist();
Ok(())
}
pub fn add_def(&mut self, line: &str) -> Result<()> {
let candidate = format!("{}{}\n", self.defs_text, line);
quarb::parse_defs(&candidate).context("parsing definition")?;
self.defs_text = candidate;
self.persist();
Ok(())
}
fn combined(&self, line: &str) -> String {
if self.defs_text.is_empty() {
line.to_string()
} else {
format!("{}\n{line}", self.defs_text)
}
}
pub fn eval(&self, line: &str) -> Result<Vec<Cell>> {
self.executor.run(&self.combined(line))
}
pub fn eval_fresh(&self, line: &str) -> Result<Vec<Cell>> {
self.executor.run_fresh(&self.combined(line))
}
pub fn commit(&mut self, line: &str, snapshot: Vec<Cell>) -> bool {
self.snapshots.insert(self.line_no, snapshot);
let candidate = format!("{}def &{}: {} ;\n", self.defs_text, self.line_no, line);
let referenceable = quarb::parse_defs(&candidate).is_ok();
if referenceable {
self.defs_text = candidate;
}
self.line_no += 1;
self.persist();
referenceable
}
pub fn frozen(&self, n: usize) -> Option<&Vec<Cell>> {
self.snapshots.get(&n)
}
pub fn record_frozen(&mut self, snapshot: Vec<Cell>) {
self.snapshots.insert(self.line_no, snapshot);
self.line_no += 1;
self.persist();
}
fn persist(&self) {
let state = SessionState {
defs_text: self.defs_text.clone(),
line_no: self.line_no,
};
let _ = self.store.save(&state);
}
pub fn line_no(&self) -> usize {
self.line_no
}
pub fn history(&self) -> &str {
&self.defs_text
}
pub fn restore(&mut self, defs_text: String, line_no: usize) {
self.defs_text = defs_text;
self.line_no = line_no.max(1);
}
pub fn reset(&mut self) {
self.defs_text.clear();
self.snapshots.clear();
self.line_no = 1;
self.persist();
}
}