mirror of
https://github.com/bobwen-dev/hunter
synced 2025-04-12 00:55:41 +02:00
extract tick function and tick for widgets too
This commit is contained in:
parent
f1fbcf0c36
commit
edc2def611
126
src/files.rs
126
src/files.rs
@ -4,7 +4,7 @@ use std::ops::Index;
|
|||||||
use std::fs::Metadata;
|
use std::fs::Metadata;
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@ -42,22 +42,13 @@ lazy_static! {
|
|||||||
static ref COLORS: LsColors = LsColors::from_env().unwrap_or_default();
|
static ref COLORS: LsColors = LsColors::from_env().unwrap_or_default();
|
||||||
static ref TAGS: RwLock<(bool, Vec<PathBuf>)> = RwLock::new((false, vec![]));
|
static ref TAGS: RwLock<(bool, Vec<PathBuf>)> = RwLock::new((false, vec![]));
|
||||||
static ref ICONS: Icons = Icons::new();
|
static ref ICONS: Icons = Icons::new();
|
||||||
static ref IOPOOL: Mutex<Option<ThreadPool>> = Mutex::new(None);
|
static ref IOTICK_CLIENTS: AtomicUsize = AtomicUsize::default();
|
||||||
static ref IOTICK: AtomicUsize = AtomicUsize::default();
|
static ref IOTICK: AtomicUsize = AtomicUsize::default();
|
||||||
static ref TICKING: AtomicBool = AtomicBool::new(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tick() {
|
|
||||||
IOTICK.fetch_add(1, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_tick() -> usize {
|
|
||||||
IOTICK.load(Ordering::Relaxed)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tick_str() -> &'static str {
|
pub fn tick_str() -> &'static str {
|
||||||
// Using mod 5 for that nice nonlinear look
|
// Using mod 5 for that nice nonlinear look
|
||||||
match get_tick() % 5 {
|
match IOTICK.load(Ordering::Relaxed) % 5 {
|
||||||
0 => " ",
|
0 => " ",
|
||||||
1 => ". ",
|
1 => ". ",
|
||||||
2 => ".. ",
|
2 => ".. ",
|
||||||
@ -65,12 +56,44 @@ pub fn tick_str() -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_ticking() -> bool {
|
pub fn start_ticking(sender: Sender<Events>) {
|
||||||
TICKING.load(Ordering::Acquire)
|
use std::time::Duration;
|
||||||
|
|
||||||
|
IOTICK_CLIENTS.fetch_add(1, Ordering::Relaxed);
|
||||||
|
if IOTICK_CLIENTS.load(Ordering::Acquire) == 1 {
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
IOTICK.store(0, Ordering::Relaxed);
|
||||||
|
|
||||||
|
// Gently slow down refreshes
|
||||||
|
let backoff = Duration::from_millis(10);
|
||||||
|
let mut cooldown = Duration::from_millis(10);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
IOTICK.fetch_add(1, Ordering::Relaxed);
|
||||||
|
|
||||||
|
// Send refresh event before sleeping
|
||||||
|
sender.send(crate::widget::Events::WidgetReady)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// All jobs done?
|
||||||
|
if IOTICK_CLIENTS.load(Ordering::Acquire) == 0 {
|
||||||
|
IOTICK.store(0, Ordering::Relaxed);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_ticking(val: bool) {
|
std::thread::sleep(cooldown);
|
||||||
TICKING.store(val, Ordering::Release);
|
|
||||||
|
// Slow down up to 1 second
|
||||||
|
if cooldown < Duration::from_millis(1000) {
|
||||||
|
cooldown += backoff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stop_ticking() {
|
||||||
|
IOTICK_CLIENTS.fetch_sub(1, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Fail, Debug, Clone)]
|
#[derive(Fail, Debug, Clone)]
|
||||||
@ -415,7 +438,6 @@ impl Files {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_jobs(&mut self, sender: Sender<Events>) {
|
pub fn run_jobs(&mut self, sender: Sender<Events>) {
|
||||||
use std::time::Duration;
|
|
||||||
let jobs = std::mem::take(&mut self.jobs);
|
let jobs = std::mem::take(&mut self.jobs);
|
||||||
let stale = self.stale
|
let stale = self.stale
|
||||||
.clone()
|
.clone()
|
||||||
@ -425,68 +447,14 @@ impl Files {
|
|||||||
|
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let pool = get_pool();
|
let pool = get_pool();
|
||||||
let stop = AtomicBool::new(false);
|
|
||||||
let stop = &stop;
|
|
||||||
let stale = &stale;
|
let stale = &stale;
|
||||||
|
|
||||||
let ticker = move || {
|
start_ticking(sender);
|
||||||
// Gently slow down refreshes
|
|
||||||
let backoff = Duration::from_millis(10);
|
|
||||||
let mut cooldown = Duration::from_millis(10);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
// Send refresh event before sleeping
|
|
||||||
sender.send(crate::widget::Events::WidgetReady)
|
|
||||||
.unwrap();
|
|
||||||
std::thread::sleep(cooldown);
|
|
||||||
|
|
||||||
// Slow down up to 1 second
|
|
||||||
if cooldown < Duration::from_secs(1) {
|
|
||||||
cooldown += backoff;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All jobs done?
|
|
||||||
if stop.load(Ordering::Relaxed) {
|
|
||||||
crate::files::tick();
|
|
||||||
std::thread::sleep(cooldown);
|
|
||||||
// Refresh one last time
|
|
||||||
sender.send(crate::widget::Events::WidgetReady)
|
|
||||||
.unwrap();
|
|
||||||
crate::files::set_ticking(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
crate::files::tick();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// To allow calling without consuming, all while Sender can't be shared
|
|
||||||
let mut ticker = Some(ticker);
|
|
||||||
|
|
||||||
// Finally this returns the ticker function as an Option
|
|
||||||
let mut ticker = move || {
|
|
||||||
// Only return ticker if no one's ticking
|
|
||||||
match !crate::files::is_ticking() {
|
|
||||||
true => {
|
|
||||||
crate::files::set_ticking(true);
|
|
||||||
ticker.take()
|
|
||||||
}
|
|
||||||
false => None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pool.scope_fifo(move |s| {
|
pool.scope_fifo(move |s| {
|
||||||
// Noop with other pool running ticker
|
for (path, mslot, dirsize) in jobs.into_iter()
|
||||||
ticker().map(|t| s.spawn_fifo(move |_| t()));
|
|
||||||
|
|
||||||
let jobs_num = jobs.len();
|
|
||||||
|
|
||||||
for (i, (path, mslot, dirsize)) in jobs.into_iter()
|
|
||||||
.stop_stale(stale.clone())
|
.stop_stale(stale.clone())
|
||||||
.enumerate()
|
|
||||||
{
|
{
|
||||||
ticker().map(|t| s.spawn_fifo(move |_| t()));
|
|
||||||
|
|
||||||
s.spawn_fifo(move |_| {
|
s.spawn_fifo(move |_| {
|
||||||
if let Some(mslot) = mslot {
|
if let Some(mslot) = mslot {
|
||||||
if let Ok(meta) = std::fs::symlink_metadata(&path) {
|
if let Ok(meta) = std::fs::symlink_metadata(&path) {
|
||||||
@ -506,19 +474,11 @@ impl Files {
|
|||||||
dirsize.0.store(true, Ordering::Relaxed);
|
dirsize.0.store(true, Ordering::Relaxed);
|
||||||
dirsize.1.store(size, Ordering::Relaxed);
|
dirsize.1.store(size, Ordering::Relaxed);
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is the last job, stop ticking
|
|
||||||
if jobs_num == i + 1 {
|
|
||||||
stop.store(true, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Stop ticking if loop breaks on stale
|
stop_ticking();
|
||||||
if stale.is_stale().unwrap_or(true) {
|
|
||||||
stop.store(true, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,11 +74,14 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
|
|||||||
let mut widget = Async::new(move |stale|
|
let mut widget = Async::new(move |stale|
|
||||||
closure(stale).map_err(|e| e.into()));
|
closure(stale).map_err(|e| e.into()));
|
||||||
widget.on_ready(move |_, stale| {
|
widget.on_ready(move |_, stale| {
|
||||||
|
crate::files::stop_ticking();
|
||||||
if !stale.is_stale()? {
|
if !stale.is_stale()? {
|
||||||
sender.lock().map(|s| s.send(crate::widget::Events::WidgetReady)).ok();
|
sender.lock().map(|s| s.send(crate::widget::Events::WidgetReady)).ok();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}).log();
|
}).log();
|
||||||
|
|
||||||
|
crate::files::start_ticking(core.get_sender());
|
||||||
widget.run().log();
|
widget.run().log();
|
||||||
|
|
||||||
AsyncWidget {
|
AsyncWidget {
|
||||||
@ -101,6 +104,7 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
widget.on_ready(move |_, stale| {
|
widget.on_ready(move |_, stale| {
|
||||||
|
crate::files::stop_ticking();
|
||||||
if !stale.is_stale()? {
|
if !stale.is_stale()? {
|
||||||
sender.lock()
|
sender.lock()
|
||||||
.map(|s| s.send(crate::widget::Events::WidgetReady))
|
.map(|s| s.send(crate::widget::Events::WidgetReady))
|
||||||
@ -109,6 +113,7 @@ impl<W: Widget + Send + 'static> AsyncWidget<W> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}).log();
|
}).log();
|
||||||
|
|
||||||
|
crate::files::start_ticking(self.core.get_sender());
|
||||||
widget.run().log();
|
widget.run().log();
|
||||||
|
|
||||||
self.widget = widget;
|
self.widget = widget;
|
||||||
@ -181,7 +186,7 @@ impl<T: Widget + Send + 'static> Widget for AsyncWidget<T> {
|
|||||||
let clear = self.core.get_clearlist()?;
|
let clear = self.core.get_clearlist()?;
|
||||||
let (xpos, ypos) = self.get_coordinates()?.u16position();
|
let (xpos, ypos) = self.get_coordinates()?.u16position();
|
||||||
let pos = crate::term::goto_xy(xpos, ypos);
|
let pos = crate::term::goto_xy(xpos, ypos);
|
||||||
return Ok(clear + &pos + "...")
|
return Ok(clear + &pos + crate::files::tick_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_stale()? {
|
if self.is_stale()? {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user