From 58ea4b21d175304d9a08d7ba70eb38b16934b7d6 Mon Sep 17 00:00:00 2001 From: Chad Denyar <6653063+cdenyar@users.noreply.github.com> Date: Thu, 13 Apr 2023 15:02:08 -0400 Subject: [PATCH] feat: add typechange to git_status module (#4829) Co-authored-by: David Knaack --- .github/config-schema.json | 5 ++ docs/config/README.md | 2 + src/configs/git_status.rs | 2 + src/modules/git_status.rs | 96 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/.github/config-schema.json b/.github/config-schema.json index 6272d23b73b9..9c572b1d53eb 100644 --- a/.github/config-schema.json +++ b/.github/config-schema.json @@ -617,6 +617,7 @@ "staged": "+", "stashed": "\\$", "style": "red bold", + "typechanged": "", "untracked": "?", "up_to_date": "" }, @@ -3284,6 +3285,10 @@ "default": "?", "type": "string" }, + "typechanged": { + "default": "", + "type": "string" + }, "ignore_submodules": { "default": false, "type": "boolean" diff --git a/docs/config/README.md b/docs/config/README.md index 8ce553d924f0..68829fc10ae2 100644 --- a/docs/config/README.md +++ b/docs/config/README.md @@ -1860,6 +1860,7 @@ You can disable the module or use the `windows_starship` option to use a Windows | `staged` | `'+'` | The format of `staged` | | `renamed` | `'»'` | The format of `renamed` | | `deleted` | `'✘'` | The format of `deleted` | +| `typechanged` | `""` | The format of `typechange` | | `style` | `'bold red'` | The style for the module. | | `ignore_submodules` | `false` | Ignore changes to submodules. | | `disabled` | `false` | Disables the `git_status` module. | @@ -1880,6 +1881,7 @@ The following variables can be used in `format`: | `staged` | Displays `staged` when a new file has been added to the staging area. | | `renamed` | Displays `renamed` when a renamed file has been added to the staging area. | | `deleted` | Displays `deleted` when a file's deletion has been added to the staging area. | +| `typechanged` | Displays `typechange` when a file's type has been changed in the staging area. | | style\* | Mirrors the value of option `style` | *: This variable can only be used as a part of a style string diff --git a/src/configs/git_status.rs b/src/configs/git_status.rs index 6f8345485d54..63016f21746f 100644 --- a/src/configs/git_status.rs +++ b/src/configs/git_status.rs @@ -21,6 +21,7 @@ pub struct GitStatusConfig<'a> { pub modified: &'a str, pub staged: &'a str, pub untracked: &'a str, + pub typechanged: &'a str, pub ignore_submodules: bool, pub disabled: bool, #[serde(skip_serializing_if = "Option::is_none")] @@ -43,6 +44,7 @@ impl<'a> Default for GitStatusConfig<'a> { modified: "!", staged: "+", untracked: "?", + typechanged: "", ignore_submodules: false, disabled: false, windows_starship: None, diff --git a/src/modules/git_status.rs b/src/modules/git_status.rs index 10fb0409dd31..852f175365c3 100644 --- a/src/modules/git_status.rs +++ b/src/modules/git_status.rs @@ -9,7 +9,8 @@ use crate::segment::Segment; use std::ffi::OsStr; use std::sync::Arc; -const ALL_STATUS_FORMAT: &str = "$conflicted$stashed$deleted$renamed$modified$staged$untracked"; +const ALL_STATUS_FORMAT: &str = + "$conflicted$stashed$deleted$renamed$modified$typechanged$staged$untracked"; /// Creates a module with the Git branch in the current directory /// @@ -98,6 +99,9 @@ pub fn module<'a>(context: &'a Context) -> Option> { "untracked" => info.get_untracked().and_then(|count| { format_count(config.untracked, "git_status.untracked", context, count) }), + "typechanged" => info.get_typechanged().and_then(|count| { + format_count(config.typechanged, "git_status.typechanged", context, count) + }), _ => None, }; segments.map(Ok) @@ -188,6 +192,10 @@ impl<'a> GitStatusInfo<'a> { pub fn get_untracked(&self) -> Option { self.get_repo_status().map(|data| data.untracked) } + + pub fn get_typechanged(&self) -> Option { + self.get_repo_status().map(|data| data.typechanged) + } } /// Gets the number of files in various git states (staged, modified, deleted, etc...) @@ -259,6 +267,7 @@ struct RepoStatus { renamed: usize, modified: usize, staged: usize, + typechanged: usize, untracked: usize, } @@ -274,8 +283,14 @@ impl RepoStatus { } fn is_staged(short_status: &str) -> bool { - // is_index_modified || is_index_added - short_status.starts_with('M') || short_status.starts_with('A') + // is_index_modified || is_index_added || is_index_typechanged + short_status.starts_with('M') + || short_status.starts_with('A') + || short_status.starts_with('T') + } + + fn is_typechanged(short_status: &str) -> bool { + short_status.ends_with('T') } fn parse_normal_status(&mut self, short_status: &str) { @@ -290,6 +305,10 @@ impl RepoStatus { if Self::is_staged(short_status) { self.staged += 1; } + + if Self::is_typechanged(short_status) { + self.typechanged += 1; + } } fn add(&mut self, s: &str) { @@ -754,6 +773,25 @@ mod tests { repo_dir.close() } + #[test] + fn shows_typechanged() -> io::Result<()> { + let repo_dir = fixture_repo(FixtureProvider::Git)?; + + create_typechanged(repo_dir.path())?; + + let actual = ModuleRenderer::new("git_status") + .config(toml::toml! { + [git_status] + typechanged = "⇢" + }) + .path(repo_dir.path()) + .collect(); + let expected = format_output("⇢"); + + assert_eq!(expected, actual); + repo_dir.close() + } + #[test] fn shows_modified() -> io::Result<()> { let repo_dir = fixture_repo(FixtureProvider::Git)?; @@ -844,6 +882,32 @@ mod tests { repo_dir.close() } + #[test] + fn shows_staged_typechange_with_count() -> io::Result<()> { + let repo_dir = fixture_repo(FixtureProvider::Git)?; + + create_staged_typechange(repo_dir.path())?; + + let actual = ModuleRenderer::new("git_status") + .config(toml::toml! { + [git_status] + staged = "+[$count](green)" + }) + .path(repo_dir.path()) + .collect(); + let expected = Some(format!( + "{} ", + AnsiStrings(&[ + Color::Red.bold().paint("[+"), + Color::Green.paint("1"), + Color::Red.bold().paint("]"), + ]) + )); + + assert_eq!(expected, actual); + repo_dir.close() + } + #[test] fn shows_staged_and_modified_file() -> io::Result<()> { let repo_dir = fixture_repo(FixtureProvider::Git)?; @@ -1057,6 +1121,32 @@ mod tests { Ok(()) } + fn create_typechanged(repo_dir: &Path) -> io::Result<()> { + fs::remove_file(repo_dir.join("readme.md"))?; + + #[cfg(not(target_os = "windows"))] + std::os::unix::fs::symlink(repo_dir.join("Cargo.toml"), repo_dir.join("readme.md"))?; + + #[cfg(target_os = "windows")] + std::os::windows::fs::symlink_file( + repo_dir.join("Cargo.toml"), + repo_dir.join("readme.md"), + )?; + + Ok(()) + } + + fn create_staged_typechange(repo_dir: &Path) -> io::Result<()> { + create_typechanged(repo_dir)?; + + create_command("git")? + .args(["add", "."]) + .current_dir(repo_dir) + .output()?; + + Ok(()) + } + fn create_conflict(repo_dir: &Path) -> io::Result<()> { create_command("git")? .args(["reset", "--hard", "HEAD^"])