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

@ -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 }}

View file

@ -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 = "*"

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();
}
}