1use std::env::var;
2
3use anyhow::Result;
4use ratatui::layout::Rect;
5
6use crate::common::{is_in_path, CHAFA, UEBERZUG};
7use crate::config::{get_prefered_imager, Imagers};
8use crate::io::{user_has_x11, Chafa, 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 Chafa(Chafa),
30}
31
32impl ImageAdapter {
33 pub fn detect() -> Self {
39 let Some(prefered_imager) = get_prefered_imager() else {
40 return Self::Unable;
41 };
42
43 match prefered_imager.imager {
44 Imagers::Disabled => Self::Unable,
45 Imagers::Inline => {
46 for variable in COMPATIBLES {
47 if var(variable).is_ok() {
48 log_info!(
49 "detected Inline Image Protocol compatible terminal from {variable}"
50 );
51 return Self::InlineImage(InlineImage::default());
52 }
53 }
54 Self::try_ueberzug()
55 }
56 Imagers::Chafa => Self::try_chafa(),
57 Imagers::Ueberzug => Self::try_ueberzug(),
58 }
59 }
60
61 fn try_ueberzug() -> Self {
62 if is_in_path(UEBERZUG) && user_has_x11() {
63 log_info!("detected ueberzug");
64 Self::Ueberzug(Ueberzug::default())
65 } else {
66 log_info!("unable to display image");
67 Self::Unable
68 }
69 }
70
71 fn try_chafa() -> Self {
72 if is_in_path(CHAFA) {
73 log_info!("detected chafa");
74 Self::Chafa(Chafa::default())
75 } else {
76 log_info!("unable to display image");
77 Self::Unable
78 }
79 }
80}
81
82pub trait ImageDisplayer {
87 fn draw(&mut self, image: &DisplayedImage, rect: Rect) -> Result<()>;
88 fn clear(&mut self, image: &DisplayedImage) -> Result<()>;
89 fn clear_all(&mut self) -> Result<()>;
90}
91
92impl ImageDisplayer for ImageAdapter {
93 fn draw(&mut self, image: &DisplayedImage, rect: Rect) -> Result<()> {
94 match self {
95 Self::Unable => Ok(()),
96 Self::Ueberzug(ueberzug) => ueberzug.draw(image, rect),
97 Self::InlineImage(inline_image) => inline_image.draw(image, rect),
98 Self::Chafa(chafa) => chafa.draw(image, rect),
99 }
100 }
101
102 fn clear(&mut self, image: &DisplayedImage) -> Result<()> {
103 match self {
104 Self::Unable => Ok(()),
105 Self::Ueberzug(ueberzug) => ueberzug.clear(image),
106 Self::InlineImage(inline_image) => inline_image.clear(image),
107 Self::Chafa(chafa) => chafa.clear(image),
108 }
109 }
110
111 fn clear_all(&mut self) -> Result<()> {
112 match self {
113 Self::Unable => Ok(()),
114 Self::Ueberzug(ueberzug) => ueberzug.clear_all(),
115 Self::InlineImage(inline_image) => inline_image.clear_all(),
116 Self::Chafa(chafa) => chafa.clear_all(),
117 }
118 }
119}