use crate::codegen::Slot;
use crate::lex;
pub struct HistoryEntry {
pub n: Option<usize>,
pub text: String,
}
#[derive(Default)]
pub struct Session {
pub file_items: Vec<String>,
pub stmts: Vec<String>,
pub history: Vec<HistoryEntry>,
pub counter: usize,
log: Vec<Slot>,
}
impl Session {
pub fn commit(&mut self, text: &str, slot: Slot) {
let stored = match slot {
Slot::FileScope => {
self.file_items.push(text.to_string());
self.log.push(slot);
return;
}
Slot::Stmt => text.to_string(),
Slot::Expr if lex::may_have_side_effects(text) => {
format!("(void)({text});")
}
Slot::Expr => return,
};
self.stmts.push(indent(&stored));
self.log.push(slot);
}
pub fn undo(&mut self) -> Option<String> {
let slot = self.log.pop()?;
match slot {
Slot::FileScope => self.file_items.pop(),
Slot::Stmt | Slot::Expr => self.stmts.pop().map(|s| s.trim().to_string()),
}
}
pub fn identifiers(&self) -> Vec<String> {
let mut seen = std::collections::BTreeSet::new();
for text in self.file_items.iter().chain(self.stmts.iter()) {
for w in lex::identifiers(text) {
if w.len() >= 2 {
seen.insert(w);
}
}
}
seen.into_iter().collect()
}
pub fn reset(&mut self) {
self.file_items.clear();
self.stmts.clear();
self.log.clear();
self.counter = 0;
}
}
fn indent(s: &str) -> String {
s.lines()
.map(|l| format!(" {l}"))
.collect::<Vec<_>>()
.join("\n")
}