use std::{borrow::Cow, fmt::Debug, sync::Arc};
use async_trait::async_trait;
use r3bl_redux::*;
use r3bl_rs_utils_core::*;
use tokio::sync::RwLock;
use crate::*;
#[derive(Clone, Default)]
pub struct EditorComponent<S, A>
where
S: Debug + Default + Clone + PartialEq + Sync + Send,
A: Debug + Default + Clone + Sync + Send,
{
pub editor_engine: EditorEngine,
pub id: FlexBoxId,
pub on_editor_buffer_change_handler: Option<OnEditorBufferChangeFn<S, A>>,
}
pub mod impl_component {
use super::*;
#[async_trait]
impl<S, A> Component<S, A> for EditorComponent<S, A>
where
S: HasEditorBuffers + Default + Clone + PartialEq + Debug + Sync + Send,
A: Debug + Default + Clone + Sync + Send,
{
fn reset(&mut self) {}
fn get_id(&self) -> FlexBoxId { self.id }
async fn handle_event(
&mut self,
args: ComponentScopeArgs<'_, S, A>,
input_event: &InputEvent,
) -> CommonResult<EventPropagation> {
throws_with_return!({
let ComponentScopeArgs {
shared_global_data,
shared_store,
state,
component_registry,
..
} = args;
let cow_editor_buffer: Cow<EditorBuffer> = {
if let Some(buffer) = state.get_editor_buffer(self.get_id()) {
Cow::Borrowed(buffer)
} else {
Cow::Owned(EditorBuffer::new_empty(
self.editor_engine
.config_options
.syntax_highlight
.get_file_extension_for_new_empty_buffer(),
))
}
};
let engine_args = EditorEngineArgs {
state,
editor_buffer: &cow_editor_buffer,
component_registry,
shared_global_data,
shared_store,
self_id: self.id,
editor_engine: &mut self.editor_engine,
};
match EditorEngine::apply_event(engine_args, input_event).await? {
EditorEngineApplyResponse::Applied(buffer) => {
if let Some(on_change_handler) = self.on_editor_buffer_change_handler {
on_change_handler(shared_store, self.get_id(), buffer);
}
EventPropagation::Consumed
}
EditorEngineApplyResponse::NotApplied => {
EventPropagation::Propagate
}
}
});
}
async fn render(
&mut self,
args: ComponentScopeArgs<'_, S, A>,
current_box: &FlexBox,
_surface_bounds: SurfaceBounds,
) -> CommonResult<RenderPipeline> {
let ComponentScopeArgs {
state,
shared_store,
shared_global_data,
component_registry,
..
} = args;
let my_buffer: Cow<EditorBuffer> = {
if let Some(buffer) = state.get_editor_buffer(self.get_id()) {
Cow::Borrowed(buffer)
} else {
Cow::Owned(EditorBuffer::new_empty(
self.editor_engine
.config_options
.syntax_highlight
.get_file_extension_for_new_empty_buffer(),
))
}
};
let render_args = EditorEngineArgs {
editor_engine: &mut self.editor_engine,
state,
editor_buffer: &my_buffer,
component_registry,
shared_global_data,
shared_store,
self_id: self.id,
};
EditorEngine::render_engine(render_args, current_box).await
}
}
}
pub use impl_component::*;
pub mod constructor {
use super::*;
impl<S, A> EditorComponent<S, A>
where
S: Debug + Default + Clone + PartialEq + Sync + Send,
A: Debug + Default + Clone + Sync + Send,
{
pub fn new(
id: FlexBoxId,
config_options: EditorEngineConfigOptions,
on_buffer_change: OnEditorBufferChangeFn<S, A>,
) -> Self {
Self {
editor_engine: EditorEngine::new(config_options),
id,
on_editor_buffer_change_handler: Some(on_buffer_change),
}
}
pub fn new_shared(
id: FlexBoxId,
config_options: EditorEngineConfigOptions,
on_buffer_change: OnEditorBufferChangeFn<S, A>,
) -> Arc<RwLock<Self>> {
Arc::new(RwLock::new(EditorComponent::new(
id,
config_options,
on_buffer_change,
)))
}
}
}
pub use constructor::*;
pub mod misc {
use super::*;
pub type OnEditorBufferChangeFn<S, A> = fn(&SharedStore<S, A>, FlexBoxId, EditorBuffer);
pub trait HasEditorBuffers {
fn get_editor_buffer(&self, id: FlexBoxId) -> Option<&EditorBuffer>;
}
}
pub use misc::*;