chore: Initial commit

This commit is contained in:
Ash (ashisbored) 2021-11-21 19:42:14 +00:00
commit c532ebcc71
No known key found for this signature in database
GPG Key ID: 1AE71DC3E127235F
6 changed files with 475 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

265
Cargo.lock generated Normal file
View File

@ -0,0 +1,265 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "autocfg"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cc"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
dependencies = [
"jobserver",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "form_urlencoded"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191"
dependencies = [
"matches",
"percent-encoding",
]
[[package]]
name = "fsh"
version = "0.1.0"
dependencies = [
"ansi_term",
"git2",
"users",
]
[[package]]
name = "git2"
version = "0.13.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "845e007a28f1fcac035715988a234e8ec5458fd825b20a20c7dec74237ef341f"
dependencies = [
"bitflags",
"libc",
"libgit2-sys",
"log",
"openssl-probe",
"openssl-sys",
"url",
]
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "jobserver"
version = "0.1.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa"
dependencies = [
"libc",
]
[[package]]
name = "libc"
version = "0.2.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
[[package]]
name = "libgit2-sys"
version = "0.12.25+1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68169ef08d6519b2fe133ecc637408d933c0174b23b80bb2f79828966fbaab"
dependencies = [
"cc",
"libc",
"libssh2-sys",
"libz-sys",
"openssl-sys",
"pkg-config",
]
[[package]]
name = "libssh2-sys"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca"
dependencies = [
"cc",
"libc",
"libz-sys",
"openssl-sys",
"pkg-config",
"vcpkg",
]
[[package]]
name = "libz-sys"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "log"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
]
[[package]]
name = "matches"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
[[package]]
name = "openssl-probe"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
[[package]]
name = "openssl-sys"
version = "0.9.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7df13d165e607909b363a4757a6f133f8a818a74e9d3a98d09c6128e15fa4c73"
dependencies = [
"autocfg",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pkg-config"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f"
[[package]]
name = "tinyvec"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "unicode-bidi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f"
[[package]]
name = "unicode-normalization"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9"
dependencies = [
"tinyvec",
]
[[package]]
name = "url"
version = "2.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
dependencies = [
"form_urlencoded",
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "users"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032"
dependencies = [
"libc",
"log",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

11
Cargo.toml Normal file
View File

@ -0,0 +1,11 @@
[package]
name = "fsh"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
git2 = "0.13"
users = "0.11"
ansi_term = "0.12"

11
README.md Normal file
View File

@ -0,0 +1,11 @@
What do you call a fish with no eyes?
# fsh
A `fish` theme based on the following:
- [queer/p](https://github.com/queer/p)
- [oh-my-zsh's half-life theme](https://github.com/ohmyzsh/ohmyzsh/blob/master/themes/half-life.zsh-theme)
- [Dracula theme](https://draculatheme.com)
Requires a font with the required icons, I use [Nerd Fonts](https://www.nerdfonts.com/).

13
setup.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
echo Compiling with cargo...
cargo build --release
echo Copying to $HOME/.local/bin
cp target/release/fsh $HOME/.local/bin/
if [ ! -f $HOME/.config/fish/functions/fish_prompt.fish ]; then
echo "Creating $HOME/.config/fish/functions/fish_prompt.fish"
echo "function fish_prompt
set FSH_LAST_STATUS \$status
fsh \$LAST_STATUS
end" > $HOME/.config/fish/functions/fish_prompt.fish
fi

174
src/main.rs Normal file
View File

@ -0,0 +1,174 @@
use ansi_term::{Colour as AnsiColour, Style};
use git2::{Repository, Status as GitStatus};
use std::{fmt::Display, path::PathBuf};
struct PromptComponent {
text: String,
style: Style,
}
enum Colour {
Red,
Green,
Blue,
Yellow,
Pink,
Purple,
}
fn from_hex(hex: u32) -> AnsiColour {
AnsiColour::RGB(
(hex >> 16 & 0xff) as u8,
(hex >> 8 & 0xff) as u8,
(hex >> 0 & 0xff) as u8,
)
}
impl Colour {
fn to_ansi(&self) -> AnsiColour {
match self {
Colour::Red => from_hex(0xff5555),
Colour::Green => from_hex(0x50fa7b),
Colour::Blue => from_hex(0x8be9fd),
Colour::Yellow => from_hex(0xf1fa8c),
Colour::Pink => from_hex(0xff79c6),
Colour::Purple => from_hex(0xbd93f9),
}
}
}
impl PromptComponent {
fn new(text: &str, style: Style) -> Self {
Self {
text: text.to_string(),
style,
}
}
fn bold(text: &str, colour: Colour) -> Self {
Self::new(text, colour.to_ansi().bold())
}
fn unstyled(text: &str) -> Self {
Self {
text: text.to_string(),
style: Style::default(),
}
}
}
impl Display for PromptComponent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{}", self.style.paint(&self.text)))
}
}
fn main() {
let last_status = if let Some(status) = std::env::args().into_iter().skip(1).next() {
status.parse().unwrap()
} else {
0
};
let mut components = Vec::new();
let user = users::get_current_username().map(|s| s.to_string_lossy().into_owned()).unwrap_or_else(|| "unknown".to_string());
components.push(PromptComponent::bold(&user, Colour::Purple));
let home_dir = std::env::var("HOME").unwrap();
let pwd = std::env::current_dir().unwrap();
let dir = if pwd.starts_with(&home_dir) {
let mut buf = PathBuf::new();
buf.push("~");
if pwd != std::path::Path::new(&home_dir) {
let rel_path = pwd.strip_prefix(&home_dir).unwrap();
buf.push(rel_path);
}
format!("{}", buf.to_string_lossy())
} else {
format!("{:?}", pwd.to_string_lossy())
};
let repo = Repository::discover(".").ok();
components.push(PromptComponent::unstyled("in"));
components.push(PromptComponent::bold(&dir, Colour::Green));
get_git_info(&mut components, &repo);
if last_status == 0 {
components.push(PromptComponent::bold("\u{f061}", Colour::Yellow));
} else {
components.push(PromptComponent::bold(&format!("{} \u{f061}", last_status), Colour::Red));
}
for component in components {
print!("{} ", component);
}
}
fn get_git_info(components: &mut Vec<PromptComponent>, repo: &Option<Repository>) {
match repo {
Some(repo) => {
let head = match repo.head() {
Ok(head) => Some(head.shorthand().unwrap().to_string()),
Err(ref e) if e.code() == git2::ErrorCode::NotFound => {
None
}
Err(ref e) if e.code() == git2::ErrorCode::UnbornBranch => {
// https://github.com/starship/starship/commit/489838e6a24ea1c08be6abe56d066724a1d59abd#diff-d6346fd7d17270b1282142aeeda9c4bc2b7d8fd0f37b24a1c871a9257f0ed0aaR324-R336
let mut head_path = repo.path().to_path_buf();
head_path.push("HEAD");
std::fs::read_to_string(&head_path)
.ok().unwrap()
.lines()
.next().unwrap()
.trim()
.split('/')
.last()
.map(|r| r.to_owned())
}
Err(e) => Err(e).unwrap(),
};
let head = head.unwrap_or("(no HEAD)".to_string());
components.push(PromptComponent::bold(&format!("\u{e725} {}", head), Colour::Blue));
let mut unstaged = false;
let mut staged = false;
for status in repo.statuses(None).unwrap().iter() {
let status = status.status();
if status.intersects(GitStatus::WT_DELETED | GitStatus::WT_MODIFIED | GitStatus::WT_NEW | GitStatus::WT_RENAMED | GitStatus::WT_TYPECHANGE) {
unstaged = true;
}
if status.intersects(GitStatus::INDEX_DELETED | GitStatus::INDEX_MODIFIED | GitStatus::INDEX_NEW | GitStatus::INDEX_RENAMED | GitStatus::INDEX_TYPECHANGE) {
staged = true;
}
}
let action = match repo.state() {
git2::RepositoryState::Merge => Some(PromptComponent::bold("merge", Colour::Pink)),
git2::RepositoryState::Revert | git2::RepositoryState::RevertSequence => Some(PromptComponent::bold("revert", Colour::Pink)),
git2::RepositoryState::CherryPick | git2::RepositoryState::CherryPickSequence => Some(PromptComponent::bold("cherry pick", Colour::Pink)),
git2::RepositoryState::Rebase | git2::RepositoryState::RebaseInteractive | git2::RepositoryState::RebaseMerge => Some(PromptComponent::bold("rebase", Colour::Pink)),
_ => None,
};
if let Some(action) = action {
components.push(PromptComponent::unstyled("performing a"));
components.push(action);
}
if staged {
components.push(PromptComponent::bold("+", Colour::Green));
}
if unstaged {
components.push(PromptComponent::bold("", Colour::Red));
}
},
None => { },
}
}