#![allow(non_camel_case_types)]
#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
use std::sync::atomic::Ordering;
use crate::ported::init::tccolours;
use crate::ported::zsh_h::{color_rgb, hookdef, module};
#[derive(Debug, Clone, Copy, Default)]
pub struct cielab { pub L: f64, pub a: f64, pub b: f64, }
pub type Cielab = Box<cielab>;
pub fn deltae(lab1: &cielab, lab2: &cielab) -> f64 { (lab1.L - lab2.L).powi(2) + (lab1.a - lab2.a).powi(2) + (lab1.b - lab2.b).powi(2) }
pub fn RGBtoLAB(red: i32, green: i32, blue: i32, lab: &mut cielab) { let mut R: f64 = red as f64 / 255.0; let mut G: f64 = green as f64 / 255.0; let mut B: f64 = blue as f64 / 255.0; R = 100.0 * if R > 0.04045 { ((R + 0.055) / 1.055).powf(2.4) } else { R / 12.92 };
G = 100.0 * if G > 0.04045 { ((G + 0.055) / 1.055).powf(2.4) } else { G / 12.92 };
B = 100.0 * if B > 0.04045 { ((B + 0.055) / 1.055).powf(2.4) } else { B / 12.92 };
let mut X: f64 = (R * 0.4124 + G * 0.3576 + B * 0.1805) / 95.047; let mut Y: f64 = (R * 0.2126 + G * 0.7152 + B * 0.0722) / 100.0; let mut Z: f64 = (R * 0.0193 + G * 0.1192 + B * 0.9505) / 108.883;
X = if X > 0.008856 { X.powf(1.0 / 3.0) } else { 7.787 * X + 16.0 / 116.0 };
Y = if Y > 0.008856 { Y.powf(1.0 / 3.0) } else { 7.787 * Y + 16.0 / 116.0 };
Z = if Z > 0.008856 { Z.powf(1.0 / 3.0) } else { 7.787 * Z + 16.0 / 116.0 };
lab.L = 116.0 * Y - 16.0; lab.a = 500.0 * (X - Y); lab.b = 200.0 * (Y - Z); }
pub fn mapRGBto88(red: i32, green: i32, blue: i32) -> i32 { let component: [i32; 11] = [
0, 0x8b, 0xcd, 0xff, 0x2e, 0x5c, 0x8b, 0xa2, 0xb9, 0xd0, 0xe7,
]; let mut orig = cielab::default(); let mut next = cielab::default(); let mut nextl: f64; let mut bestl: f64 = -1.0; let mut r: i32; let mut g: i32; let mut b: i32; let mut comp_r: i32 = 0; let mut comp_g: i32 = 0; let mut comp_b: i32 = 0;
RGBtoLAB(red, green, blue, &mut orig);
r = 0; while r < 11 { g = 0; while g <= 3 { b = 0; while b <= 3 { if r > 3 { g = r; b = r; } RGBtoLAB(component[r as usize], component[g as usize],
component[b as usize],
&mut next);
nextl = deltae(&orig, &next); if nextl < bestl || bestl < 0.0 { bestl = nextl; comp_r = r; comp_g = g; comp_b = b; }
b += 1; }
g += 1; }
r += 1; }
if comp_r > 3 { 77 + comp_r } else {
16 + (comp_r * 16) + (comp_g * 4) + comp_b }
}
pub fn mapRGBto256(red: i32, green: i32, blue: i32) -> i32 { let component: [i32; 30] = [
0, 0x5f, 0x87, 0xaf, 0xd7, 0xff, 0x8, 0x12, 0x1c, 0x26, 0x30, 0x3a, 0x44, 0x4e, 0x58, 0x62, 0x6c, 0x76, 0x80, 0x8a, 0x94, 0x9e, 0xa8, 0xb2, 0xbc, 0xc6, 0xd0, 0xda, 0xe4, 0xee, ];
let mut orig = cielab::default(); let mut next = cielab::default(); let mut nextl: f64; let mut bestl: f64 = -1.0; let mut r: i32; let mut g: i32; let mut b: i32; let mut comp_r: i32 = 0; let mut comp_g: i32 = 0; let mut comp_b: i32 = 0;
RGBtoLAB(red, green, blue, &mut orig);
let len: i32 = component.len() as i32; r = 0; while r < len { g = 0; while g <= 5 { b = 0; while b <= 5 { if r > 5 { g = r; b = r; } RGBtoLAB(component[r as usize], component[g as usize],
component[b as usize],
&mut next);
nextl = deltae(&orig, &next); if nextl < bestl || bestl < 0.0 { bestl = nextl; comp_r = r; comp_g = g; comp_b = b; }
b += 1; }
g += 1; }
r += 1; }
if comp_r > 5 { 226 + comp_r } else {
16 + (comp_r * 36) + (comp_g * 6) + comp_b }
}
#[allow(unused_variables)]
pub fn getnearestcolor(dummy: *const hookdef, col: *const color_rgb) -> i32 { let red: i32;
let green: i32;
let blue: i32;
unsafe {
red = (*col).red as i32;
green = (*col).green as i32;
blue = (*col).blue as i32;
}
if tccolours.load(Ordering::Relaxed) == 256 { return mapRGBto256(red, green, blue) + 1; }
if tccolours.load(Ordering::Relaxed) == 88 { return mapRGBto88(red, green, blue) + 1; }
-1 }
#[allow(unused_variables)]
pub fn setup_(m: *const module) -> i32 { 0 }
pub fn features_(m: *const module, features: &mut Vec<String>) -> i32 { *features = featuresarray(m, module_features());
0 }
pub fn enables_(m: *const module, enables: &mut Option<Vec<i32>>) -> i32 { handlefeatures(m, module_features(), enables) }
#[allow(unused_variables)]
pub fn boot_(m: *const module) -> i32 { addhookfunc("get_color_attr", getnearestcolor); 0 }
pub fn cleanup_(m: *const module) -> i32 { deletehookfunc("get_color_attr", getnearestcolor); setfeatureenables(m, module_features(), None) }
#[allow(unused_variables)]
pub fn finish_(m: *const module) -> i32 { 0 }
fn addhookfunc(n: &str, f: fn(*const hookdef, *const color_rgb) -> i32) -> i32 { let h = gethookdef(n);
if let Some(h) = h { return addhookdeffunc(h, f); }
1 }
fn deletehookfunc(n: &str, f: fn(*const hookdef, *const color_rgb) -> i32) { let h = gethookdef(n); if let Some(h) = h { let _ = deletehookdeffunc(h, f); }
}
fn gethookdef(_n: &str) -> Option<*const hookdef> { None
}
#[allow(unused_variables)]
fn addhookdeffunc(h: *const hookdef,
f: fn(*const hookdef, *const color_rgb) -> i32) -> i32 { 0 }
fn deletehookdeffunc(_h: *const hookdef,
_f: fn(*const hookdef, *const color_rgb) -> i32) -> i32 { 1 }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rgb_to_lab_black_is_zero() {
let mut lab = cielab::default();
RGBtoLAB(0, 0, 0, &mut lab);
assert!(lab.L.abs() < 0.5);
assert!(lab.a.abs() < 0.5);
assert!(lab.b.abs() < 0.5);
}
#[test]
fn deltae_self_is_zero() {
let mut lab = cielab::default();
RGBtoLAB(123, 45, 67, &mut lab);
assert!(deltae(&lab, &lab).abs() < 1e-9);
}
#[test]
fn map_rgb_to_256_white_is_15_or_higher() {
let idx = mapRGBto256(0xff, 0xff, 0xff);
assert!(idx >= 15);
}
#[test]
fn map_rgb_to_88_white_is_in_range() {
let idx = mapRGBto88(0xff, 0xff, 0xff);
assert!((16..=87).contains(&idx) || idx >= 77);
}
#[test]
fn getnearestcolor_dispatches_on_tccolours() {
let saved = tccolours.load(Ordering::SeqCst);
let col = color_rgb { red: 0xff, green: 0xff, blue: 0xff };
tccolours.store(256, Ordering::SeqCst);
let r256 = getnearestcolor(std::ptr::null(), &col);
assert_eq!(r256, mapRGBto256(0xff, 0xff, 0xff) + 1);
tccolours.store(88, Ordering::SeqCst);
let r88 = getnearestcolor(std::ptr::null(), &col);
assert_eq!(r88, mapRGBto88(0xff, 0xff, 0xff) + 1);
tccolours.store(16, Ordering::SeqCst);
assert_eq!(getnearestcolor(std::ptr::null(), &col), -1);
tccolours.store(saved, Ordering::SeqCst);
}
}
use crate::ported::zsh_h::features as features_t;
use std::sync::{Mutex, OnceLock};
static MODULE_FEATURES: OnceLock<Mutex<features_t>> = OnceLock::new();
fn module_features() -> &'static Mutex<features_t> {
MODULE_FEATURES.get_or_init(|| Mutex::new(features_t {
bn_list: None,
bn_size: 0,
cd_list: None,
cd_size: 0,
mf_list: None,
mf_size: 0,
pd_list: None,
pd_size: 0,
n_abstract: 0,
}))
}
fn featuresarray(_m: *const module, _f: &Mutex<features_t>) -> Vec<String> {
vec![]
}
fn handlefeatures(
_m: *const module,
_f: &Mutex<features_t>,
enables: &mut Option<Vec<i32>>,
) -> i32 {
if enables.is_none() {
*enables = Some(vec![1; 0]);
}
0
}
fn setfeatureenables(
_m: *const module,
_f: &Mutex<features_t>,
_e: Option<&[i32]>,
) -> i32 {
0
}