init
This commit is contained in:
parent
7dae789ccc
commit
2d6f4c5c58
|
|
@ -2,6 +2,15 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
|
|
@ -18,6 +27,23 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
|
||||
|
||||
[[package]]
|
||||
name = "fast-git-prompt"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"git2",
|
||||
"regex",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.1"
|
||||
|
|
@ -52,6 +78,12 @@ dependencies = [
|
|||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.32"
|
||||
|
|
@ -113,6 +145,12 @@ version = "0.4.22"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
|
|
@ -144,10 +182,134 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||
|
||||
[[package]]
|
||||
name = "rs-prompt"
|
||||
version = "0.1.0"
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
dependencies = [
|
||||
"git2",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
|
||||
[[package]]
|
||||
name = "schemars"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92"
|
||||
dependencies = [
|
||||
"dyn-clone",
|
||||
"schemars_derive",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schemars_derive"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_derive_internals",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.205"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.205"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive_internals"
|
||||
version = "0.29.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.122"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -171,6 +333,12 @@ version = "0.3.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.23"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
[package]
|
||||
name = "rs-prompt"
|
||||
name = "fast-git-prompt"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
git2 = "0.19.0"
|
||||
serde_json = "1.0.122"
|
||||
serde = { version = "1.0.205", features = ["derive"] }
|
||||
regex = "1.10.6"
|
||||
schemars = "0.8.21"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,139 @@
|
|||
# fast-git-prompt
|
||||
|
||||
A fast git prompt for zsh and bash.
|
||||
|
||||
> This is a work in progress.
|
||||
> More features will be added in the future.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
cargo install fast-git-prompt
|
||||
```
|
||||
|
||||
Make sure you have `$HOME/.cargo/bin` in your `$PATH`.
|
||||
|
||||
## Usage
|
||||
|
||||
Include `fast-git-prompt` in your `.zshrc` or `.bashrc` file as part of your prompt.
|
||||
|
||||
## Configuration
|
||||
|
||||
Create a file called `config.json` in your `$XDG_CONFIG_HOME/fast-git-prompt` or `$HOME/.config/fast-git-prompt` directory.
|
||||
The configuration of the prompt is fully modular and customizable.
|
||||
|
||||
### Example
|
||||
|
||||
````json
|
||||
{
|
||||
"version-do-not-modify": "0.1.0",
|
||||
"schema": "$XDG_CONFIG_HOME/fast-git-prompt/schema.json",
|
||||
"baseColor": "white",
|
||||
"prompt": [
|
||||
// Your prompt parts go here
|
||||
]
|
||||
}
|
||||
|
||||
### Prompt Parts
|
||||
|
||||
#### Branch Name
|
||||
|
||||
The branch name is the name of the current branch.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "branchName",
|
||||
"color": "white" // Optional
|
||||
}
|
||||
````
|
||||
|
||||
#### Origin Icon
|
||||
|
||||
The origin icon is the icon of the current branch's remote.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "originIcon",
|
||||
"icons": {
|
||||
"github.com": {
|
||||
"icon": "",
|
||||
"color": "white"
|
||||
},
|
||||
"gitlab.com": {
|
||||
"icon": "",
|
||||
"color": "brightRed"
|
||||
}
|
||||
},
|
||||
"defaultIcon": {
|
||||
"icon": "",
|
||||
"color": "orange"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Branch Status
|
||||
|
||||
The branch status is the status of the current branch.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "BranchStatus",
|
||||
"dirty": {
|
||||
"color": "red",
|
||||
"icon": "✗"
|
||||
},
|
||||
"clean": {
|
||||
"color": "green",
|
||||
"icon": ""
|
||||
},
|
||||
"deleted": {
|
||||
"color": "red",
|
||||
"icon": ""
|
||||
},
|
||||
"changed": {
|
||||
"color": "yellow",
|
||||
"icon": ""
|
||||
},
|
||||
"new": {
|
||||
"color": "yellow",
|
||||
"icon": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Branch Sync
|
||||
|
||||
The branch sync is the sync status of the current branch.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "BranchSync",
|
||||
"ahead": {
|
||||
"icon": "↑"
|
||||
},
|
||||
"behind": {
|
||||
"icon": "↓"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Colors
|
||||
|
||||
You can currently only use ansi colors. Which will use by your terminal emulator.
|
||||
|
||||
- black
|
||||
- red
|
||||
- green
|
||||
- yellow
|
||||
- blue
|
||||
- magenta
|
||||
- cyan
|
||||
- white
|
||||
- brightBlack
|
||||
- brightRed
|
||||
- brightGreen
|
||||
- brightYellow
|
||||
- brightBlue
|
||||
- brightMagenta
|
||||
- brightCyan
|
||||
- brightWhite
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema, Clone, Copy)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum Color {
|
||||
Black,
|
||||
Red,
|
||||
Green,
|
||||
Yellow,
|
||||
Blue,
|
||||
Magenta,
|
||||
Cyan,
|
||||
White,
|
||||
BrightBlack,
|
||||
BrightRed,
|
||||
BrightGreen,
|
||||
BrightYellow,
|
||||
BrightBlue,
|
||||
BrightMagenta,
|
||||
BrightCyan,
|
||||
BrightWhite,
|
||||
}
|
||||
|
||||
const ESC: &str = "\x1b";
|
||||
|
||||
pub trait Ansi {
|
||||
fn to_ansi_code(&self) -> String;
|
||||
}
|
||||
|
||||
pub fn color(color: Option<Color>) -> String {
|
||||
if let Some(color) = color {
|
||||
return color.to_ansi_code();
|
||||
}
|
||||
return "".to_string();
|
||||
}
|
||||
|
||||
impl Ansi for Color {
|
||||
fn to_ansi_code(&self) -> String {
|
||||
match self {
|
||||
Color::Black => format!("{}[30m", ESC),
|
||||
Color::Red => format!("{}[31m", ESC),
|
||||
Color::Green => format!("{}[32m", ESC),
|
||||
Color::Yellow => format!("{}[33m", ESC),
|
||||
Color::Blue => format!("{}[34m", ESC),
|
||||
Color::Magenta => format!("{}[35m", ESC),
|
||||
Color::Cyan => format!("{}[36m", ESC),
|
||||
Color::White => format!("{}[37m", ESC),
|
||||
Color::BrightBlack => format!("{}[90m", ESC),
|
||||
Color::BrightRed => format!("{}[91m", ESC),
|
||||
Color::BrightGreen => format!("{}[92m", ESC),
|
||||
Color::BrightYellow => format!("{}[93m", ESC),
|
||||
Color::BrightBlue => format!("{}[94m", ESC),
|
||||
Color::BrightMagenta => format!("{}[95m", ESC),
|
||||
Color::BrightCyan => format!("{}[96m", ESC),
|
||||
Color::BrightWhite => format!("{}[97m", ESC),
|
||||
}
|
||||
}
|
||||
}
|
||||
142
src/main.rs
142
src/main.rs
|
|
@ -1,11 +1,143 @@
|
|||
use std::env;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
|
||||
use git2::Repository;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
mod prompt_parts;
|
||||
use crate::prompt_parts::branch_name::BranchName;
|
||||
use crate::prompt_parts::branch_status::BranchStatus;
|
||||
use crate::prompt_parts::branch_sync::BranchSync;
|
||||
use crate::prompt_parts::origin_icon::OriginIcon;
|
||||
use crate::prompt_parts::prompt_part::RenderablePromptPart;
|
||||
mod colors;
|
||||
use crate::colors::{color, Color};
|
||||
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(tag = "type")]
|
||||
enum PromptPart {
|
||||
#[serde(alias = "branchName")]
|
||||
BranchName(BranchName),
|
||||
#[serde(alias = "originIcon")]
|
||||
OriginIcon(OriginIcon),
|
||||
#[serde(alias = "branchStatus")]
|
||||
BranchStatus(BranchStatus),
|
||||
#[serde(alias = "branchSync")]
|
||||
BranchSync(BranchSync),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct Config {
|
||||
#[serde(rename = "$schema")]
|
||||
schema: Option<String>,
|
||||
#[serde(rename = "version-do-not-modify")]
|
||||
version: Option<String>,
|
||||
base_color: Option<Color>,
|
||||
prompt: Vec<PromptPart>,
|
||||
}
|
||||
|
||||
fn get_config_dir() -> String {
|
||||
let config_dir_base = env::var("XDG_CONFIG_HOME").unwrap_or(format!(
|
||||
"{}/.config",
|
||||
match env::var("HOME") {
|
||||
Ok(home) => home,
|
||||
Err(_) => {
|
||||
println!("Could not find HOME env variable");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
));
|
||||
format!("{}/fast-git-prompt", config_dir_base)
|
||||
}
|
||||
|
||||
fn write_schema() {
|
||||
let schema = schemars::schema_for!(Config);
|
||||
let mut file = std::fs::File::create(format!("{}/schema.json", get_config_dir())).unwrap();
|
||||
serde_json::to_writer_pretty(&mut file, &schema).unwrap();
|
||||
}
|
||||
|
||||
fn read_config() -> Config {
|
||||
let json = std::fs::read_to_string(format!("{}/config.json", get_config_dir())).unwrap();
|
||||
serde_json::from_str(&json).unwrap()
|
||||
}
|
||||
|
||||
fn write_config(config: Config) {
|
||||
let mut config_file =
|
||||
std::fs::File::create(format!("{}/config.json", get_config_dir())).unwrap();
|
||||
serde_json::to_writer_pretty(&mut config_file, &config).unwrap()
|
||||
}
|
||||
|
||||
fn setup() {
|
||||
let config_dir = get_config_dir();
|
||||
if !Path::new(&config_dir).exists() {
|
||||
std::fs::create_dir_all(&config_dir).unwrap();
|
||||
write_schema();
|
||||
let config = Config {
|
||||
version: Some(VERSION.to_string()),
|
||||
schema: Some(format!("{}/schema.json", config_dir)),
|
||||
base_color: None,
|
||||
prompt: vec![],
|
||||
};
|
||||
write_config(config);
|
||||
} else {
|
||||
let mut config = read_config();
|
||||
if config.version != Some(VERSION.to_string()) {
|
||||
write_schema();
|
||||
config.version = Some(VERSION.to_string());
|
||||
write_config(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
setup();
|
||||
let mut prompt: Vec<String> = vec![];
|
||||
let config = read_config();
|
||||
|
||||
// let repo = match Repository::open(".") {
|
||||
let repo = match Repository::open(".") {
|
||||
Ok(repo) => repo,
|
||||
Err(e) => panic!("failed to init: {}", e),
|
||||
};
|
||||
let head = repo.head().unwrap();
|
||||
let name = head.name().unwrap();
|
||||
println!("Hello, world! {}", name);
|
||||
Err(_) => {
|
||||
exit(0);
|
||||
}
|
||||
};
|
||||
for part in config.prompt {
|
||||
match part {
|
||||
PromptPart::BranchName(branch_name) => {
|
||||
let branch_name = branch_name.render(&repo);
|
||||
if branch_name.is_some() {
|
||||
prompt.push(branch_name.unwrap());
|
||||
}
|
||||
}
|
||||
PromptPart::OriginIcon(origin_icon) => {
|
||||
let origin_icon = origin_icon.render(&repo);
|
||||
if origin_icon.is_some() {
|
||||
prompt.push(origin_icon.unwrap());
|
||||
}
|
||||
}
|
||||
PromptPart::BranchStatus(branch_status) => {
|
||||
let branch_status = branch_status.render(&repo);
|
||||
if branch_status.is_some() {
|
||||
prompt.push(branch_status.unwrap());
|
||||
}
|
||||
}
|
||||
PromptPart::BranchSync(branch_sync) => {
|
||||
let branch_sync = branch_sync.render(&repo);
|
||||
if branch_sync.is_some() {
|
||||
prompt.push(branch_sync.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
prompt = prompt.drain(..).filter(|s| !s.is_empty()).collect();
|
||||
|
||||
print!(
|
||||
"{}{}",
|
||||
color(config.base_color),
|
||||
prompt.join(format!("{} ", color(config.base_color)).as_str())
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
pub mod branch_name;
|
||||
pub mod branch_status;
|
||||
pub mod branch_sync;
|
||||
pub mod icon;
|
||||
pub mod origin_icon;
|
||||
pub mod prompt_part;
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
use crate::prompt_parts::prompt_part::RenderablePromptPart;
|
||||
use git2::Repository;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct BranchName {
|
||||
pub color: Option<String>,
|
||||
}
|
||||
|
||||
impl RenderablePromptPart for BranchName {
|
||||
fn render(self, repo: &Repository) -> Option<String> {
|
||||
let head = match repo.head() {
|
||||
Ok(r) => Some(r),
|
||||
Err(_) => None,
|
||||
}?;
|
||||
let name = head.name()?;
|
||||
let last = name.split('/').last()?;
|
||||
return Some(format!("{}{}", self.color.unwrap_or("".to_string()), last));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
use crate::prompt_parts::icon::{Icon, RenderableIcon};
|
||||
use crate::prompt_parts::prompt_part::RenderablePromptPart;
|
||||
use git2::{Repository, Status};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct BranchStatus {
|
||||
pub dirty: Icon,
|
||||
pub clean: Icon,
|
||||
pub deleted: Icon,
|
||||
pub changed: Icon,
|
||||
pub new: Icon,
|
||||
}
|
||||
|
||||
impl RenderablePromptPart for BranchStatus {
|
||||
fn render(self, repo: &Repository) -> Option<String> {
|
||||
let state = repo.state();
|
||||
let changes = repo.statuses(None).ok()?;
|
||||
let has_new = changes
|
||||
.iter()
|
||||
.any(|status| status.status() == Status::WT_NEW);
|
||||
let has_changed = changes.iter().any(|status| {
|
||||
status.status() == Status::INDEX_MODIFIED
|
||||
|| status.status() == Status::WT_MODIFIED
|
||||
|| status.status() == Status::INDEX_RENAMED
|
||||
|| status.status() == Status::WT_RENAMED
|
||||
|| status.status() == Status::WT_NEW
|
||||
});
|
||||
let has_deleted = changes.iter().any(|status| {
|
||||
status.status() == Status::INDEX_DELETED || status.status() == Status::WT_DELETED
|
||||
});
|
||||
let is_clean =
|
||||
state == git2::RepositoryState::Clean && !has_changed && !has_deleted && !has_new;
|
||||
|
||||
let mut parts = vec![];
|
||||
if is_clean {
|
||||
parts.push(self.clean.render());
|
||||
} else {
|
||||
parts.push(self.dirty.render());
|
||||
}
|
||||
if has_changed {
|
||||
parts.push(self.changed.render());
|
||||
}
|
||||
if has_new {
|
||||
parts.push(self.new.render());
|
||||
}
|
||||
if has_deleted {
|
||||
parts.push(self.deleted.render());
|
||||
}
|
||||
return Some(parts.join(" "));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
use crate::prompt_parts::icon::{Icon, RenderableIcon};
|
||||
use crate::prompt_parts::prompt_part::RenderablePromptPart;
|
||||
use git2::Repository;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct BranchSync {
|
||||
pub ahead: Icon,
|
||||
pub behind: Icon,
|
||||
}
|
||||
|
||||
impl RenderablePromptPart for BranchSync {
|
||||
fn render(self, repo: &Repository) -> Option<String> {
|
||||
let head = repo.head().ok()?;
|
||||
let head_oid = head.target()?;
|
||||
let remote = repo
|
||||
.find_branch("origin/main", git2::BranchType::Remote)
|
||||
.ok()?;
|
||||
let remote_oid = remote.get().target()?;
|
||||
let (ahead, behind) = repo.graph_ahead_behind(head_oid, remote_oid).ok()?;
|
||||
|
||||
let mut parts = vec![];
|
||||
if ahead > 0 {
|
||||
parts.push(format!("{} {}", self.ahead.render(), ahead));
|
||||
}
|
||||
if behind > 0 {
|
||||
parts.push(format!("{} {}", self.behind.render(), behind));
|
||||
}
|
||||
|
||||
return Some(parts.join(" "));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::colors::{color, Color};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct Icon {
|
||||
pub color: Option<Color>,
|
||||
pub icon: String,
|
||||
}
|
||||
|
||||
pub trait RenderableIcon {
|
||||
fn render(&self) -> String;
|
||||
}
|
||||
|
||||
impl RenderableIcon for Icon {
|
||||
fn render(&self) -> String {
|
||||
return format!("{}{}", color(self.color), self.icon);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::prompt_parts::icon::{Icon, RenderableIcon};
|
||||
use crate::prompt_parts::prompt_part::RenderablePromptPart;
|
||||
use git2::Repository;
|
||||
use regex::Regex;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct OriginIcon {
|
||||
icons: HashMap<String, Icon>,
|
||||
default_icon: Icon,
|
||||
}
|
||||
|
||||
impl RenderablePromptPart for OriginIcon {
|
||||
fn render(self, repo: &Repository) -> Option<String> {
|
||||
let host_regex = Regex::new(r"^(.*@)?(?<host>[^:\/]*)").ok()?;
|
||||
let origin = repo.find_remote("origin").ok()?;
|
||||
let url = origin.url()?;
|
||||
let captures = host_regex.captures(url)?;
|
||||
let host = captures.name("host")?.as_str();
|
||||
let icon = match self.icons.get(host) {
|
||||
Some(i) => i,
|
||||
None => &self.default_icon,
|
||||
};
|
||||
return Some(icon.render());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
use git2::Repository;
|
||||
|
||||
pub trait RenderablePromptPart {
|
||||
fn render(self, repo: &Repository) -> Option<String>;
|
||||
}
|
||||
Loading…
Reference in New Issue