use std::{fmt::{Debug, Formatter, Result},
ops::{Deref, DerefMut}};
use r3bl_rs_utils_core::*;
use serde::{Deserialize, Serialize};
use super::TERMINAL_LIB_BACKEND;
use crate::*;
#[macro_export]
macro_rules! render_ops {
(
@new $arg_z_order: expr =>
$( /* Start a repetition. */
$element:expr /* Expression. */
) /* End repetition. */
, /* Comma separated. */
* /* Zero or more times. */
) => {
{
let mut render_ops = RenderOps::default();
render_ops.z_order = $arg_z_order;
$(
render_ops.list.push($element);
)*
render_ops
}
};
}
#[derive(Default, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct RenderOps {
pub list: Vec<RenderOp>,
pub z_order: ZOrder,
}
pub mod render_ops_helpers {
use super::*;
impl Deref for RenderOps {
type Target = Vec<RenderOp>;
fn deref(&self) -> &Self::Target { &self.list }
}
impl DerefMut for RenderOps {
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.list }
}
impl Debug for RenderOps {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut vec_lines: Vec<String> = vec![format!("RenderOps.len(): {}", self.list.len())];
for render_op in self.iter() {
let line: String = format!("[{:?}]", render_op);
vec_lines.push(line);
}
write!(f, "\n - {}", vec_lines.join("\n - "))
}
}
}
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub enum RenderOp {
EnterRawMode,
ExitRawMode,
MoveCursorPositionAbs(Position),
MoveCursorPositionRelTo(Position, Position),
ClearScreen,
SetFgColor(TWColor),
SetBgColor(TWColor),
ResetColor,
ApplyColors(Option<Style>),
PrintTextWithAttributes(String, Option<Style>),
CursorShow,
CursorHide,
RequestShowCaretAtPositionAbs(Position),
RequestShowCaretAtPositionRelTo(Position, Position),
Noop,
}
impl Default for RenderOp {
fn default() -> Self { Self::Noop }
}
pub enum FlushKind {
JustFlush,
ClearBeforeFlush,
}
pub trait Flush {
fn flush(&mut self);
fn clear_before_flush(&mut self);
}
impl Flush for RenderOp {
fn flush(&mut self) {
match TERMINAL_LIB_BACKEND {
TerminalLibBackend::Crossterm => {
RenderOpImplCrossterm {}.flush();
}
TerminalLibBackend::Termion => todo!(), }
}
fn clear_before_flush(&mut self) {
match TERMINAL_LIB_BACKEND {
TerminalLibBackend::Crossterm => {
RenderOpImplCrossterm {}.clear_before_flush();
}
TerminalLibBackend::Termion => todo!(), }
}
}
impl Debug for RenderOp {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match TERMINAL_LIB_BACKEND {
TerminalLibBackend::Crossterm => CrosstermDebugFormatRenderOp {}.debug_format(self, f),
TerminalLibBackend::Termion => todo!(), }
}
}
pub trait DebugFormatRenderOp {
fn debug_format(&self, this: &RenderOp, f: &mut Formatter<'_>) -> Result;
}
#[macro_export]
macro_rules! exec_render_op {
(
$arg_cmd: expr,
$arg_log_msg: expr
) => {{
use $crate::tui::DEBUG_SHOW_TERMINAL_BACKEND;
let _fn_wrap_for_logging_err = || -> CommonResult<()> {
throws!({
if let Err(err) = $arg_cmd {
call_if_true!(
DEBUG_SHOW_TERMINAL_BACKEND,
log!(
ERROR,
"crossterm: ❌ Failed to {} due to {}",
$arg_log_msg,
err
)
);
} else {
call_if_true! {
DEBUG_SHOW_TERMINAL_BACKEND,
log!(INFO, "crossterm: ✅ {} successfully", $arg_log_msg)
};
}
})
};
if let Err(logging_err) = _fn_wrap_for_logging_err() {
let msg = format!(
"❌ Failed to log exec output of {}, {}",
stringify!($arg_cmd),
$arg_log_msg
);
call_if_true! {
DEBUG_SHOW_TERMINAL_BACKEND,
debug!(ERROR_RAW &msg, logging_err)
};
}
}};
}