Skip to content

Commit 289a1be

Browse files
committed
added Swift code generator
1 parent 5f2467b commit 289a1be

File tree

3 files changed

+166
-18
lines changed

3 files changed

+166
-18
lines changed

README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,48 @@ into this…
7272

7373
![Xcode Screenshot](./.github/Xcode.png)
7474

75+
and also this…
76+
77+
```swift
78+
import UIKit
79+
80+
extension UIColor {
81+
enum Custom {}
82+
}
83+
84+
extension UIColor.Custom {
85+
static let applicationBackgroundLight = UIColor(named: "ApplicationBackgroundLight")!
86+
static let applicationBackgroundDark = UIColor(named: "ApplicationBackgroundDark")!
87+
static let iconActive = UIColor(named: "IconActive")!
88+
static let iconInactive = UIColor(named: "IconInactive")!
89+
static let textPrimary = UIColor(named: "TextPrimary")!
90+
static let textSecondary = UIColor(named: "TextSecondary")!
91+
static let lightContentSeparator = UIColor(named: "LightContentSeparator")!
92+
static let numericInputActionKeyBackground = UIColor(named: "NumericInputActionKeyBackground")!
93+
static let numericInputActionKeyHighlight = UIColor(named: "NumericInputActionKeyHighlight")!
94+
static let numericInputActionKeyShadow = UIColor(named: "NumericInputActionKeyShadow")!
95+
static let numericInputActionKeyText = UIColor(named: "NumericInputActionKeyText")!
96+
static let numericInputDoneKeyBackground = UIColor(named: "NumericInputDoneKeyBackground")!
97+
static let numericInputDoneKeyHighlight = UIColor(named: "NumericInputDoneKeyHighlight")!
98+
static let numericInputDoneKeyShadow = UIColor(named: "NumericInputDoneKeyShadow")!
99+
static let numericInputDoneKeyText = UIColor(named: "NumericInputDoneKeyText")!
100+
static let numericInputFunctionKeyBackground = UIColor(named: "NumericInputFunctionKeyBackground")!
101+
static let numericInputFunctionKeyHighlight = UIColor(named: "NumericInputFunctionKeyHighlight")!
102+
static let numericInputFunctionKeyShadow = UIColor(named: "NumericInputFunctionKeyShadow")!
103+
static let numericInputFunctionKeyText = UIColor(named: "NumericInputFunctionKeyText")!
104+
static let numericInputNumericKeyBackground = UIColor(named: "NumericInputNumericKeyBackground")!
105+
static let numericInputNumericKeyHighlight = UIColor(named: "NumericInputNumericKeyHighlight")!
106+
static let numericInputNumericKeyShadow = UIColor(named: "NumericInputNumericKeyShadow")!
107+
static let numericInputNumericKeyText = UIColor(named: "NumericInputNumericKeyText")!
108+
static let numericInputBackground = UIColor(named: "NumericInputBackground")!
109+
}
110+
```
111+
112+
Usage:
113+
114+
```
115+
$ ./xcode-color-assets gen-assets colors.assetstyles -o Colors.xcassets
116+
$ ./xcode-color-assets gen-swift colors.assetstyles -o Colors.swift
117+
```
118+
75119
> Caveat: This project is in the "works for me" state. There is basically no error handling at this point.

src/gen_swift.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
use super::ast::{Document, DocumentItem, RuleSet, RuleSetItem};
2+
use std::fs;
3+
4+
pub fn gen_swift(doc: &Document, path: &str) -> std::io::Result<()> {
5+
let mut identifiers: Vec<String> = vec![];
6+
7+
for item in doc.items.iter() {
8+
match item {
9+
DocumentItem::RuleSet(r) => {
10+
append_identifiers_from_ruleset(r, "", &mut identifiers);
11+
}
12+
_ => {}
13+
}
14+
}
15+
16+
let prefix = r#"
17+
import UIKit
18+
19+
extension UIColor {
20+
enum Custom {}
21+
}
22+
23+
extension UIColor.Custom {
24+
"#;
25+
26+
let suffix = r#"
27+
}
28+
"#;
29+
30+
let mapped_idents: Vec<String> = identifiers
31+
.iter()
32+
.map(|ident| {
33+
format!(
34+
" static let {} = UIColor(named: \"{}\")!",
35+
lowercase_first_letter(ident),
36+
ident
37+
)
38+
})
39+
.collect();
40+
41+
let result = format!("{}{}{}", prefix, mapped_idents.join("\n"), suffix);
42+
43+
fs::write(path, result.as_bytes())
44+
}
45+
46+
fn append_identifiers_from_ruleset(
47+
ruleset: &RuleSet,
48+
identifier: &str,
49+
identifiers_bucket: &mut Vec<String>,
50+
) {
51+
for item in ruleset.items.iter() {
52+
match item {
53+
RuleSetItem::RuleSet(r) => {
54+
let identifier = format!("{}{}", identifier, r.identifier);
55+
append_identifiers_from_ruleset(r, &identifier, identifiers_bucket);
56+
}
57+
RuleSetItem::Declaration(d) => {
58+
identifiers_bucket.push(format!("{}{}", identifier, d.identifier));
59+
}
60+
}
61+
}
62+
}
63+
64+
fn lowercase_first_letter(s: &str) -> String {
65+
let mut c = s.chars();
66+
match c.next() {
67+
None => String::new(),
68+
Some(f) => f.to_lowercase().collect::<String>() + c.as_str(),
69+
}
70+
}

src/main.rs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,70 @@
11
mod asset_catalog;
22
mod ast;
3+
mod gen_swift;
34
mod parser;
45

56
use crate::asset_catalog::write_asset_catalog;
7+
use crate::gen_swift::gen_swift;
68
use crate::parser::parse_document_from_file;
7-
use clap::{App, Arg};
9+
use clap::{App, Arg, SubCommand};
810

911
fn main() {
1012
let matches = App::new("color-assets")
1113
.version("1.0")
1214
.about("Create Xcode Asset Catalog with colors for light & dark mode.")
13-
.arg(
14-
Arg::with_name("output")
15-
.short("o")
16-
.help("Sets the output filename")
17-
.value_name("OUTPUT_FILE")
18-
.required(true),
15+
.subcommand(
16+
SubCommand::with_name("gen-assets")
17+
.about("generates the Asset Catalog")
18+
.arg(
19+
Arg::with_name("output")
20+
.short("o")
21+
.help("Sets the output filename (e.g. Colors.xcassets)")
22+
.value_name("OUTPUT_FILE")
23+
.required(true),
24+
)
25+
.arg(
26+
Arg::with_name("input")
27+
.help("Sets the input file")
28+
.value_name("INPUT_FILE")
29+
.required(true)
30+
.index(1),
31+
),
1932
)
20-
.arg(
21-
Arg::with_name("input")
22-
.help("Sets the input file")
23-
.value_name("INPUT_FILE")
24-
.required(true)
25-
.index(1),
33+
.subcommand(
34+
SubCommand::with_name("gen-swift")
35+
.about("generates Swift code")
36+
.arg(
37+
Arg::with_name("output")
38+
.short("o")
39+
.help("Sets the output filename (e.g. Colors.swift)")
40+
.value_name("OUTPUT_FILE")
41+
.required(true),
42+
)
43+
.arg(
44+
Arg::with_name("input")
45+
.help("Sets the input file")
46+
.value_name("INPUT_FILE")
47+
.required(true)
48+
.index(1),
49+
),
2650
)
2751
.get_matches();
2852

29-
let input_file = matches.value_of("input").unwrap();
30-
let output_path = matches.value_of("output").unwrap();
31-
32-
let doc = parse_document_from_file(&input_file).expect("Could not parse input file.");
33-
write_asset_catalog(&doc, &output_path).expect("Could not write asset catalog.");
53+
match matches.subcommand() {
54+
("gen-assets", Some(m)) => {
55+
let input_file = m.value_of("input").unwrap();
56+
let output_path = m.value_of("output").unwrap();
57+
let doc = parse_document_from_file(&input_file).expect("Could not parse input file.");
58+
write_asset_catalog(&doc, &output_path).expect("Could not write asset catalog.");
59+
}
60+
("gen-swift", Some(m)) => {
61+
let input_file = m.value_of("input").unwrap();
62+
let output_path = m.value_of("output").unwrap();
63+
let doc = parse_document_from_file(&input_file).expect("Could not parse input file.");
64+
gen_swift(&doc, &output_path).expect("Could not generate Swift code.");
65+
}
66+
(&_, _) => {}
67+
}
3468
}
3569

3670
#[cfg(test)]

0 commit comments

Comments
 (0)