summaryrefslogtreecommitdiffstats
path: root/src/app.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/app.rs')
-rw-r--r--src/app.rs1614
1 files changed, 807 insertions, 807 deletions
diff --git a/src/app.rs b/src/app.rs
index 000fbf0f..e58c889f 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -1,829 +1,829 @@
use crate::{
- accessors,
- cmdbar::CommandBar,
- components::{
- event_pump, BlameFileComponent, BranchListComponent,
- CommandBlocking, CommandInfo, CommitComponent, Component,
- CreateBranchComponent, DrawableComponent,
- ExternalEditorComponent, HelpComponent,
- InspectCommitComponent, MsgComponent, PullComponent,
- PushComponent, PushTagsComponent, RenameBranchComponent,
- ResetComponent, RevisionFilesPopup, StashMsgComponent,
- TagCommitComponent, TagListComponent,
- },
- input::{Input, InputEvent, InputState},
- keys::{KeyConfig, SharedKeyConfig},
- queue::{Action, InternalEvent, NeedsUpdate, Queue},
- setup_popups,
- strings::{self, order},
- tabs::{FilesTab, Revlog, StashList, Stashing, Status},
- ui::style::{SharedTheme, Theme},
- AsyncAppNotification, AsyncNotification,
+ accessors,
+ cmdbar::CommandBar,
+ components::{
+ event_pump, BlameFileComponent, BranchListComponent,
+ CommandBlocking, CommandInfo, CommitComponent, Component,
+ CreateBranchComponent, DrawableComponent,
+ ExternalEditorComponent, HelpComponent,
+ InspectCommitComponent, MsgComponent, PullComponent,
+ PushComponent, PushTagsComponent, RenameBranchComponent,
+ ResetComponent, RevisionFilesPopup, StashMsgComponent,
+ TagCommitComponent, TagListComponent,
+ },
+ input::{Input, InputEvent, InputState},
+ keys::{KeyConfig, SharedKeyConfig},
+ queue::{Action, InternalEvent, NeedsUpdate, Queue},
+ setup_popups,
+ strings::{self, order},
+ tabs::{FilesTab, Revlog, StashList, Stashing, Status},
+ ui::style::{SharedTheme, Theme},
+ AsyncAppNotification, AsyncNotification,
};
use anyhow::{bail, Result};
use asyncgit::{sync, AsyncGitNotification, CWD};
use crossbeam_channel::Sender;
use crossterm::event::{Event, KeyEvent};
use std::{
- cell::{Cell, RefCell},
- path::Path,
- rc::Rc,
+ cell::{Cell, RefCell},
+ path::Path,
+ rc::Rc,
};
use tui::{
- backend::Backend,
- layout::{Constraint, Direction, Layout, Margin, Rect},
- text::{Span, Spans},
- widgets::{Block, Borders, Tabs},
- Frame,
+ backend::Backend,
+ layout::{Constraint, Direction, Layout, Margin, Rect},
+ text::{Span, Spans},
+ widgets::{Block, Borders, Tabs},
+ Frame,
};
/// the main app type
pub struct App {
- do_quit: bool,
- help: HelpComponent,
- msg: MsgComponent,
- reset: ResetComponent,
- commit: CommitComponent,
- blame_file_popup: BlameFileComponent,
- stashmsg_popup: StashMsgComponent,
- inspect_commit_popup: InspectCommitComponent,
- external_editor_popup: ExternalEditorComponent,
- revision_files_popup: RevisionFilesPopup,
- push_popup: PushComponent,
- push_tags_popup: PushTagsComponent,
- pull_popup: PullComponent,
- tag_commit_popup: TagCommitComponent,
- create_branch_popup: CreateBranchComponent,
- rename_branch_popup: RenameBranchComponent,
- select_branch_popup: BranchListComponent,
- tags_popup: TagListComponent,
- cmdbar: RefCell<CommandBar>,
- tab: usize,
- revlog: Revlog,
- status_tab: Status,
- stashing_tab: Stashing,
- stashlist_tab: StashList,
- files_tab: FilesTab,
- queue: Queue,
- theme: SharedTheme,
- key_config: SharedKeyConfig,
- input: Input,
-
- // "Flags"
- requires_redraw: Cell<bool>,
- file_to_open: Option<String>,
+ do_quit: bool,
+ help: HelpComponent,
+ msg: MsgComponent,
+ reset: ResetComponent,
+ commit: CommitComponent,
+ blame_file_popup: BlameFileComponent,
+ stashmsg_popup: StashMsgComponent,
+ inspect_commit_popup: InspectCommitComponent,
+ external_editor_popup: ExternalEditorComponent,
+ revision_files_popup: RevisionFilesPopup,
+ push_popup: PushComponent,
+ push_tags_popup: PushTagsComponent,
+ pull_popup: PullComponent,
+ tag_commit_popup: TagCommitComponent,
+ create_branch_popup: CreateBranchComponent,
+ rename_branch_popup: RenameBranchComponent,
+ select_branch_popup: BranchListComponent,
+ tags_popup: TagListComponent,
+ cmdbar: RefCell<CommandBar>,
+ tab: usize,
+ revlog: Revlog,
+ status_tab: Status,
+ stashing_tab: Stashing,
+ stashlist_tab: StashList,
+ files_tab: FilesTab,
+ queue: Queue,
+ theme: SharedTheme,
+ key_config: SharedKeyConfig,
+ input: Input,
+
+ // "Flags"
+ requires_redraw: Cell<bool>,
+ file_to_open: Option<String>,
}
// public interface
impl App {
- ///
- #[allow(clippy::too_many_lines)]
- pub fn new(
- sender: &Sender<AsyncGitNotification>,
- sender_app: &Sender<AsyncAppNotification>,
- input: Input,
- theme: Theme,
- key_config: KeyConfig,
- ) -> Self {
- let queue = Queue::new();
- let theme = Rc::new(theme);
- let key_config = Rc::new(key_config);
-
- Self {
- input,
- reset: ResetComponent::new(
- queue.clone(),
- theme.clone(),
- key_config.clone(),
- ),
- commit: CommitComponent::new(
- queue.clone(),
- theme.clone(),
- key_config.clone(),
- ),
- blame_file_popup: BlameFileComponent::new(
- &queue,
- sender,
- &strings::blame_title(&key_config),
- theme.clone(),
- key_config.clone(),
- ),
- revision_files_popup: RevisionFilesPopup::new(
- &queue,
- sender_app,
- theme.clone(),
- key_config.clone(),
- ),
- stashmsg_popup: StashMsgComponent::new(
- queue.clone(),
- theme.clone(),
- key_config.clone(),
- ),
- inspect_commit_popup: InspectCommitComponent::new(
- &queue,
- sender,
- theme.clone(),
- key_config.clone(),
- ),
- external_editor_popup: ExternalEditorComponent::new(
- theme.clone(),
- key_config.clone(),
- ),
- push_popup: PushComponent::new(
- &queue,
- sender,
- theme.clone(),
- key_config.clone(),
- ),
- push_tags_popup: PushTagsComponent::new(
- &queue,
- sender,
- theme.clone(),
- key_config.clone(),
- ),
- pull_popup: PullComponent::new(
- &queue,
- sender,
- theme.clone(),
- key_config.clone(),
- ),
- tag_commit_popup: TagCommitComponent::new(
- queue.clone(),
- theme.clone(),
- key_config.clone(),
- ),
- create_branch_popup: CreateBranchComponent::new(
- queue.clone(),
- theme.clone(),
- key_config.clone(),
- ),
- rename_branch_popup: RenameBranchComponent::new(
- queue.clone(),
- theme.clone(),
- key_config.clone(),
- ),
- select_branch_popup: BranchListComponent::new(
- queue.clone(),
- theme.clone(),
- key_config.clone(),
- ),
- tags_popup: TagListComponent::new(
- &queue,
- sender_app,
- theme.clone(),
- key_config.clone(),
- ),
- do_quit: false,
- cmdbar: RefCell::new(CommandBar::new(
- theme.clone(),
- key_config.clone(),
- )),
- help: HelpComponent::new(
- theme.clone(),
- key_config.clone(),
- ),
- msg: MsgComponent::new(theme.clone(), key_config.clone()),
- tab: 0,
- revlog: Revlog::new(
- &queue,
- sender,
- theme.clone(),
- key_config.clone(),
- ),
- status_tab: Status::new(
- &queue,
- sender,
- theme.clone(),
- key_config.clone(),
- ),
- stashing_tab: Stashing::new(
- sender,
- &queue,
- theme.clone(),
- key_config.clone(),
- ),
- stashlist_tab: StashList::new(
- &queue,
- theme.clone(),
- key_config.clone(),
- ),
- files_tab: FilesTab::new(
- sender_app,
- &queue,
- theme.clone(),
- key_config.clone(),
- ),
- queue,
- theme,
- key_config,
- requires_redraw: Cell::new(false),
- file_to_open: None,
- }
- }
-
- ///
- pub fn draw<B: Backend>(&self, f: &mut Frame<B>) -> Result<()> {
- let fsize = f.size();
-
- self.cmdbar.borrow_mut().refresh_width(fsize.width);
-
- let chunks_main = Layout::default()
- .direction(Direction::Vertical)
- .constraints(
- [
- Constraint::Length(2),
- Constraint::Min(2),
- Constraint::Length(self.cmdbar.borrow().height()),
- ]
- .as_ref(),
- )
- .split(fsize);
-
- self.cmdbar.borrow().draw(f, chunks_main[2]);
-
- self.draw_tabs(f, chunks_main[0]);
-
- //TODO: macro because of generic draw call
- match self.tab {
- 0 => self.status_tab.draw(f, chunks_main[1])?,
- 1 => self.revlog.draw(f, chunks_main[1])?,
- 2 => self.files_tab.draw(f, chunks_main[1])?,
- 3 => self.stashing_tab.draw(f, chunks_main[1])?,
- 4 => self.stashlist_tab.draw(f, chunks_main[1])?,
- _ => bail!("unknown tab"),
- };
-
- self.draw_popups(f)?;
-
- Ok(())
- }
-
- ///
- pub fn event(&mut self, ev: InputEvent) -> Result<()> {
- log::trace!("event: {:?}", ev);
-
- if let InputEvent::Input(ev) = ev {
- if self.check_hard_exit(ev) || self.check_quit(ev) {
- return Ok(());
- }
-
- let mut flags = NeedsUpdate::empty();
-
- if event_pump(ev, self.components_mut().as_mut_slice())?
- .is_consumed()
- {
- flags.insert(NeedsUpdate::COMMANDS);
- } else if let Event::Key(k) = ev {
- let new_flags = if k == self.key_config.tab_toggle {
- self.toggle_tabs(false)?;
- NeedsUpdate::COMMANDS
- } else if k == self.key_config.tab_toggle_reverse {
- self.toggle_tabs(true)?;
- NeedsUpdate::COMMANDS
- } else if k == self.key_config.tab_status
- || k == self.key_config.tab_log
- || k == self.key_config.tab_files
- || k == self.key_config.tab_stashing
- || k == self.key_config.tab_stashes
- {
- self.switch_tab(k)?;
- NeedsUpdate::COMMANDS
- } else if k == self.key_config.cmd_bar_toggle {
- self.cmdbar.borrow_mut().toggle_more();
- NeedsUpdate::empty()
- } else {
- NeedsUpdate::empty()
- };
-
- flags.insert(new_flags);
- }
-
- self.process_queue(flags)?;
- } else if let InputEvent::State(polling_state) = ev {
- self.external_editor_popup.hide();
- if let InputState::Paused = polling_state {
- let result = match self.file_to_open.take() {
- Some(path) => {
- ExternalEditorComponent::open_file_in_editor(
- Path::new(&path),
- )
- }
- None => self.commit.show_editor(),
- };
-
- if let Err(e) = result {
- let msg =
- format!("failed to launch editor:\n{}", e);
- log::error!("{}", msg.as_str());
- self.msg.show_error(msg.as_str())?;
- }
-
- self.requires_redraw.set(true);
- self.input.set_polling(true);
- }
- }
-
- Ok(())
- }
-
- //TODO: do we need this?
- /// forward ticking to components that require it
- pub fn update(&mut self) -> Result<()> {
- log::trace!("update");
-
- self.commit.update();
- self.status_tab.update()?;
- self.revlog.update()?;
- self.files_tab.update()?;
- self.stashing_tab.update()?;
- self.stashlist_tab.update()?;
-
- self.update_commands();
-
- Ok(())
- }
-
- ///
- pub fn update_async(
- &mut self,
- ev: AsyncNotification,
- ) -> Result<()> {
- log::trace!("update_async: {:?}", ev);
-
- if let AsyncNotification::Git(ev) = ev {
- self.status_tab.update_git(ev)?;
- self.stashing_tab.update_git(ev)?;
- self.revlog.update_git(ev)?;
- self.blame_file_popup.update_git(ev)?;
- self.inspect_commit_popup.update_git(ev)?;
- self.push_popup.update_git(ev)?;
- self.push_tags_popup.update_git(ev)?;
- self.pull_popup.update_git(ev)?;
- self.select_branch_popup.update_git(ev)?;
- }
-
- self.files_tab.update_async(ev);
- self.revision_files_popup.update(ev);
- self.tags_popup.update(ev);
-
- //TODO: better system for this
- // can we simply process the queue here and everyone just uses the queue to schedule a cmd update?
- self.process_queue(NeedsUpdate::COMMANDS)?;
-
- Ok(())
- }
-
- ///
- pub const fn is_quit(&self) -> bool {
- self.do_quit
- }
-
- ///
- pub fn any_work_pending(&self) -> bool {
- self.status_tab.anything_pending()
- || self.revlog.any_work_pending()
- || self.stashing_tab.anything_pending()
- || self.files_tab.anything_pending()
- || self.blame_file_popup.any_work_pending()
- || self.inspect_commit_popup.any_work_pending()
- || self.input.is_state_changing()
- || self.push_popup.any_work_pending()
- || self.push_tags_popup.any_work_pending()
- || self.pull_popup.any_work_pending()
- || self.revision_files_popup.any_work_pending()
- || self.tags_popup.any_work_pending()
- }
-
- ///
- pub fn requires_redraw(&self) -> bool {
- if self.requires_redraw.get() {
- self.requires_redraw.set(false);
- true
- } else {
- false
- }
- }
+ ///
+ #[allow(clippy::too_many_lines)]
+ pub fn new(
+ sender: &Sender<AsyncGitNotification>,
+ sender_app: &Sender<AsyncAppNotification>,
+ input: Input,
+ theme: Theme,
+ key_config: KeyConfig,
+ ) -> Self {
+ let queue = Queue::new();
+ let theme = Rc::new(theme);
+ let key_config = Rc::new(key_config);
+
+ Self {
+ input,
+ reset: ResetComponent::new(
+ queue.clone(),
+ theme.clone(),
+ key_config.clone(),
+ ),
+ commit: CommitComponent::new(
+ queue.clone(),
+ theme.clone(),
+ key_config.clone(),
+ ),
+ blame_file_popup: BlameFileComponent::new(
+ &queue,
+ sender,
+ &strings::blame_title(&key_config),
+ theme.clone(),
+ key_config.clone(),
+ ),
+ revision_files_popup: RevisionFilesPopup::new(
+ &queue,
+ sender_app,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ stashmsg_popup: StashMsgComponent::new(
+ queue.clone(),
+ theme.clone(),
+ key_config.clone(),
+ ),
+ inspect_commit_popup: InspectCommitComponent::new(
+ &queue,
+ sender,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ external_editor_popup: ExternalEditorComponent::new(
+ theme.clone(),
+ key_config.clone(),
+ ),
+ push_popup: PushComponent::new(
+ &queue,
+ sender,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ push_tags_popup: PushTagsComponent::new(
+ &queue,
+ sender,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ pull_popup: PullComponent::new(
+ &queue,
+ sender,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ tag_commit_popup: TagCommitComponent::new(
+ queue.clone(),
+ theme.clone(),
+ key_config.clone(),
+ ),
+ create_branch_popup: CreateBranchComponent::new(
+ queue.clone(),
+ theme.clone(),
+ key_config.clone(),
+ ),
+ rename_branch_popup: RenameBranchComponent::new(
+ queue.clone(),
+ theme.clone(),
+ key_config.clone(),
+ ),
+ select_branch_popup: BranchListComponent::new(
+ queue.clone(),
+ theme.clone(),
+ key_config.clone(),
+ ),
+ tags_popup: TagListComponent::new(
+ &queue,
+ sender_app,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ do_quit: false,
+ cmdbar: RefCell::new(CommandBar::new(
+ theme.clone(),
+ key_config.clone(),
+ )),
+ help: HelpComponent::new(
+ theme.clone(),
+ key_config.clone(),
+ ),
+ msg: MsgComponent::new(theme.clone(), key_config.clone()),
+ tab: 0,
+ revlog: Revlog::new(
+ &queue,
+ sender,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ status_tab: Status::new(
+ &queue,
+ sender,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ stashing_tab: Stashing::new(
+ sender,
+ &queue,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ stashlist_tab: StashList::new(
+ &queue,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ files_tab: FilesTab::new(
+ sender_app,
+ &queue,
+ theme.clone(),
+ key_config.clone(),
+ ),
+ queue,
+ theme,
+ key_config,
+ requires_redraw: Cell::new(false),
+ file_to_open: None,
+ }
+ }
+
+ ///
+ pub fn draw<B: Backend>(&self, f: &mut Frame<B>) -> Result<()> {
+ let fsize = f.size();
+
+ self.cmdbar.borrow_mut().refresh_width(fsize.width);
+
+ let chunks_main = Layout::default()
+ .direction(Direction::Vertical)
+ .constraints(
+ [
+ Constraint::Length(2),
+ Constraint::Min(2),
+ Constraint::Length(self.cmdbar.borrow().height()),
+ ]
+ .as_ref(),
+ )
+ .split(fsize);
+
+ self.cmdbar.borrow().draw(f, chunks_main[2]);
+
+ self.draw_tabs(f, chunks_main[0]);
+
+ //TODO: macro because of generic draw call
+ match self.tab {
+ 0 => self.status_tab.draw(f, chunks_main[1])?,
+ 1 => self.revlog.draw(f, chunks_main[1])?,
+ 2 => self.files_tab.draw(f, chunks_main[1])?,
+ 3 => self.stashing_tab.draw(f, chunks_main[1])?,
+ 4 => self.stashlist_tab.draw(f, chunks_main[1])?,
+ _ => bail!("unknown tab"),
+ };
+
+ self.draw_popups(f)?;
+
+ Ok(())
+ }
+
+ ///
+ pub fn event(&mut self, ev: InputEvent) -> Result<()> {
+ log::trace!("event: {:?}", ev);
+
+ if let InputEvent::Input(ev) = ev {
+ if self.check_hard_exit(ev) || self.check_quit(ev) {
+ return Ok(());
+ }
+
+ let mut flags = NeedsUpdate::empty();
+
+ if event_pump(ev, self.components_mut().as_mut_slice())?
+ .is_consumed()
+ {
+ flags.insert(NeedsUpdate::COMMANDS);
+ } else if let Event::Key(k) = ev {
+ let new_flags = if k == self.key_config.tab_toggle {
+ self.toggle_tabs(false)?;
+ NeedsUpdate::COMMANDS
+ } else if k == self.key_config.tab_toggle_reverse {
+ self.toggle_tabs(true)?;
+ NeedsUpdate::COMMANDS
+ } else if k == self.key_config.tab_status
+ || k == self.key_config.tab_log
+ || k == self.key_config.tab_files
+ || k == self.key_config.tab_stashing
+ || k == self.key_config.tab_stashes
+ {
+ self.switch_tab(k)?;
+ NeedsUpdate::COMMANDS
+ } else if k == self.key_config.cmd_bar_toggle {
+ self.cmdbar.borrow_mut().toggle_more();
+ NeedsUpdate::empty()
+ } else {
+ NeedsUpdate::empty()
+ };
+
+ flags.insert(new_flags);
+ }
+
+ self.process_queue(flags)?;
+ } else if let InputEvent::State(polling_state) = ev {
+ self.external_editor_popup.hide();
+ if let InputState::Paused = polling_state {
+ let result = match self.file_to_open.take() {
+ Some(path) => {
+ ExternalEditorComponent::open_file_in_editor(
+ Path::new(&path),
+ )
+ }
+ None => self.commit.show_editor(),
+ };
+
+ if let Err(e) = result {
+ let msg =
+ format!("failed to launch editor:\n{}", e);
+ log::error!("{}", msg.as_str());
+ self.msg.show_error(msg.as_str())?;
+ }
+
+ self.requires_redraw.set(true);
+ self.input.set_polling(true);
+ }
+ }
+
+ Ok(())
+ }
+
+ //TODO: do we need this?
+ /// forward ticking to components that require it
+ pub fn update(&mut self) -> Result<()> {
+ log::trace!("update");
+
+ self.commit.update();
+ self.status_tab.update()?;
+ self.revlog.update()?;
+ self.files_tab.update()?;
+ self.stashing_tab.update()?;
+ self.stashlist_tab.update()?;
+
+ self.update_commands();
+
+ Ok(())
+ }
+
+ ///
+ pub fn update_async(
+ &mut self,
+ ev: AsyncNotification,
+ ) -> Result<()> {
+ log::trace!("update_async: {:?}", ev);
+
+ if let AsyncNotification::Git(ev) = ev {
+ self.status_tab.update_git(ev)?;
+ self.stashing_tab.update_git(ev)?;
+ self.revlog.update_git(ev)?;
+ self.blame_file_popup.update_git(ev)?;
+ self.inspect_commit_popup.update_git(ev)?;
+ self.push_popup.update_git(ev)?;
+ self.push_tags_popup.update_git(ev)?;
+ self.pull_popup.update_git(ev)?;
+ self.select_branch_popup.update_git(ev)?;
+ }
+
+ self.files_tab.update_async(ev);
+ self.revision_files_popup.update(ev);
+ self.tags_popup.update(ev);
+
+ //TODO: better system for this
+ // can we simply process the queue here and everyone just uses the queue to schedule a cmd update?
+ self.process_queue(NeedsUpdate::COMMANDS)?;
+
+ Ok(())
+ }
+
+ ///
+ pub const fn is_quit(&self) -> bool {
+ self.do_quit
+ }
+
+ ///
+ pub fn any_work_pending(&self) -> bool {
+ self.status_tab.anything_pending()
+ || self.revlog.any_work_pending()
+ || self.stashing_tab.anything_pending()
+ || self.files_tab.anything_pending()
+ || self.blame_file_popup.any_work_pending()
+ || self.inspect_commit_popup.any_work_pending()
+ || self.input.is_state_changing()
+ || self.push_popup.any_work_pending()
+ || self.push_tags_popup.any_work_pending()
+ || self.pull_popup.any_work_pending()
+ || self.revision_files_popup.any_work_pending()
+ || self.tags_popup.any_work_pending()
+ }
+
+ ///
+ pub fn requires_redraw(&self) -> bool {
+ if self.requires_redraw.get() {
+ self.requires_redraw.set(false);
+ true
+ } else {
+ false
+ }
+ }
}
// private impls
impl App {
- accessors!(
- self,
- [
- msg,
- reset,
- commit,
- blame_file_popup,
- stashmsg_popup,
- inspect_commit_popup,
- external_editor_popup,
- push_popup,
- push_tags_popup,
- pull_popup,
- tag_commit_popup,
- create_branch_popup,
- rename_branch_popup,
- select_branch_popup,
- revision_files_popup,
- tags_popup,
- help,
- revlog,
- status_tab,
- files_tab,
- stashing_tab,
- stashlist_tab
- ]
- );
-
- setup_popups!(
- self,
- [
- commit,
- stashmsg_popup,
- help,
- inspect_commit_popup,
- blame_file_popup,
- external_editor_popup,
- tag_commit_popup,
- select_branch_popup,
- tags_popup,
- create_branch_popup,
- rename_branch_popup,
- revision_files_popup,
- push_popup,
- push_tags_popup,
- pull_popup,
- reset,
- msg
- ]
- );
-
- fn check_quit(&mut self, ev: Event) -> bool {
- if self.any_popup_visible() {
- return false;
- }
- if let Event::Key(e) = ev {
- if e == self.key_config.quit {
- self.do_quit = true;
- return true;
- }
- }
- false
- }
-
- fn check_hard_exit(&mut self, ev: Event) -> bool {
- if let Event::Key(e) = ev {
- if e == self.key_config.exit {
- self.do_quit = true;
- return true;
- }
- }
- false
- }
-
- fn get_tabs(&mut self) -> Vec<&mut dyn Component> {
- vec![
- &mut self.status_tab,
- &mut self.revlog,
- &mut self.files_tab,
- &mut self.stashing_tab,
- &mut self.stashlist_tab,
- ]
- }
-
- fn toggle_tabs(&mut self, reverse: bool) -> Result<()> {
- let tabs_len = self.get_tabs().len();
- let new_tab = if reverse {
- self.tab.wrapping_sub(1).min(tabs_len.saturating_sub(1))
- } else {
- self.tab.saturating_add(1) % tabs_len
- };
-
- self.set_tab(new_tab)
- }
-
- fn switch_tab(&mut self, k: KeyEvent) -> Result<()> {
- if k == self.key_config.tab_status {
- self.set_tab(0)?;
- } else if k == self.key_config.tab_log {
- self.set_tab(1)?;
- } else if k == self.key_config.tab_files {
- self.set_tab(2)?;
- } else if k == self.key_config.tab_stashing {
- self.set_tab(3)?;
- } else if k == self.key_config.tab_stashes {
- self.set_tab(4)?;
- }
-
- Ok(())
- }
-
- fn set_tab(&mut self, tab: usize) -> Result<()> {
- let tabs = self.get_tabs();
- for (i, t) in tabs.into_iter().enumerate() {
- if tab == i {
- t.show()?;
- } else {
- t.hide();
- }
- }
-
- self.tab = tab;
-
- Ok(())
- }
-
- fn update_commands(&mut self) {
- self.help.set_cmds(self.commands(true));
- self.cmdbar.borrow_mut().set_cmds(self.commands(false));
- }
-
- fn process_queue(&mut self, flags: NeedsUpdate) -> Result<()> {
- let mut flags = flags;
- let new_flags = self.process_internal_events()?;
- flags.insert(new_flags);
-
- if flags.contains(NeedsUpdate::ALL) {
- self.update()?;
- }
- //TODO: make this a queue event?
- //NOTE: set when any tree component changed selection
- if flags.contains(NeedsUpdate::DIFF) {
- self.status_tab.update_diff()?;
- self.inspect_commit_popup.update_diff()?;
- }
- if flags.contains(NeedsUpdate::COMMANDS) {
- self.update_commands();
- }
- if flags.contains(NeedsUpdate::BRANCHES) {
- self.select_branch_popup.update_branches()?;
- }
-
- Ok(())
- }
-
- fn process_internal_events(&mut self) -> Result<NeedsUpdate> {
- let mut flags = NeedsUpdate::empty();
-
- loop {
- let front = self.queue.pop();
- if let Some(e) = front {
- flags.insert(self.process_internal_event(e)?);
- } else {
- break;
- }
- }
- self.queue.clear();
-
- Ok(flags)
- }
-
- fn process_internal_event(
- &mut self,
- ev: InternalEvent,
- ) -> Result<NeedsUpdate> {
- let mut flags = NeedsUpdate::empty();
- match ev {
- InternalEvent::ConfirmedAction(action) => {
- self.process_confirmed_action(action, &mut flags)?;
- }
- InternalEvent::ConfirmAction(action) => {
- self.reset.open(action)?;
- flags.insert(NeedsUpdate::COMMANDS);
- }
- InternalEvent::ShowErrorMsg(msg) => {
- self.msg.show_error(msg.as_str())?;
- flags
- .insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
- }
- InternalEvent::Update(u) => flags.insert(u),
- InternalEvent::OpenCommit => self.commit.show()?,
- InternalEvent::PopupStashing(opts) => {
- self.stashmsg_popup.options(opts);
- self.stashmsg_popup.show()?;
- }
- InternalEvent::TagCommit(id) => {
- self.tag_commit_popup.open(id)?;
- }
- InternalEvent::BlameFile(path) => {
- self.blame_file_popup.open(&path)?;
- flags
- .insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
- }
- InternalEvent::CreateBranch => {
- self.create_branch_popup.open()?;
- }
- InternalEvent::RenameBranch(branch_ref, cur_name) => {
- self.rename_branch_popup
- .open(branch_ref, cur_name)?;
- }
- InternalEvent::SelectBranch => {
- self.select_branch_popup.open()?;
- }
- InternalEvent::Tags => {
- self.tags_popup.open()?;
- }
- InternalEvent::TabSwitch => self.set_tab(0)?,
- InternalEvent::InspectCommit(id, tags) => {
- self.inspect_commit_popup.open(id, tags)?;
- flags
- .insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
- }
- InternalEvent::SelectCommitInRevlog(id) => {
- if let Err(error) = self.revlog.select_commit(id) {
- self.queue.push(InternalEvent::ShowErrorMsg(
- error.to_string(),
- ));
- } else {
- self.tags_popup.hide();
- flags.insert(NeedsUpdate::ALL);
- }
- }
- InternalEvent::OpenExternalEditor(path) => {
- self.input.set_polling(false);
- self.external_editor_popup.show()?;
- self.file_to_open = path;
- flags.insert(NeedsUpdate::COMMANDS);
- }
- InternalEvent::Push(branch, force, delete) => {
- self.push_popup.push(branch, force, delete)?;
- flags.insert(NeedsUpdate::ALL);
- }
- InternalEvent::Pull(branch) => {
- self.pull_popup.fetch(branch)?;
- flags.insert(NeedsUpdate::ALL);
- }
- InternalEvent::PushTags => {
- self.push_tags_popup.push_tags()?;
- flags.insert(NeedsUpdate::ALL);
- }
- InternalEvent::StatusLastFileMoved => {
- self.status_tab.last_file_moved()?;
- }
- InternalEvent::OpenFileTree(c) => {
- self.revision_files_popup.open(c)?;
- flags
- .insert(NeedsUpdate::ALL | NeedsUpdate::COMMANDS);
- }
- };
-
- Ok(flags)
- }
-
- fn process_confirmed_action(
- &mut self,
- action: Action,
- flags: &mut NeedsUpdate,
- ) -> Result<()> {
- match action {
- Action::Reset(r) => {
- if self.status_tab.reset(&r) {
- flags.insert(NeedsUpdate::ALL);
- }
- }
- Action::StashDrop(_) | Action::StashPop(_) => {
- if self.stashlist_tab.action_confirmed(&action) {
- flags.insert(NeedsUpdate::ALL);
- }
- }
- Action::ResetHunk(path, hash) => {
- sync::reset_hunk(CWD, &path, hash)?;
- flags.insert(NeedsUpdate::ALL);
- }
- Action::ResetLines(path, lines) => {
- sync::discard_lines(CWD, &path, &lines)?;
- flags.insert(NeedsUpdate::ALL);
- }
- Action::DeleteBranch(branch_ref, true) => {
- if let Err(e) = sync::delete_branch(CWD, &branch_ref)
- {
- self.queue.push(InternalEvent::ShowErrorMsg(
- e.to_string(),
- ));
- }
- flags.insert(NeedsUpdate::ALL);
- self.select_branch_popup.update_branches()?;
- }
- Action::DeleteBranch(branch_ref, false) => {
- self.queue.push(
- if let Some(name) = branch_ref.rsplit('/').next()
- {
- InternalEvent::Push(
- name.to_string(),
-