mirror of
https://github.com/extrawurst/gitui.git
synced 2024-11-23 03:32:30 +03:00
spinner showing pending background work
This commit is contained in:
parent
7c678a941a
commit
f502c81187
@ -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)
|
||||
|
17
src/app.rs
17
src/app.rs
@ -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);
|
||||
|
34
src/main.rs
34
src/main.rs
@ -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();
|
||||
|
||||
|
@ -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
36
src/spinner.rs
Normal 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(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user