diff --git a/asyncgit/src/lib.rs b/asyncgit/src/lib.rs index 0dddfd87..3b03ee42 100644 --- a/asyncgit/src/lib.rs +++ b/asyncgit/src/lib.rs @@ -12,7 +12,7 @@ pub mod sync; pub use crate::{ diff::{AsyncDiff, DiffParams}, - revlog::AsyncLog, + revlog::{AsyncLog, FetchStatus}, status::{AsyncStatus, StatusParams}, sync::{ diff::{DiffLine, DiffLineType, FileDiff}, diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index 44c13444..38d0c110 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -13,16 +13,32 @@ use std::{ atomic::{AtomicBool, Ordering}, Arc, Mutex, }, + thread, + time::Duration, }; +/// +#[derive(PartialEq)] +pub enum FetchStatus { + /// previous fetch still running + Pending, + /// no change expected + NoChange, + /// new walk was started + Started, +} + /// pub struct AsyncLog { current: Arc>>, sender: Sender, pending: Arc, + background: Arc, } -static LIMIT_COUNT: usize = 1000; +static LIMIT_COUNT: usize = 3000; +static SLEEP_FOREGROUND: Duration = Duration::from_millis(2); +static SLEEP_BACKGROUND: Duration = Duration::from_millis(1000); impl AsyncLog { /// @@ -31,6 +47,7 @@ impl AsyncLog { current: Arc::new(Mutex::new(Vec::new())), sender, pending: Arc::new(AtomicBool::new(false)), + background: Arc::new(AtomicBool::new(false)), } } @@ -58,6 +75,11 @@ impl AsyncLog { self.pending.load(Ordering::Relaxed) } + /// + pub fn set_background(&mut self) { + self.background.store(true, Ordering::Relaxed) + } + /// fn current_head(&self) -> Result { Ok(self.current.lock()?.first().map_or(Oid::zero(), |f| *f)) @@ -79,29 +101,44 @@ impl AsyncLog { } /// - pub fn fetch(&mut self) -> Result<()> { - if !self.is_pending() && self.head_changed()? { - self.clear()?; + pub fn fetch(&mut self) -> Result { + self.background.store(false, Ordering::Relaxed); - let arc_current = Arc::clone(&self.current); - let sender = self.sender.clone(); - let arc_pending = Arc::clone(&self.pending); - - rayon_core::spawn(move || { - scope_time!("async::revlog"); - - arc_pending.store(true, Ordering::Relaxed); - AsyncLog::fetch_helper(arc_current, &sender) - .expect("failed to fetch"); - arc_pending.store(false, Ordering::Relaxed); - Self::notify(&sender); - }); + if self.is_pending() { + return Ok(FetchStatus::Pending); } - Ok(()) + + if !self.head_changed()? { + return Ok(FetchStatus::NoChange); + } + + self.clear()?; + + let arc_current = Arc::clone(&self.current); + let sender = self.sender.clone(); + let arc_pending = Arc::clone(&self.pending); + let arc_background = Arc::clone(&self.background); + + rayon_core::spawn(move || { + scope_time!("async::revlog"); + + arc_pending.store(true, Ordering::Relaxed); + AsyncLog::fetch_helper( + arc_current, + arc_background, + &sender, + ) + .expect("failed to fetch"); + arc_pending.store(false, Ordering::Relaxed); + Self::notify(&sender); + }); + + Ok(FetchStatus::Started) } fn fetch_helper( arc_current: Arc>>, + arc_background: Arc, sender: &Sender, ) -> Result<()> { let mut entries = Vec::with_capacity(LIMIT_COUNT); @@ -121,6 +158,14 @@ impl AsyncLog { break; } else { Self::notify(&sender); + + let sleep_duration = + if arc_background.load(Ordering::Relaxed) { + SLEEP_BACKGROUND + } else { + SLEEP_FOREGROUND + }; + thread::sleep(sleep_duration); } } diff --git a/src/tabs/revlog/mod.rs b/src/tabs/revlog/mod.rs index 5f977b51..60f0eb2d 100644 --- a/src/tabs/revlog/mod.rs +++ b/src/tabs/revlog/mod.rs @@ -10,7 +10,7 @@ use crate::{ ui::calc_scroll_top, ui::style::Theme, }; -use asyncgit::{sync, AsyncLog, AsyncNotification, CWD}; +use asyncgit::{sync, AsyncLog, AsyncNotification, CWD, FetchStatus}; use crossbeam_channel::Sender; use crossterm::event::Event; use std::{borrow::Cow, cmp, convert::TryFrom, time::Instant}; @@ -32,7 +32,6 @@ pub struct Revlog { items: ItemBatch, git_log: AsyncLog, visible: bool, - first_open_done: bool, scroll_state: (Instant, f32), tags: Tags, current_size: (u16, u16), @@ -52,7 +51,6 @@ impl Revlog { selection: 0, count_total: 0, visible: false, - first_open_done: false, scroll_state: (Instant::now(), 0_f32), tags: Tags::new(), current_size: (0, 0), @@ -73,20 +71,22 @@ impl Revlog { /// pub fn update(&mut self) { if self.visible { - self.git_log.fetch().unwrap(); - } + let log_changed = + self.git_log.fetch().unwrap() == FetchStatus::Started; - let old_total = self.count_total; - self.count_total = self.git_log.count().unwrap(); + self.count_total = self.git_log.count().unwrap(); - if self.items.needs_data(self.selection, self.selection_max()) - || old_total != self.count_total - { - self.fetch_commits(); - } + if self + .items + .needs_data(self.selection, self.selection_max()) + || log_changed + { + self.fetch_commits(); + } - if self.tags.is_empty() { - self.tags = sync::get_tags(CWD).unwrap(); + if self.tags.is_empty() { + self.tags = sync::get_tags(CWD).unwrap(); + } } } @@ -340,14 +340,11 @@ impl Component for Revlog { fn hide(&mut self) { self.visible = false; + self.git_log.set_background(); } fn show(&mut self) { self.visible = true; - - if !self.first_open_done { - self.first_open_done = true; - self.git_log.fetch().unwrap(); - } + self.git_log.fetch().unwrap(); } }