diff --git a/.gitignore b/.gitignore index ea8c4bf..d787b70 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +/result diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..3122490 --- /dev/null +++ b/flake.lock @@ -0,0 +1,123 @@ +{ + "nodes": { + "crane": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": [ + "nixpkgs" + ], + "rust-overlay": "rust-overlay" + }, + "locked": { + "lastModified": 1668993159, + "narHash": "sha256-9BVTtPFrHRh0HbeEm2bmXsoIWRj1tKM6Nvfl7VMK/X8=", + "owner": "ipetkov", + "repo": "crane", + "rev": "c61d98aaea5667607a36bafe5a6fa87fe5bb2c7e", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { + "locked": { + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1669029319, + "narHash": "sha256-EdTqXZ/xBk7xjSCPGNbL0WnoWHEkYjwe78C6gZoUC0E=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "79bb815a1cdc789f6b036d2047e217ab3e989fff", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": [ + "crane", + "flake-utils" + ], + "nixpkgs": [ + "crane", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1667487142, + "narHash": "sha256-bVuzLs1ZVggJAbJmEDVO9G6p8BH3HRaolK70KXvnWnU=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "cf668f737ac986c0a89e83b6b2e3c5ddbd8cf33b", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..2a33488 --- /dev/null +++ b/flake.nix @@ -0,0 +1,79 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + crane.url = "github:ipetkov/crane"; + crane.inputs.nixpkgs.follows = "nixpkgs"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, crane, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + system = system; + }; + inherit (pkgs) lib; + + craneLib = crane.lib.${system}; + + src = craneLib.cleanCargoSource ./.; + + buildInputs = [ + pkgs.pkg-config pkgs.openssl + ] ++ lib.optionals pkgs.stdenv.isDarwin [ + # Additional darwin specific inputs can be set here + pkgs.libiconv + ]; + + cargoArtifacts = craneLib.buildDepsOnly { + inherit src buildInputs; + }; + + # Build the actual crate itself, reusing the dependency + # artifacts from above. + fsh = craneLib.buildPackage { + inherit cargoArtifacts src buildInputs; + }; + in + { + checks = { + # Build the crate as part of `nix flake check` for convenience + inherit fsh; + + # Run clippy (and deny all warnings) on the crate source, + # again, resuing the dependency artifacts from above. + # + # Note that this is done as a separate derivation so that + # we can block the CI if there are issues here, but not + # prevent downstream consumers from building our crate by itself. + fsh-clippy = craneLib.cargoClippy { + inherit cargoArtifacts src buildInputs; + cargoClippyExtraArgs = "--all-targets -- --deny warnings"; + }; + + # Check formatting + fsh-fmt = craneLib.cargoFmt { + inherit src; + }; + }; + + packages.default = fsh; + + apps.default = flake-utils.lib.mkApp { + drv = fsh; + }; + + devShells.default = pkgs.mkShell { + inputsFrom = builtins.attrValues self.checks; + + # Extra inputs can be added here + nativeBuildInputs = with pkgs; [ + cargo + rustc + rustfmt + pkg-config + openssl + ]; + }; + }); +} diff --git a/src/main.rs b/src/main.rs index 42a8be6..5698cfa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ use ansi_term::{Colour as AnsiColour, Style}; +use gethostname::gethostname; use git2::{Repository, Status as GitStatus}; use std::{fmt::Display, path::PathBuf}; -use gethostname::gethostname; struct PromptComponent { text: String, @@ -21,8 +21,8 @@ enum Colour { fn from_hex(hex: u32) -> AnsiColour { AnsiColour::RGB( (hex >> 16 & 0xff) as u8, - (hex >> 8 & 0xff) as u8, - (hex >> 0 & 0xff) as u8, + (hex >> 8 & 0xff) as u8, + (hex & 0xff) as u8, ) } @@ -47,7 +47,7 @@ impl PromptComponent { space_after: true, } } - + fn bold(text: &str, colour: Colour) -> Self { Self::new(text, colour.to_ansi().bold()) } @@ -76,7 +76,7 @@ impl Display for PromptComponent { } fn main() { - let last_status = if let Some(status) = std::env::args().into_iter().skip(1).next() { + let last_status = if let Some(status) = std::env::args().into_iter().nth(1) { status.parse().unwrap() } else { 0 @@ -84,13 +84,17 @@ fn main() { 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()); + let user = users::get_current_username() + .map(|s| s.to_string_lossy().into_owned()) + .unwrap_or_else(|| "unknown".to_string()); if std::env::var("FSH_NO_HOSTNAME").is_ok() { components.push(PromptComponent::bold(&user, Colour::Purple)); } else { components.push(PromptComponent::bold(&user, Colour::Purple).no_space()); components.push(PromptComponent::unstyled("@").no_space()); - let hostname = gethostname().into_string().unwrap_or_else(|e |format!("{:?}", e)); + let hostname = gethostname() + .into_string() + .unwrap_or_else(|e| format!("{:?}", e)); components.push(PromptComponent::bold(&hostname, Colour::Pink)); } @@ -118,7 +122,10 @@ fn main() { if last_status == 0 { components.push(PromptComponent::bold("\u{f061}", Colour::Yellow)); } else { - components.push(PromptComponent::bold(&format!("{} \u{f061}", last_status), Colour::Red)); + components.push(PromptComponent::bold( + &format!("{} \u{f061}", last_status), + Colour::Red, + )); } for component in components { @@ -135,18 +142,18 @@ fn get_git_info(components: &mut Vec, repo: &Option 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::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() + .ok() + .unwrap() .lines() - .next().unwrap() + .next() + .unwrap() .trim() .split('/') .last() @@ -155,27 +162,50 @@ fn get_git_info(components: &mut Vec, repo: &Option Err(e) => Err(e).unwrap(), }; - let head = head.unwrap_or("(no HEAD)".to_string()); + let head = head.unwrap_or_else(|| "(no HEAD)".to_string()); - components.push(PromptComponent::bold(&format!("\u{e725} {}", head), Colour::Blue)); + 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) { + 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) { + 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)), + 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, }; @@ -187,11 +217,11 @@ fn get_git_info(components: &mut Vec, repo: &Option if staged { components.push(PromptComponent::bold("+", Colour::Green)); } - + if unstaged { components.push(PromptComponent::bold("●", Colour::Red)); } - }, - None => { }, + } + None => {} } }