use std::{env, path::PathBuf, sync::Arc};
use directories::BaseDirs;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Rgb {
pub red: u8,
pub green: u8,
pub blue: u8,
}
impl Rgb {
pub const fn new(red: u8, green: u8, blue: u8) -> Self {
Self { red, green, blue }
}
pub(crate) const fn channels(self) -> [u8; 3] {
[self.red, self.green, self.blue]
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct PixelSize {
pub width: u16,
pub height: u16,
}
impl PixelSize {
pub const fn new(width: u16, height: u16) -> Self {
Self {
width: if width == 0 { 1 } else { width },
height: if height == 0 { 1 } else { height },
}
}
}
impl Default for PixelSize {
fn default() -> Self {
Self::new(10, 20)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum GraphicsSupport {
Kitty,
Unsupported,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct TerminalProfile {
pub graphics: GraphicsSupport,
pub cell: PixelSize,
pub tmux: bool,
}
impl TerminalProfile {
pub const fn kitty(cell: PixelSize, tmux: bool) -> Self {
Self {
graphics: GraphicsSupport::Kitty,
cell,
tmux,
}
}
pub const fn unsupported(cell: PixelSize) -> Self {
Self {
graphics: GraphicsSupport::Unsupported,
cell,
tmux: false,
}
}
#[cfg(feature = "terminal-probe")]
pub fn query(timeout: std::time::Duration) -> Self {
use ratatui_image::picker::{Picker, ProtocolType, cap_parser::QueryStdioOptions};
let options = QueryStdioOptions {
timeout,
..QueryStdioOptions::default()
};
let tmux = env::var_os("TMUX").is_some();
match Picker::from_query_stdio_with_options(options) {
Ok(picker) => {
let (cell_width, cell_height) = picker.font_size();
Self {
graphics: if picker.protocol_type() == ProtocolType::Kitty {
GraphicsSupport::Kitty
} else {
GraphicsSupport::Unsupported
},
cell: PixelSize::new(cell_width, cell_height),
tmux,
}
}
Err(_) => Self {
graphics: GraphicsSupport::Unsupported,
cell: PixelSize::default(),
tmux,
},
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Antialiasing {
Grayscale,
LcdRgb,
LcdBgr,
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ColorScheme {
pub foreground: Rgb,
pub background: Option<Rgb>,
}
impl Default for ColorScheme {
fn default() -> Self {
Self {
foreground: Rgb::new(235, 235, 235),
background: None,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct PixelPadding {
pub horizontal: u16,
pub vertical: u16,
}
impl Default for PixelPadding {
fn default() -> Self {
Self {
horizontal: 4,
vertical: 2,
}
}
}
#[derive(Clone, Debug)]
pub struct Limits {
pub max_source_bytes: usize,
pub max_png_bytes: usize,
pub max_image_pixels: u64,
pub max_columns: u16,
pub max_rows: u16,
pub max_memory_entries: usize,
pub max_memory_bytes: usize,
pub max_disk_entries: usize,
pub request_queue: usize,
pub workers: usize,
}
impl Default for Limits {
fn default() -> Self {
Self {
max_source_bytes: 16 * 1024,
max_png_bytes: 8 * 1024 * 1024,
max_image_pixels: 8 * 1024 * 1024,
max_columns: 240,
max_rows: 96,
max_memory_entries: 128,
max_memory_bytes: 64 * 1024 * 1024,
max_disk_entries: 256,
request_queue: 32,
workers: 2,
}
}
}
pub(crate) type Wake = Arc<dyn Fn() + Send + Sync + 'static>;
#[derive(Clone)]
pub(crate) struct EngineConfig {
pub terminal: TerminalProfile,
pub colors: ColorScheme,
pub antialiasing: Antialiasing,
pub padding: PixelPadding,
pub dpi: u16,
pub cache_dir: PathBuf,
pub limits: Limits,
pub wake: Wake,
}
pub(crate) fn default_cache_dir() -> PathBuf {
BaseDirs::new().map_or_else(
|| env::temp_dir().join("ratatex-cache"),
|base| base.cache_dir().join("ratatex"),
)
}