more work on vi stuff

This commit is contained in:
2025-05-23 02:14:56 -04:00
parent ac170d31c8
commit 9db6137934
5 changed files with 1176 additions and 427 deletions

View File

@@ -1,5 +1,10 @@
use std::{os::fd::{BorrowedFd, RawFd}, thread::sleep, time::{Duration, Instant}};
use nix::{errno::Errno, fcntl::{fcntl, FcntlArg, OFlag}, libc::STDIN_FILENO, sys::termios, unistd::{isatty, read, write}};
use nix::{errno::Errno, fcntl::{fcntl, FcntlArg, OFlag}, libc::{self, STDIN_FILENO}, sys::termios, unistd::{isatty, read, write}};
use nix::libc::{winsize, TIOCGWINSZ};
use std::mem::zeroed;
use std::io;
use crate::libsh::error::ShResult;
use super::keys::{KeyCode, KeyEvent, ModKeys};
@@ -32,6 +37,34 @@ impl Terminal {
.expect("Failed to restore terminal settings");
}
pub fn get_dimensions(&self) -> ShResult<(usize, usize)> {
if !isatty(self.stdin).unwrap_or(false) {
return Err(io::Error::new(io::ErrorKind::Other, "Not a TTY"))?;
}
let mut ws: winsize = unsafe { zeroed() };
let res = unsafe { libc::ioctl(self.stdin, TIOCGWINSZ, &mut ws) };
if res == -1 {
return Err(io::Error::last_os_error())?;
}
Ok((ws.ws_row as usize, ws.ws_col as usize))
}
pub fn save_cursor_pos(&self) {
self.write("\x1b[s")
}
pub fn restore_cursor_pos(&self) {
self.write("\x1b[u")
}
pub fn move_cursor_to(&self, (row,col): (usize,usize)) {
self.write(&format!("\x1b[{row};{col}H",))
}
pub fn with_raw_mode<F: FnOnce() -> R, R>(func: F) -> R {
let saved = Self::raw_mode();
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(func));
@@ -48,6 +81,29 @@ impl Terminal {
})
}
fn read_blocks_then_read(&self, buf: &mut [u8], timeout: Duration) -> Option<usize> {
Self::with_raw_mode(|| {
self.read_blocks(false);
let start = Instant::now();
loop {
match read(self.stdin, buf) {
Ok(n) if n > 0 => {
self.read_blocks(true);
return Some(n);
}
Ok(_) => {}
Err(e) if e == Errno::EAGAIN => {}
Err(_) => return None,
}
if start.elapsed() > timeout {
self.read_blocks(true);
return None;
}
sleep(Duration::from_millis(1));
}
})
}
/// Same as read_byte(), only non-blocking with a very short timeout
pub fn peek_byte(&self, buf: &mut [u8]) -> usize {
const TIMEOUT_DUR: Duration = Duration::from_millis(50);