use {crate::WindowId, reovim_kernel::api::v1::BufferId};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct LineIndex(usize);
impl LineIndex {
#[must_use]
pub const fn new(index: usize) -> Self {
Self(index)
}
#[must_use]
pub const fn as_usize(self) -> usize {
self.0
}
pub const ZERO: Self = Self(0);
}
impl std::ops::Add<usize> for LineIndex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs)
}
}
impl std::ops::Sub<usize> for LineIndex {
type Output = Self;
fn sub(self, rhs: usize) -> Self::Output {
Self(self.0.saturating_sub(rhs))
}
}
impl std::fmt::Display for LineIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0 + 1)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
pub struct ColIndex(usize);
impl ColIndex {
#[must_use]
pub const fn new(index: usize) -> Self {
Self(index)
}
#[must_use]
pub const fn as_usize(self) -> usize {
self.0
}
pub const ZERO: Self = Self(0);
}
impl std::ops::Add<usize> for ColIndex {
type Output = Self;
fn add(self, rhs: usize) -> Self::Output {
Self(self.0 + rhs)
}
}
impl std::ops::Sub<usize> for ColIndex {
type Output = Self;
fn sub(self, rhs: usize) -> Self::Output {
Self(self.0.saturating_sub(rhs))
}
}
impl std::fmt::Display for ColIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0 + 1)
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Position {
pub line: LineIndex,
pub col: ColIndex,
}
impl Position {
#[must_use]
pub const fn new(line: LineIndex, col: ColIndex) -> Self {
Self { line, col }
}
#[must_use]
pub const fn from_raw(line: usize, col: usize) -> Self {
Self {
line: LineIndex::new(line),
col: ColIndex::new(col),
}
}
#[must_use]
pub const fn origin() -> Self {
Self {
line: LineIndex::ZERO,
col: ColIndex::ZERO,
}
}
}
#[derive(Debug, Clone)]
pub struct View {
pub buffer_id: BufferId,
pub cursor: Position,
pub scroll_top: LineIndex,
pub scroll_left: ColIndex,
}
impl View {
#[must_use]
pub const fn new(buffer_id: BufferId) -> Self {
Self {
buffer_id,
cursor: Position::origin(),
scroll_top: LineIndex::ZERO,
scroll_left: ColIndex::ZERO,
}
}
#[must_use]
pub const fn with_cursor(mut self, cursor: Position) -> Self {
self.cursor = cursor;
self
}
#[must_use]
pub const fn with_scroll(mut self, top: LineIndex, left: ColIndex) -> Self {
self.scroll_top = top;
self.scroll_left = left;
self
}
#[must_use]
pub const fn with_scroll_raw(mut self, top: usize, left: usize) -> Self {
self.scroll_top = LineIndex::new(top);
self.scroll_left = ColIndex::new(left);
self
}
}
pub trait ViewManager: Send + Sync {
fn create(&mut self, window: WindowId, buffer: BufferId) -> &View;
fn get(&self, window: WindowId) -> Option<&View>;
fn get_mut(&mut self, window: WindowId) -> Option<&mut View>;
fn remove(&mut self, window: WindowId);
fn on_focus_changed(&mut self, from: WindowId, to: WindowId);
fn all_views(&self) -> Vec<(WindowId, &View)>;
fn buffer_of(&self, window: WindowId) -> Option<BufferId> {
self.get(window).map(|v| v.buffer_id)
}
fn contains(&self, window: WindowId) -> bool {
self.get(window).is_some()
}
fn len(&self) -> usize {
self.all_views().len()
}
fn is_empty(&self) -> bool {
self.len() == 0
}
}
#[cfg(test)]
#[path = "view_tests.rs"]
mod tests;