use reovim_kernel::api::v1::{BufferId, OptionValue, WindowId};
#[derive(Debug, Clone)]
pub struct OptionChange {
pub name: String,
pub value: OptionValue,
pub window_id: Option<WindowId>,
}
impl OptionChange {
#[must_use]
pub fn global(name: impl Into<String>, value: OptionValue) -> Self {
Self {
name: name.into(),
value,
window_id: None,
}
}
#[must_use]
pub fn window(name: impl Into<String>, value: OptionValue, window_id: WindowId) -> Self {
Self {
name: name.into(),
value,
window_id: Some(window_id),
}
}
}
#[derive(Debug, Default, Clone)]
#[allow(clippy::struct_excessive_bools)]
pub struct StateChanges {
pub mode_changed: bool,
pub cursor_moved: bool,
pub selection_changed: bool,
pub buffer_modified: bool,
pub modified_buffers: Vec<BufferId>,
pub modified_buffer_edits:
Vec<(BufferId, reovim_kernel::api::v1::events::kernel::Modification)>,
pub affected_buffers: Vec<BufferId>,
pub buffers_created: Vec<BufferId>,
pub buffers_deleted: Vec<BufferId>,
pub buffers_renamed: Vec<(BufferId, String)>,
pub window_changed: bool,
pub windows_created: Vec<WindowId>,
pub windows_closed: Vec<WindowId>,
pub focus_changed: bool,
pub option_changed: bool,
pub options_changed: Vec<OptionChange>,
pub scroll_changed: bool,
pub scrolled_windows: Vec<WindowId>,
pub presence_changed: bool,
pub presence_updates: Vec<usize>,
pub extension_changed: bool,
pub extensions_updated: Vec<String>,
pub should_quit: bool,
}
impl StateChanges {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub const fn has_changes(&self) -> bool {
self.mode_changed
|| self.cursor_moved
|| self.selection_changed
|| self.buffer_modified
|| !self.buffers_created.is_empty()
|| !self.buffers_deleted.is_empty()
|| !self.buffers_renamed.is_empty()
|| self.window_changed
|| !self.windows_created.is_empty()
|| !self.windows_closed.is_empty()
|| self.focus_changed
|| self.option_changed
|| self.scroll_changed
|| self.presence_changed
|| self.extension_changed
}
pub fn merge(&mut self, other: Self) {
self.mode_changed |= other.mode_changed;
self.cursor_moved |= other.cursor_moved;
self.selection_changed |= other.selection_changed;
self.buffer_modified |= other.buffer_modified;
self.modified_buffers.extend(other.modified_buffers);
self.modified_buffer_edits
.extend(other.modified_buffer_edits);
self.affected_buffers.extend(other.affected_buffers);
self.buffers_created.extend(other.buffers_created);
self.buffers_deleted.extend(other.buffers_deleted);
self.buffers_renamed.extend(other.buffers_renamed);
self.window_changed |= other.window_changed;
self.windows_created.extend(other.windows_created);
self.windows_closed.extend(other.windows_closed);
self.focus_changed |= other.focus_changed;
self.option_changed |= other.option_changed;
self.options_changed.extend(other.options_changed);
self.scroll_changed |= other.scroll_changed;
self.scrolled_windows.extend(other.scrolled_windows);
self.presence_changed |= other.presence_changed;
for client_id in other.presence_updates {
if !self.presence_updates.contains(&client_id) {
self.presence_updates.push(client_id);
}
}
self.extension_changed |= other.extension_changed;
for kind in other.extensions_updated {
if !self.extensions_updated.contains(&kind) {
self.extensions_updated.push(kind);
}
}
self.should_quit |= other.should_quit;
}
pub const fn record_mode_change(&mut self) {
self.mode_changed = true;
}
pub fn record_cursor_move(&mut self, buffer: BufferId) {
self.cursor_moved = true;
if !self.affected_buffers.contains(&buffer) {
self.affected_buffers.push(buffer);
}
}
pub fn record_buffer_modified(&mut self, buffer: BufferId) {
self.buffer_modified = true;
if !self.modified_buffers.contains(&buffer) {
self.modified_buffers.push(buffer);
}
if !self.affected_buffers.contains(&buffer) {
self.affected_buffers.push(buffer);
}
}
pub fn record_buffer_modified_with_edit(
&mut self,
buffer: BufferId,
modification: reovim_kernel::api::v1::events::kernel::Modification,
) {
self.record_buffer_modified(buffer);
self.modified_buffer_edits.push((buffer, modification));
}
pub fn record_buffer_created(&mut self, buffer: BufferId) {
self.buffers_created.push(buffer);
}
pub fn record_buffer_deleted(&mut self, buffer: BufferId) {
self.buffers_deleted.push(buffer);
}
pub fn record_buffer_renamed(&mut self, buffer: BufferId, new_name: String) {
self.buffers_renamed.push((buffer, new_name));
}
pub fn record_window_created(&mut self, window: WindowId) {
self.window_changed = true;
self.windows_created.push(window);
}
pub fn record_window_closed(&mut self, window: WindowId) {
self.window_changed = true;
self.windows_closed.push(window);
}
pub const fn record_focus_change(&mut self) {
self.focus_changed = true;
}
pub fn record_selection_change(&mut self, buffer: BufferId) {
self.selection_changed = true;
if !self.affected_buffers.contains(&buffer) {
self.affected_buffers.push(buffer);
}
}
pub fn record_option_change(&mut self, change: OptionChange) {
self.option_changed = true;
self.options_changed.push(change);
}
pub fn record_global_option_change(&mut self, name: impl Into<String>, value: OptionValue) {
self.record_option_change(OptionChange::global(name, value));
}
pub fn record_window_option_change(
&mut self,
name: impl Into<String>,
value: OptionValue,
window_id: WindowId,
) {
self.record_option_change(OptionChange::window(name, value, window_id));
}
pub fn record_scroll_change(&mut self, window: WindowId) {
self.scroll_changed = true;
if !self.scrolled_windows.contains(&window) {
self.scrolled_windows.push(window);
}
}
pub fn record_presence_change(&mut self, client_id: usize) {
self.presence_changed = true;
if !self.presence_updates.contains(&client_id) {
self.presence_updates.push(client_id);
}
}
pub fn record_extension_change(&mut self, kind: String) {
self.extension_changed = true;
if !self.extensions_updated.contains(&kind) {
self.extensions_updated.push(kind);
}
}
pub const fn record_quit_requested(&mut self) {
self.should_quit = true;
}
}
pub trait ChangeTracker: Send {
fn take_changes(&mut self) -> StateChanges;
fn record_cursor_move(&mut self, buffer: BufferId);
fn record_selection_change(&mut self, buffer: BufferId);
}
#[cfg(test)]
#[path = "tests/changes.rs"]
mod tests;