init
This commit is contained in:
parent
7dae789ccc
commit
2d6f4c5c58
|
|
@ -2,6 +2,15 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
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]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
|
|
@ -18,6 +27,23 @@ dependencies = [
|
||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
|
|
@ -52,6 +78,12 @@ dependencies = [
|
||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jobserver"
|
name = "jobserver"
|
||||||
version = "0.1.32"
|
version = "0.1.32"
|
||||||
|
|
@ -113,6 +145,12 @@ version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
|
@ -144,10 +182,134 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rs-prompt"
|
name = "proc-macro2"
|
||||||
version = "0.1.0"
|
version = "1.0.86"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
|
|
@ -171,6 +333,12 @@ version = "0.3.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-normalization"
|
name = "unicode-normalization"
|
||||||
version = "0.1.23"
|
version = "0.1.23"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rs-prompt"
|
name = "fast-git-prompt"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
git2 = "0.19.0"
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
140
src/main.rs
140
src/main.rs
|
|
@ -1,11 +1,143 @@
|
||||||
|
use std::env;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::process::exit;
|
||||||
|
|
||||||
use git2::Repository;
|
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() {
|
fn main() {
|
||||||
|
setup();
|
||||||
|
let mut prompt: Vec<String> = vec![];
|
||||||
|
let config = read_config();
|
||||||
|
|
||||||
|
// let repo = match Repository::open(".") {
|
||||||
let repo = match Repository::open(".") {
|
let repo = match Repository::open(".") {
|
||||||
Ok(repo) => repo,
|
Ok(repo) => repo,
|
||||||
Err(e) => panic!("failed to init: {}", e),
|
Err(_) => {
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let head = repo.head().unwrap();
|
for part in config.prompt {
|
||||||
let name = head.name().unwrap();
|
match part {
|
||||||
println!("Hello, world! {}", name);
|
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