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 asciicast;
|
||||||
pub mod recorder;
|
pub mod recorder;
|
||||||
|
mod raw_term;
|
||||||
// pub mod recorder;
|
// pub mod recorder;
|
||||||
// pub mod term;
|
// pub mod term;
|
||||||
// pub mod writer;
|
// 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::env;
|
||||||
use std::ffi::CString;
|
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::process::{Command, Stdio};
|
||||||
use std::sync::mpsc::{self, Receiver, Sender};
|
use std::sync::mpsc::{self, Receiver, Sender};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
@ -11,14 +12,21 @@ use anyhow::{Context, Result};
|
||||||
use libc::{O_RDWR, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
use libc::{O_RDWR, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
|
||||||
use nix::fcntl::{open, OFlag};
|
use nix::fcntl::{open, OFlag};
|
||||||
use nix::pty::{openpty, OpenptyResult};
|
use nix::pty::{openpty, OpenptyResult};
|
||||||
use nix::sys::select::{select, FdSet};
|
use nix::sys::termios::{
|
||||||
use nix::sys::stat::Mode;
|
ControlFlags, InputFlags, LocalFlags, OutputFlags, SetArg,
|
||||||
|
};
|
||||||
|
use nix::sys::{
|
||||||
|
select::{select, FdSet},
|
||||||
|
stat::Mode,
|
||||||
|
termios,
|
||||||
|
};
|
||||||
use nix::unistd::{
|
use nix::unistd::{
|
||||||
close, dup, dup2, execvp, execvpe, fork, fsync, read, setsid, ttyname, write,
|
close, dup, dup2, execvp, execvpe, fork, fsync, read, setsid, ttyname, write,
|
||||||
ForkResult,
|
ForkResult,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::asciicast::{Event, EventKind};
|
use crate::asciicast::{Event, EventKind};
|
||||||
|
use crate::raw_term::RawTerm;
|
||||||
|
|
||||||
pub struct Terminal {
|
pub struct Terminal {
|
||||||
event_tx: Sender<Event>,
|
event_tx: Sender<Event>,
|
||||||
|
@ -56,6 +64,10 @@ impl Terminal {
|
||||||
command.env(key, val);
|
command.env(key, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set raw mode
|
||||||
|
let stdin = stdin();
|
||||||
|
let _term = RawTerm::init(stdin.as_raw_fd())?;
|
||||||
|
|
||||||
// Open a pty
|
// Open a pty
|
||||||
let pty = openpty(None, None)?;
|
let pty = openpty(None, None)?;
|
||||||
let parent_stdout_dup = dup(STDOUT_FILENO)?;
|
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
|
// Master is ready for read, which means child process stdout has data
|
||||||
// (child process stdout) -> (pty.slave) -> (pty.master)
|
// (child process stdout) -> (pty.slave) -> (pty.master)
|
||||||
if read_fd_set.contains(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 =
|
let bytes_read =
|
||||||
read(pty.master, &mut buf).context("Read from master")?;
|
read(pty.master, &mut buf).context("Read from master")?;
|
||||||
if bytes_read == 0 {
|
if bytes_read == 0 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue