Add raw mode module
This commit is contained in:
parent
c555b2e006
commit
250793b330
3 changed files with 57 additions and 3 deletions
|
@ -7,6 +7,7 @@ extern crate tracing;
|
|||
|
||||
pub mod asciicast;
|
||||
pub mod recorder;
|
||||
mod raw_term;
|
||||
// pub mod recorder;
|
||||
// pub mod term;
|
||||
// pub mod writer;
|
||||
|
|
38
src/raw_term.rs
Normal file
38
src/raw_term.rs
Normal file
|
@ -0,0 +1,38 @@
|
|||
use std::os::unix::prelude::RawFd;
|
||||
|
||||
use anyhow::Result;
|
||||
use nix::sys::termios::Termios;
|
||||
|
||||
/// Wraps a RawFd in order to enable raw mode.
|
||||
pub struct RawTerm(RawFd, Termios);
|
||||
|
||||
impl RawTerm {
|
||||
pub fn init(fd: RawFd) -> Result<Self> {
|
||||
use nix::sys::termios::*;
|
||||
let saved_mode = tcgetattr(fd)?;
|
||||
let mut mode = saved_mode.clone();
|
||||
mode.input_flags &= !(InputFlags::BRKINT
|
||||
| InputFlags::ICRNL
|
||||
| InputFlags::INPCK
|
||||
| InputFlags::ISTRIP
|
||||
| InputFlags::IXON);
|
||||
mode.output_flags &= !OutputFlags::OPOST;
|
||||
mode.control_flags &= !(ControlFlags::CSIZE | ControlFlags::PARENB);
|
||||
mode.control_flags |= ControlFlags::CS8;
|
||||
mode.local_flags &= !(LocalFlags::ECHO
|
||||
| LocalFlags::ICANON
|
||||
| LocalFlags::IEXTEN
|
||||
| LocalFlags::ISIG);
|
||||
mode.control_chars[libc::VMIN] = 1;
|
||||
mode.control_chars[libc::VTIME] = 0;
|
||||
tcsetattr(fd, SetArg::TCSAFLUSH, &mode)?;
|
||||
Ok(RawTerm(fd, saved_mode))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawTerm {
|
||||
fn drop(&mut self) {
|
||||
use nix::sys::termios::*;
|
||||
tcsetattr(self.0, SetArg::TCSAFLUSH, &self.1).unwrap();
|
||||
}
|
||||
}
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
use std::env;
|
||||
use std::ffi::CString;
|
||||
use std::os::unix::prelude::{AsRawFd, OsStrExt, RawFd};
|
||||
use std::io::stdin;
|
||||
use std::os::unix::prelude::{AsFd, AsRawFd, OsStrExt, RawFd};
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::mpsc::{self, Receiver, Sender};
|
||||
use std::time::Instant;
|
||||
|
@ -11,14 +12,21 @@ use anyhow::{Context, Result};
|
|||
use libc::{O_RDWR, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
||||
use nix::fcntl::{open, OFlag};
|
||||
use nix::pty::{openpty, OpenptyResult};
|
||||
use nix::sys::select::{select, FdSet};
|
||||
use nix::sys::stat::Mode;
|
||||
use nix::sys::termios::{
|
||||
ControlFlags, InputFlags, LocalFlags, OutputFlags, SetArg,
|
||||
};
|
||||
use nix::sys::{
|
||||
select::{select, FdSet},
|
||||
stat::Mode,
|
||||
termios,
|
||||
};
|
||||
use nix::unistd::{
|
||||
close, dup, dup2, execvp, execvpe, fork, fsync, read, setsid, ttyname, write,
|
||||
ForkResult,
|
||||
};
|
||||
|
||||
use crate::asciicast::{Event, EventKind};
|
||||
use crate::raw_term::RawTerm;
|
||||
|
||||
pub struct Terminal {
|
||||
event_tx: Sender<Event>,
|
||||
|
@ -56,6 +64,10 @@ impl Terminal {
|
|||
command.env(key, val);
|
||||
}
|
||||
|
||||
// Set raw mode
|
||||
let stdin = stdin();
|
||||
let _term = RawTerm::init(stdin.as_raw_fd())?;
|
||||
|
||||
// Open a pty
|
||||
let pty = openpty(None, None)?;
|
||||
let parent_stdout_dup = dup(STDOUT_FILENO)?;
|
||||
|
@ -135,6 +147,9 @@ impl Terminal {
|
|||
// Master is ready for read, which means child process stdout has data
|
||||
// (child process stdout) -> (pty.slave) -> (pty.master)
|
||||
if read_fd_set.contains(pty.master) {
|
||||
// TODO: This line trips if the child process dies from, say, Ctrl+D. Need to catch this
|
||||
// somehow and gracefully react to it.
|
||||
// Possibly signals would be a good solution here?
|
||||
let bytes_read =
|
||||
read(pty.master, &mut buf).context("Read from master")?;
|
||||
if bytes_read == 0 {
|
||||
|
|
Loading…
Reference in a new issue