mirror of
https://github.com/itsjunetime/tdf.git
synced 2026-06-02 08:01:47 -04:00
Add extra method to detect window size on terminals that don't handle ioctls correctly
This commit is contained in:
+67
-2
@@ -1,6 +1,10 @@
|
|||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
|
|
||||||
use std::{io::stdout, path::PathBuf, str::FromStr};
|
use std::{
|
||||||
|
io::{stdout, Read, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
str::FromStr
|
||||||
|
};
|
||||||
|
|
||||||
use converter::{run_conversion_loop, ConvertedPage, ConverterMsg};
|
use converter::{run_conversion_loop, ConvertedPage, ConverterMsg};
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
@@ -23,6 +27,18 @@ mod renderer;
|
|||||||
mod skip;
|
mod skip;
|
||||||
mod tui;
|
mod tui;
|
||||||
|
|
||||||
|
// Dummy struct for easy errors in main
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct BadTermSizeStdin(String);
|
||||||
|
|
||||||
|
impl std::fmt::Display for BadTermSizeStdin {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for BadTermSizeStdin {}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut args = std::env::args().skip(1);
|
let mut args = std::env::args().skip(1);
|
||||||
@@ -49,7 +65,56 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let file_path = format!("file://{}", path.clone().into_os_string().to_string_lossy());
|
let file_path = format!("file://{}", path.clone().into_os_string().to_string_lossy());
|
||||||
let (render_tx, mut tui_rx) = tokio::sync::mpsc::unbounded_channel();
|
let (render_tx, mut tui_rx) = tokio::sync::mpsc::unbounded_channel();
|
||||||
|
|
||||||
let window_size = window_size()?;
|
let mut window_size = window_size()?;
|
||||||
|
|
||||||
|
if window_size.width == 0 || window_size.height == 0 {
|
||||||
|
// send the command code to get the terminal window size
|
||||||
|
print!("\x1b[14t");
|
||||||
|
std::io::stdout().flush()?;
|
||||||
|
|
||||||
|
// we need to enable raw mode here since this bit of output won't print a newline; it'll
|
||||||
|
// just print the info it wants to tell us. So we want to get all characters as they come
|
||||||
|
enable_raw_mode()?;
|
||||||
|
|
||||||
|
// read in the returned size until we hit a 't' (which indicates to us it's done)
|
||||||
|
let input_vec = std::io::stdin()
|
||||||
|
.bytes()
|
||||||
|
.flat_map(|b| b.ok())
|
||||||
|
.take_while(|b| *b != b't')
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// and then disable raw mode again in case we return an error in this next section
|
||||||
|
disable_raw_mode()?;
|
||||||
|
|
||||||
|
let input_line = String::from_utf8(input_vec)?;
|
||||||
|
|
||||||
|
if input_line.starts_with("\x1b[4;") {
|
||||||
|
// it should input it to us as `\e[4;<height>;<width>t`, so we need to split to get the h/w
|
||||||
|
let mut splits = input_line.split([';', 't']);
|
||||||
|
// ignore the first val
|
||||||
|
_ = splits.next();
|
||||||
|
|
||||||
|
window_size.height = splits
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
BadTermSizeStdin(format!(
|
||||||
|
"Terminal responded with unparseable size response '{input_line}'"
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
.parse::<u16>()?;
|
||||||
|
|
||||||
|
window_size.width = splits
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
BadTermSizeStdin(format!(
|
||||||
|
"Terminal responded with unparseable size response '{input_line}'"
|
||||||
|
))
|
||||||
|
})?
|
||||||
|
.parse::<u16>()?;
|
||||||
|
} else {
|
||||||
|
return Err("Your terminal is falsely reporting a window size of 0; tdf needs an accurate window size to display graphics".into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We need to create `picker` on this thread because if we create it on the `renderer` thread,
|
// We need to create `picker` on this thread because if we create it on the `renderer` thread,
|
||||||
// it messes up something with user input. Input never makes it to the crossterm thing
|
// it messes up something with user input. Input never makes it to the crossterm thing
|
||||||
|
|||||||
Reference in New Issue
Block a user