From d625d536468704793484910b13d15f044a7eb150 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Sun, 25 Oct 2020 16:57:44 +0100 Subject: [PATCH 1/4] visualize outgoing/incoming changes --- asyncgit/src/sync/branch.rs | 37 ++++++++++++++++++++++++++--- asyncgit/src/sync/mod.rs | 5 ++-- src/tabs/status.rs | 46 +++++++++++++++++++++++++++++++++++-- 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/asyncgit/src/sync/branch.rs b/asyncgit/src/sync/branch.rs index d60ab80921..8126385580 100644 --- a/asyncgit/src/sync/branch.rs +++ b/asyncgit/src/sync/branch.rs @@ -2,14 +2,12 @@ use crate::{ error::{Error, Result}, - sync::utils, + sync::{utils, CommitId}, }; use git2::BranchType; use scopetime::scope_time; use utils::get_head_repo; -use super::CommitId; - /// returns the branch-name head is currently pointing to /// this might be expensive, see `cached::BranchName` pub(crate) fn get_branch_name(repo_path: &str) -> Result { @@ -79,6 +77,39 @@ pub fn get_branches_to_display( Ok(branches_for_display) } +/// +#[derive(Debug, Default)] +pub struct BranchCompare { + /// + pub ahead: usize, + /// + pub behind: usize, +} + +/// +pub fn branch_compare_upstream( + repo_path: &str, + branch: &str, +) -> Result { + scope_time!("branch_compare_upstream"); + + let repo = utils::repo(repo_path)?; + + let branch = repo.find_branch(branch, BranchType::Local)?; + let upstream = branch.upstream()?; + + let branch_commit = + branch.into_reference().peel_to_commit()?.id(); + + let upstream_commit = + upstream.into_reference().peel_to_commit()?.id(); + + let (ahead, behind) = + repo.graph_ahead_behind(branch_commit, upstream_commit)?; + + Ok(BranchCompare { ahead, behind }) +} + /// Modify HEAD to point to a branch then checkout head, does not work if there are uncommitted changes pub fn checkout_branch( repo_path: &str, diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index 0ace7b0d49..0425381fef 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -20,8 +20,9 @@ pub mod utils; pub(crate) use branch::get_branch_name; pub use branch::{ - checkout_branch, create_branch, delete_branch, - get_branches_to_display, rename_branch, BranchForDisplay, + branch_compare_upstream, checkout_branch, create_branch, + delete_branch, get_branches_to_display, rename_branch, + BranchCompare, BranchForDisplay, }; pub use commit::{amend, commit, tag}; pub use commit_details::{ diff --git a/src/tabs/status.rs b/src/tabs/status.rs index d30a619f73..eff023b7df 100644 --- a/src/tabs/status.rs +++ b/src/tabs/status.rs @@ -12,13 +12,17 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ + sync::BranchCompare, sync::{self, status::StatusType}, AsyncDiff, AsyncNotification, AsyncStatus, DiffParams, DiffType, StatusParams, CWD, }; use crossbeam_channel::Sender; use crossterm::event::Event; -use tui::layout::{Constraint, Direction, Layout}; +use tui::{ + layout::{Alignment, Constraint, Direction, Layout}, + widgets::Paragraph, +}; /// #[derive(PartialEq)] @@ -45,6 +49,7 @@ pub struct Status { git_diff: AsyncDiff, git_status_workdir: AsyncStatus, git_status_stage: AsyncStatus, + git_branch_state: BranchCompare, queue: Queue, git_action_executed: bool, key_config: SharedKeyConfig, @@ -95,6 +100,7 @@ impl DrawableComponent for Status { self.index_wd.draw(f, left_chunks[0])?; self.index.draw(f, left_chunks[1])?; self.diff.draw(f, chunks[1])?; + self.draw_branch_state(f, left_chunks[0]); Ok(()) } @@ -141,10 +147,31 @@ impl Status { git_status_workdir: AsyncStatus::new(sender.clone()), git_status_stage: AsyncStatus::new(sender.clone()), git_action_executed: false, + git_branch_state: BranchCompare::default(), key_config, } } + fn draw_branch_state( + &self, + f: &mut tui::Frame, + rect: tui::layout::Rect, + ) { + let w = Paragraph::new(format!( + "\u{2191}{} \u{2193}{}", + self.git_branch_state.ahead, self.git_branch_state.behind + )) + .alignment(Alignment::Right); + + let mut rect = rect; + rect.x += 1; + rect.width = rect.width.saturating_sub(2); + rect.y = rect.y + rect.height.saturating_sub(1); + rect.height = 1; + + f.render_widget(w, rect); + } + fn can_focus_diff(&self) -> bool { match self.focus { Focus::WorkDir => self.index_wd.is_file_seleted(), @@ -216,6 +243,7 @@ impl Status { .fetch(StatusParams::new(StatusType::Stage, true))?; self.index_wd.update()?; + self.check_branch_state(); } Ok(()) @@ -356,6 +384,20 @@ impl Status { } } } + + fn check_branch_state(&mut self) { + self.git_branch_state = + if let Some(branch) = self.index_wd.branch_name() { + sync::branch_compare_upstream(CWD, branch.as_str()) + .unwrap_or_default() + } else { + BranchCompare::default() + }; + } + + fn can_push(&self) -> bool { + self.git_branch_state.ahead > 0 + } } impl Component for Status { @@ -381,7 +423,7 @@ impl Component for Status { out.push(CommandInfo::new( strings::commands::status_push(&self.key_config), - self.index_wd.branch_name().is_some(), + self.can_push(), true, )); } From 4a25f338c3641507c1ba98266b495c5f2a2dee4f Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Sun, 25 Oct 2020 17:09:21 +0100 Subject: [PATCH 2/4] also show incoming/outgoing in staged --- src/tabs/status.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/tabs/status.rs b/src/tabs/status.rs index eff023b7df..a87614277e 100644 --- a/src/tabs/status.rs +++ b/src/tabs/status.rs @@ -100,7 +100,7 @@ impl DrawableComponent for Status { self.index_wd.draw(f, left_chunks[0])?; self.index.draw(f, left_chunks[1])?; self.diff.draw(f, chunks[1])?; - self.draw_branch_state(f, left_chunks[0]); + self.draw_branch_state(f, &left_chunks); Ok(()) } @@ -155,7 +155,7 @@ impl Status { fn draw_branch_state( &self, f: &mut tui::Frame, - rect: tui::layout::Rect, + chunks: &[tui::layout::Rect], ) { let w = Paragraph::new(format!( "\u{2191}{} \u{2193}{}", @@ -163,11 +163,18 @@ impl Status { )) .alignment(Alignment::Right); - let mut rect = rect; + let mut rect = if self.index_wd.focused() { + let mut rect = chunks[0]; + rect.y = rect.y + rect.height.saturating_sub(1); + rect + } else { + chunks[1] + }; + rect.x += 1; rect.width = rect.width.saturating_sub(2); - rect.y = rect.y + rect.height.saturating_sub(1); - rect.height = 1; + rect.height = + rect.height.saturating_sub(rect.height.saturating_sub(1)); f.render_widget(w, rect); } From 4b25d5e4be7a2333bec83fe1174f4bda8e7dde02 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Sun, 25 Oct 2020 17:14:11 +0100 Subject: [PATCH 3/4] update changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8febc6b3db..4bfaf212c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,11 +12,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - added gitui to [chocolatey](https://chocolatey.org/packages/gitui) on windows by [@nils-a](https://github.com/nils-a) - push to remote ([#265](https://github.com/extrawurst/gitui/issues/265)) ([#267](https://github.com/extrawurst/gitui/issues/267)) -![branches](assets/push.gif) +![push](assets/push.gif) +- incoming/outgoing commits to upstream ([#362](https://github.com/extrawurst/gitui/issues/362)) - new branch list popup incl. checkout/delete/rename [[@WizardOhio24](https://github.com/WizardOhio24)] ([#303](https://github.com/extrawurst/gitui/issues/303)) ([#323](https://github.com/extrawurst/gitui/issues/323)) -![push](assets/branches.gif) +![branches](assets/branches.gif) - scrollbar in long commit messages [[@timaliberdov](https://github.com/timaliberdov)] ([#308](https://github.com/extrawurst/gitui/issues/308)) From 96b7cf7fe4932f18ec3be272d976033633bf0a5f Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Sun, 25 Oct 2020 17:18:25 +0100 Subject: [PATCH 4/4] clippy fies --- src/tabs/status.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tabs/status.rs b/src/tabs/status.rs index a87614277e..7d9a10dcdf 100644 --- a/src/tabs/status.rs +++ b/src/tabs/status.rs @@ -165,7 +165,7 @@ impl Status { let mut rect = if self.index_wd.focused() { let mut rect = chunks[0]; - rect.y = rect.y + rect.height.saturating_sub(1); + rect.y += rect.height.saturating_sub(1); rect } else { chunks[1] @@ -393,16 +393,16 @@ impl Status { } fn check_branch_state(&mut self) { - self.git_branch_state = - if let Some(branch) = self.index_wd.branch_name() { + self.git_branch_state = self.index_wd.branch_name().map_or( + BranchCompare::default(), + |branch| { sync::branch_compare_upstream(CWD, branch.as_str()) .unwrap_or_default() - } else { - BranchCompare::default() - }; + }, + ); } - fn can_push(&self) -> bool { + const fn can_push(&self) -> bool { self.git_branch_state.ahead > 0 } }