use super::{FlushKind, RenderOpsLocalData, RenderPipeline};
use crate::{DEBUG_TUI_COMPOSITOR, DEBUG_TUI_SHOW_PIPELINE_EXPANDED, GlobalData,
LengthOps, LockedOutputDevice, OffscreenBuffer, OffscreenBufferPaint,
OffscreenBufferPaintImplCrossterm, PixelCharDiffChunks, Pos, Size,
TERMINAL_LIB_BACKEND, TerminalLibBackend};
use std::fmt::Debug;
fn perform_diff_paint(
diff_chunks: &PixelCharDiffChunks,
window_size: Size,
locked_output_device: LockedOutputDevice<'_>,
is_mock: bool,
) {
match TERMINAL_LIB_BACKEND {
TerminalLibBackend::Crossterm => {
let mut crossterm_impl = OffscreenBufferPaintImplCrossterm {};
let render_ops = crossterm_impl.render_diff(diff_chunks);
crossterm_impl.paint_diff(
render_ops,
window_size,
locked_output_device,
is_mock,
);
}
TerminalLibBackend::DirectToAnsi => {
let mut converter = OffscreenBufferPaintImplCrossterm {};
let render_ops = converter.render_diff(diff_chunks);
converter.paint_diff(render_ops, window_size, locked_output_device, is_mock);
}
}
}
fn perform_full_paint(
ofs_buf: &OffscreenBuffer,
flush_kind: FlushKind,
window_size: Size,
locked_output_device: LockedOutputDevice<'_>,
is_mock: bool,
) {
match TERMINAL_LIB_BACKEND {
TerminalLibBackend::Crossterm => {
let mut crossterm_impl = OffscreenBufferPaintImplCrossterm {};
let render_ops = crossterm_impl.render(ofs_buf);
crossterm_impl.paint(
render_ops,
flush_kind,
window_size,
locked_output_device,
is_mock,
);
}
TerminalLibBackend::DirectToAnsi => {
let mut converter = OffscreenBufferPaintImplCrossterm {};
let render_ops = converter.render(ofs_buf);
converter.paint(
render_ops,
flush_kind,
window_size,
locked_output_device,
is_mock,
);
}
}
}
pub fn paint<S, AS>(
pipeline: &RenderPipeline,
flush_kind: FlushKind,
global_data: &mut GlobalData<S, AS>,
locked_output_device: LockedOutputDevice<'_>,
is_mock: bool,
) where
S: Debug + Default + Clone + Sync + Send,
AS: Debug + Default + Clone + Sync + Send,
{
let maybe_saved_ofs_buf = global_data.maybe_saved_ofs_buf.clone();
let window_size = global_data.window_size;
let Some(mut buffer_from_pool) = global_data.offscreen_buffer_pool.take() else {
panic!("All offscreen buffers are currently taken. This should never happen.");
};
pipeline.compose_render_ops_into_ofs_buf(
window_size,
&mut buffer_from_pool,
&mut global_data.memoized_text_widths,
);
match maybe_saved_ofs_buf {
None => {
perform_full_paint(
&buffer_from_pool,
flush_kind,
window_size,
locked_output_device,
is_mock,
);
}
Some(saved_offscreen_buffer) => {
match saved_offscreen_buffer.diff(&buffer_from_pool) {
None => {
perform_full_paint(
&buffer_from_pool,
flush_kind,
window_size,
locked_output_device,
is_mock,
);
}
Some(ref diff_chunks) => {
perform_diff_paint(
diff_chunks,
window_size,
locked_output_device,
is_mock,
);
}
}
}
}
if let Some(old_buffer) = global_data.maybe_saved_ofs_buf.take() {
global_data.offscreen_buffer_pool.give_back(old_buffer);
}
global_data.maybe_saved_ofs_buf = Some(buffer_from_pool);
}
pub fn sanitize_and_save_abs_pos(
orig_abs_pos: Pos,
window_size: Size,
render_local_data: &mut RenderOpsLocalData,
) -> Pos {
let Size {
col_width: window_width,
row_height: window_height,
} = window_size;
let mut sanitized_abs_pos = orig_abs_pos;
sanitized_abs_pos.col_index = sanitized_abs_pos
.col_index
.min(window_width.convert_to_index());
sanitized_abs_pos.row_index = sanitized_abs_pos
.row_index
.min(window_height.convert_to_index());
render_local_data.cursor_pos = sanitized_abs_pos;
debug(orig_abs_pos, sanitized_abs_pos);
sanitized_abs_pos
}
fn debug(orig_pos: Pos, sanitized_pos: Pos) {
DEBUG_TUI_COMPOSITOR.then(|| {
if sanitized_pos != orig_pos {
tracing::info!(
message = "pipeline : ⮻ Attempt to set cursor position (orig) outside of terminal window; clamping to nearest edge of window (sanitized)",
orig = ?orig_pos,
sanitized = ?sanitized_pos
);
}
});
DEBUG_TUI_SHOW_PIPELINE_EXPANDED.then(|| {
tracing::info!(
message = "pipeline : ⮺ Save the cursor position (sanitized) to SharedGlobalData",
sanitized = ?sanitized_pos
);
});
}