tlc: fix terminal resize detection with poll-based event loop

MC uses SIGWINCH→self-pipe→select(stdin+pipe) for resize detection.
In safe Rust (#![deny(unsafe_code)]), the equivalent is polling stdin
with a 200ms timeout via rustix::event::poll. This wakes the main loop
every 200ms even without key input, allowing terminal size check and
full redraw on resize. Same result as MC's signal-driven approach
without requiring unsafe signal handlers.

Previously the event loop blocked indefinitely on events.next() —
terminal resize was only detected on the next keypress.
This commit is contained in:
2026-06-19 17:49:56 +03:00
parent 940e5f55c5
commit ac12f9e398
+26 -2
View File
@@ -10,9 +10,11 @@
use std::path::PathBuf;
use std::io::Write;
use std::os::fd::AsFd;
use std::time::Duration;
use anyhow::Result;
use rustix::event::{poll, PollFd, PollFlags, Timespec};
use termion::event::{Event as TermEvent, Key as TermKey};
use termion::input::TermReadEventsAndRaw;
@@ -55,7 +57,16 @@ impl Application {
let mut last_size = tui.size();
// Main event loop — blocking stdin, raw mode is active.
// Stdin fd for poll — obtained without locking so the subshell
// can still read from stdin when we drop into CTRL+O.
let stdin = std::io::stdin();
let stdin_fd = stdin.as_fd();
let poll_timeout =
Timespec::try_from(Duration::from_millis(200)).unwrap_or_default();
// Main event loop — MC-style resize detection via poll timeout.
// poll() wakes every 200ms even without key input, letting us
// detect terminal resize without requiring a keypress.
loop {
let cur_size = tui.size();
if cur_size != last_size {
@@ -72,7 +83,20 @@ impl Application {
render(&mut tui, &mut fm)?;
}
let stdin = std::io::stdin();
// Poll stdin with 200ms timeout. On timeout (no key), loop
// back and re-check terminal size. On data, read the key.
let mut poll_fds = [PollFd::new(&stdin, PollFlags::IN)];
match poll(&mut poll_fds, Some(&poll_timeout)) {
Ok(0) => continue,
Ok(_) => {
if !poll_fds[0].revents().contains(PollFlags::IN) {
continue;
}
}
Err(_) => continue,
}
// Data available on stdin — read the key event.
let mut events = stdin.lock().events_and_raw();
let (event, raw) = match events.next() {
Some(Ok(pair)) => pair,