From a0c6a94854a126572de2baf59e5f4ae323a6cc2d Mon Sep 17 00:00:00 2001 From: Dheepak Krishnamurthy Date: Tue, 28 Jul 2020 00:58:43 -0600 Subject: [PATCH] Make crossterm default --- .github/workflows/ci.yml | 50 +++++++++++++------------- Cargo.toml | 4 +-- src/app.rs | 47 +++++++++---------------- src/main.rs | 46 ++++++++++++++++++++++-- src/util.rs | 76 ++++++++++++++++++++++++++++------------ 5 files changed, 141 insertions(+), 82 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f5e791..775d3a9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,23 +11,20 @@ jobs: target: x86_64-apple-darwin rust_flags: '' features: '' - target_binary: 'target/x86_64-apple-darwin/release/taskwarrior-tui' - binary: 'taskwarrior-tui-x86_64-apple-darwin' + binary_postfix: '' upx_args: --best strip: true - os: ubuntu-latest target: x86_64-unknown-linux-gnu rust_flags: '' features: '' - target_binary: 'target/x86_64-unknown-linux-gnu/release/taskwarrior-tui' - binary: 'taskwarrior-tui-x86_64-unknown-linux-gnu' + binary_postfix: '' upx_args: --best --lzma strip: true - os: ubuntu-latest target: x86_64-unknown-linux-musl rust_flags: '' features: '' - target_binary: 'target/x86_64-unknown-linux-musl/release/taskwarrior-tui' binary: 'taskwarrior-tui-x86_64-unknown-linux-musl' upx_args: --best --lzma strip: true @@ -35,32 +32,28 @@ jobs: target: i686-unknown-linux-musl rust_flags: '' features: '' - target_binary: 'target/i686-unknown-linux-musl/release/taskwarrior-tui' - binary: 'taskwarrior-tui-i686-unknown-linux-musl' + binary_postfix: '' upx_args: --best --lzma strip: true - os: windows-latest target: x86_64-pc-windows-gnu rust_flags: -C target-feature=+crt-static - features: '--no-default-features --features=crossterm-backend' - target_binary: 'target\x86_64-pc-windows-gnu\release\taskwarrior-tui.exe' - binary: 'taskwarrior-tui-x86_64-pc-windows-gnu.exe' + features: '' + binary_postfix: 'exe' upx_args: -9 strip: false - os: windows-latest target: x86_64-pc-windows-msvc rust_flags: -C target-feature=+crt-static - features: '--no-default-features --features=crossterm-backend' - target_binary: 'target\x86_64-pc-windows-msvc\release\taskwarrior-tui.exe' - binary: 'taskwarrior-tui-x86_64-pc-windows-msvc.exe' + features: '' + binary_postfix: 'exe' upx_args: -9 strip: false - os: windows-latest target: i686-pc-windows-msvc rust_flags: -C target-feature=+crt-static - features: '--no-default-features --features=crossterm-backend' - target_binary: 'target\i686-pc-windows-msvc\release\taskwarrior-tui.exe' - binary: 'taskwarrior-tui-i686-pc-windows-msvc.exe' + features: '' + binary_postfix: 'exe' upx_args: -9 strip: false env: @@ -77,21 +70,28 @@ jobs: with: command: build args: --release ${{matrix.features}} --target=${{ matrix.target }} - # - uses: actions-rs/cargo@v1 - # with: - # command: test - # args: --release --target=${{ matrix.target }} - name: Compress binaries uses: svenstaro/upx-action@v2 with: - file: ${{ matrix.target_binary }} + file: target/${{ matrix.target }}/release/taskwarrior-tui${{ matrix.binary_postfix }} args: ${{ matrix.upx_args }} strip: ${{ matrix.strip }} - - run: mv ${{ matrix.target_binary }} ${{ matrix.binary }} - - name: Release - if: startsWith(github.ref, 'refs/tags/') + - name: Packaging binary + shell: bash + run: | + cd target/${{ matrix.target }}/release + strip taskwarrior-tui${{ matrix.binary_postfix }} + tar czvf taskwarrior-tui-${{ matrix.target }}.tar.gz taskwarrior-tui${{ matrix.binary_postfix }} + if [[ ${{ runner.os }} == 'Windows' ]]; then + certutil -hashfile taskwarrior-tui-${{ matrix.target }}.tar.gz sha256 | grep -E [A-Fa-f0-9]{64} > taskwarrior-tui-${{ matrix.target }}.sha256 + else + shasum -a 256 taskwarrior-tui-${{ matrix.target }}.tar.gz > taskwarrior-tui-${{ matrix.target }}.sha256 + fi + - name: Releasing assets uses: softprops/action-gh-release@v1 with: - files: taskwarrior-tui-* + files: | + target/${{ matrix.target }}/release/taskwarrior-tui-${{ matrix.target }}.tar.gz + target/${{ matrix.target }}/release/taskwarrior-tui-${{ matrix.target }}.sha256 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Cargo.toml b/Cargo.toml index ab3e44e..79be6aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,9 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["termion-backend"] -termion-backend = ["tui/termion", "termion"] +default = ["crossterm-backend"] crossterm-backend = ["tui/crossterm", "crossterm"] +termion-backend = ["tui/termion", "termion"] [dependencies] clap = "*" diff --git a/src/app.rs b/src/app.rs index 6335550..0ab5db3 100644 --- a/src/app.rs +++ b/src/app.rs @@ -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 {} -> {}", diff --git a/src/main.rs b/src/main.rs index e35532c..7c72b45 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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> { // Terminal initialization @@ -37,7 +47,39 @@ fn main() -> Result<(), Box> { // 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(), } diff --git a/src/util.rs b/src/util.rs index 3e70e18..e9432e0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -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 { Input(I), @@ -80,8 +77,8 @@ pub fn destruct_terminal(mut terminal: Terminal>) { #[cfg(all(feature = "termion", not(feature = "crossterm")))] pub fn setup_terminal( ) -> Terminal>>>> { - 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>, + pub rx: mpsc::Receiver>, + pub tx: mpsc::Sender>, + pub pause_stdin: Arc>, } 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, mpsc::RecvError> { self.rx.recv() } + + #[cfg(all(feature = "termion", not(feature = "crossterm")))] + pub fn pause_event_loop(&self, terminal: & mut Terminal>>>>) { + *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>>>>) { + 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>) { + *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>) { + 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(); + } }