mirror of
https://github.com/extrawurst/gitui.git
synced 2024-11-22 02:12:58 +03:00
Fix 730 files tab (#743)
This commit is contained in:
parent
1149ddddd3
commit
739d7e7f84
33
src/app.rs
33
src/app.rs
@ -8,7 +8,7 @@ use crate::{
|
||||
ExternalEditorComponent, HelpComponent,
|
||||
InspectCommitComponent, MsgComponent, PullComponent,
|
||||
PushComponent, PushTagsComponent, RenameBranchComponent,
|
||||
ResetComponent, RevisionFilesComponent, StashMsgComponent,
|
||||
ResetComponent, RevisionFilesPopup, StashMsgComponent,
|
||||
TagCommitComponent, TagListComponent,
|
||||
},
|
||||
input::{Input, InputEvent, InputState},
|
||||
@ -16,7 +16,7 @@ use crate::{
|
||||
queue::{Action, InternalEvent, NeedsUpdate, Queue},
|
||||
setup_popups,
|
||||
strings::{self, order},
|
||||
tabs::{Revlog, StashList, Stashing, Status},
|
||||
tabs::{FilesTab, Revlog, StashList, Stashing, Status},
|
||||
ui::style::{SharedTheme, Theme},
|
||||
};
|
||||
use anyhow::{bail, Result};
|
||||
@ -47,7 +47,7 @@ pub struct App {
|
||||
stashmsg_popup: StashMsgComponent,
|
||||
inspect_commit_popup: InspectCommitComponent,
|
||||
external_editor_popup: ExternalEditorComponent,
|
||||
revision_files_popup: RevisionFilesComponent,
|
||||
revision_files_popup: RevisionFilesPopup,
|
||||
push_popup: PushComponent,
|
||||
push_tags_popup: PushTagsComponent,
|
||||
pull_popup: PullComponent,
|
||||
@ -62,6 +62,7 @@ pub struct App {
|
||||
status_tab: Status,
|
||||
stashing_tab: Stashing,
|
||||
stashlist_tab: StashList,
|
||||
files_tab: FilesTab,
|
||||
queue: Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
@ -105,7 +106,7 @@ impl App {
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
revision_files_popup: RevisionFilesComponent::new(
|
||||
revision_files_popup: RevisionFilesPopup::new(
|
||||
&queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
@ -203,6 +204,12 @@ impl App {
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
files_tab: FilesTab::new(
|
||||
sender,
|
||||
&queue,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
queue,
|
||||
theme,
|
||||
key_config,
|
||||
@ -237,8 +244,9 @@ impl App {
|
||||
match self.tab {
|
||||
0 => self.status_tab.draw(f, chunks_main[1])?,
|
||||
1 => self.revlog.draw(f, chunks_main[1])?,
|
||||
2 => self.stashing_tab.draw(f, chunks_main[1])?,
|
||||
3 => self.stashlist_tab.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"),
|
||||
};
|
||||
|
||||
@ -271,6 +279,7 @@ impl App {
|
||||
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
|
||||
{
|
||||
@ -322,6 +331,7 @@ impl App {
|
||||
self.commit.update()?;
|
||||
self.status_tab.update()?;
|
||||
self.revlog.update()?;
|
||||
self.files_tab.update()?;
|
||||
self.stashing_tab.update()?;
|
||||
self.stashlist_tab.update()?;
|
||||
|
||||
@ -339,6 +349,7 @@ impl App {
|
||||
|
||||
self.status_tab.update_git(ev)?;
|
||||
self.stashing_tab.update_git(ev)?;
|
||||
self.files_tab.update_git(ev)?;
|
||||
self.revlog.update_git(ev)?;
|
||||
self.blame_file_popup.update_git(ev)?;
|
||||
self.inspect_commit_popup.update_git(ev)?;
|
||||
@ -364,6 +375,7 @@ impl App {
|
||||
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()
|
||||
@ -408,6 +420,7 @@ impl App {
|
||||
help,
|
||||
revlog,
|
||||
status_tab,
|
||||
files_tab,
|
||||
stashing_tab,
|
||||
stashlist_tab
|
||||
]
|
||||
@ -450,6 +463,7 @@ impl App {
|
||||
vec![
|
||||
&mut self.status_tab,
|
||||
&mut self.revlog,
|
||||
&mut self.files_tab,
|
||||
&mut self.stashing_tab,
|
||||
&mut self.stashlist_tab,
|
||||
]
|
||||
@ -471,10 +485,12 @@ impl App {
|
||||
self.set_tab(0)?
|
||||
} else if k == self.key_config.tab_log {
|
||||
self.set_tab(1)?
|
||||
} else if k == self.key_config.tab_stashing {
|
||||
} else if k == self.key_config.tab_files {
|
||||
self.set_tab(2)?
|
||||
} else if k == self.key_config.tab_stashes {
|
||||
} 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(())
|
||||
@ -748,6 +764,7 @@ impl App {
|
||||
let tabs = [
|
||||
Span::raw(strings::tab_status(&self.key_config)),
|
||||
Span::raw(strings::tab_log(&self.key_config)),
|
||||
Span::raw(strings::tab_files(&self.key_config)),
|
||||
Span::raw(strings::tab_stashing(&self.key_config)),
|
||||
Span::raw(strings::tab_stashes(&self.key_config)),
|
||||
]
|
||||
|
@ -19,6 +19,7 @@ mod push_tags;
|
||||
mod rename_branch;
|
||||
mod reset;
|
||||
mod revision_files;
|
||||
mod revision_files_popup;
|
||||
mod stashmsg;
|
||||
mod syntax_text;
|
||||
mod tag_commit;
|
||||
@ -46,6 +47,7 @@ pub use push_tags::PushTagsComponent;
|
||||
pub use rename_branch::RenameBranchComponent;
|
||||
pub use reset::ResetComponent;
|
||||
pub use revision_files::RevisionFilesComponent;
|
||||
pub use revision_files_popup::RevisionFilesPopup;
|
||||
pub use stashmsg::StashMsgComponent;
|
||||
pub use syntax_text::SyntaxTextComponent;
|
||||
pub use tag_commit::TagCommitComponent;
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{
|
||||
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||
DrawableComponent, EventState, SyntaxTextComponent,
|
||||
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
||||
EventState, SyntaxTextComponent,
|
||||
};
|
||||
use crate::{
|
||||
keys::SharedKeyConfig,
|
||||
@ -23,7 +23,7 @@ use tui::{
|
||||
backend::Backend,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
text::Span,
|
||||
widgets::{Block, Borders, Clear},
|
||||
widgets::{Block, Borders},
|
||||
Frame,
|
||||
};
|
||||
|
||||
@ -38,7 +38,6 @@ enum Focus {
|
||||
|
||||
pub struct RevisionFilesComponent {
|
||||
queue: Queue,
|
||||
title: String,
|
||||
theme: SharedTheme,
|
||||
//TODO: store TreeFiles in `tree`
|
||||
files: Vec<TreeFile>,
|
||||
@ -46,7 +45,6 @@ pub struct RevisionFilesComponent {
|
||||
tree: FileTree,
|
||||
scroll_top: Cell<usize>,
|
||||
revision: Option<CommitId>,
|
||||
visible: bool,
|
||||
focus: Focus,
|
||||
key_config: SharedKeyConfig,
|
||||
}
|
||||
@ -61,7 +59,6 @@ impl RevisionFilesComponent {
|
||||
) -> Self {
|
||||
Self {
|
||||
queue: queue.clone(),
|
||||
title: String::new(),
|
||||
tree: FileTree::default(),
|
||||
scroll_top: Cell::new(0),
|
||||
current_file: SyntaxTextComponent::new(
|
||||
@ -72,30 +69,26 @@ impl RevisionFilesComponent {
|
||||
theme,
|
||||
files: Vec::new(),
|
||||
revision: None,
|
||||
visible: false,
|
||||
focus: Focus::Tree,
|
||||
key_config,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn open(&mut self, commit: CommitId) -> Result<()> {
|
||||
self.files = sync::tree_files(CWD, commit)?;
|
||||
let filenames: Vec<&str> = self
|
||||
.files
|
||||
.iter()
|
||||
.map(|f| f.path.to_str().unwrap_or_default())
|
||||
.collect();
|
||||
self.tree = FileTree::new(&filenames, &BTreeSet::new())?;
|
||||
self.tree.collapse_but_root();
|
||||
self.revision = Some(commit);
|
||||
self.title = format!(
|
||||
"Files at [{}]",
|
||||
self.revision
|
||||
.map(|c| c.get_short_string())
|
||||
.unwrap_or_default()
|
||||
);
|
||||
self.show()?;
|
||||
pub fn set_commit(&mut self, commit: CommitId) -> Result<()> {
|
||||
let same_id =
|
||||
self.revision.map(|c| c == commit).unwrap_or_default();
|
||||
if !same_id {
|
||||
self.files = sync::tree_files(CWD, commit)?;
|
||||
let filenames: Vec<&str> = self
|
||||
.files
|
||||
.iter()
|
||||
.map(|f| f.path.to_str().unwrap_or_default())
|
||||
.collect();
|
||||
self.tree = FileTree::new(&filenames, &BTreeSet::new())?;
|
||||
self.tree.collapse_but_root();
|
||||
self.revision = Some(commit);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -228,35 +221,21 @@ impl DrawableComponent for RevisionFilesComponent {
|
||||
f: &mut Frame<B>,
|
||||
area: Rect,
|
||||
) -> Result<()> {
|
||||
if self.is_visible() {
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.margin(1)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(60),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(area);
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.margin(1)
|
||||
.constraints(
|
||||
[
|
||||
Constraint::Percentage(40),
|
||||
Constraint::Percentage(60),
|
||||
]
|
||||
.as_ref(),
|
||||
)
|
||||
.split(area);
|
||||
|
||||
f.render_widget(Clear, area);
|
||||
f.render_widget(
|
||||
Block::default()
|
||||
.borders(Borders::TOP)
|
||||
.title(Span::styled(
|
||||
format!(" {}", self.title),
|
||||
self.theme.title(true),
|
||||
))
|
||||
.border_style(self.theme.block(true)),
|
||||
area,
|
||||
);
|
||||
self.draw_tree(f, chunks[0]);
|
||||
|
||||
self.draw_tree(f, chunks[0]);
|
||||
|
||||
self.current_file.draw(f, chunks[1])?;
|
||||
}
|
||||
self.current_file.draw(f, chunks[1])?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -268,90 +247,60 @@ impl Component for RevisionFilesComponent {
|
||||
out: &mut Vec<CommandInfo>,
|
||||
force_all: bool,
|
||||
) -> CommandBlocking {
|
||||
if self.is_visible() || force_all {
|
||||
if matches!(self.focus, Focus::Tree) || force_all {
|
||||
out.push(
|
||||
CommandInfo::new(
|
||||
strings::commands::close_popup(&self.key_config),
|
||||
true,
|
||||
strings::commands::blame_file(&self.key_config),
|
||||
self.tree.selected_file().is_some(),
|
||||
true,
|
||||
)
|
||||
.order(1),
|
||||
.order(order::NAV),
|
||||
);
|
||||
|
||||
if matches!(self.focus, Focus::Tree) || force_all {
|
||||
out.push(
|
||||
CommandInfo::new(
|
||||
strings::commands::blame_file(
|
||||
&self.key_config,
|
||||
),
|
||||
self.tree.selected_file().is_some(),
|
||||
true,
|
||||
)
|
||||
.order(order::NAV),
|
||||
);
|
||||
tree_nav_cmds(&self.tree, &self.key_config, out);
|
||||
} else {
|
||||
self.current_file.commands(out, force_all);
|
||||
}
|
||||
tree_nav_cmds(&self.tree, &self.key_config, out);
|
||||
} else {
|
||||
self.current_file.commands(out, force_all);
|
||||
}
|
||||
|
||||
visibility_blocking(self)
|
||||
CommandBlocking::PassingOn
|
||||
}
|
||||
|
||||
fn event(
|
||||
&mut self,
|
||||
event: crossterm::event::Event,
|
||||
) -> Result<EventState> {
|
||||
if self.is_visible() {
|
||||
if let Event::Key(key) = event {
|
||||
let is_tree_focused =
|
||||
matches!(self.focus, Focus::Tree);
|
||||
if key == self.key_config.exit_popup {
|
||||
if let Event::Key(key) = event {
|
||||
let is_tree_focused = matches!(self.focus, Focus::Tree);
|
||||
if is_tree_focused
|
||||
&& tree_nav(&mut self.tree, &self.key_config, key)
|
||||
{
|
||||
self.selection_changed();
|
||||
return Ok(EventState::Consumed);
|
||||
} else if key == self.key_config.blame {
|
||||
if self.blame() {
|
||||
self.hide();
|
||||
} else if is_tree_focused
|
||||
&& tree_nav(&mut self.tree, &self.key_config, key)
|
||||
{
|
||||
self.selection_changed();
|
||||
} else if key == self.key_config.blame {
|
||||
if self.blame() {
|
||||
self.hide();
|
||||
}
|
||||
} else if key == self.key_config.move_right {
|
||||
if is_tree_focused {
|
||||
self.focus = Focus::File;
|
||||
self.current_file.focus(true);
|
||||
self.focus(true);
|
||||
}
|
||||
} else if key == self.key_config.move_left {
|
||||
if !is_tree_focused {
|
||||
self.focus = Focus::Tree;
|
||||
self.current_file.focus(false);
|
||||
self.focus(false);
|
||||
}
|
||||
} else if !is_tree_focused {
|
||||
self.current_file.event(event)?;
|
||||
return Ok(EventState::Consumed);
|
||||
}
|
||||
} else if key == self.key_config.move_right {
|
||||
if is_tree_focused {
|
||||
self.focus = Focus::File;
|
||||
self.current_file.focus(true);
|
||||
self.focus(true);
|
||||
return Ok(EventState::Consumed);
|
||||
}
|
||||
} else if key == self.key_config.move_left {
|
||||
if !is_tree_focused {
|
||||
self.focus = Focus::Tree;
|
||||
self.current_file.focus(false);
|
||||
self.focus(false);
|
||||
return Ok(EventState::Consumed);
|
||||
}
|
||||
} else if !is_tree_focused {
|
||||
return self.current_file.event(event);
|
||||
}
|
||||
|
||||
return Ok(EventState::Consumed);
|
||||
}
|
||||
|
||||
Ok(EventState::NotConsumed)
|
||||
}
|
||||
|
||||
fn is_visible(&self) -> bool {
|
||||
self.visible
|
||||
}
|
||||
|
||||
fn hide(&mut self) {
|
||||
self.visible = false
|
||||
}
|
||||
|
||||
fn show(&mut self) -> Result<()> {
|
||||
self.visible = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: reuse for other tree usages
|
||||
|
153
src/components/revision_files_popup.rs
Normal file
153
src/components/revision_files_popup.rs
Normal file
@ -0,0 +1,153 @@
|
||||
use super::{
|
||||
revision_files::RevisionFilesComponent, visibility_blocking,
|
||||
CommandBlocking, CommandInfo, Component, DrawableComponent,
|
||||
EventState,
|
||||
};
|
||||
use crate::{
|
||||
keys::SharedKeyConfig,
|
||||
queue::Queue,
|
||||
strings::{self},
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{sync::CommitId, AsyncNotification};
|
||||
use crossbeam_channel::Sender;
|
||||
use crossterm::event::Event;
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::Rect,
|
||||
text::Span,
|
||||
widgets::{Block, Borders, Clear},
|
||||
Frame,
|
||||
};
|
||||
|
||||
pub struct RevisionFilesPopup {
|
||||
title: String,
|
||||
theme: SharedTheme,
|
||||
visible: bool,
|
||||
key_config: SharedKeyConfig,
|
||||
files: RevisionFilesComponent,
|
||||
}
|
||||
|
||||
impl RevisionFilesPopup {
|
||||
///
|
||||
pub fn new(
|
||||
queue: &Queue,
|
||||
sender: &Sender<AsyncNotification>,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
title: String::new(),
|
||||
files: RevisionFilesComponent::new(
|
||||
queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
theme,
|
||||
visible: false,
|
||||
key_config,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn open(&mut self, commit: CommitId) -> Result<()> {
|
||||
self.files.set_commit(commit)?;
|
||||
self.title =
|
||||
format!("Files at [{}]", commit.get_short_string());
|
||||
self.show()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
pub fn update(&mut self, ev: AsyncNotification) {
|
||||
self.files.update(ev);
|
||||
}
|
||||
|
||||
///
|
||||
pub fn any_work_pending(&self) -> bool {
|
||||
self.files.any_work_pending()
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawableComponent for RevisionFilesPopup {
|
||||
fn draw<B: Backend>(
|
||||
&self,
|
||||
f: &mut Frame<B>,
|
||||
area: Rect,
|
||||
) -> Result<()> {
|
||||
if self.is_visible() {
|
||||
f.render_widget(Clear, area);
|
||||
f.render_widget(
|
||||
Block::default()
|
||||
.borders(Borders::TOP)
|
||||
.title(Span::styled(
|
||||
format!(" {}", self.title),
|
||||
self.theme.title(true),
|
||||
))
|
||||
.border_style(self.theme.block(true)),
|
||||
area,
|
||||
);
|
||||
|
||||
self.files.draw(f, area)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for RevisionFilesPopup {
|
||||
fn commands(
|
||||
&self,
|
||||
out: &mut Vec<CommandInfo>,
|
||||
force_all: bool,
|
||||
) -> CommandBlocking {
|
||||
if self.is_visible() || force_all {
|
||||
out.push(
|
||||
CommandInfo::new(
|
||||
strings::commands::close_popup(&self.key_config),
|
||||
true,
|
||||
true,
|
||||
)
|
||||
.order(1),
|
||||
);
|
||||
|
||||
self.files.commands(out, force_all);
|
||||
}
|
||||
|
||||
visibility_blocking(self)
|
||||
}
|
||||
|
||||
fn event(
|
||||
&mut self,
|
||||
event: crossterm::event::Event,
|
||||
) -> Result<EventState> {
|
||||
if self.is_visible() {
|
||||
if let Event::Key(key) = &event {
|
||||
if *key == self.key_config.exit_popup {
|
||||
self.hide();
|
||||
}
|
||||
}
|
||||
|
||||
return self.files.event(event);
|
||||
}
|
||||
|
||||
Ok(EventState::NotConsumed)
|
||||
}
|
||||
|
||||
fn is_visible(&self) -> bool {
|
||||
self.visible
|
||||
}
|
||||
|
||||
fn hide(&mut self) {
|
||||
self.visible = false
|
||||
}
|
||||
|
||||
fn show(&mut self) -> Result<()> {
|
||||
self.visible = true;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@ pub type SharedKeyConfig = Rc<KeyConfig>;
|
||||
pub struct KeyConfig {
|
||||
pub tab_status: KeyEvent,
|
||||
pub tab_log: KeyEvent,
|
||||
pub tab_files: KeyEvent,
|
||||
pub tab_stashing: KeyEvent,
|
||||
pub tab_stashes: KeyEvent,
|
||||
pub tab_toggle: KeyEvent,
|
||||
@ -88,8 +89,9 @@ impl Default for KeyConfig {
|
||||
Self {
|
||||
tab_status: KeyEvent { code: KeyCode::Char('1'), modifiers: KeyModifiers::empty()},
|
||||
tab_log: KeyEvent { code: KeyCode::Char('2'), modifiers: KeyModifiers::empty()},
|
||||
tab_stashing: KeyEvent { code: KeyCode::Char('3'), modifiers: KeyModifiers::empty()},
|
||||
tab_stashes: KeyEvent { code: KeyCode::Char('4'), modifiers: KeyModifiers::empty()},
|
||||
tab_files: KeyEvent { code: KeyCode::Char('3'), modifiers: KeyModifiers::empty()},
|
||||
tab_stashing: KeyEvent { code: KeyCode::Char('4'), modifiers: KeyModifiers::empty()},
|
||||
tab_stashes: KeyEvent { code: KeyCode::Char('5'), modifiers: KeyModifiers::empty()},
|
||||
tab_toggle: KeyEvent { code: KeyCode::Tab, modifiers: KeyModifiers::empty()},
|
||||
tab_toggle_reverse: KeyEvent { code: KeyCode::BackTab, modifiers: KeyModifiers::SHIFT},
|
||||
toggle_workarea: KeyEvent { code: KeyCode::Char('w'), modifiers: KeyModifiers::empty()},
|
||||
|
@ -41,6 +41,9 @@ pub fn tab_status(key_config: &SharedKeyConfig) -> String {
|
||||
pub fn tab_log(key_config: &SharedKeyConfig) -> String {
|
||||
format!("Log [{}]", key_config.get_hint(key_config.tab_log))
|
||||
}
|
||||
pub fn tab_files(key_config: &SharedKeyConfig) -> String {
|
||||
format!("Files [{}]", key_config.get_hint(key_config.tab_files))
|
||||
}
|
||||
pub fn tab_stashing(key_config: &SharedKeyConfig) -> String {
|
||||
format!(
|
||||
"Stashing [{}]",
|
||||
|
127
src/tabs/files.rs
Normal file
127
src/tabs/files.rs
Normal file
@ -0,0 +1,127 @@
|
||||
#![allow(
|
||||
dead_code,
|
||||
clippy::missing_const_for_fn,
|
||||
clippy::unused_self
|
||||
)]
|
||||
|
||||
use crate::{
|
||||
components::{
|
||||
visibility_blocking, CommandBlocking, CommandInfo, Component,
|
||||
DrawableComponent, EventState, RevisionFilesComponent,
|
||||
},
|
||||
keys::SharedKeyConfig,
|
||||
queue::Queue,
|
||||
ui::style::SharedTheme,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use asyncgit::{sync, AsyncNotification, CWD};
|
||||
use crossbeam_channel::Sender;
|
||||
|
||||
pub struct FilesTab {
|
||||
visible: bool,
|
||||
theme: SharedTheme,
|
||||
queue: Queue,
|
||||
key_config: SharedKeyConfig,
|
||||
files: RevisionFilesComponent,
|
||||
}
|
||||
|
||||
impl FilesTab {
|
||||
///
|
||||
pub fn new(
|
||||
sender: &Sender<AsyncNotification>,
|
||||
queue: &Queue,
|
||||
theme: SharedTheme,
|
||||
key_config: SharedKeyConfig,
|
||||
) -> Self {
|
||||
Self {
|
||||
visible: false,
|
||||
queue: queue.clone(),
|
||||
files: RevisionFilesComponent::new(
|
||||
queue,
|
||||
sender,
|
||||
theme.clone(),
|
||||
key_config.clone(),
|
||||
),
|
||||
theme,
|
||||
key_config,
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
pub fn update(&mut self) -> Result<()> {
|
||||
if self.is_visible() {
|
||||
self.files.set_commit(sync::get_head(CWD)?)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
///
|
||||
pub fn anything_pending(&self) -> bool {
|
||||
self.files.any_work_pending()
|
||||
}
|
||||
|
||||
///
|
||||
pub fn update_git(
|
||||
&mut self,
|
||||
ev: AsyncNotification,
|
||||
) -> Result<()> {
|
||||
if self.is_visible() {
|
||||
self.files.update(ev);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl DrawableComponent for FilesTab {
|
||||
fn draw<B: tui::backend::Backend>(
|
||||
&self,
|
||||
f: &mut tui::Frame<B>,
|
||||
rect: tui::layout::Rect,
|
||||
) -> Result<()> {
|
||||
if self.is_visible() {
|
||||
self.files.draw(f, rect)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for FilesTab {
|
||||
fn commands(
|
||||
&self,
|
||||
out: &mut Vec<CommandInfo>,
|
||||
force_all: bool,
|
||||
) -> CommandBlocking {
|
||||
if self.visible || force_all {
|
||||
return self.files.commands(out, force_all);
|
||||
}
|
||||
|
||||
visibility_blocking(self)
|
||||
}
|
||||
|
||||
fn event(
|
||||
&mut self,
|
||||
ev: crossterm::event::Event,
|
||||
) -> Result<EventState> {
|
||||
if self.visible {
|
||||
return self.files.event(ev);
|
||||
}
|
||||
|
||||
Ok(EventState::NotConsumed)
|
||||
}
|
||||
|
||||
fn is_visible(&self) -> bool {
|
||||
self.visible
|
||||
}
|
||||
|
||||
fn hide(&mut self) {
|
||||
self.visible = false;
|
||||
}
|
||||
|
||||
fn show(&mut self) -> Result<()> {
|
||||
self.visible = true;
|
||||
self.update()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
mod files;
|
||||
mod revlog;
|
||||
mod stashing;
|
||||
mod stashlist;
|
||||
mod status;
|
||||
|
||||
pub use files::FilesTab;
|
||||
pub use revlog::Revlog;
|
||||
pub use stashing::{Stashing, StashingOptions};
|
||||
pub use stashlist::StashList;
|
||||
|
@ -201,7 +201,6 @@ impl Component for StashList {
|
||||
self.drop_stash()
|
||||
} else if k == self.key_config.stash_open {
|
||||
self.inspect()
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,9 @@
|
||||
(
|
||||
tab_status: ( code: Char('1'), modifiers: ( bits: 0,),),
|
||||
tab_log: ( code: Char('2'), modifiers: ( bits: 0,),),
|
||||
tab_stashing: ( code: Char('3'), modifiers: ( bits: 0,),),
|
||||
tab_stashes: ( code: Char('4'), modifiers: ( bits: 0,),),
|
||||
tab_files: ( code: Char('3'), modifiers: ( bits: 0,),),
|
||||
tab_stashing: ( code: Char('4'), modifiers: ( bits: 0,),),
|
||||
tab_stashes: ( code: Char('5'), modifiers: ( bits: 0,),),
|
||||
|
||||
tab_toggle: ( code: Tab, modifiers: ( bits: 0,),),
|
||||
tab_toggle_reverse: ( code: BackTab, modifiers: ( bits: 1,),),
|
||||
|
Loading…
Reference in New Issue
Block a user