Skip to content

Commit 492cb5f

Browse files
authoredNov 2, 2020
Merge pull request #305 from yoichi/iterm2-support
Add iTerm2 image protocol support
2 parents 8f7dcf6 + 47dbab3 commit 492cb5f

File tree

3 files changed

+68
-1
lines changed

3 files changed

+68
-1
lines changed
 

‎src/onefetch/cli.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl Cli {
3636
/// Build `Options` from command line arguments.
3737
pub fn new() -> Result<Self> {
3838
#[cfg(not(windows))]
39-
let possible_backends = ["kitty", "sixel"];
39+
let possible_backends = ["kitty", "iterm2", "sixel"];
4040
#[cfg(windows)]
4141
let possible_backends = [];
4242
let color_values = &[

‎src/onefetch/image_backends/iterm2.rs

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
use {
2+
image::{imageops::FilterType, DynamicImage, GenericImageView},
3+
libc::{ioctl, winsize, STDOUT_FILENO, TIOCGWINSZ},
4+
std::env,
5+
};
6+
7+
pub struct ITerm2Backend {}
8+
9+
impl ITerm2Backend {
10+
pub fn new() -> Self {
11+
Self {}
12+
}
13+
14+
pub fn supported() -> bool {
15+
let term_program = env::var("TERM_PROGRAM").unwrap_or("".to_string());
16+
term_program == "iTerm.app"
17+
}
18+
}
19+
20+
impl super::ImageBackend for ITerm2Backend {
21+
fn add_image(&self, lines: Vec<String>, image: &DynamicImage, _colors: usize) -> String {
22+
let tty_size = unsafe {
23+
let tty_size: winsize = std::mem::zeroed();
24+
ioctl(STDOUT_FILENO, TIOCGWINSZ, &tty_size);
25+
tty_size
26+
};
27+
let width_ratio = f64::from(tty_size.ws_col) / f64::from(tty_size.ws_xpixel);
28+
let height_ratio = f64::from(tty_size.ws_row) / f64::from(tty_size.ws_ypixel);
29+
30+
// resize image to fit the text height with the Lanczos3 algorithm
31+
let image = image.resize(
32+
u32::max_value(),
33+
(lines.len() as f64 / height_ratio) as u32,
34+
FilterType::Lanczos3,
35+
);
36+
let _image_columns = width_ratio * f64::from(image.width());
37+
let image_rows = height_ratio * f64::from(image.height());
38+
39+
let mut bytes: Vec<u8> = Vec::new();
40+
image
41+
.write_to(&mut bytes, image::ImageOutputFormat::Png)
42+
.unwrap();
43+
let encoded_image = base64::encode(bytes);
44+
let mut image_data = Vec::<u8>::new();
45+
46+
image_data.extend(b"\x1B]1337;File=inline=1:");
47+
image_data.extend(encoded_image.bytes());
48+
image_data.extend(b"\x07");
49+
50+
image_data.extend(format!("\x1B[{}A", image_rows as u32 - 1).as_bytes()); // move cursor to start of image
51+
let mut i = 0;
52+
for line in &lines {
53+
image_data.extend(format!("\x1B[s{}\x1B[u\x1B[1B", line).as_bytes());
54+
i += 1;
55+
}
56+
image_data
57+
.extend(format!("\n\x1B[{}B", lines.len().max(image_rows as usize) - i).as_bytes()); // move cursor to end of image
58+
59+
String::from_utf8(image_data).unwrap()
60+
}
61+
}

‎src/onefetch/image_backends/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::onefetch::error::*;
22
use image::DynamicImage;
33

4+
#[cfg(not(windows))]
5+
pub mod iterm2;
46
#[cfg(not(windows))]
57
pub mod kitty;
68
#[cfg(not(windows))]
@@ -14,6 +16,8 @@ pub trait ImageBackend {
1416
pub fn get_best_backend() -> Option<Box<dyn ImageBackend>> {
1517
if kitty::KittyBackend::supported() {
1618
Some(Box::new(kitty::KittyBackend::new()))
19+
} else if iterm2::ITerm2Backend::supported() {
20+
Some(Box::new(iterm2::ITerm2Backend::new()))
1721
} else if sixel::SixelBackend::supported() {
1822
Some(Box::new(sixel::SixelBackend::new()))
1923
} else {
@@ -32,6 +36,7 @@ pub fn check_if_supported(backend_name: &str) -> Result<()> {
3236
return Err("Kitty image backend is not supported".into());
3337
}
3438
}
39+
"iterm2" => {}
3540
"sixel" => {
3641
if !sixel::SixelBackend::supported() {
3742
return Err("Sixel image backend is not supported".into());
@@ -47,6 +52,7 @@ pub fn get_image_backend(backend_name: &str) -> Option<Box<dyn ImageBackend>> {
4752
#[cfg(not(windows))]
4853
let backend = Some(match backend_name {
4954
"kitty" => Box::new(kitty::KittyBackend::new()) as Box<dyn ImageBackend>,
55+
"iterm2" => Box::new(iterm2::ITerm2Backend::new()) as Box<dyn ImageBackend>,
5056
"sixel" => Box::new(sixel::SixelBackend::new()) as Box<dyn ImageBackend>,
5157
_ => unreachable!(),
5258
});

0 commit comments

Comments
 (0)
Please sign in to comment.