use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Write};
pub fn query_start(esc: &[u8]) -> io::Result<File> {
let mut tty = OpenOptions::new().read(true).write(true).open("/dev/tty")?;
tty.write_all(esc)?;
tty.flush()?;
Ok(tty)
}
enum Curp {
Nil,
Esc,
Esc2,
Y(u16, u16),
Semi(u16),
X(u16, u16, u16),
}
fn ascii2digit(x: u8) -> u16 {
(x - b'0') as u16
}
fn get_cursor_xy_with_esc(esc: &[u8]) -> io::Result<(u16, u16)> {
let mut state = Curp::Nil;
for b in query_start(esc)?.bytes() {
let b = b?;
state = match (state, b) {
(Curp::Nil, b'\x1b') => Curp::Esc,
(Curp::Nil, _) => Curp::Nil,
(Curp::Esc, b'[') => Curp::Esc2,
(Curp::Esc, _) => Curp::Nil,
(Curp::Esc2, b'0'..=b'9') => Curp::Y(10, ascii2digit(b)),
(Curp::Esc2, _) => Curp::Nil,
(Curp::Y(_, y), b';') => Curp::Semi(y),
(Curp::Y(z, y), b'0'..=b'9') => Curp::Y(z * 10, y + ascii2digit(b) * z),
(Curp::Y(_, _), _) => Curp::Nil,
(Curp::Semi(y), b'0'..=b'9') => Curp::X(10, ascii2digit(b), y),
(Curp::Semi(_), _) => Curp::Nil,
(Curp::X(_, x, y), b'R') => return Ok((x, y)),
(Curp::X(z, x, y), b'0'..=b'9') => Curp::X(z * 10, x + ascii2digit(b) * z, y),
(Curp::X(_, _, _), _) => Curp::Nil,
}
}
Err(io::Error::new(
io::ErrorKind::NotFound,
"End of tty before cursor pos matched",
))
}
pub fn get_cursor_xy() -> io::Result<(u16, u16)> {
get_cursor_xy_with_esc(b"\x1b[6n")
}
pub fn get_tty_wh_dirty() -> io::Result<(u16, u16)> {
get_cursor_xy_with_esc(b"\x1b[999;999H\x1b[6n")
}
pub fn get_tty_wh() -> io::Result<(u16, u16)> {
get_cursor_xy_with_esc(b"\x1b7\x1b[999;999H\x1b[6n\x1b8")
}