use crate::inboxview::InboxEntry;
use crate::theme::{Role, message_role};
use crate::transcript::{EntryKind, Transcript};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Step {
Back,
Forward,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Caret {
pub row: usize,
pub rows: usize,
}
impl Caret {
pub fn open(&self, dir: Step) -> bool {
match dir {
Step::Back => self.row == 0,
Step::Forward => self.row + 1 >= self.rows,
}
}
}
pub fn prompts(pending: &[InboxEntry], transcript: &Transcript) -> Vec<String> {
let mut said: Vec<String> = transcript
.entries
.iter()
.filter_map(|entry| match &entry.kind {
EntryKind::Delivered {
sender,
epitaph,
body,
} => mine(sender, epitaph.is_some()).then(|| body.clone()),
_ => None,
})
.collect();
said.extend(pending.iter().filter_map(|entry| {
let deposit = &entry.deposit;
mine(
deposit.sender.as_deref().unwrap_or_default(),
deposit.epitaph.is_some(),
)
.then(|| deposit.body.clone())
}));
said.reverse();
said
}
fn mine(sender: &str, has_epitaph: bool) -> bool {
message_role(sender, has_epitaph) == Role::User
}
#[derive(Debug, Default)]
pub struct Recall {
stash: Option<String>,
depth: usize,
}
impl Recall {
pub fn settle(&mut self, draft: &str, prompts: &[String]) {
let shown = self.depth.checked_sub(1).and_then(|at| prompts.get(at));
if self.depth > 0 && shown.map(String::as_str) != Some(draft) {
*self = Self::default();
}
}
pub fn step(
&mut self,
dir: Step,
caret: Caret,
draft: &str,
prompts: &[String],
) -> Option<String> {
if !caret.open(dir) {
return None;
}
match dir {
Step::Back => {
let further = prompts.get(self.depth)?.clone();
if self.depth == 0 {
self.stash = Some(draft.to_owned());
}
self.depth += 1;
Some(further)
}
Step::Forward => {
self.depth = self.depth.checked_sub(1)?;
Some(match self.depth.checked_sub(1) {
Some(at) => prompts.get(at).cloned().unwrap_or_default(),
None => self.stash.take().unwrap_or_default(),
})
}
}
}
}
#[cfg(test)]
mod tests;