Skip to content

Commit 0ae82b3

Browse files
authored
No unsafe (#1646)
1 parent 100f9b8 commit 0ae82b3

File tree

7 files changed

+150
-163
lines changed

7 files changed

+150
-163
lines changed

Cargo.lock

Lines changed: 68 additions & 26 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

image/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ image.workspace = true
1515
[target.'cfg(not(windows))'.dependencies]
1616
color_quant = "1.1.0"
1717
base64 = "0.22.1"
18-
libc = "0.2.177"
18+
rustix = { version = "1.1.2", features = ["termios", "event"] }

image/src/iterm.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,27 @@
1-
use crate::get_dimensions;
21
use anyhow::Result;
32
use base64::{engine, Engine};
43
use image::{imageops::FilterType, DynamicImage};
4+
use rustix::termios::tcgetwinsize;
55
use std::env;
66
use std::io::Cursor;
77

8-
pub struct ITermBackend {}
8+
pub struct ITermBackend;
99

1010
impl ITermBackend {
11-
pub fn new() -> Self {
12-
ITermBackend {}
13-
}
14-
1511
pub fn supported() -> bool {
1612
let term_program = env::var("TERM_PROGRAM").unwrap_or_else(|_| "".to_string());
1713
term_program == "iTerm.app"
1814
}
1915
}
2016

21-
impl Default for ITermBackend {
22-
fn default() -> Self {
23-
Self::new()
24-
}
25-
}
26-
2717
impl super::ImageBackend for ITermBackend {
2818
fn add_image(
2919
&self,
3020
lines: Vec<String>,
3121
image: &DynamicImage,
3222
_colors: usize,
3323
) -> Result<String> {
34-
let tty_size = unsafe { get_dimensions() };
24+
let tty_size = tcgetwinsize(std::io::stdin())?;
3525
let width_ratio = f64::from(tty_size.ws_col) / f64::from(tty_size.ws_xpixel);
3626
let height_ratio = f64::from(tty_size.ws_row) / f64::from(tty_size.ws_ypixel);
3727

image/src/kitty.rs

Lines changed: 33 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,30 @@
1-
use crate::get_dimensions;
2-
use anyhow::Result;
1+
use anyhow::{Context as _, Result};
32
use base64::{engine, Engine};
43
use image::{imageops::FilterType, DynamicImage};
5-
use libc::{
6-
c_void, poll, pollfd, read, tcgetattr, tcsetattr, termios, ECHO, ICANON, POLLIN, STDIN_FILENO,
7-
TCSANOW,
8-
};
4+
5+
use rustix::event::{poll, PollFd, PollFlags, Timespec};
6+
use rustix::io::read;
7+
use rustix::termios::{tcgetattr, tcgetwinsize, tcsetattr, LocalModes, OptionalActions};
8+
99
use std::io::{stdout, Write};
10+
use std::os::fd::AsFd as _;
1011
use std::time::Instant;
1112

12-
pub struct KittyBackend {}
13+
pub struct KittyBackend;
1314

1415
impl KittyBackend {
15-
pub fn new() -> Self {
16-
Self {}
17-
}
18-
19-
pub fn supported() -> bool {
16+
pub fn supported() -> Result<bool> {
17+
let stdin = std::io::stdin();
2018
// save terminal attributes and disable canonical input processing mode
21-
let old_attributes = unsafe {
22-
let mut old_attributes: termios = std::mem::zeroed();
23-
tcgetattr(STDIN_FILENO, &mut old_attributes);
19+
let old_attributes = {
20+
let old = tcgetattr(&stdin).context("Failed to recieve terminal attibutes")?;
2421

25-
let mut new_attributes = old_attributes;
26-
new_attributes.c_lflag &= !ICANON;
27-
new_attributes.c_lflag &= !ECHO;
28-
tcsetattr(STDIN_FILENO, TCSANOW, &new_attributes);
29-
old_attributes
22+
let mut new = old.clone();
23+
new.local_modes &= !LocalModes::ICANON;
24+
new.local_modes &= !LocalModes::ECHO;
25+
tcsetattr(&stdin, OptionalActions::Now, &new)
26+
.context("Failed to update terminal attributes")?;
27+
old
3028
};
3129

3230
// generate red rgba test image
@@ -38,57 +36,44 @@ impl KittyBackend {
3836
"\x1B_Gi=1,f=32,s=32,v=32,a=q;{}\x1B\\",
3937
engine::general_purpose::STANDARD.encode(&test_image)
4038
);
41-
stdout().flush().unwrap();
39+
stdout().flush()?;
4240

4341
let start_time = Instant::now();
44-
let mut stdin_pollfd = pollfd {
45-
fd: STDIN_FILENO,
46-
events: POLLIN,
47-
revents: 0,
48-
};
42+
let stdin_fd = stdin.as_fd();
43+
let mut stdin_pollfd = [PollFd::new(&stdin_fd, PollFlags::IN)];
4944
let allowed_bytes = [0x1B, b'_', b'G', b'\\'];
5045
let mut buf = Vec::<u8>::new();
5146
loop {
5247
// check for timeout while polling to avoid blocking the main thread
53-
while unsafe { poll(&mut stdin_pollfd, 1, 0) < 1 } {
48+
while poll(&mut stdin_pollfd, Some(&Timespec::default()))? < 1 {
5449
if start_time.elapsed().as_millis() > 50 {
55-
unsafe {
56-
tcsetattr(STDIN_FILENO, TCSANOW, &old_attributes);
57-
}
58-
return false;
50+
tcsetattr(&stdin, OptionalActions::Now, &old_attributes)
51+
.context("Failed to update terminal attributes")?;
52+
return Ok(false);
5953
}
6054
}
61-
let mut byte = 0;
62-
unsafe {
63-
read(STDIN_FILENO, &mut byte as *mut _ as *mut c_void, 1);
64-
}
65-
if allowed_bytes.contains(&byte) {
66-
buf.push(byte);
55+
let mut byte = [0];
56+
read(&stdin, &mut byte)?;
57+
if allowed_bytes.contains(&byte[0]) {
58+
buf.push(byte[0]);
6759
}
6860
if buf.starts_with(&[0x1B, b'_', b'G']) && buf.ends_with(&[0x1B, b'\\']) {
69-
unsafe {
70-
tcsetattr(STDIN_FILENO, TCSANOW, &old_attributes);
71-
}
72-
return true;
61+
tcsetattr(&stdin, OptionalActions::Now, &old_attributes)
62+
.context("Failed to update terminal attributes")?;
63+
return Ok(true);
7364
}
7465
}
7566
}
7667
}
7768

78-
impl Default for KittyBackend {
79-
fn default() -> Self {
80-
Self::new()
81-
}
82-
}
83-
8469
impl super::ImageBackend for KittyBackend {
8570
fn add_image(
8671
&self,
8772
lines: Vec<String>,
8873
image: &DynamicImage,
8974
_colors: usize,
9075
) -> Result<String> {
91-
let tty_size = unsafe { get_dimensions() };
76+
let tty_size = tcgetwinsize(std::io::stdin())?;
9277
let width_ratio = f64::from(tty_size.ws_col) / f64::from(tty_size.ws_xpixel);
9378
let height_ratio = f64::from(tty_size.ws_row) / f64::from(tty_size.ws_ypixel);
9479

0 commit comments

Comments
 (0)