<commit_before>use std::ops::{Index, IndexMut};
use std::io::prelude::*;
use std::fs::OpenOptions;
use std::fs::File;
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use std::collections::VecDeque;

use nix::sys::termios;
use nix::sys::termios::{IGNBRK, BRKINT, PARMRK, ISTRIP, INLCR, IGNCR, ICRNL, IXON};
use nix::sys::termios::{OPOST, ECHO, ECHONL, ICANON, ISIG, IEXTEN, CSIZE, PARENB, CS8};
use nix::sys::termios::{VMIN, VTIME};
use nix::sys::termios::SetArg;
use nix::sys::signal;
use nix::sys::signal::{SockFlag, SigSet};
use nix::sys::signal::signal::SIGWINCH;
use nix::sys::ioctl;
use nix::sys::epoll::{epoll_create, epoll_ctl, epoll_wait};
use nix::sys::epoll::{EpollOp, EpollEvent, EpollEventKind};
use nix::sys::epoll;
use nix::errno::Errno;

use util::error::Error;
use core::device::{Device, DevFunc};
use core::cellbuffer::{CellBuffer, Cell, Style, Color, Attr};
use core::cursor::Cursor;
use core::input::Event;

/// Set to true by the sigwinch handler. Reset to false when buffers are resized.
static SIGWINCH_STATUS: AtomicBool = ATOMIC_BOOL_INIT;

/// Ensures that there is only ever one Terminal object at any one time.
/// Set to true on creation of a Terminal object.
/// Reset to false when terminal object goes out of scope.
static RUSTTY_STATUS: AtomicBool = ATOMIC_BOOL_INIT;

/// Constant for TIOCGWINSZ syscall on OS X.
#[cfg(target_os="macos")]
const TIOCGWINSZ: u64 = 0x40087468;

/// Constant for TIOCGWINSZ syscall on Linux.
#[cfg(target_os="linux")]
const TIOCGWINSZ: u64 = 0x00005413;

type OutBuffer = Vec<u8>;
type EventBuffer = VecDeque<Event>;

/// A representation of the current terminal window.
///
/// Only one `Terminal` object can exist at any one time.
/// When a `Terminal` goes out of scope it resets the underlying terminal to its original state.
pub struct Terminal {
    orig_tios: termios::Termios, // Original underlying terminal state.
    tty: File, // Underlying terminal file.
    rawtty: RawFd, // Raw file descriptor of underlying terminal file.
    epfd: RawFd, // Epoll file descriptor.
    epev: EpollEvent, // Epoll event bound to /dev/tty.
    cols: usize, // Number of columns in the terminal window.
    rows: usize, // Number of rows in the terminal window.
    device: &'static Device, // Underlying terminal device (xterm, gnome, etc.).
    backbuffer: CellBuffer, // Internal backbuffer.
    frontbuffer: CellBuffer, // Internal frontbuffer.
    outbuffer: OutBuffer, // Internal output buffer.
    eventbuffer: EventBuffer, // Event buffer.
    lastfg: Style, // Last foreground style written to the output buffer.
    lastbg: Style, // Last background style written to the input buffer.
    cursor: Cursor, // Current cursor position.
    cursor_last: Cursor, // Last cursor position.
}

impl Terminal {
    /// Creates a new `Terminal` with default settings.
    pub fn new() -> Result<Terminal, Error> {
        Terminal::with_cell(Cell::default())
    }

    /// Creates a new `Terminal` with each cell set to the given character.
    pub fn with_char(ch: char) -> Result<Terminal, Error> {
        Terminal::with_cell(Cell::with_char(ch))
    }

    /// Creates a new `Terminal` with each cell set to the given styles.
    pub fn with_styles(fg: Style, bg: Style) -> Result<Terminal, Error> {
        Terminal::with_cell(Cell::with_styles(fg, bg))
    }

    /// Creates a new `Terminal` with each cell set to the given cell.
    pub fn with_cell(cell: Cell) -> Result<Terminal, Error> {
        // Make sure there is only ever one instance.
        if RUSTTY_STATUS.compare_and_swap(false, true, Ordering::SeqCst) {
            return Err(Error::new("Rustty already initialized"))
        }

        // Return the device for the user's terminal.
        let device = try!(Device::new());

        // Open the terminal file for the controlling process.
        let tty = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .open("/dev/tty"));

        // Get the raw file descriptor for the terminal file to use with system calls.
        let rawtty = tty.as_raw_fd();

        // Set up the signal handler for SIGWINCH, which will notify us when the window size has
        // changed; it does this by setting SIGWINCH_STATUS to 'true'.
        let sa_winch = signal::SigAction::new(sigwinch_handler, SockFlag::empty(), SigSet::empty());
        try!(unsafe {
            signal::sigaction(SIGWINCH, &sa_winch)
        });

        // Get the original state of the terminal so we can restore it on drop.
        let orig_tios = try!(termios::tcgetattr(rawtty));

        // Make a mutable clone of the terminal state so we can modify parameters.
        let mut tios = orig_tios.clone();

        // Set required terminal parameters.
        tios.c_iflag = tios.c_iflag & !(IGNBRK | BRKINT | PARMRK | ISTRIP |
                                        INLCR | IGNCR | ICRNL | IXON);
        tios.c_oflag = tios.c_oflag & !OPOST;
        tios.c_lflag = tios.c_lflag & !(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
        tios.c_cflag = tios.c_cflag & !(CSIZE | PARENB);
        tios.c_cflag = tios.c_cflag | CS8;
        tios.c_cc[VMIN] = 0;
        tios.c_cc[VTIME] = 0;

        // Make the system call to change terminal parameters.
        try!(termios::tcsetattr(rawtty, SetArg::TCSAFLUSH, &tios));

        let epfd = try!(epoll_create());
        let epev = EpollEvent {
            events: epoll::EPOLLIN,
            data: 0,
        };
        try!(epoll_ctl(epfd, EpollOp::EpollCtlAdd, rawtty, &epev));

        // Create the terminal object to hold all of our required state.
        let mut terminal = Terminal {
            orig_tios: orig_tios,
            tty: tty,
            rawtty: rawtty,
            epfd: epfd,
            epev: epev,
            cols: 0,
            rows: 0,
            device: device,
            backbuffer: CellBuffer::with_cell(0, 0, cell),
            frontbuffer: CellBuffer::with_cell(0, 0, cell),
            outbuffer: OutBuffer::with_capacity(32 * 1024),
            eventbuffer: EventBuffer::with_capacity(128),
            lastfg: cell.fg(),
            lastbg: cell.bg(),
            cursor: Cursor::Invalid,
            cursor_last: Cursor::Invalid,
        };

        // Switch to alternate screen buffer. Writes the control code to the output buffer.
        try!(write!(terminal.outbuffer, "{}", &terminal.device[DevFunc::EnterCa]));
<commit_msg>remove unused event<commit_after>use std::ops::{Index, IndexMut};
use std::io::prelude::*;
use std::fs::OpenOptions;
use std::fs::File;
use std::os::unix::io::{AsRawFd, RawFd};
use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use std::collections::VecDeque;

use nix::sys::termios;
use nix::sys::termios::{IGNBRK, BRKINT, PARMRK, ISTRIP, INLCR, IGNCR, ICRNL, IXON};
use nix::sys::termios::{OPOST, ECHO, ECHONL, ICANON, ISIG, IEXTEN, CSIZE, PARENB, CS8};
use nix::sys::termios::{VMIN, VTIME};
use nix::sys::termios::SetArg;
use nix::sys::signal;
use nix::sys::signal::{SockFlag, SigSet};
use nix::sys::signal::signal::SIGWINCH;
use nix::sys::ioctl;
use nix::sys::epoll::{epoll_create, epoll_ctl, epoll_wait};
use nix::sys::epoll::{EpollOp, EpollEvent, EpollEventKind};
use nix::sys::epoll;
use nix::errno::Errno;

use util::error::Error;
use core::device::{Device, DevFunc};
use core::cellbuffer::{CellBuffer, Cell, Style, Color, Attr};
use core::cursor::Cursor;
use core::input::Event;

/// Set to true by the sigwinch handler. Reset to false when buffers are resized.
static SIGWINCH_STATUS: AtomicBool = ATOMIC_BOOL_INIT;

/// Ensures that there is only ever one Terminal object at any one time.
/// Set to true on creation of a Terminal object.
/// Reset to false when terminal object goes out of scope.
static RUSTTY_STATUS: AtomicBool = ATOMIC_BOOL_INIT;

/// Constant for TIOCGWINSZ syscall on OS X.
#[cfg(target_os="macos")]
const TIOCGWINSZ: u64 = 0x40087468;

/// Constant for TIOCGWINSZ syscall on Linux.
#[cfg(target_os="linux")]
const TIOCGWINSZ: u64 = 0x00005413;

type OutBuffer = Vec<u8>;
type EventBuffer = VecDeque<Event>;

/// A representation of the current terminal window.
///
/// Only one `Terminal` object can exist at any one time.
/// When a `Terminal` goes out of scope it resets the underlying terminal to its original state.
pub struct Terminal {
    orig_tios: termios::Termios, // Original underlying terminal state.
    tty: File, // Underlying terminal file.
    rawtty: RawFd, // Raw file descriptor of underlying terminal file.
    epfd: RawFd, // Epoll file descriptor.
    cols: usize, // Number of columns in the terminal window.
    rows: usize, // Number of rows in the terminal window.
    device: &'static Device, // Underlying terminal device (xterm, gnome, etc.).
    backbuffer: CellBuffer, // Internal backbuffer.
    frontbuffer: CellBuffer, // Internal frontbuffer.
    outbuffer: OutBuffer, // Internal output buffer.
    eventbuffer: EventBuffer, // Event buffer.
    lastfg: Style, // Last foreground style written to the output buffer.
    lastbg: Style, // Last background style written to the input buffer.
    cursor: Cursor, // Current cursor position.
    cursor_last: Cursor, // Last cursor position.
}

impl Terminal {
    /// Creates a new `Terminal` with default settings.
    pub fn new() -> Result<Terminal, Error> {
        Terminal::with_cell(Cell::default())
    }

    /// Creates a new `Terminal` with each cell set to the given character.
    pub fn with_char(ch: char) -> Result<Terminal, Error> {
        Terminal::with_cell(Cell::with_char(ch))
    }

    /// Creates a new `Terminal` with each cell set to the given styles.
    pub fn with_styles(fg: Style, bg: Style) -> Result<Terminal, Error> {
        Terminal::with_cell(Cell::with_styles(fg, bg))
    }

    /// Creates a new `Terminal` with each cell set to the given cell.
    pub fn with_cell(cell: Cell) -> Result<Terminal, Error> {
        // Make sure there is only ever one instance.
        if RUSTTY_STATUS.compare_and_swap(false, true, Ordering::SeqCst) {
            return Err(Error::new("Rustty already initialized"))
        }

        // Return the device for the user's terminal.
        let device = try!(Device::new());

        // Open the terminal file for the controlling process.
        let tty = try!(OpenOptions::new()
            .write(true)
            .read(true)
            .open("/dev/tty"));

        // Get the raw file descriptor for the terminal file to use with system calls.
        let rawtty = tty.as_raw_fd();

        // Set up the signal handler for SIGWINCH, which will notify us when the window size has
        // changed; it does this by setting SIGWINCH_STATUS to 'true'.
        let sa_winch = signal::SigAction::new(sigwinch_handler, SockFlag::empty(), SigSet::empty());
        try!(unsafe {
            signal::sigaction(SIGWINCH, &sa_winch)
        });

        // Get the original state of the terminal so we can restore it on drop.
        let orig_tios = try!(termios::tcgetattr(rawtty));

        // Make a mutable clone of the terminal state so we can modify parameters.
        let mut tios = orig_tios.clone();

        // Set required terminal parameters.
        tios.c_iflag = tios.c_iflag & !(IGNBRK | BRKINT | PARMRK | ISTRIP |
                                        INLCR | IGNCR | ICRNL | IXON);
        tios.c_oflag = tios.c_oflag & !OPOST;
        tios.c_lflag = tios.c_lflag & !(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
        tios.c_cflag = tios.c_cflag & !(CSIZE | PARENB);
        tios.c_cflag = tios.c_cflag | CS8;
        tios.c_cc[VMIN] = 0;
        tios.c_cc[VTIME] = 0;

        // Make the system call to change terminal parameters.
        try!(termios::tcsetattr(rawtty, SetArg::TCSAFLUSH, &tios));

        let epfd = try!(epoll_create());
        let epev = EpollEvent {
            events: epoll::EPOLLIN,
            data: 0,
        };
        try!(epoll_ctl(epfd, EpollOp::EpollCtlAdd, rawtty, &epev));

        // Create the terminal object to hold all of our required state.
        let mut terminal = Terminal {
            orig_tios: orig_tios,
            tty: tty,
            rawtty: rawtty,
            epfd: epfd,
            cols: 0,
            rows: 0,
            device: device,
            backbuffer: CellBuffer::with_cell(0, 0, cell),
            frontbuffer: CellBuffer::with_cell(0, 0, cell),
            outbuffer: OutBuffer::with_capacity(32 * 1024),
            eventbuffer: EventBuffer::with_capacity(128),
            lastfg: cell.fg(),
            lastbg: cell.bg(),
            cursor: Cursor::Invalid,
            cursor_last: Cursor::Invalid,
        };

        // Switch to alternate screen buffer. Writes the control code to the output buffer.
        try!(write!(terminal.outbuffer, "{}", &terminal.device[DevFunc::EnterCa]));

{'fraction_non_alphanumeric': 0.12280292424949447, 'fraction_numerical': 0.006688442992689376, 'mean_word_length': 2.8755274261603376, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4471802', 'n_tokens_mistral': 4130, 'n_tokens_neox': 4013, 'n_words': 1253}