//! ### Cursor Controller //! A [Controller] implementation for [crate::api::Cursor] actions in a [crate::Workspace] use std::sync::Arc; use tokio::sync::{mpsc, oneshot, watch}; use crate::{ api::{ controller::{AsyncReceiver, AsyncSender, ControllerCallback}, Controller, Cursor, Selection, }, errors::ControllerResult, }; use codemp_proto::{ cursor::{CursorPosition, RowCol}, files::BufferNode, }; /// A [Controller] for asynchronously sending and receiving [Cursor] event. /// /// An unique [CursorController] exists for each active [crate::Workspace]. #[derive(Debug, Clone)] #[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass)] #[cfg_attr(feature = "js", napi_derive::napi)] pub struct CursorController(pub(crate) Arc<CursorControllerInner>); #[derive(Debug)] pub(crate) struct CursorControllerInner { pub(crate) op: mpsc::UnboundedSender<CursorPosition>, pub(crate) stream: mpsc::Sender<oneshot::Sender<Option<Cursor>>>, pub(crate) poll: mpsc::UnboundedSender<oneshot::Sender<()>>, pub(crate) callback: watch::Sender<Option<ControllerCallback<CursorController>>>, } #[cfg_attr(feature = "async-trait", async_trait::async_trait)] impl Controller<Selection, Cursor> for CursorController {} #[cfg_attr(feature = "async-trait", async_trait::async_trait)] impl AsyncSender<Selection> for CursorController { fn send(&self, mut cursor: Selection) -> ControllerResult<()> { if cursor.start_row > cursor.end_row || (cursor.start_row == cursor.end_row && cursor.start_col > cursor.end_col) { std::mem::swap(&mut cursor.start_row, &mut cursor.end_row); std::mem::swap(&mut cursor.start_col, &mut cursor.end_col); } Ok(self.0.op.send(CursorPosition { buffer: BufferNode { path: cursor.buffer, }, start: RowCol { row: cursor.start_row, col: cursor.start_col, }, end: RowCol { row: cursor.end_row, col: cursor.end_col, }, })?) } } #[cfg_attr(feature = "async-trait", async_trait::async_trait)] impl AsyncReceiver<Cursor> for CursorController { async fn try_recv(&self) -> ControllerResult<Option<Cursor>> { let (tx, rx) = oneshot::channel(); self.0.stream.send(tx).await?; Ok(rx.await?) } async fn poll(&self) -> ControllerResult<()> { let (tx, rx) = oneshot::channel(); self.0.poll.send(tx)?; rx.await?; Ok(()) } fn callback(&self, cb: impl Into<ControllerCallback<CursorController>>) { if self.0.callback.send(Some(cb.into())).is_err() { // TODO should we panic? we failed what we were supposed to do tracing::error!("no active cursor worker to run registered callback!"); } } fn clear_callback(&self) { if self.0.callback.send(None).is_err() { tracing::warn!("no active cursor worker to clear callback"); } } }