mirror of
https://github.com/kdheepak/taskwarrior-tui.git
synced 2025-08-24 14:36:42 +02:00
Make crossterm default
This commit is contained in:
parent
2a08fb2f33
commit
a0c6a94854
5 changed files with 141 additions and 82 deletions
50
.github/workflows/ci.yml
vendored
50
.github/workflows/ci.yml
vendored
|
@ -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 }}
|
||||
|
|
|
@ -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 = "*"
|
||||
|
|
47
src/app.rs
47
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 {} -> {}",
|
||||
|
|
46
src/main.rs
46
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<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(),
|
||||
}
|
||||
|
||||
|
|
76
src/util.rs
76
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<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();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue