summaryrefslogtreecommitdiffstats
path: root/src/tabs/revlog.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tabs/revlog.rs')
-rw-r--r--src/tabs/revlog.rs664
1 files changed, 332 insertions, 332 deletions
diff --git a/src/tabs/revlog.rs b/src/tabs/revlog.rs
index 7a52a4a7..22c5b07d 100644
--- a/src/tabs/revlog.rs
+++ b/src/tabs/revlog.rs
@@ -1,358 +1,358 @@
use crate::{
- components::{
- visibility_blocking, CommandBlocking, CommandInfo,
- CommitDetailsComponent, CommitList, Component,
- DrawableComponent, EventState,
- },
- keys::SharedKeyConfig,
- queue::{InternalEvent, Queue},
- strings,
- ui::style::SharedTheme,
+ components::{
+ visibility_blocking, CommandBlocking, CommandInfo,
+ CommitDetailsComponent, CommitList, Component,
+ DrawableComponent, EventState,
+ },
+ keys::SharedKeyConfig,
+ queue::{InternalEvent, Queue},
+ strings,
+ ui::style::SharedTheme,
};
use anyhow::Result;
use asyncgit::{
- cached,
- sync::{self, CommitId},
- AsyncGitNotification, AsyncLog, AsyncTags, FetchStatus, CWD,
+ cached,
+ sync::{self, CommitId},
+ AsyncGitNotification, AsyncLog, AsyncTags, FetchStatus, CWD,
};
use crossbeam_channel::Sender;
use crossterm::event::Event;
use std::time::Duration;
use sync::CommitTags;
use tui::{
- backend::Backend,
- layout::{Constraint, Direction, Layout, Rect},
- Frame,
+ backend::Backend,
+ layout::{Constraint, Direction, Layout, Rect},
+ Frame,
};
const SLICE_SIZE: usize = 1200;
///
pub struct Revlog {
- commit_details: CommitDetailsComponent,
- list: CommitList,
- git_log: AsyncLog,
- git_tags: AsyncTags,
- queue: Queue,
- visible: bool,
- branch_name: cached::BranchName,
- key_config: SharedKeyConfig,
+ commit_details: CommitDetailsComponent,
+ list: CommitList,
+ git_log: AsyncLog,
+ git_tags: AsyncTags,
+ queue: Queue,
+ visible: bool,
+ branch_name: cached::BranchName,
+ key_config: SharedKeyConfig,
}
impl Revlog {
- ///
- pub fn new(
- queue: &Queue,
- sender: &Sender<AsyncGitNotification>,
- theme: SharedTheme,
- key_config: SharedKeyConfig,
- ) -> Self {
- Self {
- queue: queue.clone(),
- commit_details: CommitDetailsComponent::new(
- queue,
- sender,
- theme.clone(),
- key_config.clone(),
- ),
- list: CommitList::new(
- &strings::log_title(&key_config),
- theme,
- key_config.clone(),
- ),
- git_log: AsyncLog::new(sender, None),
- git_tags: AsyncTags::new(sender),
- visible: false,
- branch_name: cached::BranchName::new(CWD),
- key_config,
- }
- }
-
- ///
- pub fn any_work_pending(&self) -> bool {
- self.git_log.is_pending()
- || self.git_tags.is_pending()
- || self.commit_details.any_work_pending()
- }
-
- ///
- pub fn update(&mut self) -> Result<()> {
- if self.is_visible() {
- let log_changed =
- self.git_log.fetch()? == FetchStatus::Started;
-
- self.list.set_count_total(self.git_log.count()?);
-
- let selection = self.list.selection();
- let selection_max = self.list.selection_max();
- if self.list.items().needs_data(selection, selection_max)
- || log_changed
- {
- self.fetch_commits()?;
- }
-
- self.git_tags.request(Duration::from_secs(3), false)?;
-
- self.list.set_branch(
- self.branch_name.lookup().map(Some).unwrap_or(None),
- );
-
- if self.commit_details.is_visible() {
- let commit = self.selected_commit();
- let tags = self.selected_commit_tags(&commit);
-
- self.commit_details.set_commit(commit, tags)?;
- }
- }
-
- Ok(())
- }
-
- ///
- pub fn update_git(
- &mut self,
- ev: AsyncGitNotification,
- ) -> Result<()> {
- if self.visible {
- match ev {
- AsyncGitNotification::CommitFiles
- | AsyncGitNotification::Log => self.update()?,
- AsyncGitNotification::Tags => {
- if let Some(tags) = self.git_tags.last()? {
- self.list.set_tags(tags);
- self.update()?;
- }
- }
- _ => (),
- }
- }
-
- Ok(())
- }
-
- fn fetch_commits(&mut self) -> Result<()> {
- let want_min =
- self.list.selection().saturating_sub(SLICE_SIZE / 2);
-
- let commits = sync::get_commits_info(
- CWD,
- &self.git_log.get_slice(want_min, SLICE_SIZE)?,
- self.list.current_size().0.into(),
- );
-
- if let Ok(commits) = commits {
- self.list.items().set_items(want_min, commits);
- }
-
- Ok(())
- }
-
- fn selected_commit(&self) -> Option<CommitId> {
- self.list.selected_entry().map(|e| e.id)
- }
-
- fn copy_commit_hash(&self) -> Result<()> {
- self.list.copy_entry_hash()?;
- Ok(())
- }
-
- fn selected_commit_tags(
- &self,
- commit: &Option<CommitId>,
- ) -> Option<CommitTags> {
- let tags = self.list.tags();
-
- commit.and_then(|commit| {
- tags.and_then(|tags| tags.get(&commit).cloned())
- })
- }
-
- pub fn select_commit(&mut self, id: CommitId) -> Result<()> {
- let position = self.git_log.position(id)?;
-
- if let Some(position) = position {
- self.list.select_entry(position);
-
- Ok(())
- } else {
- anyhow::bail!("Could not select commit in revlog. It might not be loaded yet or it might be on a different branch.");
- }
- }
+ ///
+ pub fn new(
+ queue: &Queue,
+ sender: &Sender<AsyncGitNotification>,
+ theme: SharedTheme,
+ key_config: SharedKeyConfig,
+ ) -> Self {
+ Self {
+ queue: queue.clone(),
+ commit_details: CommitDetailsComponent::new(
+ queue,
+ sender,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ list: CommitList::new(
+ &strings::log_title(&key_config),
+ theme,
+ key_config.clone(),
+ ),
+ git_log: AsyncLog::new(sender, None),
+ git_tags: AsyncTags::new(sender),
+ visible: false,
+ branch_name: cached::BranchName::new(CWD),
+ key_config,
+ }
+ }
+
+ ///
+ pub fn any_work_pending(&self) -> bool {
+ self.git_log.is_pending()
+ || self.git_tags.is_pending()
+ || self.commit_details.any_work_pending()
+ }
+
+ ///
+ pub fn update(&mut self) -> Result<()> {
+ if self.is_visible() {
+ let log_changed =
+ self.git_log.fetch()? == FetchStatus::Started;
+
+ self.list.set_count_total(self.git_log.count()?);
+
+ let selection = self.list.selection();
+ let selection_max = self.list.selection_max();
+ if self.list.items().needs_data(selection, selection_max)
+ || log_changed
+ {
+ self.fetch_commits()?;
+ }
+
+ self.git_tags.request(Duration::from_secs(3), false)?;
+
+ self.list.set_branch(
+ self.branch_name.lookup().map(Some).unwrap_or(None),
+ );
+
+ if self.commit_details.is_visible() {
+ let commit = self.selected_commit();
+ let tags = self.selected_commit_tags(&commit);
+
+ self.commit_details.set_commit(commit, tags)?;
+ }
+ }
+
+ Ok(())
+ }
+
+ ///
+ pub fn update_git(
+ &mut self,
+ ev: AsyncGitNotification,
+ ) -> Result<()> {
+ if self.visible {
+ match ev {
+ AsyncGitNotification::CommitFiles
+ | AsyncGitNotification::Log => self.update()?,
+ AsyncGitNotification::Tags => {
+ if let Some(tags) = self.git_tags.last()? {
+ self.list.set_tags(tags);
+ self.update()?;
+ }
+ }
+ _ => (),
+ }
+ }
+
+ Ok(())
+ }
+
+ fn fetch_commits(&mut self) -> Result<()> {
+ let want_min =
+ self.list.selection().saturating_sub(SLICE_SIZE / 2);
+
+ let commits = sync::get_commits_info(
+ CWD,
+ &self.git_log.get_slice(want_min, SLICE_SIZE)?,
+ self.list.current_size().0.into(),
+ );
+
+ if let Ok(commits) = commits {
+ self.list.items().set_items(want_min, commits);
+ }
+
+ Ok(())
+ }
+
+ fn selected_commit(&self) -> Option<CommitId> {
+ self.list.selected_entry().map(|e| e.id)
+ }
+
+ fn copy_commit_hash(&self) -> Result<()> {
+ self.list.copy_entry_hash()?;
+ Ok(())
+ }
+
+ fn selected_commit_tags(
+ &self,
+ commit: &Option<CommitId>,
+ ) -> Option<CommitTags> {
+ let tags = self.list.tags();
+
+ commit.and_then(|commit| {
+ tags.and_then(|tags| tags.get(&commit).cloned())
+ })
+ }
+
+ pub fn select_commit(&mut self, id: CommitId) -> Result<()> {
+ let position = self.git_log.position(id)?;
+
+ if let Some(position) = position {
+ self.list.select_entry(position);
+
+ Ok(())
+ } else {
+ anyhow::bail!("Could not select commit in revlog. It might not be loaded yet or it might be on a different branch.");
+ }
+ }
}
impl DrawableComponent for Revlog {
- fn draw<B: Backend>(
- &self,
- f: &mut Frame<B>,
- area: Rect,
- ) -> Result<()> {
- let chunks = Layout::default()
- .direction(Direction::Horizontal)
- .constraints(
- [
- Constraint::Percentage(60),
- Constraint::Percentage(40),
- ]
- .as_ref(),
- )
- .split(area);
-
- if self.commit_details.is_visible() {
- self.list.draw(f, chunks[0])?;
- self.commit_details.draw(f, chunks[1])?;
- } else {
- self.list.draw(f, area)?;
- }
-
- Ok(())
- }
+ fn draw<B: Backend>(
+ &self,
+ f: &mut Frame<B>,
+ area: Rect,
+ ) -> Result<()> {
+ let chunks = Layout::default()
+ .direction(Direction::Horizontal)
+ .constraints(
+ [
+ Constraint::Percentage(60),
+ Constraint::Percentage(40),
+ ]
+ .as_ref(),
+ )
+ .split(area);
+
+ if self.commit_details.is_visible() {
+ self.list.draw(f, chunks[0])?;
+ self.commit_details.draw(f, chunks[1])?;
+ } else {
+ self.list.draw(f, area)?;
+ }
+
+ Ok(())
+ }
}
impl Component for Revlog {
- fn event(&mut self, ev: Event) -> Result<EventState> {
- if self.visible {
- let event_used = self.list.event(ev)?;
-
- if event_used.is_consumed() {
- self.update()?;
- return Ok(EventState::Consumed);
- } else if let Event::Key(k) = ev {
- if k == self.key_config.enter {
- self.commit_details.toggle_visible()?;
- self.update()?;
- return Ok(EventState::Consumed);
- } else if k == self.key_config.copy {
- self.copy_commit_hash()?;
- return Ok(EventState::Consumed);
- } else if k == self.key_config.push {
- self.queue.push(InternalEvent::PushTags);
- return Ok(EventState::Consumed);
- } else if k == self.key_config.log_tag_commit {
- return self.selected_commit().map_or(
- Ok(EventState::NotConsumed),
- |id| {
- self.queue
- .push(InternalEvent::TagCommit(id));
- Ok(EventState::Consumed)
- },
- );
- } else if k == self.key_config.focus_right
- && self.commit_details.is_visible()
- {
- return self.selected_commit().map_or(
- Ok(EventState::NotConsumed),
- |id| {
- self.queue.push(
- InternalEvent::InspectCommit(
- id,
- self.selected_commit_tags(&Some(
- id,
- )),
- ),
- );
- Ok(EventState::Consumed)
- },
- );
- } else if k == self.key_config.select_branch {
- self.queue.push(InternalEvent::SelectBranch);
- return Ok(EventState::Consumed);
- } else if k == self.key_config.open_file_tree {
- return self.selected_commit().map_or(
- Ok(EventState::NotConsumed),
- |id| {
- self.queue.push(
- InternalEvent::OpenFileTree(id),
- );
- Ok(EventState::Consumed)
- },
- );
- } else if k == self.key_config.tags {
- self.queue.push(InternalEvent::Tags);
- return Ok(EventState::Consumed);
- }
- }
- }
-
- Ok(EventState::NotConsumed)
- }
-
- fn commands(
- &self,
- out: &mut Vec<CommandInfo>,
- force_all: bool,
- ) -> CommandBlocking {
- if self.visible || force_all {
- self.list.commands(out, force_all);
- }
-
- out.push(CommandInfo::new(
- strings::commands::log_details_toggle(&self.key_config),
- true,
- self.visible,
- ));
-
- out.push(CommandInfo::new(
- strings::commands::log_details_open(&self.key_config),
- true,
- (self.visible && self.commit_details.is_visible())
- || force_all,
- ));
-
- out.push(CommandInfo::new(
- strings::commands::log_tag_commit(&self.key_config),
- self.selected_commit().is_some(),
- self.visible || force_all,
- ));
-
- out.push(CommandInfo::new(
- strings::commands::open_branch_select_popup(
- &self.key_config,
- ),
- true,
- self.visible || force_all,
- ));
-
- out.push(CommandInfo::new(
- strings::commands::open_tags_popup(&self.key_config),
- true,
- self.visible || force_all,
- ));
-
- out.push(CommandInfo::new(
- strings::commands::copy_hash(&self.key_config),
- self.selected_commit().is_some(),
- self.visible || force_all,
- ));
-
- out.push(CommandInfo::new(
- strings::commands::push_tags(&self.key_config),
- true,
- self.visible || force_all,
- ));
-
- out.push(CommandInfo::new(
- strings::commands::inspect_file_tree(&self.key_config),
- self.selected_commit().is_some(),
- self.visible || force_all,
- ));
-
- visibility_blocking(self)
- }
-
- fn is_visible(&self) -> bool {
- self.visible
- }
-
- fn hide(&mut self) {
- self.visible = false;
- self.git_log.set_background();
- }
-
- fn show(&mut self) -> Result<()> {
- self.visible = true;
- self.list.clear();
- self.update()?;
-
- Ok(())
- }
+ fn event(&mut self, ev: Event) -> Result<EventState> {
+ if self.visible {
+ let event_used = self.list.event(ev)?;
+
+ if event_used.is_consumed() {
+ self.update()?;
+ return Ok(EventState::Consumed);
+ } else if let Event::Key(k) = ev {
+ if k == self.key_config.enter {
+ self.commit_details.toggle_visible()?;
+ self.update()?;
+ return Ok(EventState::Consumed);
+ } else if k == self.key_config.copy {
+ self.copy_commit_hash()?;
+ return Ok(EventState::Consumed);
+ } else if k == self.key_config.push {
+ self.queue.push(InternalEvent::PushTags);
+ return Ok(EventState::Consumed);
+ } else if k == self.key_config.log_tag_commit {
+ return self.selected_commit().map_or(
+ Ok(EventState::NotConsumed),
+ |id| {
+ self.queue
+ .push(InternalEvent::TagCommit(id));
+ Ok(EventState::Consumed)
+ },
+ );
+ } else if k == self.key_config.focus_right
+ && self.commit_details.is_visible()
+ {
+ return self.selected_commit().map_or(
+ Ok(EventState::NotConsumed),
+ |id| {
+ self.queue.push(
+ InternalEvent::InspectCommit(
+ id,
+ self.selected_commit_tags(&Some(
+ id,
+ )),
+ ),
+ );
+ Ok(EventState::Consumed)
+ },
+ );
+ } else if k == self.key_config.select_branch {
+ self.queue.push(InternalEvent::SelectBranch);
+ return Ok(EventState::Consumed);
+ } else if k == self.key_config.open_file_tree {
+ return self.selected_commit().map_or(
+ Ok(EventState::NotConsumed),
+ |id| {
+ self.queue.push(
+ InternalEvent::OpenFileTree(id),
+ );
+ Ok(EventState::Consumed)
+ },
+ );
+ } else if k == self.key_config.tags {
+ self.queue.push(InternalEvent::Tags);
+ return Ok(EventState::Consumed);
+ }
+ }
+ }
+
+ Ok(EventState::NotConsumed)
+ }
+
+ fn commands(
+ &self,
+ out: &mut Vec<CommandInfo>,
+ force_all: bool,
+ ) -> CommandBlocking {
+ if self.visible || force_all {
+ self.list.commands(out, force_all);
+ }
+
+ out.push(CommandInfo::new(
+ strings::commands::log_details_toggle(&self.key_config),
+ true,
+ self.visible,
+ ));
+
+ out.push(CommandInfo::new(
+ strings::commands::log_details_open(&self.key_config),
+ true,
+ (self.visible && self.commit_details.is_visible())
+ || force_all,
+ ));
+
+ out.push(CommandInfo::new(
+ strings::commands::log_tag_commit(&self.key_config),
+ self.selected_commit().is_some(),
+ self.visible || force_all,
+ ));
+
+ out.push(CommandInfo::new(
+ strings::commands::open_branch_select_popup(
+ &self.key_config,
+ ),
+ true,
+ self.visible || force_all,
+ ));
+
+ out.push(CommandInfo::new(
+ strings::commands::open_tags_popup(&self.key_config),
+ true,
+ self.visible || force_all,
+ ));
+
+ out.push(CommandInfo::new(
+ strings::commands::copy_hash(&self.key_config),
+ self.selected_commit().is_some(),
+ self.visible || force_all,
+ ));
+
+ out.push(CommandInfo::new(
+ strings::commands::push_tags(&self.key_config),
+ true,
+ self.visible || force_all,
+ ));
+
+ out.push(CommandInfo::new(
+ strings::commands::inspect_file_tree(&self.key_config),
+ self.selected_commit().is_some(),
+ self.visible || force_all,
+ ));
+
+ visibility_blocking(self)
+ }
+
+ fn is_visible(&self) -> bool {
+ self.visible
+ }
+
+ fn hide(&mut self) {
+ self.visible = false;
+ self.git_log.set_background();
+ }
+
+ fn show(&mut self) -> Result<()> {
+ self.visible = true;
+ self.list.clear();
+ self.update()?;
+
+ Ok(())
+ }
}