Browse Source

No unsafe (#1646)

pull/1651/head
Fedor Finenko 2 weeks ago committed by GitHub
parent
commit
0ae82b3a1f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 94
      Cargo.lock
  2. 2
      image/Cargo.toml
  3. 16
      image/src/iterm.rs
  4. 81
      image/src/kitty.rs
  5. 37
      image/src/lib.rs
  6. 79
      image/src/sixel.rs
  7. 4
      src/ui/printer/factory.rs

94
Cargo.lock generated

@ -741,11 +741,11 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]] [[package]]
name = "enable-ansi-support" name = "enable-ansi-support"
version = "0.3.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea7457668b3da8a4b702f3d79e131aa3e81cd7e81cc95fb2d54fce9f182ecc77" checksum = "aa4ff3ae2a9aa54bf7ee0983e59303224de742818c1822d89f07da9856d9bc60"
dependencies = [ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.42.0",
] ]
[[package]] [[package]]
@ -2616,9 +2616,9 @@ dependencies = [
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.9.4" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]] [[package]]
name = "litemap" name = "litemap"
@ -2970,7 +2970,7 @@ dependencies = [
"clap", "clap",
"color_quant", "color_quant",
"image", "image",
"libc", "rustix",
] ]
[[package]] [[package]]
@ -3563,9 +3563,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "1.0.8" version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@ -4473,7 +4473,7 @@ checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [ dependencies = [
"windows-implement", "windows-implement",
"windows-interface", "windows-interface",
"windows-link 0.1.3", "windows-link",
"windows-result", "windows-result",
"windows-strings", "windows-strings",
] ]
@ -4506,19 +4506,13 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]] [[package]]
name = "windows-result" name = "windows-result"
version = "0.3.4" version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [ dependencies = [
"windows-link 0.1.3", "windows-link",
] ]
[[package]] [[package]]
@ -4527,7 +4521,22 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [ dependencies = [
"windows-link 0.1.3", "windows-link",
]
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
] ]
[[package]] [[package]]
@ -4557,15 +4566,6 @@ dependencies = [
"windows-targets 0.53.5", "windows-targets 0.53.5",
] ]
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link 0.2.1",
]
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.48.5" version = "0.48.5"
@ -4614,6 +4614,12 @@ dependencies = [
"windows_x86_64_msvc 0.53.1", "windows_x86_64_msvc 0.53.1",
] ]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.48.5" version = "0.48.5"
@ -4632,6 +4638,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.48.5" version = "0.48.5"
@ -4650,6 +4662,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.48.5" version = "0.48.5"
@ -4680,6 +4698,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.48.5" version = "0.48.5"
@ -4698,6 +4722,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.48.5" version = "0.48.5"
@ -4716,6 +4746,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.48.5" version = "0.48.5"
@ -4734,6 +4770,12 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.48.5" version = "0.48.5"

2
image/Cargo.toml

@ -15,4 +15,4 @@ image.workspace = true
[target.'cfg(not(windows))'.dependencies] [target.'cfg(not(windows))'.dependencies]
color_quant = "1.1.0" color_quant = "1.1.0"
base64 = "0.22.1" base64 = "0.22.1"
libc = "0.2.177" rustix = { version = "1.1.2", features = ["termios", "event"] }

16
image/src/iterm.rs

@ -1,29 +1,19 @@
use crate::get_dimensions;
use anyhow::Result; use anyhow::Result;
use base64::{engine, Engine}; use base64::{engine, Engine};
use image::{imageops::FilterType, DynamicImage}; use image::{imageops::FilterType, DynamicImage};
use rustix::termios::tcgetwinsize;
use std::env; use std::env;
use std::io::Cursor; use std::io::Cursor;
pub struct ITermBackend {} pub struct ITermBackend;
impl ITermBackend { impl ITermBackend {
pub fn new() -> Self {
ITermBackend {}
}
pub fn supported() -> bool { pub fn supported() -> bool {
let term_program = env::var("TERM_PROGRAM").unwrap_or_else(|_| "".to_string()); let term_program = env::var("TERM_PROGRAM").unwrap_or_else(|_| "".to_string());
term_program == "iTerm.app" term_program == "iTerm.app"
} }
} }
impl Default for ITermBackend {
fn default() -> Self {
Self::new()
}
}
impl super::ImageBackend for ITermBackend { impl super::ImageBackend for ITermBackend {
fn add_image( fn add_image(
&self, &self,
@ -31,7 +21,7 @@ impl super::ImageBackend for ITermBackend {
image: &DynamicImage, image: &DynamicImage,
_colors: usize, _colors: usize,
) -> Result<String> { ) -> Result<String> {
let tty_size = unsafe { get_dimensions() }; let tty_size = tcgetwinsize(std::io::stdin())?;
let width_ratio = f64::from(tty_size.ws_col) / f64::from(tty_size.ws_xpixel); let width_ratio = f64::from(tty_size.ws_col) / f64::from(tty_size.ws_xpixel);
let height_ratio = f64::from(tty_size.ws_row) / f64::from(tty_size.ws_ypixel); let height_ratio = f64::from(tty_size.ws_row) / f64::from(tty_size.ws_ypixel);

81
image/src/kitty.rs

@ -1,32 +1,30 @@
use crate::get_dimensions; use anyhow::{Context as _, Result};
use anyhow::Result;
use base64::{engine, Engine}; use base64::{engine, Engine};
use image::{imageops::FilterType, DynamicImage}; use image::{imageops::FilterType, DynamicImage};
use libc::{
c_void, poll, pollfd, read, tcgetattr, tcsetattr, termios, ECHO, ICANON, POLLIN, STDIN_FILENO, use rustix::event::{poll, PollFd, PollFlags, Timespec};
TCSANOW, use rustix::io::read;
}; use rustix::termios::{tcgetattr, tcgetwinsize, tcsetattr, LocalModes, OptionalActions};
use std::io::{stdout, Write}; use std::io::{stdout, Write};
use std::os::fd::AsFd as _;
use std::time::Instant; use std::time::Instant;
pub struct KittyBackend {} pub struct KittyBackend;
impl KittyBackend { impl KittyBackend {
pub fn new() -> Self { pub fn supported() -> Result<bool> {
Self {} let stdin = std::io::stdin();
}
pub fn supported() -> bool {
// save terminal attributes and disable canonical input processing mode // save terminal attributes and disable canonical input processing mode
let old_attributes = unsafe { let old_attributes = {
let mut old_attributes: termios = std::mem::zeroed(); let old = tcgetattr(&stdin).context("Failed to recieve terminal attibutes")?;
tcgetattr(STDIN_FILENO, &mut old_attributes);
let mut new_attributes = old_attributes; let mut new = old.clone();
new_attributes.c_lflag &= !ICANON; new.local_modes &= !LocalModes::ICANON;
new_attributes.c_lflag &= !ECHO; new.local_modes &= !LocalModes::ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &new_attributes); tcsetattr(&stdin, OptionalActions::Now, &new)
old_attributes .context("Failed to update terminal attributes")?;
old
}; };
// generate red rgba test image // generate red rgba test image
@ -38,49 +36,36 @@ impl KittyBackend {
"\x1B_Gi=1,f=32,s=32,v=32,a=q;{}\x1B\\", "\x1B_Gi=1,f=32,s=32,v=32,a=q;{}\x1B\\",
engine::general_purpose::STANDARD.encode(&test_image) engine::general_purpose::STANDARD.encode(&test_image)
); );
stdout().flush().unwrap(); stdout().flush()?;
let start_time = Instant::now(); let start_time = Instant::now();
let mut stdin_pollfd = pollfd { let stdin_fd = stdin.as_fd();
fd: STDIN_FILENO, let mut stdin_pollfd = [PollFd::new(&stdin_fd, PollFlags::IN)];
events: POLLIN,
revents: 0,
};
let allowed_bytes = [0x1B, b'_', b'G', b'\\']; let allowed_bytes = [0x1B, b'_', b'G', b'\\'];
let mut buf = Vec::<u8>::new(); let mut buf = Vec::<u8>::new();
loop { loop {
// check for timeout while polling to avoid blocking the main thread // check for timeout while polling to avoid blocking the main thread
while unsafe { poll(&mut stdin_pollfd, 1, 0) < 1 } { while poll(&mut stdin_pollfd, Some(&Timespec::default()))? < 1 {
if start_time.elapsed().as_millis() > 50 { if start_time.elapsed().as_millis() > 50 {
unsafe { tcsetattr(&stdin, OptionalActions::Now, &old_attributes)
tcsetattr(STDIN_FILENO, TCSANOW, &old_attributes); .context("Failed to update terminal attributes")?;
} return Ok(false);
return false;
} }
} }
let mut byte = 0; let mut byte = [0];
unsafe { read(&stdin, &mut byte)?;
read(STDIN_FILENO, &mut byte as *mut _ as *mut c_void, 1); if allowed_bytes.contains(&byte[0]) {
} buf.push(byte[0]);
if allowed_bytes.contains(&byte) {
buf.push(byte);
} }
if buf.starts_with(&[0x1B, b'_', b'G']) && buf.ends_with(&[0x1B, b'\\']) { if buf.starts_with(&[0x1B, b'_', b'G']) && buf.ends_with(&[0x1B, b'\\']) {
unsafe { tcsetattr(&stdin, OptionalActions::Now, &old_attributes)
tcsetattr(STDIN_FILENO, TCSANOW, &old_attributes); .context("Failed to update terminal attributes")?;
} return Ok(true);
return true;
} }
} }
} }
} }
impl Default for KittyBackend {
fn default() -> Self {
Self::new()
}
}
impl super::ImageBackend for KittyBackend { impl super::ImageBackend for KittyBackend {
fn add_image( fn add_image(
&self, &self,
@ -88,7 +73,7 @@ impl super::ImageBackend for KittyBackend {
image: &DynamicImage, image: &DynamicImage,
_colors: usize, _colors: usize,
) -> Result<String> { ) -> Result<String> {
let tty_size = unsafe { get_dimensions() }; let tty_size = tcgetwinsize(std::io::stdin())?;
let width_ratio = f64::from(tty_size.ws_col) / f64::from(tty_size.ws_xpixel); let width_ratio = f64::from(tty_size.ws_col) / f64::from(tty_size.ws_xpixel);
let height_ratio = f64::from(tty_size.ws_row) / f64::from(tty_size.ws_ypixel); let height_ratio = f64::from(tty_size.ws_row) / f64::from(tty_size.ws_ypixel);

37
image/src/lib.rs

@ -19,47 +19,32 @@ pub trait ImageBackend {
fn add_image(&self, lines: Vec<String>, image: &DynamicImage, colors: usize) -> Result<String>; fn add_image(&self, lines: Vec<String>, image: &DynamicImage, colors: usize) -> Result<String>;
} }
pub fn get_best_backend() -> Option<Box<dyn ImageBackend>> { pub fn get_best_backend() -> Result<Option<Box<dyn ImageBackend>>> {
#[cfg(not(windows))] #[cfg(not(windows))]
if sixel::SixelBackend::supported() { if sixel::SixelBackend::supported()? {
Some(Box::new(sixel::SixelBackend::new())) Ok(Some(Box::new(sixel::SixelBackend)))
} else if kitty::KittyBackend::supported() { } else if kitty::KittyBackend::supported()? {
Some(Box::new(kitty::KittyBackend::new())) Ok(Some(Box::new(kitty::KittyBackend)))
} else if iterm::ITermBackend::supported() { } else if iterm::ITermBackend::supported() {
Some(Box::new(iterm::ITermBackend::new())) Ok(Some(Box::new(iterm::ITermBackend)))
} else { } else {
None Ok(None)
} }
#[cfg(windows)] #[cfg(windows)]
None Ok(None)
} }
#[allow(unused_variables)] #[allow(unused_variables)]
pub fn get_image_backend(image_protocol: ImageProtocol) -> Option<Box<dyn ImageBackend>> { pub fn get_image_backend(image_protocol: ImageProtocol) -> Option<Box<dyn ImageBackend>> {
#[cfg(not(windows))] #[cfg(not(windows))]
let backend = Some(match image_protocol { let backend = Some(match image_protocol {
ImageProtocol::Kitty => Box::new(kitty::KittyBackend::new()) as Box<dyn ImageBackend>, ImageProtocol::Kitty => Box::new(kitty::KittyBackend) as Box<dyn ImageBackend>,
ImageProtocol::Iterm => Box::new(iterm::ITermBackend::new()) as Box<dyn ImageBackend>, ImageProtocol::Iterm => Box::new(iterm::ITermBackend) as Box<dyn ImageBackend>,
ImageProtocol::Sixel => Box::new(sixel::SixelBackend::new()) as Box<dyn ImageBackend>, ImageProtocol::Sixel => Box::new(sixel::SixelBackend) as Box<dyn ImageBackend>,
}); });
#[cfg(windows)] #[cfg(windows)]
let backend = None; let backend = None;
backend backend
} }
#[cfg(not(windows))]
unsafe fn get_dimensions() -> libc::winsize {
use libc::{ioctl, winsize, STDOUT_FILENO, TIOCGWINSZ};
use std::mem::zeroed;
let mut window: winsize = zeroed();
let result = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window);
if result == -1 {
zeroed()
} else {
window
}
}

79
image/src/sixel.rs

@ -1,70 +1,61 @@
use crate::get_dimensions; use anyhow::{Context as _, Result};
use anyhow::{Context, Result};
use color_quant::NeuQuant; use color_quant::NeuQuant;
use image::{ use image::{
imageops::{colorops, FilterType}, imageops::{colorops, FilterType},
DynamicImage, GenericImageView, ImageBuffer, Pixel, Rgb, DynamicImage, GenericImageView, ImageBuffer, Pixel, Rgb,
}; };
use libc::{
c_void, poll, pollfd, read, tcgetattr, tcsetattr, termios, ECHO, ICANON, POLLIN, STDIN_FILENO, use rustix::event::{poll, PollFd, PollFlags, Timespec};
TCSANOW, use rustix::io::read;
}; use rustix::termios::{tcgetattr, tcgetwinsize, tcsetattr, LocalModes, OptionalActions};
use std::io::{stdout, Write}; use std::io::{stdout, Write};
use std::os::fd::AsFd;
use std::time::Instant; use std::time::Instant;
pub struct SixelBackend {} pub struct SixelBackend;
impl SixelBackend { impl SixelBackend {
pub fn new() -> Self { pub fn supported() -> Result<bool> {
Self {} let stdin = std::io::stdin();
}
pub fn supported() -> bool {
// save terminal attributes and disable canonical input processing mode // save terminal attributes and disable canonical input processing mode
let old_attributes = unsafe { let old_attributes = {
let mut old_attributes: termios = std::mem::zeroed(); let old = tcgetattr(&stdin).context("Failed to recieve terminal attibutes")?;
tcgetattr(STDIN_FILENO, &mut old_attributes);
let mut new_attributes = old_attributes; let mut new = old.clone();
new_attributes.c_lflag &= !ICANON; new.local_modes &= !LocalModes::ICANON;
new_attributes.c_lflag &= !ECHO; new.local_modes &= !LocalModes::ECHO;
tcsetattr(STDIN_FILENO, TCSANOW, &new_attributes); tcsetattr(&stdin, OptionalActions::Now, &new)
old_attributes .context("Failed to update terminal attributes")?;
old
}; };
// ask for the primary device attribute string // ask for the primary device attribute string
print!("\x1B[c"); print!("\x1B[c");
stdout().flush().unwrap(); stdout().flush()?;
let start_time = Instant::now(); let start_time = Instant::now();
let mut stdin_pollfd = pollfd { let stdin_fd = stdin.as_fd();
fd: STDIN_FILENO, let mut stdin_pollfd = [PollFd::new(&stdin_fd, PollFlags::IN)];
events: POLLIN,
revents: 0,
};
let mut buf = Vec::<u8>::new(); let mut buf = Vec::<u8>::new();
loop { loop {
// check for timeout while polling to avoid blocking the main thread // check for timeout while polling to avoid blocking the main thread
while unsafe { poll(&mut stdin_pollfd, 1, 0) < 1 } { while poll(&mut stdin_pollfd, Some(&Timespec::default()))? < 1 {
if start_time.elapsed().as_millis() > 50 { if start_time.elapsed().as_millis() > 50 {
unsafe { tcsetattr(stdin, OptionalActions::Now, &old_attributes)
tcsetattr(STDIN_FILENO, TCSANOW, &old_attributes); .context("Failed to update terminal attributes")?;
} return Ok(false);
return false;
} }
} }
let mut byte = 0; let mut byte = [0];
unsafe { read(&stdin, &mut byte)?;
read(STDIN_FILENO, &mut byte as *mut _ as *mut c_void, 1); buf.push(byte[0]);
}
buf.push(byte);
if buf.starts_with(&[0x1B, b'[', b'?']) && buf.ends_with(b"c") { if buf.starts_with(&[0x1B, b'[', b'?']) && buf.ends_with(b"c") {
for attribute in buf[3..(buf.len() - 1)].split(|x| *x == b';') { for attribute in buf[3..(buf.len() - 1)].split(|x| *x == b';') {
if attribute == [b'4'] { if attribute == [b'4'] {
unsafe { tcsetattr(stdin, OptionalActions::Now, &old_attributes)
tcsetattr(STDIN_FILENO, TCSANOW, &old_attributes); .context("Failed to update terminal attributes")?;
} return Ok(true);
return true;
} }
} }
} }
@ -72,16 +63,10 @@ impl SixelBackend {
} }
} }
impl Default for SixelBackend {
fn default() -> Self {
Self::new()
}
}
impl super::ImageBackend for SixelBackend { impl super::ImageBackend for SixelBackend {
#[allow(clippy::map_entry)] #[allow(clippy::map_entry)]
fn add_image(&self, lines: Vec<String>, image: &DynamicImage, colors: usize) -> Result<String> { fn add_image(&self, lines: Vec<String>, image: &DynamicImage, colors: usize) -> Result<String> {
let tty_size = unsafe { get_dimensions() }; let tty_size = tcgetwinsize(std::io::stdin())?;
let cw = tty_size.ws_xpixel / tty_size.ws_col; let cw = tty_size.ws_xpixel / tty_size.ws_col;
let lh = tty_size.ws_ypixel / tty_size.ws_row; let lh = tty_size.ws_ypixel / tty_size.ws_row;
let width_ratio = 1.0 / cw as f64; let width_ratio = 1.0 / cw as f64;

4
src/ui/printer/factory.rs

@ -34,8 +34,8 @@ impl PrinterFactory {
.image .image
.image_protocol .image_protocol
.map_or_else(onefetch_image::get_best_backend, |s| { .map_or_else(onefetch_image::get_best_backend, |s| {
onefetch_image::get_image_backend(s) Ok(onefetch_image::get_image_backend(s))
}) })?
} else { } else {
None None
}; };

Loading…
Cancel
Save