fix(git_status): show working tree status if index status is present (#2973)

This commit is contained in:
Elia Geretto 2021-08-18 19:55:40 +02:00 committed by GitHub
parent 2865f135f0
commit 2e9223dd8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 131 additions and 27 deletions

View File

@ -233,43 +233,48 @@ struct RepoStatus {
}
impl RepoStatus {
fn is_conflicted(status: &str) -> bool {
status.starts_with("u ")
}
fn is_deleted(status: &str) -> bool {
fn is_deleted(short_status: &str) -> bool {
// is_wt_deleted || is_index_deleted
status.starts_with("1 .D") || status.starts_with("1 D")
short_status.contains('D')
}
fn is_renamed(status: &str) -> bool {
// is_wt_renamed || is_index_renamed
// Potentially a copy and not a rename
status.starts_with("2 ")
fn is_modified(short_status: &str) -> bool {
// is_wt_modified || is_wt_added
short_status.ends_with('M') || short_status.ends_with('A')
}
fn is_modified(status: &str) -> bool {
// is_wt_modified
status.starts_with("1 .M") || status.starts_with("1 .A")
fn is_staged(short_status: &str) -> bool {
// is_index_modified || is_index_added
short_status.starts_with('M') || short_status.starts_with('A')
}
fn is_staged(status: &str) -> bool {
// is_index_modified || is_index_new
status.starts_with("1 M") || status.starts_with("1 A")
}
fn parse_normal_status(&mut self, short_status: &str) {
if Self::is_deleted(short_status) {
self.deleted += 1;
}
fn is_untracked(status: &str) -> bool {
// is_wt_new
status.starts_with("? ")
if Self::is_modified(short_status) {
self.modified += 1;
}
if Self::is_staged(short_status) {
self.staged += 1;
}
}
fn add(&mut self, s: &str) {
self.conflicted += Self::is_conflicted(s) as usize;
self.deleted += Self::is_deleted(s) as usize;
self.renamed += Self::is_renamed(s) as usize;
self.modified += Self::is_modified(s) as usize;
self.staged += Self::is_staged(s) as usize;
self.untracked += Self::is_untracked(s) as usize;
match s.chars().next() {
Some('1') => self.parse_normal_status(&s[2..4]),
Some('2') => {
self.renamed += 1;
self.parse_normal_status(&s[2..4])
}
Some('u') => self.conflicted += 1,
Some('?') => self.untracked += 1,
Some('!') => (),
Some(_) => log::error!("Unknown line type in git status output"),
None => log::error!("Missing line type in git status output"),
}
}
fn set_ahead_behind(&mut self, s: &str) {
@ -316,7 +321,7 @@ fn format_symbol(format_str: &str, config_path: &str) -> Option<Vec<Segment>> {
mod tests {
use ansi_term::{ANSIStrings, Color};
use std::fs::{self, File};
use std::io;
use std::io::{self, prelude::*};
use std::path::Path;
use crate::test::{fixture_repo, FixtureProvider, ModuleRenderer};
@ -704,6 +709,21 @@ mod tests {
repo_dir.close()
}
#[test]
fn shows_staged_and_modified_file() -> io::Result<()> {
let repo_dir = fixture_repo(FixtureProvider::Git)?;
create_staged_and_modified(repo_dir.path())?;
let actual = ModuleRenderer::new("git_status")
.path(&repo_dir.path())
.collect();
let expected = format_output("!+");
assert_eq!(expected, actual);
repo_dir.close()
}
#[test]
fn shows_renamed_file() -> io::Result<()> {
let repo_dir = fixture_repo(FixtureProvider::Git)?;
@ -738,6 +758,21 @@ mod tests {
repo_dir.close()
}
#[test]
fn shows_renamed_and_modified_file() -> io::Result<()> {
let repo_dir = fixture_repo(FixtureProvider::Git)?;
create_renamed_and_modified(repo_dir.path())?;
let actual = ModuleRenderer::new("git_status")
.path(&repo_dir.path())
.collect();
let expected = format_output("»!");
assert_eq!(expected, actual);
repo_dir.close()
}
#[test]
fn shows_deleted_file() -> io::Result<()> {
let repo_dir = fixture_repo(FixtureProvider::Git)?;
@ -772,6 +807,21 @@ mod tests {
repo_dir.close()
}
#[test]
fn doesnt_show_ignored_file() -> io::Result<()> {
let repo_dir = fixture_repo(FixtureProvider::Git)?;
create_staged_and_ignored(repo_dir.path())?;
let actual = ModuleRenderer::new("git_status")
.path(&repo_dir.path())
.collect();
let expected = format_output("+");
assert_eq!(expected, actual);
repo_dir.close()
}
#[test]
fn worktree_in_different_dir() -> io::Result<()> {
let worktree_dir = tempfile::tempdir()?;
@ -956,6 +1006,22 @@ mod tests {
Ok(())
}
fn create_staged_and_modified(repo_dir: &Path) -> io::Result<()> {
let mut file = File::create(repo_dir.join("readme.md"))?;
file.sync_all()?;
create_command("git")?
.args(&["add", "."])
.current_dir(repo_dir)
.output()?;
barrier();
writeln!(&mut file, "modified")?;
file.sync_all()?;
Ok(())
}
fn create_renamed(repo_dir: &Path) -> io::Result<()> {
create_command("git")?
.args(&["mv", "readme.md", "readme.md.bak"])
@ -972,9 +1038,47 @@ mod tests {
Ok(())
}
fn create_renamed_and_modified(repo_dir: &Path) -> io::Result<()> {
create_command("git")?
.args(&["mv", "readme.md", "readme.md.bak"])
.current_dir(repo_dir)
.output()?;
barrier();
create_command("git")?
.args(&["add", "-A"])
.current_dir(repo_dir)
.output()?;
barrier();
let mut file = File::create(repo_dir.join("readme.md.bak"))?;
writeln!(&mut file, "modified")?;
file.sync_all()?;
Ok(())
}
fn create_deleted(repo_dir: &Path) -> io::Result<()> {
fs::remove_file(repo_dir.join("readme.md"))?;
Ok(())
}
fn create_staged_and_ignored(repo_dir: &Path) -> io::Result<()> {
let mut file = File::create(repo_dir.join(".gitignore"))?;
writeln!(&mut file, "ignored.txt")?;
file.sync_all()?;
create_command("git")?
.args(&["add", ".gitignore"])
.current_dir(repo_dir)
.output()?;
barrier();
let mut file = File::create(repo_dir.join("ignored.txt"))?;
writeln!(&mut file, "modified")?;
file.sync_all()?;
Ok(())
}
}