ishou_render/
fleet_fonts.rs1use ishou_tokens::TokenSet;
63use ishou_tokens::typography::{ItalicStyle, MonoFonts};
64
65use crate::nix_ast::{AttrEntry, NixExpr, NixFile, attrset, lambda, list, raw, str_};
66
67#[must_use]
69pub fn render(t: &TokenSet) -> String {
70 let mono = &t.typography.mono_fonts;
71
72 let primary = attrset(vec![
73 AttrEntry::new("name", str_(mono.primary)),
74 AttrEntry::new("package", primary_pkg(mono)),
75 ]);
76
77 let italic = attrset(vec![
78 AttrEntry::new("name", str_(mono.italic)),
79 AttrEntry::new("style_intent", str_(italic_style_name(mono.italic_style))),
80 AttrEntry::new("package", italic_pkg(mono)),
81 ]);
82
83 let bold = attrset(vec![
84 AttrEntry::new("name", str_(mono.bold)),
85 AttrEntry::new("package", primary_pkg(mono)),
86 ]);
87
88 let symbols = attrset(vec![
89 AttrEntry::new("name", str_("Symbols Nerd Font Mono")),
90 AttrEntry::new("package", raw("pkgs.nerd-fonts.symbols-only")),
91 ]);
92
93 let emoji = attrset(vec![
94 AttrEntry::new("name", str_("Apple Color Emoji")),
95 AttrEntry::new("fallback_name", str_("Noto Color Emoji")),
96 AttrEntry::new("package", NixExpr::Null),
97 ]);
98
99 let fallback_chain = list(
100 mono.fallback
101 .iter()
102 .map(|name| str_(*name))
103 .collect(),
104 );
105
106 let body = attrset(vec![
107 AttrEntry::new("primary", primary)
108 .with_comment(["Primary monospace family.", "Source of every cell's regular glyph."]),
109 AttrEntry::new("italic", italic)
110 .with_comment(["Italic face — same family slanted (ghostty's model)."]),
111 AttrEntry::new("bold", bold)
112 .with_comment(["Bold face — shares the primary package."]),
113 AttrEntry::new("symbols", symbols)
114 .with_comment(["Nerd Font icons (powerline / starship / atuin)."]),
115 AttrEntry::new("emoji", emoji)
116 .with_comment([
117 "macOS uses Apple Color Emoji at the OS layer;",
118 "Linux substitutes Noto Color Emoji (operator-installed).",
119 ]),
120 AttrEntry::new("fallback_chain", fallback_chain)
121 .with_comment(["Ordered fallback list cosmic-text walks for missing codepoints."]),
122 ]);
123
124 let file = NixFile::new(
125 [
126 "Generated by ishou-render::fleet_fonts — DO NOT EDIT",
127 "Source of truth: pleme-io/ishou/crates/ishou-tokens/src/typography.rs",
128 "Architecture: pleme-io/theory/THEME-ARCHITECTURE.md",
129 "",
130 "Consumed as `let fonts = import this { inherit pkgs; }; in …`",
131 "by every pleme-io GPU app's HM module (mado, ghostty, fumi, …).",
132 ],
133 lambda(vec!["pkgs"], body),
134 );
135
136 file.render()
137}
138
139fn primary_pkg(mono: &MonoFonts) -> NixExpr {
140 match mono.nerd_font_package_attr {
141 Some(attr) => raw(format!("pkgs.nerd-fonts.{attr}")),
142 None => NixExpr::Null,
143 }
144}
145
146fn italic_pkg(mono: &MonoFonts) -> NixExpr {
147 match mono.italic_package_attr {
148 Some(attr) => raw(format!("pkgs.{attr}")),
149 None => NixExpr::Null,
150 }
151}
152
153fn italic_style_name(s: ItalicStyle) -> &'static str {
154 match s {
155 ItalicStyle::MatchesPrimary => "matches_primary",
156 ItalicStyle::Calligraphic => "calligraphic",
157 ItalicStyle::Cursive => "cursive",
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn output_is_deterministic() {
167 let t = TokenSet::pleme();
168 assert_eq!(render(&t), render(&t));
169 }
170
171 #[test]
172 fn output_contains_all_canonical_slots() {
173 let out = render(&TokenSet::pleme());
174 for slot in ["primary", "italic", "bold", "symbols", "emoji", "fallback_chain"] {
175 assert!(out.contains(&format!("{slot} = ")), "missing slot {slot}\n{out}");
176 }
177 }
178
179 #[test]
180 fn primary_pins_jetbrains_mono_nerd_font_with_correct_package() {
181 let out = render(&TokenSet::pleme());
182 assert!(out.contains("name = \"JetBrainsMono Nerd Font\""));
183 assert!(out.contains("package = pkgs.nerd-fonts.jetbrains-mono"));
184 }
185
186 #[test]
187 fn italic_carries_style_intent() {
188 let out = render(&TokenSet::pleme());
189 assert!(out.contains("style_intent = \"matches_primary\""));
193 }
194
195 #[test]
196 fn symbols_slot_points_at_symbols_only_nerd_font() {
197 let out = render(&TokenSet::pleme());
198 assert!(out.contains("package = pkgs.nerd-fonts.symbols-only"));
199 }
200
201 #[test]
202 fn header_documents_provenance() {
203 let out = render(&TokenSet::pleme());
204 assert!(out.contains("ishou-render::fleet_fonts"));
205 assert!(out.contains("typography.rs"));
206 }
207
208 #[test]
209 fn fallback_chain_is_emitted_in_order() {
210 let out = render(&TokenSet::pleme());
211 let ts = TokenSet::pleme();
212 for name in ts.typography.mono_fonts.fallback {
213 assert!(out.contains(&format!("\"{name}\"")), "missing fallback {name}");
214 }
215 }
216
217 #[test]
218 fn output_starts_with_pkgs_lambda() {
219 let out = render(&TokenSet::pleme());
220 let body = out
223 .lines()
224 .find(|l| !l.starts_with('#'))
225 .unwrap_or("");
226 assert_eq!(body, "{ pkgs }:");
227 }
228}