diff --git a/README.md b/README.md index 9d863669..2a6d969a 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,6 @@ GITUI_LOGGING=true gitui # todo for 0.1 (first release) -* [ ] fix: diff is not updated when changed * [ ] better help command * [ ] -> fix: dont show scroll option when any popup open * [ ] confirm destructive commands (revert/reset) diff --git a/asyncgit/src/diff.rs b/asyncgit/src/diff.rs index 6a7c4738..3cfa2f63 100644 --- a/asyncgit/src/diff.rs +++ b/asyncgit/src/diff.rs @@ -6,14 +6,23 @@ use std::{ sync::{Arc, Mutex}, }; -#[derive(Default, Hash)] -struct DiffRequest(String, bool); +/// +#[derive(Default, Hash, Clone)] +pub struct DiffParams(pub String, pub bool); struct Request(R, Option); +#[derive(Default, Clone)] +struct LastResult { + params: P, + hash: u64, + result: R, +} + /// pub struct AsyncDiff { current: Arc>>, + last: Arc>>>, sender: Sender, } @@ -22,21 +31,34 @@ impl AsyncDiff { pub fn new(sender: Sender) -> Self { Self { current: Arc::new(Mutex::new(Request(0, None))), + last: Arc::new(Mutex::new(None)), sender, } } /// - pub fn request( - &mut self, - file_path: String, - stage: bool, - ) -> Option { + pub fn last(&mut self) -> Option { + let last = self.last.lock().unwrap(); + if let Some(res) = last.clone() { + Some(res.result.clone()) + } else { + None + } + } + + /// + pub fn refresh(&mut self) { + if let Some(param) = self.get_last_param() { + self.clear_current(); + self.request(param); + } + } + + /// + pub fn request(&mut self, params: DiffParams) -> Option { trace!("request"); - let request = DiffRequest(file_path.clone(), stage); - - let hash = hash(&request); + let hash = hash(¶ms); { let mut current = self.current.lock().unwrap(); @@ -49,19 +71,30 @@ impl AsyncDiff { current.1 = None; } - let arc_clone = Arc::clone(&self.current); + let arc_current = Arc::clone(&self.current); + let arc_last = Arc::clone(&self.last); let sender = self.sender.clone(); rayon_core::spawn(move || { - let res = sync::diff::get_diff(file_path.clone(), stage); + let res = + sync::diff::get_diff(params.0.clone(), params.1); let mut notify = false; { - let mut current = arc_clone.lock().unwrap(); + let mut current = arc_current.lock().unwrap(); if current.0 == hash { - current.1 = Some(res); + current.1 = Some(res.clone()); notify = true; } } + { + let mut last = arc_last.lock().unwrap(); + *last = Some(LastResult { + result: res, + hash: hash, + params: params, + }); + } + if notify { sender.send(AsyncNotification::Diff).unwrap(); } @@ -69,4 +102,18 @@ impl AsyncDiff { None } + + fn get_last_param(&self) -> Option { + self.last + .lock() + .unwrap() + .clone() + .map_or(None, |e| Some(e.params)) + } + + fn clear_current(&mut self) { + let mut current = self.current.lock().unwrap(); + current.0 = 0; + current.1 = None; + } } diff --git a/asyncgit/src/lib.rs b/asyncgit/src/lib.rs index 44e18d30..a1aa57d6 100644 --- a/asyncgit/src/lib.rs +++ b/asyncgit/src/lib.rs @@ -7,7 +7,7 @@ mod status; pub mod sync; pub use crate::{ - diff::AsyncDiff, + diff::{AsyncDiff, DiffParams}, status::AsyncStatus, sync::{ diff::{Diff, DiffLine, DiffLineType}, diff --git a/src/app.rs b/src/app.rs index 356da077..8973d356 100644 --- a/src/app.rs +++ b/src/app.rs @@ -7,6 +7,7 @@ use crate::{ }; use asyncgit::{ current_tick, sync, AsyncDiff, AsyncNotification, AsyncStatus, + DiffParams, }; use crossbeam_channel::Sender; use crossterm::event::Event; @@ -201,8 +202,7 @@ impl App { pub fn update(&mut self) { trace!("update"); - self.update_diff(); - + self.git_diff.refresh(); self.git_status.fetch(current_tick()); } @@ -215,15 +215,6 @@ impl App { } } - /// - pub fn update_status(&mut self) { - let status = self.git_status.last(); - self.index.update(&status.stage); - self.index_wd.update(&status.work_dir); - self.update_diff(); - self.help.set_cmds(self.commands()); - } - /// pub fn is_quit(&self) -> bool { self.do_quit @@ -240,21 +231,38 @@ impl App { if let Some(i) = idx.selection() { let path = i.path; + let diff_params = DiffParams(path.clone(), is_stage); if self.diff.current() != (path.clone(), is_stage) { - if let Some(diff) = - self.git_diff.request(path.clone(), is_stage) + // we dont show the right diff right now, so we need to request + if let Some(diff) = self.git_diff.request(diff_params) { self.diff.update(path.clone(), is_stage, diff); } else { self.diff.clear(); } + } else { + // we are already showing a diff of the right file + // maybe the diff changed (outside file change) + if let Some(last) = self.git_diff.last() { + self.diff.update(path.clone(), is_stage, last); + } } } else { self.diff.clear(); } } + fn update_status(&mut self) { + let status = self.git_status.last(); + self.index.update(&status.stage); + self.index_wd.update(&status.work_dir); + + self.update_diff(); + + self.help.set_cmds(self.commands()); + } + fn commands(&self) -> Vec { let mut res = self.commit.commands(); res.extend(self.help.commands()); diff --git a/src/components/diff.rs b/src/components/diff.rs index 6a2b901b..12fe8c23 100644 --- a/src/components/diff.rs +++ b/src/components/diff.rs @@ -2,7 +2,7 @@ use crate::{ components::{CommandInfo, Component}, strings, }; -use asyncgit::{Diff, DiffLine, DiffLineType}; +use asyncgit::{hash, Diff, DiffLine, DiffLineType}; use crossterm::event::{Event, KeyCode}; use tui::{ backend::Backend, @@ -19,6 +19,7 @@ pub struct DiffComponent { scroll: u16, focused: bool, current: (String, bool), + current_hash: u64, } impl DiffComponent { @@ -28,7 +29,7 @@ impl DiffComponent { } /// pub fn current(&self) -> (String, bool) { - self.current.clone() + (self.current.0.clone(), self.current.1) } /// pub fn clear(&mut self) { @@ -36,10 +37,17 @@ impl DiffComponent { self.diff = Diff::default(); } /// - pub fn update(&mut self, path: String, stage: bool, diff: Diff) { - self.current = (path, stage); + pub fn update( + &mut self, + path: String, + is_stage: bool, + diff: Diff, + ) { + let hash = hash(&diff); - if diff != self.diff { + if self.current_hash != hash { + self.current = (path, is_stage); + self.current_hash = hash; self.diff = diff; self.scroll = 0; }