1mod color;
2#[cfg(feature = "generator")]
3mod generator;
4mod palette;
5#[cfg(feature = "generator")]
6pub mod terminal;
7
8pub use color::Rgb;
9#[cfg(feature = "generator")]
10pub use generator::Generator;
11pub use palette::Palette;
12
13#[cfg(feature = "generator")]
14use std::path::PathBuf;
15
16#[derive(Debug, thiserror::Error)]
17pub enum Error {
18 #[error("io error: {0}")]
19 Io(#[from] std::io::Error),
20 #[error("invalid palette: {0}")]
21 ParsePalette(#[from] toml::de::Error),
22 #[error("unresolved reference: {0}")]
23 UnresolvedRef(String),
24 #[cfg(feature = "generator")]
25 #[error("template {context}: {source}")]
26 Template {
27 context: &'static str,
28 #[source]
29 source: tera::Error,
30 },
31 #[error("invalid hex color: {0}")]
32 InvalidHex(String),
33 #[cfg(feature = "generator")]
34 #[error("non-UTF-8 path: {0}")]
35 InvalidPath(PathBuf),
36 #[cfg(feature = "generator")]
37 #[error("project root not found (expected palette/ and Cargo.toml)")]
38 ProjectRootNotFound,
39 #[cfg(feature = "generator")]
40 #[error("plist error: {0}")]
41 Plist(#[from] plist::Error),
42 #[cfg(feature = "generator")]
43 #[error("plist output was not valid UTF-8")]
44 PlistUtf8,
45 #[error("invalid color expression: {0}")]
46 InvalidColorExpr(String),
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50pub enum Variant {
51 Night,
52 Dawn,
53}
54
55impl Variant {
56 #[must_use]
57 pub const fn name(self) -> &'static str {
58 match self {
59 Self::Night => "night",
60 Self::Dawn => "dawn",
61 }
62 }
63
64 #[must_use]
65 pub const fn title(self) -> &'static str {
66 match self {
67 Self::Night => "Night",
68 Self::Dawn => "Dawn",
69 }
70 }
71
72 #[must_use]
73 pub const fn palette_filename(self) -> &'static str {
74 match self {
75 Self::Night => "akari-night.toml",
76 Self::Dawn => "akari-dawn.toml",
77 }
78 }
79}
80
81pub const VARIANTS: [Variant; 2] = [Variant::Night, Variant::Dawn];
82
83#[cfg(feature = "generator")]
84#[derive(Debug, Clone)]
86pub enum ArtifactContent {
87 Text(String),
89 Copy(PathBuf),
91}
92
93#[cfg(feature = "generator")]
94#[derive(Debug, Clone)]
96pub struct Artifact {
97 pub rel_path: PathBuf,
99 pub content: ArtifactContent,
101}
102
103#[cfg(feature = "generator")]
104impl Artifact {
105 pub fn text(rel_path: impl Into<PathBuf>, content: impl Into<String>) -> Self {
106 Self {
107 rel_path: rel_path.into(),
108 content: ArtifactContent::Text(content.into()),
109 }
110 }
111
112 pub fn copy(rel_path: impl Into<PathBuf>, src: impl Into<PathBuf>) -> Self {
113 Self {
114 rel_path: rel_path.into(),
115 content: ArtifactContent::Copy(src.into()),
116 }
117 }
118}
119
120#[cfg(feature = "generator")]
121pub fn find_project_root() -> Result<PathBuf, Error> {
122 let mut current = std::env::current_dir()?;
123
124 loop {
125 if current.join("palette").is_dir() && current.join("Cargo.toml").is_file() {
126 return Ok(current);
127 }
128
129 if !current.pop() {
130 return Err(Error::ProjectRootNotFound);
131 }
132 }
133}