use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ViewportState {
pub id: u64,
pub buffer_id: u64,
pub top_line: u32,
pub left_col: u32,
pub cursor_line: u32,
pub cursor_col: u32,
}
impl ViewportState {
#[must_use]
pub const fn new(id: u64, buffer_id: u64) -> Self {
Self {
id,
buffer_id,
top_line: 0,
left_col: 0,
cursor_line: 0,
cursor_col: 0,
}
}
#[must_use]
pub const fn with_cursor(mut self, line: u32, col: u32) -> Self {
self.cursor_line = line;
self.cursor_col = col;
self
}
#[must_use]
pub const fn with_scroll(mut self, top_line: u32, left_col: u32) -> Self {
self.top_line = top_line;
self.left_col = left_col;
self
}
#[must_use]
pub const fn is_line_visible(&self, line: u32, visible_lines: u32) -> bool {
line >= self.top_line && line < self.top_line + visible_lines
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[cfg_attr(feature = "wasm", derive(tsify_next::Tsify))]
#[cfg_attr(feature = "wasm", tsify(into_wasm_abi, from_wasm_abi))]
pub struct ViewportUpdate {
pub viewport_id: u64,
pub top_line: Option<u32>,
pub left_col: Option<u32>,
pub cursor_line: Option<u32>,
pub cursor_col: Option<u32>,
}
impl ViewportUpdate {
#[must_use]
pub const fn new(viewport_id: u64) -> Self {
Self {
viewport_id,
top_line: None,
left_col: None,
cursor_line: None,
cursor_col: None,
}
}
#[must_use]
pub const fn scroll_to(mut self, top_line: u32, left_col: u32) -> Self {
self.top_line = Some(top_line);
self.left_col = Some(left_col);
self
}
#[must_use]
pub const fn cursor_to(mut self, line: u32, col: u32) -> Self {
self.cursor_line = Some(line);
self.cursor_col = Some(col);
self
}
#[cfg_attr(coverage_nightly, coverage(off))]
pub fn apply_to(&self, state: &mut ViewportState) {
debug_assert_eq!(self.viewport_id, state.id);
if let Some(line) = self.top_line {
state.top_line = line;
}
if let Some(col) = self.left_col {
state.left_col = col;
}
if let Some(line) = self.cursor_line {
state.cursor_line = line;
}
if let Some(col) = self.cursor_col {
state.cursor_col = col;
}
}
#[must_use]
#[cfg_attr(coverage_nightly, coverage(off))]
pub const fn is_empty(&self) -> bool {
self.top_line.is_none()
&& self.left_col.is_none()
&& self.cursor_line.is_none()
&& self.cursor_col.is_none()
}
}
#[cfg(test)]
#[path = "viewport_tests.rs"]
mod tests;