Skip to content

Commit

Permalink
feat: better status
Browse files Browse the repository at this point in the history
  • Loading branch information
altsem committed Feb 11, 2024
1 parent f01bbd3 commit b48b1db
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 170 deletions.
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,8 @@ mod tests {
let (ref mut terminal, ref mut state, dir) = setup(60, 20);
run(&dir, &["git", "init", "--initial-branch", "master"]);
run(&dir, &["touch", "new-file"]);
update(terminal, state, &[key('g'), key('j'), key('s'), key('g')]).unwrap();
run(&dir, &["git", "add", "new-file"]);
update(terminal, state, &[key('g')]).unwrap();
insta::assert_snapshot!(redact_hashes(terminal, dir));
}

Expand Down
231 changes: 122 additions & 109 deletions src/screen/status.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::iter;

use super::Screen;
use crate::{
git::{self, diff::Diff, status::BranchStatus},
Expand All @@ -18,64 +20,81 @@ pub(crate) fn create(config: &Config, size: Rect) -> Res<Screen> {
size,
Box::new(move || {
let status = git::status(&config.dir)?;
let rebase_status = git::rebase_status(&config.dir)?;
let merge_status = git::merge_status(&config.dir)?;
let untracked = untracked(&status);
let unmerged = unmerged(&status);

let items = rebase(rebase_status)
.or_else(|| merge(merge_status))
.or_else(|| branch(status))
let items = if let Some(rebase) = git::rebase_status(&config.dir)? {
vec![Item {
id: "rebase_status".into(),
display: Text::styled(
format!("Rebasing {} onto {}", rebase.head_name, &rebase.onto),
Style::new().fg(CURRENT_THEME.section).bold(),
),
..Default::default()
}]
.into_iter()
} else if let Some(merge) = git::merge_status(&config.dir)? {
vec![Item {
id: "merge_status".into(),
display: Text::styled(
format!("Merging {}", &merge.head),
Style::new().fg(CURRENT_THEME.section).bold(),
),
..Default::default()
}]
.into_iter()
.chain(if untracked.is_empty() {
vec![]
} else {
vec![
blank_line(),
Item {
id: "untracked".into(),
display: Text::styled(
"Untracked files".to_string(),
Style::new().fg(CURRENT_THEME.section).bold(),
),
section: true,
depth: 0,
..Default::default()
},
]
})
.chain(untracked)
.chain(if unmerged.is_empty() {
vec![]
} else {
vec![
blank_line(),
Item {
id: "unmerged".into(),
display: Text::styled(
"Unmerged".to_string(),
Style::new().fg(CURRENT_THEME.section).bold(),
),
section: true,
depth: 0,
..Default::default()
},
]
})
.chain(unmerged)
.chain(create_status_section_items(
"Unstaged changes",
&git::diff_unstaged(&config.dir)?,
))
.chain(create_status_section_items(
"Staged changes",
&git::diff_staged(&config.dir)?,
))
.chain(create_log_section_items(
"Recent commits",
&git::log_recent(&config.dir)?,
))
.collect();
} else {
branch_status_items(&status.branch_status).into_iter()
}
.chain(if untracked.is_empty() {
vec![]
} else {
vec![
blank_line(),
Item {
id: "untracked".into(),
display: Text::styled(
"Untracked files".to_string(),
Style::new().fg(CURRENT_THEME.section).bold(),
),
section: true,
depth: 0,
..Default::default()
},
]
})
.chain(untracked)
.chain(if unmerged.is_empty() {
vec![]
} else {
vec![
blank_line(),
Item {
id: "unmerged".into(),
display: Text::styled(
"Unmerged".to_string(),
Style::new().fg(CURRENT_THEME.section).bold(),
),
section: true,
depth: 0,
..Default::default()
},
]
})
.chain(unmerged)
.chain(create_status_section_items(
"Unstaged changes",
&git::diff_unstaged(&config.dir)?,
))
.chain(create_status_section_items(
"Staged changes",
&git::diff_staged(&config.dir)?,
))
.chain(create_log_section_items(
"Recent commits",
&git::log_recent(&config.dir)?,
))
.collect();

Ok(items)
}),
Expand All @@ -90,38 +109,6 @@ fn blank_line() -> Item {
..Default::default()
}
}

fn rebase(rebase_status: Option<git::rebase_status::RebaseStatus>) -> Option<Item> {
rebase_status.map(|rebase| Item {
id: "rebase_status".into(),
display: Text::styled(
format!("Rebasing {} onto {}", rebase.head_name, &rebase.onto),
Style::new().fg(CURRENT_THEME.section).bold(),
),
..Default::default()
})
}

fn merge(merge_status: Option<git::merge_status::MergeStatus>) -> Option<Item> {
merge_status.map(|merge| Item {
id: "merge_status".into(),
display: Text::styled(
format!("Merging {}", &merge.head),
Style::new().fg(CURRENT_THEME.section).bold(),
),
..Default::default()
})
}

fn branch(status: git::status::Status) -> Option<Item> {
Some(Item {
id: "branch_status".into(),
display: format_branch_status(&status.branch_status),
unselectable: true,
..Default::default()
})
}

fn untracked(status: &git::status::Status) -> Vec<Item> {
status
.files
Expand Down Expand Up @@ -158,34 +145,60 @@ fn unmerged(status: &git::status::Status) -> Vec<Item> {
.collect::<Vec<_>>()
}

fn format_branch_status(status: &BranchStatus) -> Text<'static> {
fn branch_status_items(status: &BranchStatus) -> Vec<Item> {
match (&status.local, &status.remote) {
(None, None) => Text::raw("No branch"),
(Some(local), None) => Text::raw(format!("On branch {}.", local)),
(Some(local), Some(remote)) => {
if status.ahead == 0 && status.behind == 0 {
Text::raw(format!(
"On branch {}\nYour branch is up to date with '{}'.",
local, remote
))
} else if status.ahead > 0 && status.behind == 0 {
Text::raw(format!(
"On branch {}\nYour branch is ahead of '{}' by {} commit.",
local, remote, status.ahead
))
} else if status.ahead == 0 && status.behind > 0 {
Text::raw(format!(
"On branch {}\nYour branch is behind '{}' by {} commit.",
local, remote, status.behind
))
} else {
Text::raw(format!("On branch {}\nYour branch and '{}' have diverged,\nand have {} and {} different commits each, respectively.", local, remote, status.ahead, status.behind))
}
}
(None, None) => vec![Item {
id: "branch_status".into(),
display: Text::styled("No branch", Style::new().fg(CURRENT_THEME.section).bold()),
section: true,
depth: 0,
..Default::default()
}],
(Some(local), maybe_remote) => Vec::from_iter(
iter::once(Item {
id: "branch_status".into(),
display: Text::styled(
format!("On branch {}", local),
Style::new().fg(CURRENT_THEME.section).bold(),
),
section: true,
depth: 0,
..Default::default()
})
.chain(
maybe_remote
.as_ref()
.map(|remote| branch_status_remote_description(status, remote)),
),
),
(None, Some(_)) => unreachable!(),
}
}

fn branch_status_remote_description(status: &BranchStatus, remote: &str) -> Item {
Item {
id: "branch_status".into(),
display: if status.ahead == 0 && status.behind == 0 {
Text::raw(format!("Your branch is up to date with '{}'.", remote))
} else if status.ahead > 0 && status.behind == 0 {
Text::raw(format!(
"Your branch is ahead of '{}' by {} commit.",
remote, status.ahead
))
} else if status.ahead == 0 && status.behind > 0 {
Text::raw(format!(
"Your branch is behind '{}' by {} commit.",
remote, status.behind
))
} else {
Text::raw(format!("Your branch and '{}' have diverged,\nand have {} and {} different commits each, respectively.", remote, status.ahead, status.behind))
},
depth: 1,
unselectable: true,
..Default::default()
}
}

fn create_status_section_items<'a>(
header: &str,
diff: &'a Diff,
Expand Down
17 changes: 9 additions & 8 deletions src/snapshots/gitu__tests__fresh_init.snap
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
source: src/main.rs
source: src/lib.rs
expression: "redact_hashes(terminal, dir)"
---
Buffer {
area: Rect { x: 0, y: 0, width: 60, height: 20 },
content: [
" No branch ",
"🢒No branch ",
" ",
"🢒Recent commits ",
" Recent commits ",
" ",
" ",
" ",
Expand All @@ -27,10 +27,11 @@ Buffer {
" ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 2, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 2, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 15, y: 2, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 0, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 0, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 10, y: 0, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 2, fg: Rgb(216, 166, 87), bg: Reset, underline: Reset, modifier: BOLD,
x: 15, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}
17 changes: 9 additions & 8 deletions src/snapshots/gitu__tests__help_menu.snap
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
---
source: src/main.rs
source: src/lib.rs
expression: "redact_hashes(terminal, dir)"
---
Buffer {
area: Rect { x: 0, y: 0, width: 60, height: 20 },
content: [
" No branch ",
"🢒No branch ",
" ",
"🢒Recent commits ",
" Recent commits ",
" ",
" ",
" ",
Expand All @@ -27,11 +27,12 @@ Buffer {
"y ShowRefs ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 2, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 2, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 15, y: 2, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 0, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 0, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 10, y: 0, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 2, fg: Rgb(216, 166, 87), bg: Reset, underline: Reset, modifier: BOLD,
x: 15, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 7, fg: Rgb(80, 73, 69), bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 8, fg: Rgb(125, 174, 163), bg: Reset, underline: Reset, modifier: BOLD,
x: 4, y: 8, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
Expand Down
22 changes: 10 additions & 12 deletions src/snapshots/gitu__tests__merge_conflict.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ expression: "redact_hashes(terminal, dir)"
Buffer {
area: Rect { x: 0, y: 0, width: 60, height: 20 },
content: [
" Merging other-branch ",
"🢒Merging other-branch ",
" ",
"🢒Unmerged ",
" Unmerged ",
" new-file ",
" ",
" Recent commits ",
Expand All @@ -27,16 +27,14 @@ Buffer {
" ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 0, fg: Rgb(216, 166, 87), bg: Reset, underline: Reset, modifier: BOLD,
x: 21, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 2, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 2, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 9, y: 2, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 3, fg: Reset, bg: Rgb(42, 40, 39), underline: Reset, modifier: NONE,
x: 1, y: 3, fg: Rgb(234, 105, 98), bg: Rgb(42, 40, 39), underline: Reset, modifier: BOLD,
x: 9, y: 3, fg: Reset, bg: Rgb(42, 40, 39), underline: Reset, modifier: NONE,
x: 0, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 0, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 0, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 21, y: 0, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 1, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 2, fg: Rgb(216, 166, 87), bg: Reset, underline: Reset, modifier: BOLD,
x: 9, y: 2, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 3, fg: Rgb(234, 105, 98), bg: Reset, underline: Reset, modifier: BOLD,
x: 9, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 5, fg: Rgb(216, 166, 87), bg: Reset, underline: Reset, modifier: BOLD,
x: 15, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 6, fg: Yellow, bg: Reset, underline: Reset, modifier: NONE,
Expand Down
Loading

0 comments on commit b48b1db

Please sign in to comment.