use crate::buffer::Buffer;
use crate::state::coordinator::StateCoordinator;
use crate::state::events::{StateChange, StateEvent};
use std::cell::RefCell;
use std::rc::{Rc, Weak};
use tracing::{debug, info, warn};
pub trait StateSubscriber {
fn on_state_event(&mut self, event: &StateEvent, buffer: &Buffer);
fn name(&self) -> &str;
}
#[derive(Debug)]
pub enum SubscriberCommand {
None,
ClearSearch,
UpdateViewport,
RefreshDisplay,
}
pub struct StateDispatcher {
buffer: Weak<RefCell<Buffer>>,
subscribers: Vec<Box<dyn StateSubscriber>>,
event_history: Vec<StateEvent>,
max_history: usize,
}
impl Default for StateDispatcher {
fn default() -> Self {
Self::new()
}
}
impl StateDispatcher {
#[must_use]
pub fn new() -> Self {
Self {
buffer: Weak::new(),
subscribers: Vec::new(),
event_history: Vec::new(),
max_history: 100,
}
}
pub fn set_buffer(&mut self, buffer: Rc<RefCell<Buffer>>) {
self.buffer = Rc::downgrade(&buffer);
}
pub fn subscribe(&mut self, subscriber: Box<dyn StateSubscriber>) {
info!("StateDispatcher: Adding subscriber: {}", subscriber.name());
self.subscribers.push(subscriber);
}
pub fn dispatch(&mut self, event: StateEvent) {
debug!("StateDispatcher: Dispatching event: {:?}", event);
self.event_history.push(event.clone());
if self.event_history.len() > self.max_history {
self.event_history.remove(0);
}
let buffer_rc = if let Some(b) = self.buffer.upgrade() {
b
} else {
warn!("StateDispatcher: Buffer reference lost!");
return;
};
let change = {
let buffer = buffer_rc.borrow();
buffer.process_event(&event)
};
if !matches!(
change,
StateChange {
mode: None,
search_state: None,
filter_state: None,
fuzzy_filter_state: None,
clear_all_searches: false
}
) {
info!("StateDispatcher: Applying state change: {:?}", change);
buffer_rc.borrow_mut().apply_change(change);
}
let buffer = buffer_rc.borrow();
for subscriber in &mut self.subscribers {
debug!(
"StateDispatcher: Notifying subscriber: {}",
subscriber.name()
);
subscriber.on_state_event(&event, &buffer);
}
}
pub fn dispatch_mode_change(
&mut self,
from: crate::buffer::AppMode,
to: crate::buffer::AppMode,
) {
self.dispatch(StateEvent::ModeChanged { from, to });
}
pub fn dispatch_search_start(
&mut self,
search_type: crate::ui::state::shadow_state::SearchType,
) {
self.dispatch(StateEvent::SearchStarted { search_type });
}
pub fn dispatch_search_end(&mut self, search_type: crate::ui::state::shadow_state::SearchType) {
self.dispatch(StateEvent::SearchEnded { search_type });
}
#[must_use]
pub fn get_event_history(&self) -> &[StateEvent] {
&self.event_history
}
}
pub struct VimSearchSubscriber {
active: bool,
}
impl Default for VimSearchSubscriber {
fn default() -> Self {
Self::new()
}
}
impl VimSearchSubscriber {
#[must_use]
pub fn new() -> Self {
Self { active: false }
}
}
impl StateSubscriber for VimSearchSubscriber {
fn on_state_event(&mut self, event: &StateEvent, buffer: &Buffer) {
match event {
StateEvent::SearchStarted { search_type } => {
if matches!(search_type, crate::ui::state::shadow_state::SearchType::Vim) {
info!("VimSearchSubscriber: Activating for vim search");
self.active = true;
}
}
StateEvent::SearchEnded { search_type } => {
if matches!(search_type, crate::ui::state::shadow_state::SearchType::Vim) {
info!("VimSearchSubscriber: Deactivating - search ended");
self.active = false;
}
}
StateEvent::ModeChanged { from: _, to } => {
if *to == crate::buffer::AppMode::Results && buffer.search_state.pattern.is_empty()
{
if self.active {
info!("VimSearchSubscriber: Deactivating - mode changed to Results with empty search");
}
self.active = false;
}
}
_ => {}
}
}
fn name(&self) -> &'static str {
"VimSearchSubscriber"
}
}