spinner showing pending background work

This commit is contained in:
Stephan Dilly 2020-04-29 15:28:15 +02:00
parent 7c678a941a
commit f502c81187
5 changed files with 93 additions and 12 deletions

View File

@ -3,7 +3,10 @@ use crossbeam_channel::Sender;
use log::trace;
use std::{
hash::Hash,
sync::{Arc, Mutex},
sync::{
atomic::{AtomicUsize, Ordering},
Arc, Mutex,
},
};
///
@ -24,6 +27,7 @@ pub struct AsyncDiff {
current: Arc<Mutex<Request<u64, FileDiff>>>,
last: Arc<Mutex<Option<LastResult<DiffParams, FileDiff>>>>,
sender: Sender<AsyncNotification>,
pending: Arc<AtomicUsize>,
}
impl AsyncDiff {
@ -33,6 +37,7 @@ impl AsyncDiff {
current: Arc::new(Mutex::new(Request(0, None))),
last: Arc::new(Mutex::new(None)),
sender,
pending: Arc::new(AtomicUsize::new(0)),
}
}
@ -54,6 +59,11 @@ impl AsyncDiff {
}
}
///
pub fn is_pending(&self) -> bool {
self.pending.load(Ordering::Relaxed) > 0
}
///
pub fn request(
&mut self,
@ -77,7 +87,10 @@ impl AsyncDiff {
let arc_current = Arc::clone(&self.current);
let arc_last = Arc::clone(&self.last);
let sender = self.sender.clone();
let arc_pending = Arc::clone(&self.pending);
rayon_core::spawn(move || {
arc_pending.fetch_add(1, Ordering::Relaxed);
let res =
sync::diff::get_diff(CWD, params.0.clone(), params.1);
let mut notify = false;
@ -98,6 +111,8 @@ impl AsyncDiff {
});
}
arc_pending.fetch_sub(1, Ordering::Relaxed);
if notify {
sender
.send(AsyncNotification::Diff)

View File

@ -229,12 +229,9 @@ impl App {
self.do_quit
}
fn can_focus_diff(&self) -> bool {
match self.focus {
Focus::WorkDir => self.index_wd.is_file_seleted(),
Focus::Stage => self.index.is_file_seleted(),
_ => false,
}
///
pub fn any_work_pending(&self) -> bool {
self.git_diff.is_pending()
}
}
@ -278,6 +275,14 @@ impl App {
None
}
fn can_focus_diff(&self) -> bool {
match self.focus {
Focus::WorkDir => self.index_wd.is_file_seleted(),
Focus::Stage => self.index.is_file_seleted(),
_ => false,
}
}
fn update_commands(&mut self) {
self.help.set_cmds(self.commands(true));
self.current_commands = self.commands(false);

View File

@ -8,6 +8,7 @@ mod components;
mod keys;
mod poll;
mod queue;
mod spinner;
mod strings;
mod ui;
mod version;
@ -28,6 +29,7 @@ use log::error;
use scopeguard::defer;
use scopetime::scope_time;
use simplelog::{Config, LevelFilter, WriteLogger};
use spinner::Spinner;
use std::{
env, fs,
fs::File,
@ -40,6 +42,7 @@ use tui::{
};
static TICK_INTERVAL: Duration = Duration::from_secs(5);
static SPINNER_INTERVAL: Duration = Duration::from_millis(50);
fn main() -> Result<()> {
setup_logging();
@ -65,28 +68,44 @@ fn main() -> Result<()> {
set_panic_handlers();
let rx_input = poll::start_polling_thread();
let ticker = tick(TICK_INTERVAL);
let spinner_ticker = tick(SPINNER_INTERVAL);
app.update();
draw(&mut terminal, &mut app)?;
let mut spinner = Spinner::default();
loop {
let events: Vec<QueueEvent> =
select_event(&rx_input, &rx_git, &ticker);
let events: Vec<QueueEvent> = select_event(
&rx_input,
&rx_git,
&ticker,
&spinner_ticker,
);
{
scope_time!("loop");
let mut needs_draw = true;
for e in events {
match e {
QueueEvent::InputEvent(ev) => app.event(ev),
QueueEvent::Tick => app.update(),
QueueEvent::GitEvent(ev) => app.update_git(ev),
QueueEvent::SpinnerUpdate => {
needs_draw = false;
spinner.update()
}
}
}
draw(&mut terminal, &mut app)?;
if needs_draw {
draw(&mut terminal, &mut app)?;
}
spinner.draw(&mut terminal, app.any_work_pending())?;
if app.is_quit() {
break;
@ -112,6 +131,7 @@ fn select_event(
rx_input: &Receiver<Vec<QueueEvent>>,
rx_git: &Receiver<AsyncNotification>,
rx_ticker: &Receiver<Instant>,
rx_spinner: &Receiver<Instant>,
) -> Vec<QueueEvent> {
let mut events: Vec<QueueEvent> = Vec::new();
@ -120,6 +140,7 @@ fn select_event(
sel.recv(rx_input);
sel.recv(rx_git);
sel.recv(rx_ticker);
sel.recv(rx_spinner);
let oper = sel.select();
let index = oper.index();
@ -132,7 +153,10 @@ fn select_event(
2 => oper
.recv(rx_ticker)
.map(|_| events.push(QueueEvent::Tick)),
_ => Ok(()),
3 => oper
.recv(rx_spinner)
.map(|_| events.push(QueueEvent::SpinnerUpdate)),
_ => panic!("unknown select source"),
}
.unwrap();

View File

@ -7,6 +7,7 @@ use std::time::{Duration, Instant};
#[derive(Clone, Copy)]
pub enum QueueEvent {
Tick,
SpinnerUpdate,
GitEvent(AsyncNotification),
InputEvent(Event),
}

36
src/spinner.rs Normal file
View File

@ -0,0 +1,36 @@
use std::io;
use tui::{backend::Backend, buffer::Cell, Terminal};
static SPINNER_CHARS: &[char] = &['|', '/', '-', '\\'];
///
#[derive(Default)]
pub struct Spinner {
idx: usize,
}
impl Spinner {
///
pub fn update(&mut self) {
self.idx += 1;
self.idx %= SPINNER_CHARS.len();
}
pub fn draw<B: Backend>(
&self,
terminal: &mut Terminal<B>,
pending: bool,
) -> io::Result<()> {
let idx = self.idx;
let c: Cell = Cell::default()
.set_char(if pending { SPINNER_CHARS[idx] } else { ' ' })
.clone();
terminal
.backend_mut()
.draw(vec![(0_u16, 0_u16, &c)].into_iter())?;
tui::backend::Backend::flush(terminal.backend_mut())?;
Ok(())
}
}