update diff if changed externally

This commit is contained in:
Stephan Dilly 2020-03-25 15:36:57 +01:00
parent 7e78a182b2
commit d52308ea0a
5 changed files with 96 additions and 34 deletions

View File

@ -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)

View File

@ -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, A>(R, Option<A>);
#[derive(Default, Clone)]
struct LastResult<P, R> {
params: P,
hash: u64,
result: R,
}
///
pub struct AsyncDiff {
current: Arc<Mutex<Request<u64, Diff>>>,
last: Arc<Mutex<Option<LastResult<DiffParams, Diff>>>>,
sender: Sender<AsyncNotification>,
}
@ -22,21 +31,34 @@ impl AsyncDiff {
pub fn new(sender: Sender<AsyncNotification>) -> 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<Diff> {
pub fn last(&mut self) -> Option<Diff> {
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<Diff> {
trace!("request");
let request = DiffRequest(file_path.clone(), stage);
let hash = hash(&request);
let hash = hash(&params);
{
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<DiffParams> {
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;
}
}

View File

@ -7,7 +7,7 @@ mod status;
pub mod sync;
pub use crate::{
diff::AsyncDiff,
diff::{AsyncDiff, DiffParams},
status::AsyncStatus,
sync::{
diff::{Diff, DiffLine, DiffLineType},

View File

@ -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<CommandInfo> {
let mut res = self.commit.commands();
res.extend(self.help.commands());

View File

@ -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;
}