Skip to content

Commit

Permalink
Remove nix and signal-hook dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
malbarbo committed May 5, 2020
1 parent a58bb5f commit fcf7737
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 115 deletions.
61 changes: 4 additions & 57 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ unicode-width = "0.1.7"

[target.'cfg(unix)'.dependencies]
libc = "0.2.69"
nix = "0.17.0"
signal-hook = "0.1.14"

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.8", default-features = false, features = ["wincon"] }
Expand Down
19 changes: 4 additions & 15 deletions src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

use std::io::{self, BufRead, BufReader, ErrorKind::NotFound, Read, Seek, Write};
use std::iter::{self, repeat, successors};
use std::sync::mpsc::{Receiver, TryRecvError};
use std::{fmt::Display, fs::File, path::Path, thread, time::Instant};

use crate::row::{HLState, Row};
Expand Down Expand Up @@ -102,9 +101,6 @@ pub struct Editor {
syntax: SyntaxConf,
/// The number of bytes contained in `rows`. This excludes new lines.
n_bytes: u64,
/// A channel receiver for the "window size changed" message. A message is received shortly
/// after a SIGWINCH signal is received.
ws_changed_receiver: Option<Receiver<()>>,
/// The original terminal mode. It will be restored when the `Editor` instance is dropped.
orig_term_mode: Option<sys::TermMode>,
}
Expand Down Expand Up @@ -146,10 +142,10 @@ impl Editor {
/// Will return `Err` if an error occurs when enabling termios raw mode, creating the signal hook
/// or when obtaining the terminal window size.
pub fn new(config: Config) -> Result<Self, Error> {
sys::register_winsize_change_signal_handler()?;
let mut editor = Self::default();
editor.quit_times = config.quit_times;
editor.config = config;
editor.ws_changed_receiver = sys::get_window_size_update_receiver()?;

// Enable raw mode and store the original (non-raw) terminal mode.
editor.orig_term_mode = Some(sys::enable_raw_mode()?);
Expand Down Expand Up @@ -209,16 +205,9 @@ impl Editor {
fn loop_until_keypress(&mut self) -> Result<Key, Error> {
loop {
// Handle window size if a signal has be received
match self.ws_changed_receiver.as_ref().map(Receiver::try_recv) {
// If there is no receiver or no "window size updated" signal has been received, do
// nothing.
None | Some(Err(TryRecvError::Empty)) => (),
// A "window size updated" signal has been received
Some(Ok(())) => {
self.update_window_size()?;
self.refresh_screen()?;
}
Some(Err(err)) => return Err(Error::MPSCTryRecv(err)),
if sys::get_windows_size_was_changed() {
self.update_window_size()?;
self.refresh_screen()?;
}
let mut bytes = io::stdin().bytes();
// Match on the next byte received or, if the first byte is <ESC> ('\x1b'), on the next
Expand Down
11 changes: 0 additions & 11 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,6 @@
pub enum Error {
/// Wrapper around `std::io::Error`
IO(std::io::Error),
/// Wrapper around `nix::Error`
#[cfg(unix)]
Nix(nix::Error),
/// Wrapper around `std::sync::mpsc::TryRecvError`
MPSCTryRecv(std::sync::mpsc::TryRecvError),
/// Error returned when the window size obtained through a system call is invalid.
InvalidWindowSize,
/// Error setting or retrieving the cursor position.
Expand All @@ -26,9 +21,3 @@ impl From<std::io::Error> for Error {
/// Convert an IO Error into a Kibi Error.
fn from(err: std::io::Error) -> Self { Self::IO(err) }
}

#[cfg(unix)]
impl From<nix::Error> for Error {
/// Convert a nix Error into a Kibi Error.
fn from(err: nix::Error) -> Self { Self::Nix(err) }
}
71 changes: 43 additions & 28 deletions src/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,23 @@
//! UNIX-specific structs and functions. Will be imported as `sys` on UNIX systems.

use std::env::var;
use std::sync::mpsc::{self, Receiver};

use libc::{STDIN_FILENO, STDOUT_FILENO, TIOCGWINSZ, VMIN, VTIME};
use nix::{pty::Winsize, sys::termios};
use signal_hook::{iterator::Signals, SIGWINCH};
use std::sync::atomic::{AtomicBool, Ordering};

// On UNIX systems, Termios represents the terminal mode.
pub use nix::sys::termios::Termios as TermMode;
pub use libc::termios as TermMode;
use libc::{c_int, c_void, sigaction, sighandler_t, siginfo_t, winsize};
use libc::{STDIN_FILENO, STDOUT_FILENO, TCSAFLUSH, TIOCGWINSZ, VMIN, VTIME};

use crate::Error;

fn cerr(err: c_int) -> Result<(), Error> {
if err < 0 {
Err(std::io::Error::last_os_error().into())
} else {
Ok(())
}
}

/// Return directories following the XDG Base Directory Specification
///
/// See `conf_dirs()` and `data_dirs()` for usage example.
Expand Down Expand Up @@ -52,42 +58,51 @@ pub fn data_dirs() -> Vec<String> {
/// populated.
/// This ioctl is described here: <http://man7.org/linux/man-pages/man4/tty_ioctl.4.html>
pub fn get_window_size() -> Result<(usize, usize), Error> {
nix::ioctl_read_bad!(get_ws, TIOCGWINSZ, Winsize);

let mut maybe_ws = std::mem::MaybeUninit::<Winsize>::uninit();

unsafe { get_ws(STDOUT_FILENO, maybe_ws.as_mut_ptr()).ok().map(|_| maybe_ws.assume_init()) }
let mut maybe_ws = std::mem::MaybeUninit::<winsize>::uninit();
cerr(unsafe { libc::ioctl(STDOUT_FILENO, TIOCGWINSZ, maybe_ws.as_mut_ptr()) })
.ok()
.map(|_| unsafe { maybe_ws.assume_init() })
.filter(|ws| ws.ws_col != 0 && ws.ws_row != 0)
.map_or(Err(Error::InvalidWindowSize), |ws| Ok((ws.ws_row as usize, ws.ws_col as usize)))
}

/// Return a MPSC receiver that receives a message whenever the window size is updated.
pub fn get_window_size_update_receiver() -> Result<Option<Receiver<()>>, Error> {
// Create a channel for receiving window size update requests
let (ws_changed_tx, ws_changed_rx) = mpsc::sync_channel(1);
// Spawn a new thread that will push to the aforementioned channel every time the SIGWINCH
// signal is received
let signals = Signals::new(&[SIGWINCH])?;
std::thread::spawn(move || signals.forever().for_each(|_| ws_changed_tx.send(()).unwrap()));
Ok(Some(ws_changed_rx))
pub fn register_winsize_change_signal_handler() -> Result<(), Error> {
unsafe {
let mut maybe_sa = std::mem::MaybeUninit::<sigaction>::uninit();
libc::sigemptyset(&mut (*maybe_sa.as_mut_ptr()).sa_mask);
(*maybe_sa.as_mut_ptr()).sa_flags = 0;
(*maybe_sa.as_mut_ptr()).sa_sigaction = set_windows_size_was_changed as sighandler_t;
cerr(libc::sigaction(libc::SIGWINCH, maybe_sa.as_mut_ptr(), std::ptr::null_mut()))
}
}

static WIN_CHANGED: AtomicBool = AtomicBool::new(false);

#[no_mangle]
extern "C" fn set_windows_size_was_changed(_: c_int, _: *mut siginfo_t, _: *mut c_void) {
WIN_CHANGED.store(true, Ordering::Relaxed);
}

pub fn get_windows_size_was_changed() -> bool { WIN_CHANGED.swap(false, Ordering::Relaxed) }

/// Set the terminal mode.
pub fn set_term_mode(term: &TermMode) -> Result<(), nix::Error> {
termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSAFLUSH, term)
pub fn set_term_mode(term: &TermMode) -> Result<(), Error> {
cerr(unsafe { libc::tcsetattr(STDIN_FILENO, TCSAFLUSH, term) })
}

/// Setup the termios to enable raw mode, and return the original termios.
///
/// termios manual is available at: <http://man7.org/linux/man-pages/man3/termios.3.html>
pub fn enable_raw_mode() -> Result<TermMode, Error> {
let orig_termios = termios::tcgetattr(STDIN_FILENO)?;
let mut term = orig_termios.clone();
termios::cfmakeraw(&mut term);
let mut term = std::mem::MaybeUninit::<TermMode>::uninit();
let orig_term = cerr(unsafe { libc::tcgetattr(STDIN_FILENO, term.as_mut_ptr()) })
.map(|_| unsafe { term.assume_init() })?;
let mut term = orig_term;
unsafe { libc::cfmakeraw(&mut term) };
// Set the minimum number of characters for non-canonical reads
term.control_chars[VMIN] = 0;
term.c_cc[VMIN] = 0;
// Set the timeout in deciseconds for non-canonical reads
term.control_chars[VTIME] = 1;
term.c_cc[VTIME] = 1;
set_term_mode(&term)?;
Ok(orig_termios)
Ok(orig_term)
}
6 changes: 4 additions & 2 deletions src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#![allow(clippy::wildcard_imports)]

use std::{convert::TryInto, env::var, io, sync::mpsc::Receiver};
use std::{convert::TryInto, env::var, io};

use winapi::um::wincon::*;
use winapi_util::{console as cons, HandleRef};
Expand All @@ -30,7 +30,9 @@ pub fn get_window_size() -> Result<(usize, usize), Error> {
}
}

pub fn get_window_size_update_receiver() -> Result<Option<Receiver<()>>, Error> { Ok(None) }
pub fn register_winsize_change_signal_handler() -> Result<(), Error> { Ok(()) }

pub fn get_windows_size_was_changed() -> bool { false }

/// Set the terminal mode.
#[allow(clippy::trivially_copy_pass_by_ref)]
Expand Down

0 comments on commit fcf7737

Please sign in to comment.