diff --git a/CHANGELOG.md b/CHANGELOG.md index a74ef8c97d..2428857d08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - hooks ignored when running `gitui` in subfolder of workdir ([#151](https://github.com/extrawurst/gitui/issues/151)) - better scrolling in file-trees [[@tisorlawan](https://github.com/tisorlawan)] ([#144](https://github.com/extrawurst/gitui/issues/144)) - show untracked files in stash commit details [[@MCord](https://github.com/MCord)] ([#130](https://github.com/extrawurst/gitui/issues/130)) +- in some repos looking up the branch name was a bottleneck ([#159](https://github.com/extrawurst/gitui/issues/159)) - some optimizations in reflog ## [0.7.0] - 2020-06-15 diff --git a/asyncgit/src/cached/branchname.rs b/asyncgit/src/cached/branchname.rs new file mode 100644 index 0000000000..c65a1b6900 --- /dev/null +++ b/asyncgit/src/cached/branchname.rs @@ -0,0 +1,41 @@ +use crate::{ + error::Result, + sync::{self, CommitId}, +}; + +/// +pub struct BranchName { + last_result: Option<(CommitId, String)>, + repo_path: String, +} + +impl BranchName { + /// + pub fn new(path: &str) -> Self { + Self { + repo_path: path.to_string(), + last_result: None, + } + } + + /// + pub fn lookup(&mut self) -> Result { + let current_head = sync::get_head(self.repo_path.as_str())?; + + if let Some((last_head, branch_name)) = + self.last_result.as_ref() + { + if *last_head == current_head { + return Ok(branch_name.clone()); + } + } + + self.fetch(current_head) + } + + fn fetch(&mut self, head: CommitId) -> Result { + let name = sync::get_branch_name(self.repo_path.as_str())?; + self.last_result = Some((head, name.clone())); + Ok(name) + } +} diff --git a/asyncgit/src/cached/mod.rs b/asyncgit/src/cached/mod.rs new file mode 100644 index 0000000000..ea16edf5cc --- /dev/null +++ b/asyncgit/src/cached/mod.rs @@ -0,0 +1,7 @@ +//! cached lookups: +//! parts of the sync api that might take longer +//! to compute but change seldom so doing them async might be overkill + +mod branchname; + +pub use branchname::BranchName; diff --git a/asyncgit/src/lib.rs b/asyncgit/src/lib.rs index f2007a5c73..e1632a00e0 100644 --- a/asyncgit/src/lib.rs +++ b/asyncgit/src/lib.rs @@ -6,6 +6,7 @@ #![deny(clippy::result_unwrap_used)] #![deny(clippy::panic)] +pub mod cached; mod commit_files; mod diff; mod error; diff --git a/asyncgit/src/sync/branch.rs b/asyncgit/src/sync/branch.rs index 16df76f70b..2d8bdacfec 100644 --- a/asyncgit/src/sync/branch.rs +++ b/asyncgit/src/sync/branch.rs @@ -7,7 +7,8 @@ use crate::{ use scopetime::scope_time; /// returns the branch-name head is currently pointing to -pub fn get_branch_name(repo_path: &str) -> Result { +/// this might be expensive, see `cached::BranchName` +pub(crate) fn get_branch_name(repo_path: &str) -> Result { scope_time!("get_branch_name"); let repo = utils::repo(repo_path)?; diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index 1120bcad5f..9e5b742f98 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -16,7 +16,7 @@ pub mod status; mod tags; pub mod utils; -pub use branch::get_branch_name; +pub(crate) use branch::get_branch_name; pub use commit::{amend, commit}; pub use commit_details::{get_commit_details, CommitDetails}; pub use commit_files::get_commit_files; diff --git a/src/components/changes.rs b/src/components/changes.rs index 6f7067c15f..8dbf2e14ce 100644 --- a/src/components/changes.rs +++ b/src/components/changes.rs @@ -11,7 +11,7 @@ use crate::{ ui::style::SharedTheme, }; use anyhow::Result; -use asyncgit::{sync, StatusItem, StatusItemType, CWD}; +use asyncgit::{cached, sync, StatusItem, StatusItemType, CWD}; use crossterm::event::Event; use std::path::Path; use strings::commands; @@ -39,6 +39,7 @@ pub struct ChangesComponent { files: FileTreeComponent, is_working_dir: bool, queue: Queue, + branch_name: cached::BranchName, } impl ChangesComponent { @@ -60,13 +61,14 @@ impl ChangesComponent { ), is_working_dir, queue, + branch_name: cached::BranchName::new(CWD), } } /// pub fn update(&mut self, list: &[StatusItem]) -> Result<()> { if self.is_working_dir { - if let Ok(branch_name) = sync::get_branch_name(CWD) { + if let Ok(branch_name) = self.branch_name.lookup() { self.files.set_title(format!( "{} - {{{}}}", &self.title, branch_name, diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs index 4310818e30..463d756294 100644 --- a/src/tabs/revlog.rs +++ b/src/tabs/revlog.rs @@ -11,6 +11,7 @@ use crate::{ }; use anyhow::Result; use asyncgit::{ + cached, sync::{self, CommitId}, AsyncLog, AsyncNotification, FetchStatus, CWD, }; @@ -31,6 +32,7 @@ pub struct Revlog { git_log: AsyncLog, queue: Queue, visible: bool, + branch_name: cached::BranchName, } impl Revlog { @@ -50,6 +52,7 @@ impl Revlog { list: CommitList::new(strings::LOG_TITLE, theme), git_log: AsyncLog::new(sender), visible: false, + branch_name: cached::BranchName::new(CWD), } } @@ -80,7 +83,7 @@ impl Revlog { } self.list.set_branch( - sync::get_branch_name(CWD).map(Some).unwrap_or(None), + self.branch_name.lookup().map(Some).unwrap_or(None), ); if self.commit_details.is_visible() {