use crate::{
component::Component,
event::{MatchListEvent, PromptEvent},
match_list::MatchList,
prompt::{Prompt, PromptStatus},
util::as_u32,
Injector, Render,
};
pub struct LazyMatchList<'a, T: Send + Sync + 'static, R: Render<T>> {
match_list: &'a mut MatchList<T, R>,
buffered_selection: u32,
}
impl<'a, T: Send + Sync + 'static, R: Render<T>> LazyMatchList<'a, T, R> {
pub fn new(match_list: &'a mut MatchList<T, R>) -> Self {
let buffered_selection = match_list.selection();
Self {
match_list,
buffered_selection,
}
}
pub fn restart(&mut self) -> Injector<T, R> {
self.match_list.restart();
self.buffered_selection = 0;
self.match_list.injector()
}
pub fn is_empty(&self) -> bool {
self.match_list.is_empty()
}
pub fn selection(&self) -> u32 {
self.buffered_selection
}
fn decr(&mut self, n: usize) {
self.buffered_selection = self.buffered_selection.saturating_sub(as_u32(n));
}
fn incr(&mut self, n: usize) {
self.buffered_selection = self
.buffered_selection
.saturating_add(as_u32(n))
.min(self.match_list.max_selection());
}
pub fn handle(&mut self, event: MatchListEvent) {
match event {
MatchListEvent::Up(n) => {
if self.match_list.reversed() {
self.decr(n);
} else {
self.incr(n);
}
}
MatchListEvent::Down(n) => {
if self.match_list.reversed() {
self.incr(n);
} else {
self.decr(n);
}
}
MatchListEvent::Reset => {
self.buffered_selection = 0;
}
}
}
pub fn finish(self) -> bool {
self.match_list.set_selection(self.buffered_selection)
}
}
pub struct LazyPrompt<'a> {
prompt: &'a mut Prompt,
buffered_event: Option<PromptEvent>,
status: PromptStatus,
}
impl<'a> LazyPrompt<'a> {
pub fn is_empty(&self) -> bool {
self.prompt.is_empty()
}
pub fn new(prompt: &'a mut Prompt) -> Self {
Self {
prompt,
buffered_event: None,
status: PromptStatus::default(),
}
}
fn swap_and_process_buffer(&mut self, mut event: PromptEvent) {
std::mem::swap(
unsafe { self.buffered_event.as_mut().unwrap_unchecked() },
&mut event,
);
self.status |= self.prompt.handle(event);
}
pub fn finish(mut self) -> PromptStatus {
if let Some(event) = self.buffered_event {
self.status |= self.prompt.handle(event);
}
self.status
}
pub fn handle(&mut self, mut event: PromptEvent) {
match self.buffered_event {
None => {
self.buffered_event = Some(event);
}
Some(ref mut buffered) => match event {
PromptEvent::Left(ref mut n1) => {
if let PromptEvent::Left(n2) = buffered {
*n1 += *n2;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::WordLeft(ref mut n1) => {
if let PromptEvent::WordLeft(n2) = buffered {
*n1 += *n2;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::Right(ref mut n1) => {
if let PromptEvent::Right(n2) = buffered {
*n1 += *n2;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::WordRight(ref mut n1) => {
if let PromptEvent::WordRight(n2) = buffered {
*n1 += *n2;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::ToStart => {
if buffered.is_cursor_movement() {
*buffered = PromptEvent::ToStart;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::ToEnd => {
if buffered.is_cursor_movement() {
*buffered = PromptEvent::ToEnd;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::Backspace(ref mut n1) => {
if let PromptEvent::Backspace(n2) = buffered {
*n1 += *n2;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::Delete(ref mut n1) => {
if let PromptEvent::Delete(n2) = buffered {
*n1 += *n2;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::BackspaceWord(ref mut n1) => {
if let PromptEvent::BackspaceWord(n2) = buffered {
*n1 += *n2;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::ClearBefore => {
if matches!(
buffered,
PromptEvent::Backspace(_)
| PromptEvent::ClearBefore
| PromptEvent::BackspaceWord(_)
) {
*buffered = PromptEvent::ClearBefore;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::ClearAfter => {
if matches!(buffered, PromptEvent::Delete(_) | PromptEvent::ClearAfter) {
*buffered = PromptEvent::ClearAfter;
} else {
self.swap_and_process_buffer(event);
}
}
PromptEvent::Insert(ch1) => match buffered {
PromptEvent::Insert(ch2) => {
let mut s = ch1.to_string();
s.push(*ch2);
*buffered = PromptEvent::Paste(s);
}
PromptEvent::Paste(new) => {
let mut s = ch1.to_string();
s.push_str(new);
*buffered = PromptEvent::Paste(s);
}
_ => {
self.swap_and_process_buffer(event);
}
},
PromptEvent::Paste(ref mut s) => match buffered {
PromptEvent::Insert(ch2) => {
s.push(*ch2);
}
PromptEvent::Paste(new) => {
s.push_str(new);
}
_ => {
self.swap_and_process_buffer(event);
}
},
PromptEvent::Reset(_) => {
*buffered = event;
}
},
};
}
}