Make crossterm default

This commit is contained in:
Dheepak Krishnamurthy 2020-07-28 00:58:43 -06:00
parent 2a08fb2f33
commit a0c6a94854
5 changed files with 141 additions and 82 deletions

View file

@ -23,7 +23,15 @@ use tui::{
Terminal,
};
use crate::util::Key;
#[cfg(all(feature = "termion", not(feature = "crossterm")))]
use tui::backend::TermionBackend;
#[cfg(all(feature = "termion", not(feature = "crossterm")))]
use termion::{
event,
input::{MouseTerminal, TermRead},
raw::{IntoRawMode, RawTerminal},
screen::AlternateScreen,
};
pub fn cmp(t1: &Task, t2: &Task) -> Ordering {
let urgency1 = match &t1.uda()["urgency"] {
@ -431,7 +439,8 @@ impl App {
task_id
)[..],
);
println!("Opening task ...");
// TODO: should we sleep here to show output of the editor?
// std::thread::sleep(std::time::Duration::from_millis(500));
}
_ => {
println!("Vim failed to start");
@ -439,40 +448,12 @@ impl App {
}
}
pub fn handle_input(&mut self, event: Key) {
match self.mode {
AppMode::Report => match event {
Key::Ctrl('c') | Key::Char('q') => self.should_quit = true,
Key::Char('r') => self.update(),
Key::Down | Key::Char('j') => self.next(),
Key::Up | Key::Char('k') => self.previous(),
Key::Char('d') => self.task_done(),
Key::Char('u') => self.task_undo(),
Key::Char('e') => self.task_edit(),
Key::Char('/') => {
self.mode = AppMode::Filter;
}
_ => {}
},
AppMode::Filter => match event {
Key::Char('\n') | Key::Esc => {
self.mode = AppMode::Report;
}
Key::Char(c) => {
self.filter.push(c);
}
Key::Backspace => {
self.filter.pop();
}
_ => {}
},
}
}
}
#[cfg(test)]
mod tests {
use crate::app::App;
use crate::util::setup_terminal;
use std::io::stdin;
use task_hookrs::import::import;
@ -492,6 +473,10 @@ mod tests {
println!("{:?}", t);
println!("{:?}", t);
println!("{:?}", t);
app.next();
app.next();
app.next();
app.task_edit();
// if let Ok(tasks) = import(stdin()) {
// for task in tasks {
// println!("Task: {}, entered {:?} is {} -> {}",

View file

@ -17,7 +17,17 @@ use std::time::{Duration, Instant};
use tui::backend::Backend;
use unicode_width::UnicodeWidthStr;
use app::App;
use app::{App, AppMode};
use crate::util::Key;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
const APP_VERSION: &'static str = env!("CARGO_PKG_VERSION");
const APP_NAME: &'static str = env!("CARGO_PKG_NAME");
fn main() -> Result<(), Box<dyn Error>> {
// Terminal initialization
@ -37,7 +47,39 @@ fn main() -> Result<(), Box<dyn Error>> {
// Handle input
match events.next()? {
Event::Input(input) => app.handle_input(input),
Event::Input(input) => {
match app.mode {
AppMode::Report => match input {
Key::Ctrl('c') | Key::Char('q') => app.should_quit = true,
Key::Char('r') => app.update(),
Key::Down | Key::Char('j') => app.next(),
Key::Up | Key::Char('k') => app.previous(),
Key::Char('d') => app.task_done(),
Key::Char('u') => app.task_undo(),
Key::Char('e') => {
events.pause_event_loop(&mut terminal);
app.task_edit();
events.resume_event_loop(&mut terminal);
},
Key::Char('/') => {
app.mode = AppMode::Filter;
}
_ => {}
},
AppMode::Filter => match input {
Key::Char('\n') | Key::Esc => {
app.mode = AppMode::Report;
}
Key::Char(c) => {
app.filter.push(c);
}
Key::Backspace => {
app.filter.pop();
}
_ => {}
},
}
}
Event::Tick => app.handle_tick(),
}

View file

@ -12,13 +12,18 @@ use termion::{
event,
input::{MouseTerminal, TermRead},
raw::{IntoRawMode, RawTerminal},
screen::AlternateScreen,
screen::{AlternateScreen,ToMainScreen, ToAlternateScreen},
};
#[cfg(all(feature = "termion", not(feature = "crossterm")))]
use tui::{backend::TermionBackend, Terminal};
use std::io::{self, Write};
use std::{sync::mpsc, thread, time::Duration};
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc, Mutex,
};
#[derive(Debug, Clone, Copy)]
pub enum Key {
@ -47,14 +52,6 @@ pub struct EventConfig {
pub tick_rate: Duration,
}
impl Default for EventConfig {
fn default() -> EventConfig {
EventConfig {
tick_rate: Duration::from_millis(5),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum Event<I> {
Input(I),
@ -80,8 +77,8 @@ pub fn destruct_terminal(mut terminal: Terminal<CrosstermBackend<io::Stdout>>) {
#[cfg(all(feature = "termion", not(feature = "crossterm")))]
pub fn setup_terminal(
) -> Terminal<TermionBackend<AlternateScreen<MouseTerminal<RawTerminal<io::Stdout>>>>> {
let stdout = io::stdout().into_raw_mode().unwrap();
let stdout = MouseTerminal::from(stdout);
let raw_stdout = io::stdout().into_raw_mode().unwrap();
let stdout = MouseTerminal::from(raw_stdout);
let stdout = AlternateScreen::from(stdout);
let backend = TermionBackend::new(stdout);
Terminal::new(backend).unwrap()
@ -94,23 +91,19 @@ pub fn destruct_terminal(
}
pub struct Events {
rx: mpsc::Receiver<Event<Key>>,
pub rx: mpsc::Receiver<Event<Key>>,
pub tx: mpsc::Sender<Event<Key>>,
pub pause_stdin: Arc<Mutex<bool>>,
}
impl Events {
/// Constructs an new instance of `Events` with the default config.
pub fn new(tick_rate: u64) -> Events {
Events::with_config(EventConfig {
tick_rate: Duration::from_millis(tick_rate),
..Default::default()
})
}
#[cfg(feature = "crossterm")]
pub fn with_config(config: EventConfig) -> Events {
use crossterm::event::{KeyCode::*, KeyModifiers};
let (tx, rx) = mpsc::channel();
let pause_stdin = Arc::new(Mutex::new(false));
let pause_stdin = pause_stdin.clone();
let event_tx = tx.clone();
thread::spawn(move || {
loop {
@ -149,18 +142,23 @@ impl Events {
event_tx.send(Event::Tick).unwrap();
}
});
Events { rx }
Events { rx, tx, pause_stdin }
}
#[cfg(all(feature = "termion", not(feature = "crossterm")))]
pub fn with_config(config: EventConfig) -> Events {
use termion::event::Key::*;
let (tx, rx) = mpsc::channel();
let pause_stdin = Arc::new(Mutex::new(false));
let input_handle = {
let tx = tx.clone();
let pause_stdin = pause_stdin.clone();
thread::spawn(move || {
let stdin = io::stdin();
for evt in stdin.keys() {
while *pause_stdin.lock().unwrap() {
thread::sleep(config.tick_rate);
}
if let Ok(key) = evt {
let key = match key {
Backspace => Key::Backspace,
@ -192,6 +190,7 @@ impl Events {
})
};
let tick_handle = {
let tx = tx.clone();
thread::spawn(move || loop {
if tx.send(Event::Tick).is_err() {
break;
@ -199,7 +198,7 @@ impl Events {
thread::sleep(config.tick_rate);
})
};
Events { rx }
Events { rx, tx, pause_stdin }
}
/// Attempts to read an event.
@ -207,4 +206,37 @@ impl Events {
pub fn next(&self) -> Result<Event<Key>, mpsc::RecvError> {
self.rx.recv()
}
#[cfg(all(feature = "termion", not(feature = "crossterm")))]
pub fn pause_event_loop(&self, terminal: & mut Terminal<TermionBackend<AlternateScreen<MouseTerminal<RawTerminal<io::Stdout>>>>>) {
*self.pause_stdin.lock().unwrap() = true;
std::thread::sleep(std::time::Duration::from_millis(50));
write!(terminal.backend_mut(), "{}", ToMainScreen).unwrap();
}
#[cfg(all(feature = "termion", not(feature = "crossterm")))]
pub fn resume_event_loop(&self, terminal: & mut Terminal<TermionBackend<AlternateScreen<MouseTerminal<RawTerminal<io::Stdout>>>>>) {
write!(terminal.backend_mut(), "{}", ToAlternateScreen).unwrap();
std::thread::sleep(std::time::Duration::from_millis(50));
*self.pause_stdin.lock().unwrap() = false;
terminal.resize(terminal.size().unwrap()).unwrap();
}
#[cfg(feature = "crossterm")]
pub fn pause_event_loop(&self, terminal: & mut Terminal<CrosstermBackend<io::Stdout>>) {
*self.pause_stdin.lock().unwrap() = true;
std::thread::sleep(std::time::Duration::from_millis(50));
disable_raw_mode().unwrap();
execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture).unwrap();
terminal.show_cursor().unwrap();
}
#[cfg(feature = "crossterm")]
pub fn resume_event_loop(&self, terminal: & mut Terminal<CrosstermBackend<io::Stdout>>) {
enable_raw_mode().unwrap();
execute!(io::stdout(), EnterAlternateScreen, EnableMouseCapture).unwrap();
std::thread::sleep(std::time::Duration::from_millis(50));
*self.pause_stdin.lock().unwrap() = false;
terminal.resize(terminal.size().unwrap()).unwrap();
}
}