use crate::{
accessors,
app::Environment,
components::{
command_pump, event_pump, visibility_blocking,
ChangesComponent, CommandBlocking, CommandInfo, Component,
DiffComponent, DrawableComponent, EventState,
FileTreeItemKind,
},
keys::{key_match, SharedKeyConfig},
options::SharedOptions,
queue::{Action, InternalEvent, NeedsUpdate, Queue, ResetItem},
strings, try_or_popup,
ui::style::Theme,
};
use anyhow::Result;
use asyncgit::{
cached,
sync::{
self, status::StatusType, RepoPath, RepoPathRef, RepoState,
},
sync::{BranchCompare, CommitId},
AsyncDiff, AsyncGitNotification, AsyncStatus, DiffParams,
DiffType, PushType, StatusItem, StatusParams,
};
use crossterm::event::Event;
use itertools::Itertools;
use ratatui::{
layout::{Alignment, Constraint, Direction, Layout},
style::{Color, Style},
widgets::{Block, BorderType, Borders, Paragraph},
};
/// what part of the screen is focused
#[derive(PartialEq)]
enum Focus {
WorkDir,
Diff,
Stage,
}
/// focus can toggle between workdir and stage
impl Focus {
const fn toggled_focus(&self) -> Self {
match self {
Self::WorkDir => Self::Stage,
Self::Stage => Self::WorkDir,
Self::Diff => Self::Diff,
}
}
}
/// which target are we showing a diff against
#[derive(PartialEq, Copy, Clone)]
enum DiffTarget {
Stage,
WorkingDir,
}
pub struct Status {
repo: RepoPathRef,
visible: bool,
focus: Focus,
diff_target: DiffTarget,
index: ChangesComponent,
index_wd: ChangesComponent,
diff: DiffComponent,
git_diff: AsyncDiff,
has_remotes: bool,
git_state: RepoState,
git_status_workdir: AsyncStatus,
git_status_stage: AsyncStatus,
git_branch_state: Option<BranchCompare>,
git_branch_name: cached::BranchName,
queue: Queue,
git_action_executed: bool,
options: SharedOptions,
key_config: SharedKeyConfig,
}
impl DrawableComponent for Status {
fn draw(
&self,
f: &mut ratatui::Frame,
rect: ratatui::layout::Rect,
) -> Result<()> {
let repo_unclean = self.repo_state_unclean();
let rects = if repo_unclean {
Layout::default()
.direction(Direction::Vertical)
.constraints(
[Constraint::Min(1), Constraint::Length(3)]
.as_ref(),
)
.split(rect)
} else {
std::rc::Rc::new([rect])
};
let chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints(
if self.focus == Focus::Diff {
[
Constraint::Percentage(0),
Constraint::Percentage(100),
]
} else {
[
Constraint::Percentage(50),
Constraint::Percentage(50),
]
}
.as_ref(),
)
.split(rects[0]);
let left_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints(
if self.diff_target == DiffTarget::WorkingDir {
[
Constraint::Percentage(60),
Constraint::Percentage(40),
]
} else {
[
Constraint::Percentage(40),
Constraint::Percentage(60),
]
}
.as_ref(),
)
.split(chunks[0]);
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);
if repo_unclean {
self.draw_repo_state(f, rects[1