Skip to content

Commit

Permalink
feat: status improvements and added rebase status
Browse files Browse the repository at this point in the history
  • Loading branch information
altsem committed Feb 11, 2024
1 parent e740ce7 commit 4545a7d
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 101 deletions.
62 changes: 48 additions & 14 deletions src/git/mod.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,65 @@
use crate::Res;
use std::{
error::Error,
fs,
io::ErrorKind,
path::Path,
process::Command,
str::{self, FromStr},
};

use self::diff::Diff;
use self::{diff::Diff, rebase_status::RebaseStatus};

pub(crate) mod diff;
mod parse;
pub(crate) mod rebase_status;
pub(crate) mod status;

// TODO Check for.git/index.lock and block if it exists
// TODO Use only plumbing commands

pub(crate) fn rebase_status(dir: &Path) -> Res<Option<RebaseStatus>> {
let mut rebase_onto_file = dir.to_path_buf();
rebase_onto_file.push(".git/rebase-merge/onto");

let mut rebase_head_name_file = dir.to_path_buf();
rebase_head_name_file.push(".git/rebase-merge/head-name");

match fs::read_to_string(&rebase_onto_file) {
Ok(content) => {
let onto_hash = content.trim().to_string();
Ok(Some(RebaseStatus {
onto: branch_name(dir, &onto_hash)?.unwrap_or_else(|| onto_hash[..7].to_string()),
head_name: fs::read_to_string(rebase_head_name_file)?
.strip_prefix("refs/heads/")
.unwrap()
.to_string(),
// TODO include log of 'done' items
}))
}
Err(err) => {
if err.kind() == ErrorKind::NotFound {
Ok(None)
} else {
Err(Box::new(err))
}
}
}
}

fn branch_name(dir: &Path, hash: &str) -> Res<Option<String>> {
let out = Command::new("git")
.args(["for-each-ref", "--format", "%(objectname) %(refname:short)"])
.current_dir(dir)
.output()?
.stdout;

Ok(str::from_utf8(&out)?
.lines()
.find(|line| line.starts_with(hash))
.map(|line| line.split(" ").skip(1).next().unwrap().to_string()))
}

pub(crate) fn diff(dir: &Path, args: &[&str]) -> Res<Diff> {
run_git(dir, &["diff"], args)
}
Expand All @@ -31,10 +76,6 @@ pub(crate) fn status(dir: &Path) -> Res<status::Status> {
run_git(dir, &["status", "--porcelain", "--branch"], &[])
}

pub(crate) fn status_simple(dir: &Path) -> Res<String> {
run_git_no_parse(dir, &["-c", "color.status=always", "status"], &[])
}

pub(crate) fn show(dir: &Path, args: &[&str]) -> Res<Diff> {
run_git(dir, &["show"], args)
}
Expand Down Expand Up @@ -64,7 +105,7 @@ pub(crate) fn show_refs(dir: &Path) -> Res<Vec<(String, String, String)>> {
"--sort",
"-creatordate",
"--format",
"%(refname) %(upstream) %(subject)",
"%(refname:short) %(upstream:short) %(subject)",
"refs/heads",
])
.current_dir(dir)
Expand All @@ -79,14 +120,7 @@ pub(crate) fn show_refs(dir: &Path) -> Res<Vec<(String, String, String)>> {
let remote = columns.next().unwrap().to_string();
let subject = columns.next().unwrap().to_string();

(
local.strip_prefix("refs/heads/").unwrap().to_string(),
remote
.strip_prefix("refs/remotes/")
.unwrap_or("")
.to_string(),
subject,
)
(local, remote, subject)
})
.collect())
}
Expand Down
4 changes: 4 additions & 0 deletions src/git/rebase_status.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub(crate) struct RebaseStatus {
pub onto: String,
pub head_name: String,
}
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl State {
Some(cli::Commands::Diff { git_diff_args }) => {
vec![screen::diff::create(&config, size, git_diff_args)?]
}
None => vec![screen::status::create(&config, size, args.status)?],
None => vec![screen::status::create(&config, size)?],
};

Ok(Self {
Expand Down
92 changes: 54 additions & 38 deletions src/screen/status.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
use super::Screen;
use crate::{
git::{self, diff::Diff},
git::{self, diff::Diff, status::BranchStatus},
items::{self, Item},
theme::CURRENT_THEME,
Config, Res,
};
use ansi_to_tui::IntoText;
use ratatui::{
prelude::Rect,
style::{Style, Stylize},
text::Text,
};

pub(crate) fn create(config: &Config, size: Rect, status: bool) -> Res<Screen> {
pub(crate) fn create(config: &Config, size: Rect) -> Res<Screen> {
let config = config.clone();

Screen::new(
size,
Box::new(move || {
let untracked = git::status(&config.dir)?
let status = git::status(&config.dir)?;
let rebase_status = git::rebase_status(&config.dir)?;

let untracked = status
.files
.iter()
.filter(|file| file.is_untracked())
Expand All @@ -33,7 +36,7 @@ pub(crate) fn create(config: &Config, size: Rect, status: bool) -> Res<Screen> {
})
.collect::<Vec<_>>();

let unmerged = git::status(&config.dir)?
let unmerged = status
.files
.iter()
.filter(|file| file.is_unmerged())
Expand All @@ -49,15 +52,25 @@ pub(crate) fn create(config: &Config, size: Rect, status: bool) -> Res<Screen> {
})
.collect::<Vec<_>>();

let items = status
.then_some(Item {
id: "status".into(),
display: git::status_simple(&config.dir)?
.replace("", "")
.into_text()
.expect("Error parsing status ansi"),
unselectable: true,
..Default::default()
let items = rebase_status
.map(|rebase| {
let rebase = rebase;
Item {
id: "rebase_status".into(),
display: Text::raw(format!(
"Rebasing {} onto {}",
rebase.head_name, &rebase.onto
)),
..Default::default()
}
})
.or_else(|| {
Some(Item {
id: "branch_status".into(),
display: format_branch_status(&status.branch_status),
unselectable: true,
..Default::default()
})
})
.into_iter()
.chain(if untracked.is_empty() {
Expand Down Expand Up @@ -125,30 +138,33 @@ pub(crate) fn create(config: &Config, size: Rect, status: bool) -> Res<Screen> {
)
}

// fn format_branch_status(status: &BranchStatus) -> String {
// let Some(ref remote) = status.remote else {
// return format!("On branch {}.", status.local);
// };

// if status.ahead == 0 && status.behind == 0 {
// format!(
// "On branch {}\nYour branch is up to date with '{}'.",
// status.local, remote
// )
// } else if status.ahead > 0 && status.behind == 0 {
// format!(
// "On branch {}\nYour branch is ahead of '{}' by {} commit.",
// status.local, remote, status.ahead
// )
// } else if status.ahead == 0 && status.behind > 0 {
// format!(
// "On branch {}\nYour branch is behind '{}' by {} commit.",
// status.local, remote, status.behind
// )
// } else {
// format!("On branch {}\nYour branch and '{}' have diverged,\nand have {} and {} different commits each, respectively.", status.local, remote, status.ahead, status.behind)
// }
// }
fn format_branch_status(status: &BranchStatus) -> Text<'static> {
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, Some(_)) => unreachable!(),
}
}

fn create_status_section_items<'a>(
header: &str,
Expand Down
10 changes: 5 additions & 5 deletions src/snapshots/gitu__tests__fresh_init.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ expression: "redact_hashes(terminal, dir)"
Buffer {
area: Rect { x: 0, y: 0, width: 60, height: 20 },
content: [
" No branch ",
" ",
"🢒Recent commits ",
" ",
Expand All @@ -24,13 +25,12 @@ Buffer {
" ",
" ",
" ",
" ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 1, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 1, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 15, y: 1, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 2, 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,
]
}
10 changes: 5 additions & 5 deletions src/snapshots/gitu__tests__help_menu.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ expression: "redact_hashes(terminal, dir)"
Buffer {
area: Rect { x: 0, y: 0, width: 60, height: 20 },
content: [
" No branch ",
" ",
"🢒Recent commits ",
" ",
" ",
" ",
" ",
" ",
"────────────────────────────────────────────────────────────",
"Help Submenu ",
"g Refresh h Help ",
Expand All @@ -28,10 +28,10 @@ Buffer {
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 1, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 1, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 15, y: 1, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 2, 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: 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
20 changes: 10 additions & 10 deletions src/snapshots/gitu__tests__new_file.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ expression: "redact_hashes(terminal, dir)"
Buffer {
area: Rect { x: 0, y: 0, width: 60, height: 20 },
content: [
" No branch ",
" ",
"🢒Untracked files ",
" new-file ",
Expand All @@ -24,18 +25,17 @@ Buffer {
" ",
" ",
" ",
" ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 1, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 1, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 16, y: 1, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 2, fg: Reset, bg: Rgb(42, 40, 39), underline: Reset, modifier: NONE,
x: 1, y: 2, fg: Rgb(234, 105, 98), bg: Rgb(42, 40, 39), underline: Reset, modifier: BOLD,
x: 9, y: 2, fg: Reset, bg: Rgb(42, 40, 39), underline: Reset, modifier: NONE,
x: 0, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 4, fg: Rgb(216, 166, 87), bg: Reset, underline: Reset, modifier: BOLD,
x: 15, y: 4, 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: 16, 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: 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,
]
}
38 changes: 19 additions & 19 deletions src/snapshots/gitu__tests__rebase_conflict.snap
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ expression: "redact_hashes(terminal, dir)"
Buffer {
area: Rect { x: 0, y: 0, width: 60, height: 20 },
content: [
" Rebasing other-branch ",
" onto master ",
" ",
"🢒Unmerged ",
" new-file ",
Expand All @@ -23,27 +25,25 @@ Buffer {
" ",
" ",
" ",
" ",
" ",
],
styles: [
x: 0, y: 0, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 1, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 1, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 9, y: 1, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 2, fg: Reset, bg: Rgb(42, 40, 39), underline: Reset, modifier: NONE,
x: 1, y: 2, fg: Rgb(234, 105, 98), bg: Rgb(42, 40, 39), underline: Reset, modifier: BOLD,
x: 9, y: 2, fg: Reset, bg: Rgb(42, 40, 39), underline: Reset, modifier: NONE,
x: 0, y: 3, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 4, fg: Rgb(216, 166, 87), bg: Reset, underline: Reset, modifier: BOLD,
x: 15, y: 4, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 5, fg: Yellow, bg: Reset, underline: Reset, modifier: NONE,
x: 10, y: 5, fg: Cyan, bg: Reset, underline: Reset, modifier: BOLD,
x: 14, y: 5, fg: Yellow, bg: Reset, underline: Reset, modifier: NONE,
x: 16, y: 5, fg: Green, bg: Reset, underline: Reset, modifier: BOLD,
x: 22, y: 5, fg: Yellow, bg: Reset, underline: Reset, modifier: NONE,
x: 23, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 6, fg: Yellow, bg: Reset, underline: Reset, modifier: NONE,
x: 8, y: 6, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 0, y: 3, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 1, y: 3, fg: Rgb(216, 166, 87), bg: Rgb(80, 73, 69), underline: Reset, modifier: BOLD,
x: 9, y: 3, fg: Reset, bg: Rgb(80, 73, 69), underline: Reset, modifier: NONE,
x: 0, y: 4, fg: Reset, bg: Rgb(42, 40, 39), underline: Reset, modifier: NONE,
x: 1, y: 4, fg: Rgb(234, 105, 98), bg: Rgb(42, 40, 39), underline: Reset, modifier: BOLD,
x: 9, y: 4, fg: Reset, bg: Rgb(42, 40, 39), underline: Reset, modifier: NONE,
x: 0, y: 5, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 6, fg: Rgb(216, 166, 87), bg: Reset, underline: Reset, modifier: BOLD,
x: 15, y: 6, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 7, fg: Yellow, bg: Reset, underline: Reset, modifier: NONE,
x: 10, y: 7, fg: Cyan, bg: Reset, underline: Reset, modifier: BOLD,
x: 14, y: 7, fg: Yellow, bg: Reset, underline: Reset, modifier: NONE,
x: 16, y: 7, fg: Green, bg: Reset, underline: Reset, modifier: BOLD,
x: 22, y: 7, fg: Yellow, bg: Reset, underline: Reset, modifier: NONE,
x: 23, y: 7, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
x: 1, y: 8, fg: Yellow, bg: Reset, underline: Reset, modifier: NONE,
x: 8, y: 8, fg: Reset, bg: Reset, underline: Reset, modifier: NONE,
]
}
Loading

0 comments on commit 4545a7d

Please sign in to comment.