nyi: animated 3d fetch
This commit is contained in:
8 files changed
+5425
No files matched your search
Executable
+4
@@ -0,0 +1,4 @@
|
||||
nyi
|
||||
/target
|
||||
result
|
||||
/dist
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
|
||||
|
||||
[[package]]
|
||||
name = "nyi"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "nyi"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
rust-version = "1.74"
|
||||
description = "Animated 3D fetch with cool features"
|
||||
homepage = "https://github.com/elwrcl/nyi"
|
||||
repository = "https://github.com/elwrcl/nyi"
|
||||
license = "ISC"
|
||||
readme = "README.md"
|
||||
|
||||
[[bin]]
|
||||
name = "nyi"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
strip = true
|
||||
@@ -0,0 +1,15 @@
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2026 elwrcl
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
@@ -0,0 +1,86 @@
|
||||
// very bad pyramid
|
||||
|
||||
use crate::eq_ci;
|
||||
const LOGO_TRIANGLE: &[&str] = &[
|
||||
"\x1b[92m M",
|
||||
"\x1b[92m NNMNN",
|
||||
"\x1b[92m mmNNMNNmm",
|
||||
"\x1b[93m dmmNNMNNmmd",
|
||||
"\x1b[93m hddmmNNMNNmmddh",
|
||||
"\x1b[93m yhhddmmNNMNNmmddhhy",
|
||||
"\x1b[91m yyhhddmmNNMNNmmddhhyy",
|
||||
"\x1b[91m ooyyhhddmmNNMNNmmddhhyyoo",
|
||||
"\x1b[91m sooyyhhddmmNNMNNmmddhhyyoos",
|
||||
"\x1b[31m =ssooyyhhddmmNNMNNmmddhhyyooss=",
|
||||
"\x1b[31m ===ssooyyhhddmmNNMNNmmddhhyyooss===",
|
||||
"\x1b[31m :===ssooyyhhddmmNNMNNmmddhhyyooss===:",
|
||||
"\x1b[95m -::===ssooyyhhddmmNNMNNmmddhhyyooss===::-",
|
||||
"\x1b[95m --::===ssooyyhhddmmNNMNNmmddhhyyooss===::--",
|
||||
"\x1b[95m //--::===ssooyyhhddmmNNMNNmmddhhyyooss===::--//",
|
||||
"\x1b[95m .///--::===ssooyyhhddmmNNMNNmmddhhyyooss===::--///.",
|
||||
"\x1b[94m ..///--::===ssooyyhhddmmNNMNNmmddhhyyooss===::--///..",
|
||||
"\x1b[94m ``..///--::===ssooyyhhddmmNNMNNmmddhhyyooss===::--///..``",
|
||||
"\x1b[94m```..///--::===ssooyyhhddmmNNMNNmmddhhyyooss===::--///..```",
|
||||
];
|
||||
|
||||
pub struct BuiltinLogo {
|
||||
pub names: &'static [&'static str],
|
||||
pub rows: &'static [&'static str],
|
||||
}
|
||||
|
||||
pub const BUILTIN_LOGOS: &[BuiltinLogo] = &[BuiltinLogo {
|
||||
names: &["triangle", "pyramid", "nyi"],
|
||||
rows: LOGO_TRIANGLE,
|
||||
}];
|
||||
|
||||
pub fn builtin_logo(name: &str) -> Option<Vec<String>> {
|
||||
BUILTIN_LOGOS
|
||||
.iter()
|
||||
.find(|l| l.names.iter().any(|n| eq_ci(n, name)))
|
||||
.map(|l| l.rows.iter().map(|s| s.to_string()).collect())
|
||||
}
|
||||
|
||||
pub const DEFAULT_NAME: &str = "triangle";
|
||||
pub fn default_logo() -> Vec<String> {
|
||||
LOGO_TRIANGLE.iter().map(|s| s.to_string()).collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{visible_width, Logo};
|
||||
|
||||
#[test]
|
||||
fn default_logo_is_reachable_by_name() {
|
||||
assert_eq!(builtin_logo(DEFAULT_NAME), Some(default_logo()));
|
||||
assert!(builtin_logo("no-such-thing").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn names_do_not_collide() {
|
||||
let mut seen: Vec<&str> = Vec::new();
|
||||
for l in BUILTIN_LOGOS {
|
||||
for n in l.names {
|
||||
assert!(!seen.contains(n), "{n} is listed twice");
|
||||
seen.push(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pyramid_fits_the_canvas() {
|
||||
let rows = default_logo();
|
||||
assert!(rows.len() >= 8);
|
||||
assert!(rows.iter().all(|r| visible_width(r) <= 60));
|
||||
let widths: Vec<usize> = rows.iter().map(|r| visible_width(r)).collect();
|
||||
assert_eq!(*widths.last().unwrap(), *widths.iter().max().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pyramid_carries_its_own_colors() {
|
||||
let logo = Logo::process(&default_logo());
|
||||
assert!(logo.has_ansi, "the escapes did not survive parsing");
|
||||
let last = logo.rows - 1;
|
||||
assert!(logo.weight_at(last, logo.cols / 2) > logo.weight_at(last, 0));
|
||||
}
|
||||
}
|
||||
+5186
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,93 @@
|
||||
// for mobile eg; termux, i$h, newterm.
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
use crate::{contains_ci, count_file_lines, is_shell_safe, run, strip_eol, uname};
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
use std::fs;
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn is_android() -> bool {
|
||||
static CACHE: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||
*CACHE.get_or_init(|| {
|
||||
cfg!(target_os = "android")
|
||||
|| std::env::var_os("TERMUX_VERSION").is_some()
|
||||
|| fs::metadata("/system/build.prop").is_ok()
|
||||
|| std::env::var("PREFIX").is_ok_and(|p| p.contains("com.termux"))
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn is_ish() -> bool {
|
||||
static CACHE: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
|
||||
*CACHE.get_or_init(|| fs::metadata("/proc/ish").is_ok() || uname().release.contains("ish"))
|
||||
}
|
||||
|
||||
/// android `getprop` is on PATH under termux.
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn getprop(key: &str) -> Option<String> {
|
||||
if !is_shell_safe(key) {
|
||||
return None;
|
||||
}
|
||||
let out = run(&format!("getprop {key} 2>/dev/null"))?;
|
||||
let v = strip_eol(out.split('\n').next()?).trim().to_string();
|
||||
if v.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(v)
|
||||
}
|
||||
}
|
||||
|
||||
/// android has no /etc/os-release; the version lives in the properties.
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn os_name() -> String {
|
||||
match (
|
||||
getprop("ro.build.version.release"),
|
||||
getprop("ro.build.version.sdk"),
|
||||
) {
|
||||
(Some(r), Some(s)) => format!("Android {r} (API {s})"),
|
||||
(Some(r), None) => format!("Android {r}"),
|
||||
_ => "Android".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn host() -> Option<String> {
|
||||
let brand = getprop("ro.product.manufacturer").or_else(|| getprop("ro.product.brand"));
|
||||
let model = getprop("ro.product.model")?;
|
||||
Some(match brand {
|
||||
Some(b) if !contains_ci(&model, &b) => format!("{b} {model}"),
|
||||
_ => model,
|
||||
})
|
||||
}
|
||||
|
||||
/// termux keeps the dpkg database under $PREFIX, not /var/lib.
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn package_count() -> Option<String> {
|
||||
let prefix = std::env::var("PREFIX").ok()?;
|
||||
let n = count_file_lines(&format!("{prefix}/var/lib/dpkg/status"), Some("Package:"));
|
||||
if n > 0 {
|
||||
Some(format!("{n} (dpkg)"))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// walking the process tree finds nothing here termux is an 'seperate' app.
|
||||
pub fn terminal() -> Option<String> {
|
||||
let v = std::env::var("TERMUX_VERSION").ok()?;
|
||||
if v.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(format!("Termux {v}"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn logo_override() -> Option<&'static str> {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
{
|
||||
if is_ish() {
|
||||
return Some("apple");
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
Reference in new issue
Block a user