1use std::env::var;
2
3use anyhow::Result;
4use ratatui::layout::Rect;
5
6use crate::common::{is_in_path, UEBERZUG};
7use crate::config::{get_prefered_imager, Imagers};
8use crate::io::{user_has_x11, InlineImage, Ueberzug};
9use crate::log_info;
10use crate::modes::DisplayedImage;
11
12const COMPATIBLES: [&str; 4] = [
13 "WEZTERM_EXECUTABLE",
14 "WARP_HONOR_PS1",
15 "TABBY_CONFIG_DIRECTORY",
16 "VSCODE_INJECTION",
17];
18
19#[derive(Default)]
24pub enum ImageAdapter {
25 #[default]
26 Unable,
27 Ueberzug(Ueberzug),
28 InlineImage(InlineImage),
29}
30
31impl ImageAdapter {
32 pub fn detect() -> Self {
38 let Some(prefered_imager) = get_prefered_imager() else {
39 return Self::Unable;
40 };
41
42 match prefered_imager.imager {
43 Imagers::Disabled => Self::Unable,
44 Imagers::Inline => {
45 for variable in COMPATIBLES {
46 if var(variable).is_ok() {
47 log_info!(
48 "detected Inline Image Protocol compatible terminal from {variable}"
49 );
50 return Self::InlineImage(InlineImage::default());
51 }
52 }
53 Self::try_ueberzug()
54 }
55 Imagers::Ueberzug => Self::try_ueberzug(),
56 }
57 }
58
59 fn try_ueberzug() -> Self {
60 if is_in_path(UEBERZUG) && user_has_x11() {
61 log_info!("detected ueberzug");
62 Self::Ueberzug(Ueberzug::default())
63 } else {
64 log_info!("unable to display image");
65 Self::Unable
66 }
67 }
68}
69
70pub trait ImageDisplayer {
75 fn draw(&mut self, image: &DisplayedImage, rect: Rect) -> Result<()>;
76 fn clear(&mut self, image: &DisplayedImage) -> Result<()>;
77 fn clear_all(&mut self) -> Result<()>;
78}
79
80impl ImageDisplayer for ImageAdapter {
81 fn draw(&mut self, image: &DisplayedImage, rect: Rect) -> Result<()> {
82 match self {
83 Self::Unable => Ok(()),
84 Self::Ueberzug(ueberzug) => ueberzug.draw(image, rect),
85 Self::InlineImage(inline_image) => inline_image.draw(image, rect),
86 }
87 }
88
89 fn clear(&mut self, image: &DisplayedImage) -> Result<()> {
90 match self {
91 Self::Unable => Ok(()),
92 Self::Ueberzug(ueberzug) => ueberzug.clear(image),
93 Self::InlineImage(inline_image) => inline_image.clear(image),
94 }
95 }
96
97 fn clear_all(&mut self) -> Result<()> {
98 match self {
99 Self::Unable => Ok(()),
100 Self::Ueberzug(ueberzug) => ueberzug.clear_all(),
101 Self::InlineImage(inline_image) => inline_image.clear_all(),
102 }
103 }
104}