config.rs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. use crate::theme::ThemeFileType as FileType;
  2. use crate::theme::*;
  3. use nu_ansi_term::{Color, Style};
  4. use serde::{Deserialize, Deserializer, Serialize};
  5. use serde_yaml;
  6. use std::collections::HashMap;
  7. use std::path::PathBuf;
  8. #[derive(Debug, Default, Eq, PartialEq)]
  9. pub struct ThemeConfig {
  10. // This is rather bare for now, will be expanded with config file
  11. location: ConfigLoc,
  12. }
  13. #[derive(Debug, Default, PartialEq, Eq)]
  14. pub enum ConfigLoc {
  15. #[default]
  16. Default, // $XDG_CONFIG_HOME/eza/config|theme.yml
  17. Env(PathBuf), // $EZA_CONFIG_DIR
  18. }
  19. trait FromOverride<T>: Sized {
  20. fn from(value: T, default: Self) -> Self;
  21. }
  22. impl<S, T> FromOverride<Option<S>> for Option<T>
  23. where
  24. T: FromOverride<S> + Default,
  25. {
  26. fn from(value: Option<S>, default: Option<T>) -> Option<T> {
  27. match (value, default) {
  28. (Some(value), Some(default)) => Some(FromOverride::from(value, default)),
  29. (Some(value), None) => Some(FromOverride::from(value, T::default())),
  30. (None, Some(default)) => Some(default),
  31. (None, None) => None,
  32. }
  33. }
  34. }
  35. #[rustfmt::skip]
  36. fn color_from_str(s: &str) -> Option<Color> {
  37. use Color::*;
  38. match s {
  39. // nothing
  40. "" | "none" | "None" => None,
  41. // hardcoded colors
  42. "default" | "Default" => Some(Default),
  43. "black" | "Black" => Some(Black),
  44. "darkgray" | "DarkGray" => Some(DarkGray),
  45. "red" | "Red" => Some(Red),
  46. "lightred" | "LightRed" => Some(LightRed),
  47. "green" | "Green" => Some(Green),
  48. "lightgreen" | "LightGreen" => Some(LightGreen),
  49. "yellow" | "Yellow" => Some(Yellow),
  50. "lightyellow" | "LightYellow" => Some(LightYellow),
  51. "blue" | "Blue" => Some(Blue),
  52. "lightblue" | "LightBlue" => Some(LightBlue),
  53. "purple" | "Purple" => Some(Purple),
  54. "lightpurple" | "LightPurple" => Some(LightPurple),
  55. "magenta" | "Magenta" => Some(Magenta),
  56. "lightmagenta" | "LightMagenta" => Some(LightMagenta),
  57. "cyan" | "Cyan" => Some(Cyan),
  58. "lightcyan" | "LightCyan" => Some(LightCyan),
  59. "white" | "White" => Some(White),
  60. "lightgray" | "LightGray" => Some(LightGray),
  61. // some other string
  62. s => match s.chars().collect::<Vec<_>>()[..] {
  63. // #rrggbb hex color
  64. ['#', r1, r2, g1, g2, b1, b2] => {
  65. let Ok(r) = u8::from_str_radix(&format!("{}{}", r1, r2), 16)
  66. else { return None };
  67. let Ok(g) = u8::from_str_radix(&format!("{}{}", g1, g2), 16)
  68. else { return None };
  69. let Ok(b) = u8::from_str_radix(&format!("{}{}", b1, b2), 16)
  70. else { return None };
  71. Some(Rgb(r, g, b))
  72. },
  73. // #rgb shorthand hex color
  74. ['#', r, g, b] => {
  75. let Ok(r) = u8::from_str_radix(&format!("{}{}", r, r), 16)
  76. else { return None };
  77. let Ok(g) = u8::from_str_radix(&format!("{}{}", g, g), 16)
  78. else { return None };
  79. let Ok(b) = u8::from_str_radix(&format!("{}{}", b, b), 16)
  80. else { return None };
  81. Some(Rgb(r, g, b))
  82. },
  83. // 0-255 color code
  84. [c1, c2] => {
  85. let Ok(c) = u8::from_str_radix(&format!("{}{}", c1, c2), 10)
  86. else { return None };
  87. Some(Fixed(c))
  88. },
  89. // unknown format
  90. _ => None,
  91. }
  92. }
  93. }
  94. #[rustfmt::skip]
  95. fn deserialize_color<'de, D>(deserializer: D) -> Result<Option<Color>, D::Error>
  96. where D: Deserializer<'de> {
  97. Ok(color_from_str(&String::deserialize(deserializer)?))
  98. }
  99. #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Default)]
  100. pub struct StyleOverride {
  101. /// The style's foreground color, if it has one.
  102. #[serde(alias = "fg", deserialize_with = "deserialize_color", default)]
  103. pub foreground: Option<Color>,
  104. /// The style's background color, if it has one.
  105. #[serde(alias = "bg", deserialize_with = "deserialize_color", default)]
  106. pub background: Option<Color>,
  107. /// Whether this style is bold.
  108. #[serde(alias = "bold")]
  109. pub is_bold: Option<bool>,
  110. /// Whether this style is dimmed.
  111. #[serde(alias = "dimmed")]
  112. pub is_dimmed: Option<bool>,
  113. /// Whether this style is italic.
  114. #[serde(alias = "italic")]
  115. pub is_italic: Option<bool>,
  116. /// Whether this style is underlined.
  117. #[serde(alias = "underline")]
  118. pub is_underline: Option<bool>,
  119. /// Whether this style is blinking.
  120. #[serde(alias = "blink")]
  121. pub is_blink: Option<bool>,
  122. /// Whether this style has reverse colors.
  123. #[serde(alias = "reverse")]
  124. pub is_reverse: Option<bool>,
  125. /// Whether this style is hidden.
  126. #[serde(alias = "hidden")]
  127. pub is_hidden: Option<bool>,
  128. /// Whether this style is struckthrough.
  129. #[serde(alias = "strikethrough")]
  130. pub is_strikethrough: Option<bool>,
  131. /// Wether this style is always displayed starting with a reset code to clear any remaining style artifacts
  132. #[serde(alias = "prefix_reset")]
  133. pub prefix_with_reset: Option<bool>,
  134. }
  135. impl FromOverride<StyleOverride> for Style {
  136. fn from(value: StyleOverride, default: Self) -> Self {
  137. let mut style = default;
  138. if value.foreground.is_some() {
  139. style.foreground = value.foreground;
  140. }
  141. if value.background.is_some() {
  142. style.background = value.background;
  143. }
  144. if let Some(bold) = value.is_bold {
  145. style.is_bold = bold;
  146. }
  147. if let Some(dimmed) = value.is_dimmed {
  148. style.is_dimmed = dimmed;
  149. }
  150. if let Some(italic) = value.is_italic {
  151. style.is_italic = italic;
  152. }
  153. if let Some(underline) = value.is_underline {
  154. style.is_underline = underline;
  155. }
  156. if let Some(blink) = value.is_blink {
  157. style.is_blink = blink;
  158. }
  159. if let Some(reverse) = value.is_reverse {
  160. style.is_reverse = reverse;
  161. }
  162. if let Some(hidden) = value.is_hidden {
  163. style.is_hidden = hidden;
  164. }
  165. if let Some(strikethrough) = value.is_strikethrough {
  166. style.is_strikethrough = strikethrough;
  167. }
  168. if let Some(reset) = value.prefix_with_reset {
  169. style.prefix_with_reset = reset;
  170. }
  171. style
  172. }
  173. }
  174. #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
  175. pub struct IconStyleOverride {
  176. pub glyph: Option<char>,
  177. pub style: Option<StyleOverride>,
  178. }
  179. impl FromOverride<char> for char {
  180. fn from(value: char, _default: char) -> char {
  181. value
  182. }
  183. }
  184. impl FromOverride<IconStyleOverride> for IconStyle {
  185. fn from(value: IconStyleOverride, default: Self) -> Self {
  186. IconStyle {
  187. glyph: FromOverride::from(value.glyph, default.glyph),
  188. style: FromOverride::from(value.style, default.style),
  189. }
  190. }
  191. }
  192. #[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)]
  193. pub struct FileNameStyleOverride {
  194. pub icon: Option<IconStyleOverride>,
  195. pub filename: Option<StyleOverride>,
  196. }
  197. impl FromOverride<FileNameStyleOverride> for FileNameStyle {
  198. fn from(value: FileNameStyleOverride, default: Self) -> Self {
  199. FileNameStyle {
  200. icon: FromOverride::from(value.icon, default.icon),
  201. filename: FromOverride::from(value.filename, default.filename),
  202. }
  203. }
  204. }
  205. impl<R, S, T> FromOverride<HashMap<R, S>> for HashMap<R, T>
  206. where
  207. T: FromOverride<S>,
  208. R: Clone + Eq + std::hash::Hash,
  209. T: Clone + Eq + Default,
  210. {
  211. fn from(value: HashMap<R, S>, default: HashMap<R, T>) -> HashMap<R, T> {
  212. let mut result = default.clone();
  213. for (r, s) in value {
  214. let t = match default.get(&r) {
  215. Some(t) => t.clone(),
  216. None => T::default(),
  217. };
  218. result.insert(r, FromOverride::from(s, t));
  219. }
  220. result
  221. }
  222. }
  223. #[rustfmt::skip]
  224. #[derive(Clone, Eq, Copy, Debug, PartialEq, Serialize, Deserialize)]
  225. pub struct FileKindsOverride {
  226. pub normal: Option<StyleOverride>, // fi
  227. pub directory: Option<StyleOverride>, // di
  228. pub symlink: Option<StyleOverride>, // ln
  229. pub pipe: Option<StyleOverride>, // pi
  230. pub block_device: Option<StyleOverride>, // bd
  231. pub char_device: Option<StyleOverride>, // cd
  232. pub socket: Option<StyleOverride>, // so
  233. pub special: Option<StyleOverride>, // sp
  234. pub executable: Option<StyleOverride>, // ex
  235. pub mount_point: Option<StyleOverride>, // mp
  236. }
  237. impl FromOverride<FileKindsOverride> for FileKinds {
  238. fn from(value: FileKindsOverride, default: Self) -> Self {
  239. FileKinds {
  240. normal: FromOverride::from(value.normal, default.normal),
  241. directory: FromOverride::from(value.directory, default.directory),
  242. symlink: FromOverride::from(value.symlink, default.symlink),
  243. pipe: FromOverride::from(value.pipe, default.pipe),
  244. block_device: FromOverride::from(value.block_device, default.block_device),
  245. char_device: FromOverride::from(value.char_device, default.char_device),
  246. socket: FromOverride::from(value.socket, default.socket),
  247. special: FromOverride::from(value.special, default.special),
  248. executable: FromOverride::from(value.executable, default.executable),
  249. mount_point: FromOverride::from(value.mount_point, default.mount_point),
  250. }
  251. }
  252. }
  253. #[rustfmt::skip]
  254. #[derive(Clone, Copy,Eq, Debug, Default, PartialEq, Serialize, Deserialize)]
  255. pub struct PermissionsOverride {
  256. pub user_read: Option<StyleOverride>, // ur
  257. pub user_write: Option<StyleOverride>, // uw
  258. pub user_execute_file: Option<StyleOverride>, // ux
  259. pub user_execute_other: Option<StyleOverride>, // ue
  260. pub group_read: Option<StyleOverride>, // gr
  261. pub group_write: Option<StyleOverride>, // gw
  262. pub group_execute: Option<StyleOverride>, // gx
  263. pub other_read: Option<StyleOverride>, // tr
  264. pub other_write: Option<StyleOverride>, // tw
  265. pub other_execute: Option<StyleOverride>, // tx
  266. pub special_user_file: Option<StyleOverride>, // su
  267. pub special_other: Option<StyleOverride>, // sf
  268. pub attribute: Option<StyleOverride>, // xa
  269. }
  270. impl FromOverride<PermissionsOverride> for Permissions {
  271. fn from(value: PermissionsOverride, default: Self) -> Self {
  272. Permissions {
  273. user_read: FromOverride::from(value.user_read, default.user_read),
  274. user_write: FromOverride::from(value.user_write, default.user_write),
  275. user_execute_file: FromOverride::from(
  276. value.user_execute_file,
  277. default.user_execute_file,
  278. ),
  279. user_execute_other: FromOverride::from(
  280. value.user_execute_other,
  281. default.user_execute_other,
  282. ),
  283. group_read: FromOverride::from(value.group_read, default.group_read),
  284. group_write: FromOverride::from(value.group_write, default.group_write),
  285. group_execute: FromOverride::from(value.group_execute, default.group_execute),
  286. other_read: FromOverride::from(value.other_read, default.other_read),
  287. other_write: FromOverride::from(value.other_write, default.other_write),
  288. other_execute: FromOverride::from(value.other_execute, default.other_execute),
  289. special_user_file: FromOverride::from(
  290. value.special_user_file,
  291. default.special_user_file,
  292. ),
  293. special_other: FromOverride::from(value.special_other, default.special_other),
  294. attribute: FromOverride::from(value.attribute, default.attribute),
  295. }
  296. }
  297. }
  298. #[rustfmt::skip]
  299. #[derive(Clone, Copy, Eq, Debug, Default, PartialEq, Serialize, Deserialize)]
  300. pub struct SizeOverride {
  301. pub major: Option<StyleOverride>, // df
  302. pub minor: Option<StyleOverride>, // ds
  303. pub number_byte: Option<StyleOverride>, // sn nb
  304. pub number_kilo: Option<StyleOverride>, // sn nk
  305. pub number_mega: Option<StyleOverride>, // sn nm
  306. pub number_giga: Option<StyleOverride>, // sn ng
  307. pub number_huge: Option<StyleOverride>, // sn nt
  308. pub unit_byte: Option<StyleOverride>, // sb ub
  309. pub unit_kilo: Option<StyleOverride>, // sb uk
  310. pub unit_mega: Option<StyleOverride>, // sb um
  311. pub unit_giga: Option<StyleOverride>, // sb ug
  312. pub unit_huge: Option<StyleOverride>, // sb ut
  313. }
  314. impl FromOverride<SizeOverride> for Size {
  315. fn from(value: SizeOverride, default: Self) -> Self {
  316. Size {
  317. major: FromOverride::from(value.major, default.major),
  318. minor: FromOverride::from(value.minor, default.minor),
  319. number_byte: FromOverride::from(value.number_byte, default.number_byte),
  320. number_kilo: FromOverride::from(value.number_kilo, default.number_kilo),
  321. number_mega: FromOverride::from(value.number_mega, default.number_mega),
  322. number_giga: FromOverride::from(value.number_giga, default.number_giga),
  323. number_huge: FromOverride::from(value.number_huge, default.number_huge),
  324. unit_byte: FromOverride::from(value.unit_byte, default.unit_byte),
  325. unit_kilo: FromOverride::from(value.unit_kilo, default.unit_kilo),
  326. unit_mega: FromOverride::from(value.unit_mega, default.unit_mega),
  327. unit_giga: FromOverride::from(value.unit_giga, default.unit_giga),
  328. unit_huge: FromOverride::from(value.unit_huge, default.unit_huge),
  329. }
  330. }
  331. }
  332. #[rustfmt::skip]
  333. #[derive(Clone, Copy, Debug,Eq, Default, PartialEq, Serialize, Deserialize)]
  334. pub struct UsersOverride {
  335. pub user_you: Option<StyleOverride>, // uu
  336. pub user_root: Option<StyleOverride>, // uR
  337. pub user_other: Option<StyleOverride>, // un
  338. pub group_yours: Option<StyleOverride>, // gu
  339. pub group_other: Option<StyleOverride>, // gn
  340. pub group_root: Option<StyleOverride>, // gR
  341. }
  342. impl FromOverride<UsersOverride> for Users {
  343. fn from(value: UsersOverride, default: Self) -> Self {
  344. Users {
  345. user_you: FromOverride::from(value.user_you, default.user_you),
  346. user_root: FromOverride::from(value.user_root, default.user_root),
  347. user_other: FromOverride::from(value.user_other, default.user_other),
  348. group_yours: FromOverride::from(value.group_yours, default.group_yours),
  349. group_other: FromOverride::from(value.group_other, default.group_other),
  350. group_root: FromOverride::from(value.group_root, default.group_root),
  351. }
  352. }
  353. }
  354. #[rustfmt::skip]
  355. #[derive(Clone, Copy, Debug, Eq, Default, PartialEq, Serialize, Deserialize)]
  356. pub struct LinksOverride {
  357. pub normal: Option<StyleOverride>, // lc
  358. pub multi_link_file: Option<StyleOverride>, // lm
  359. }
  360. impl FromOverride<LinksOverride> for Links {
  361. fn from(value: LinksOverride, default: Self) -> Self {
  362. Links {
  363. normal: FromOverride::from(value.normal, default.normal),
  364. multi_link_file: FromOverride::from(value.multi_link_file, default.multi_link_file),
  365. }
  366. }
  367. }
  368. #[rustfmt::skip]
  369. #[derive(Clone, Copy, Debug,Eq, PartialEq, Serialize, Deserialize)]
  370. pub struct GitOverride {
  371. pub new: Option<StyleOverride>, // ga
  372. pub modified: Option<StyleOverride>, // gm
  373. pub deleted: Option<StyleOverride>, // gd
  374. pub renamed: Option<StyleOverride>, // gv
  375. pub typechange: Option<StyleOverride>, // gt
  376. pub ignored: Option<StyleOverride>, // gi
  377. pub conflicted: Option<StyleOverride>, // gc
  378. }
  379. impl FromOverride<GitOverride> for Git {
  380. fn from(value: GitOverride, default: Self) -> Self {
  381. Git {
  382. new: FromOverride::from(value.new, default.new),
  383. modified: FromOverride::from(value.modified, default.modified),
  384. deleted: FromOverride::from(value.deleted, default.deleted),
  385. renamed: FromOverride::from(value.renamed, default.renamed),
  386. typechange: FromOverride::from(value.typechange, default.typechange),
  387. ignored: FromOverride::from(value.ignored, default.ignored),
  388. conflicted: FromOverride::from(value.conflicted, default.conflicted),
  389. }
  390. }
  391. }
  392. #[rustfmt::skip]
  393. #[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
  394. pub struct GitRepoOverride {
  395. pub branch_main: Option<StyleOverride>, //Gm
  396. pub branch_other: Option<StyleOverride>, //Go
  397. pub git_clean: Option<StyleOverride>, //Gc
  398. pub git_dirty: Option<StyleOverride>, //Gd
  399. }
  400. impl FromOverride<GitRepoOverride> for GitRepo {
  401. fn from(value: GitRepoOverride, default: Self) -> Self {
  402. GitRepo {
  403. branch_main: FromOverride::from(value.branch_main, default.branch_main),
  404. branch_other: FromOverride::from(value.branch_other, default.branch_other),
  405. git_clean: FromOverride::from(value.git_clean, default.git_clean),
  406. git_dirty: FromOverride::from(value.git_dirty, default.git_dirty),
  407. }
  408. }
  409. }
  410. #[derive(Clone, Copy, Debug, Eq, Default, PartialEq, Serialize, Deserialize)]
  411. pub struct SELinuxContextOverride {
  412. pub colon: Option<StyleOverride>,
  413. pub user: Option<StyleOverride>, // Su
  414. pub role: Option<StyleOverride>, // Sr
  415. pub typ: Option<StyleOverride>, // St
  416. pub range: Option<StyleOverride>, // Sl
  417. }
  418. impl FromOverride<SELinuxContextOverride> for SELinuxContext {
  419. fn from(value: SELinuxContextOverride, default: Self) -> Self {
  420. SELinuxContext {
  421. colon: FromOverride::from(value.colon, default.colon),
  422. user: FromOverride::from(value.user, default.user),
  423. role: FromOverride::from(value.role, default.role),
  424. typ: FromOverride::from(value.typ, default.typ),
  425. range: FromOverride::from(value.range, default.range),
  426. }
  427. }
  428. }
  429. #[rustfmt::skip]
  430. #[derive(Clone, Eq, Copy, Debug, PartialEq, Serialize, Deserialize)]
  431. pub struct SecurityContextOverride {
  432. pub none: Option<StyleOverride>, // Sn
  433. pub selinux: Option<SELinuxContextOverride>,
  434. }
  435. impl FromOverride<SecurityContextOverride> for SecurityContext {
  436. fn from(value: SecurityContextOverride, default: Self) -> Self {
  437. SecurityContext {
  438. none: FromOverride::from(value.none, default.none),
  439. selinux: FromOverride::from(value.selinux, default.selinux),
  440. }
  441. }
  442. }
  443. #[rustfmt::skip]
  444. #[derive(Clone, Copy, Debug, Eq, Default, PartialEq, Serialize, Deserialize)]
  445. pub struct FileTypeOverride {
  446. pub image: Option<StyleOverride>, // im - image file
  447. pub video: Option<StyleOverride>, // vi - video file
  448. pub music: Option<StyleOverride>, // mu - lossy music
  449. pub lossless: Option<StyleOverride>, // lo - lossless music
  450. pub crypto: Option<StyleOverride>, // cr - related to cryptography
  451. pub document: Option<StyleOverride>, // do - document file
  452. pub compressed: Option<StyleOverride>, // co - compressed file
  453. pub temp: Option<StyleOverride>, // tm - temporary file
  454. pub compiled: Option<StyleOverride>, // cm - compilation artifact
  455. pub build: Option<StyleOverride>, // bu - file that is used to build a project
  456. pub source: Option<StyleOverride>, // sc - source code
  457. }
  458. impl FromOverride<FileTypeOverride> for FileType {
  459. fn from(value: FileTypeOverride, default: Self) -> Self {
  460. FileType {
  461. image: FromOverride::from(value.image, default.image),
  462. video: FromOverride::from(value.video, default.video),
  463. music: FromOverride::from(value.music, default.music),
  464. lossless: FromOverride::from(value.lossless, default.lossless),
  465. crypto: FromOverride::from(value.crypto, default.crypto),
  466. document: FromOverride::from(value.document, default.document),
  467. compressed: FromOverride::from(value.compressed, default.compressed),
  468. temp: FromOverride::from(value.temp, default.temp),
  469. compiled: FromOverride::from(value.compiled, default.compiled),
  470. build: FromOverride::from(value.build, default.build),
  471. source: FromOverride::from(value.source, default.source),
  472. }
  473. }
  474. }
  475. #[rustfmt::skip]
  476. #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
  477. pub struct UiStylesOverride {
  478. pub colourful: Option<bool>,
  479. pub filekinds: Option<FileKindsOverride>,
  480. pub perms: Option<PermissionsOverride>,
  481. pub size: Option<SizeOverride>,
  482. pub users: Option<UsersOverride>,
  483. pub links: Option<LinksOverride>,
  484. pub git: Option<GitOverride>,
  485. pub git_repo: Option<GitRepoOverride>,
  486. pub security_context: Option<SecurityContextOverride>,
  487. pub file_type: Option<FileTypeOverride>,
  488. pub punctuation: Option<StyleOverride>, // xx
  489. pub date: Option<StyleOverride>, // da
  490. pub inode: Option<StyleOverride>, // in
  491. pub blocks: Option<StyleOverride>, // bl
  492. pub header: Option<StyleOverride>, // hd
  493. pub octal: Option<StyleOverride>, // oc
  494. pub flags: Option<StyleOverride>, // ff
  495. pub symlink_path: Option<StyleOverride>, // lp
  496. pub control_char: Option<StyleOverride>, // cc
  497. pub broken_symlink: Option<StyleOverride>, // or
  498. pub broken_path_overlay: Option<StyleOverride>, // bO
  499. pub filenames: Option<HashMap<String, FileNameStyleOverride>>,
  500. pub extensions: Option<HashMap<String, FileNameStyleOverride>>,
  501. }
  502. impl FromOverride<UiStylesOverride> for UiStyles {
  503. fn from(value: UiStylesOverride, default: Self) -> Self {
  504. UiStyles {
  505. colourful: value.colourful,
  506. filekinds: FromOverride::from(value.filekinds, default.filekinds),
  507. perms: FromOverride::from(value.perms, default.perms),
  508. size: FromOverride::from(value.size, default.size),
  509. users: FromOverride::from(value.users, default.users),
  510. links: FromOverride::from(value.links, default.links),
  511. git: FromOverride::from(value.git, default.git),
  512. git_repo: FromOverride::from(value.git_repo, default.git_repo),
  513. security_context: FromOverride::from(value.security_context, default.security_context),
  514. file_type: FromOverride::from(value.file_type, default.file_type),
  515. punctuation: FromOverride::from(value.punctuation, default.punctuation),
  516. date: FromOverride::from(value.date, default.date),
  517. inode: FromOverride::from(value.inode, default.inode),
  518. blocks: FromOverride::from(value.blocks, default.blocks),
  519. header: FromOverride::from(value.header, default.header),
  520. octal: FromOverride::from(value.octal, default.octal),
  521. flags: FromOverride::from(value.flags, default.flags),
  522. symlink_path: FromOverride::from(value.symlink_path, default.symlink_path),
  523. control_char: FromOverride::from(value.control_char, default.control_char),
  524. broken_symlink: FromOverride::from(value.broken_symlink, default.broken_symlink),
  525. broken_path_overlay: FromOverride::from(
  526. value.broken_path_overlay,
  527. default.broken_path_overlay,
  528. ),
  529. filenames: FromOverride::from(value.filenames, default.filenames),
  530. extensions: FromOverride::from(value.extensions, default.extensions),
  531. }
  532. }
  533. }
  534. impl ThemeConfig {
  535. pub fn from_path(path: &str) -> Self {
  536. let path = PathBuf::from(path);
  537. ThemeConfig {
  538. location: ConfigLoc::Env(path),
  539. }
  540. }
  541. pub fn to_theme(&self) -> Option<UiStyles> {
  542. let ui_styles_override: Option<UiStylesOverride> = match &self.location {
  543. ConfigLoc::Default => {
  544. let path = dirs::config_dir()?.join("eza").join("theme.yml");
  545. let file = std::fs::File::open(path).ok()?;
  546. serde_yaml::from_reader(&file).ok()
  547. }
  548. ConfigLoc::Env(path) => {
  549. let file = std::fs::File::open(path).ok()?;
  550. serde_yaml::from_reader(&file).ok()
  551. }
  552. };
  553. FromOverride::from(ui_styles_override, Some(UiStyles::default()))
  554. }
  555. }
  556. #[cfg(test)]
  557. mod tests {
  558. use super::*;
  559. #[test]
  560. fn parse_none_color_from_string() {
  561. ["", "none", "None"].iter().for_each(|case| {
  562. assert_eq!(color_from_str(case), None);
  563. });
  564. }
  565. #[test]
  566. fn parse_default_color_from_string() {
  567. ["default", "Default"].iter().for_each(|case| {
  568. assert_eq!(color_from_str(case), Some(Color::Default));
  569. });
  570. }
  571. #[test]
  572. fn parse_fixed_color_from_string() {
  573. ["black", "Black"].iter().for_each(|case| {
  574. assert_eq!(color_from_str(case), Some(Color::Black));
  575. });
  576. }
  577. #[test]
  578. fn parse_long_hex_color_from_string() {
  579. ["#ff00ff", "#FF00FF"].iter().for_each(|case| {
  580. assert_eq!(color_from_str(case), Some(Color::Rgb(255, 0, 255)));
  581. });
  582. }
  583. #[test]
  584. fn parse_short_hex_color_from_string() {
  585. ["#f0f", "#F0F"].iter().for_each(|case| {
  586. assert_eq!(color_from_str(case), Some(Color::Rgb(255, 0, 255)));
  587. });
  588. }
  589. #[test]
  590. fn parse_color_code_from_string() {
  591. [("10", 10), ("01", 1)].iter().for_each(|(s, c)| {
  592. assert_eq!(color_from_str(s), Some(Color::Fixed(*c)));
  593. });
  594. }
  595. }