1
use std::cmp::Reverse;
2
use std::str::FromStr;
3

            
4
pub struct Sheet(pub Vec<Rule>);
5

            
6
impl Sheet {
7
3
    pub fn add_rule(mut self, rule: Rule) -> Self {
8
3
        self.0.push(rule);
9
3
        self
10
3
    }
11
}
12

            
13
impl From<&Sheet> for String {
14
1
    fn from(sheet: &Sheet) -> String {
15
1
        let Sheet(rules) = sheet;
16
1
        rules.iter().fold("".to_owned(), |acc, rule| {
17
1
            format!("{}{}", acc, String::from(rule))
18
1
        })
19
1
    }
20
}
21

            
22
pub struct Rule {
23
    pub selectors: Vec<Selector>,
24
    pub declarations: Vec<Declaration>,
25
}
26

            
27
impl Rule {
28
6
    pub fn add_selector(mut self, selector: Selector) -> Self {
29
6
        self.selectors.push(selector);
30
6
        self
31
6
    }
32

            
33
6
    pub fn add_declaration(mut self, name: &str, value: Value) -> Self {
34
6
        self.declarations.push(Declaration {
35
6
            name: name.to_owned(),
36
6
            value,
37
6
        });
38
6
        self
39
6
    }
40
}
41

            
42
impl From<&Rule> for String {
43
1
    fn from(rule: &Rule) -> String {
44
1
        let selectors_str = rule
45
1
            .selectors
46
1
            .iter()
47
1
            .map(String::from)
48
1
            .collect::<Vec<_>>()
49
1
            .join(",");
50
1

            
51
1
        let declarations_str = rule
52
1
            .declarations
53
1
            .iter()
54
1
            .map(String::from)
55
1
            .collect::<Vec<_>>()
56
1
            .join(";");
57
1

            
58
1
        format!("{}{{{}}}", selectors_str, declarations_str)
59
1
    }
60
}
61

            
62
pub type Specificity = (usize, usize, usize);
63

            
64
1
#[derive(Clone, Debug, PartialEq)]
65
pub struct Selector {
66
    pub tag: Option<String>,
67
    pub class: Vec<String>,
68
    pub id: Option<String>,
69
    pub attr: Vec<(String, AttrOp, String)>,
70
}
71

            
72
impl Selector {
73
6
    pub fn add_tag(mut self, tag_name: &str) -> Self {
74
6
        self.tag = Some(tag_name.to_owned());
75
6
        self
76
6
    }
77

            
78
2
    pub fn add_class(mut self, class_name: &str) -> Self {
79
2
        self.class.push(class_name.to_owned());
80
2
        self
81
2
    }
82

            
83
    pub fn add_id(mut self, id_name: &str) -> Self {
84
        self.id = Some(id_name.to_owned());
85
        self
86
    }
87

            
88
1
    pub fn add_attr(mut self, attr_name: &str, attr_op: AttrOp, attr_value: &str) -> Self {
89
1
        self.attr.push((attr_name.to_owned(), attr_op, attr_value.to_owned()));
90
1
        self
91
1
    }
92

            
93
30
    pub fn get_specificity(&self) -> Specificity {
94
30
        let a = self.id.iter().count();
95
30
        let b = self.class.iter().count() + self.attr.iter().count();
96
30
        let c = self.tag.iter().count();
97
30
        (a, b, c)
98
30
    }
99
}
100

            
101
impl From<&Selector> for String {
102
2
    fn from(selector: &Selector) -> String {
103
2
        let mut selector_str = String::new();
104

            
105
2
        if let Some(ref tag_name) = selector.tag {
106
2
            selector_str.push_str(tag_name);
107
2
        }
108

            
109
2
        for c in &selector.class {
110
            selector_str.push('.');
111
            selector_str.push_str(&c);
112
        }
113

            
114
2
        if let Some(ref id_name) = selector.id {
115
            selector_str.push('#');
116
            selector_str.push_str(id_name);
117
2
        }
118

            
119
3
        for a in &selector.attr {
120
1
            selector_str.push('[');
121
1
            selector_str.push_str(&a.0);
122
1
            selector_str.push_str(&String::from(&a.1));
123
1
            selector_str.push('"');
124
1
            selector_str.push_str(&a.2);
125
1
            selector_str.push('"');
126
1
            selector_str.push(']');
127
1
        }
128

            
129
2
        selector_str
130
2
    }
131
}
132

            
133
#[derive(Clone, Debug, PartialEq)]
134
pub enum AttrOp {
135
    Eq,
136
}
137

            
138
impl From<&AttrOp> for String {
139
1
    fn from(op: &AttrOp) -> String {
140
1
        match op {
141
1
            AttrOp::Eq => "=".to_owned(),
142
1
        }
143
1
    }
144
}
145

            
146
3
#[derive(Clone, Debug, PartialEq)]
147
pub struct Declaration {
148
    pub name: String,
149
    pub value: Value,
150
}
151

            
152
impl From<&Declaration> for String {
153
2
    fn from(declaration: &Declaration) -> String {
154
2
        format!("{}:{}", declaration.name, String::from(&declaration.value))
155
2
    }
156
}
157

            
158
161
#[derive(Clone, Debug, PartialEq)]
159
pub enum Value {
160
    Keyword(String),
161
    Length(f32, Unit),
162
    ColorValue(Color),
163
}
164

            
165
impl Value {
166
142
    pub fn to_px(&self) -> f32 {
167
142
        match *self {
168
134
            Value::Length(f, Unit::Px) => f, // TODO: device-independent pixels
169
8
            _ => 0.0,
170
        }
171
142
    }
172
}
173

            
174
impl From<&Value> for String {
175
4
    fn from(value: &Value) -> String {
176
4
        match value {
177
2
            Value::Keyword(ref s) => String::from(s),
178
2
            Value::Length(v, ref u) => format!("{}{}", v, String::from(u)),
179
            Value::ColorValue(c) => format!("rgba({},{},{},{})", c.r, c.g, c.b, c.a),
180
        }
181
4
    }
182
}
183

            
184
110
#[derive(Clone, Debug, PartialEq)]
185
pub enum Unit {
186
    Px,
187
}
188

            
189
impl From<&Unit> for String {
190
2
    fn from(unit: &Unit) -> String {
191
2
        match unit {
192
2
            Unit::Px => "px".to_owned(),
193
2
        }
194
2
    }
195
}
196

            
197
4
#[derive(Clone, Debug, PartialEq, Default)]
198
pub struct Color {
199
    pub r: u8,
200
    pub g: u8,
201
    pub b: u8,
202
    pub a: u8,
203
}
204

            
205
3
pub fn sheet() -> Sheet {
206
3
    Sheet(vec![])
207
3
}
208

            
209
3
pub fn rule() -> Rule {
210
3
    Rule {
211
3
        selectors: vec![],
212
3
        declarations: vec![],
213
3
    }
214
3
}
215

            
216
6
pub fn selector() -> Selector {
217
6
    Selector {
218
6
        tag: None,
219
6
        class: vec![],
220
6
        id: None,
221
6
        attr: vec![],
222
6
    }
223
6
}
224

            
225
impl From<&str> for Sheet {
226
3
    fn from(s: &str) -> Sheet {
227
3
        css_parser::rules(s).unwrap()
228
3
    }
229
}
230

            
231

            
232
enum SelectorComponent {
233
    Id(String),
234
    Class(String),
235
    Attribute(String, AttrOp, String),
236
    Tag(String),
237
    Universal,
238
}
239

            
240
16
peg::parser! {
241
14
    grammar css_parser() for str {
242
14
        pub rule rules() -> Sheet
243
14
            = __ r:(css_rule() ** __) __ { Sheet(r) }
244
14

            
245
14
        pub rule css_rule() -> Rule
246
14
            = s:selectors() __ d:declaration_block() {
247
9
                Rule {
248
9
                    selectors: s,
249
9
                    declarations: d,
250
9
                }
251
9
            }
252
14

            
253
14
        pub rule selectors() -> Vec<Selector>
254
14
            = selectors:(simple_selector() ++ selector_delimiter()) {
255
10
                let mut ordered_selectors = selectors as Vec<Selector>;
256
12
                ordered_selectors.sort_by_key(|s| Reverse(s.get_specificity()));
257
10
                ordered_selectors
258
10
            }
259
14

            
260
16
        rule selector_delimiter()
261
14
            = __ "," __
262
14

            
263
19
        pub rule simple_selector() -> Selector
264
14
            = components:(
265
14
                id_selector() /
266
14
                class_selector() /
267
14
                attribute_selector() /
268
14
                tag_selector() /
269
14
                universal_selector()
270
14
            )+ {?
271
16
                let mut ids = vec![];
272
16
                let mut classes = vec![];
273
16
                let mut attributes = vec![];
274
16
                let mut tags = vec![];
275
14

            
276
33
                for c in components {
277
17
                    match c {
278
14
                        SelectorComponent::Id(s) => ids.push(s),
279
14
                        SelectorComponent::Class(s) => classes.push(s),
280
14
                        SelectorComponent::Attribute(n, o, v) => attributes.push((n, o, v)),
281
16
                        SelectorComponent::Tag(s) => tags.push(s),
282
14
                        SelectorComponent::Universal => (),
283
14
                    }
284
14
                }
285
14

            
286
16
                if ids.len() > 1 {
287
14
                    return Err("a maximum of one id");
288
16
                }
289
16

            
290
16
                if tags.len() > 1 {
291
14
                    return Err("a maximum of one tag");
292
16
                }
293
16

            
294
16
                Ok(Selector {
295
16
                    tag: if tags.len() == 0 { None } else { Some(tags[0].clone()) },
296
16
                    class: classes,
297
16
                    id: if ids.len() == 0 { None } else { Some(ids[0].clone()) },
298
16
                    attr: attributes,
299
14
                })
300
14
            }
301
14

            
302
14
        rule id_selector() -> SelectorComponent
303
14
            = "#" s:identifier() { SelectorComponent::Id(s) }
304
14

            
305
14
        rule class_selector() -> SelectorComponent
306
14
            = "." s:identifier() { SelectorComponent::Class(s) }
307
14

            
308
14
        rule attribute_selector() -> SelectorComponent
309
14
            = "[" n:identifier() o:operator() v:identifier() "]" { SelectorComponent::Attribute(n, o, v) }
310
14

            
311
14
        pub rule operator() -> AttrOp
312
14
            = "=" { AttrOp::Eq }
313
14

            
314
16
        rule tag_selector() -> SelectorComponent
315
16
            = s:identifier() { SelectorComponent::Tag(s) }
316
14

            
317
19
        rule universal_selector() -> SelectorComponent
318
14
            = "*" { SelectorComponent::Universal }
319
14

            
320
14
        pub rule declaration_block() -> Vec<Declaration>
321
14
            = __ "{" __ d:(declaration() ** decl_delimiter()) decl_delimiter()? __ "}" __ { d }
322
10

            
323
36
        pub rule decl_delimiter()
324
14
            = __ ";" __
325
14

            
326
27
        pub rule declaration() -> Declaration
327
27
            = n:identifier() __ ":" __ v:value() {
328
27
                Declaration { name: n, value: v }
329
27
            }
330
14

            
331
27
        pub rule value() -> Value
332
14
            = color_value()
333
14
            / length_value()
334
14
            / keyword_value()
335
14

            
336
14
        pub rule keyword_value() -> Value
337
14
            = s:identifier() { Value::Keyword(s.to_owned()) }
338
14

            
339
15
        pub rule length_value() -> Value
340
14
            = "0" "px"? { Value::Length(0.0, Unit::Px) }
341
15
            / n:f32_value() "px" { Value::Length(n, Unit::Px) }
342
14

            
343
31
        pub rule color_value() -> Value
344
14
            = v:(
345
14
                color_rgb_value() /
346
14
                color_rgba_value() /
347
14
                color_hex_value_six() /
348
14
                color_hex_value_three()
349
14
            ) { Value::ColorValue(v) }
350
14

            
351
14
        pub rule color_rgb_value() -> Color
352
14
            = "rgb(" r:dec_value() "," g:dec_value() "," b:dec_value() ")" {
353
1
                Color { r, g, b, a: 255 }
354
1
            }
355
14

            
356
14
        pub rule color_rgba_value() -> Color
357
14
            = "rgba(" r:dec_value() "," g:dec_value() "," b:dec_value() "," a:dec_value() ")" {
358
1
                Color { r, g, b, a }
359
1
            }
360
14

            
361
14
        pub rule color_hex_value_three() -> Color
362
14
            = "#" v:hex_value_one()*<3,3> {
363
1
                Color {
364
1
                    r: v[0] + v[0] * 16,
365
1
                    g: v[1] + v[1] * 16,
366
1
                    b: v[2] + v[2] * 16,
367
1
                    a: 255,
368
1
                }
369
1
            }
370
14
            / expected!("# followed by three hexadecimal digits")
371
14

            
372
14
        pub rule color_hex_value_six() -> Color
373
14
            = "#" v:hex_value_two()*<3,3> {
374
3
                Color {
375
3
                    r: v[0],
376
3
                    g: v[1],
377
3
                    b: v[2],
378
3
                    a: 255,
379
3
                }
380
3
            }
381
14
            / expected!("# followed by six hexadecimal digits")
382
14

            
383
15
        pub rule f32_value() -> f32
384
14
            = n:$(
385
14
                "-"? ['0'..='9']+ ("." ['0'..='9']+)? /
386
14
                "-"? "." ['0'..='9']+
387
15
            ) { f32::from_str(n).unwrap() }
388
14

            
389
14
        pub rule dec_value() -> u8
390
14
            = n:$(['0'..='9']+) { u8::from_str_radix(n, 10).unwrap() }
391
14

            
392
14
        pub rule hex_value_one() -> u8
393
14
            = n:$(['0'..='9' | 'a'..='f' | 'A'..='F']) { u8::from_str_radix(n, 16).unwrap() }
394
14

            
395
14
        pub rule hex_value_two() -> u8
396
14
            = n:$(['0'..='9' | 'a'..='f' | 'A'..='F']*<2,2>) { u8::from_str_radix(n, 16).unwrap() }
397
14

            
398
144
        pub rule identifier() -> String
399
55
            = s:$(['a'..='z' | 'A'..='Z'] ['a'..='z' | 'A'..='Z' | '0'..='9' | '-' | '_']*) {
400
55
                s.to_owned()
401
55
            }
402
14

            
403
212
        pub rule __
404
14
            = (whitespace() / comment())*
405
14

            
406
1141
        pub rule whitespace()
407
14
            = " " / "\r" / "\n" / "\t"
408
14

            
409
214
        pub rule comment()
410
14
            = "/*" (!"*/"[_])* "*/"
411
14
    }
412
14
}
413

            
414
#[cfg(test)]
415
mod tests {
416
    use crate::css::*;
417

            
418
1
    #[test]
419
1
    fn test_comment() {
420
1
        let actual = css_parser::comment("/* foo */");
421
1
        let expected = Ok(());
422
1
        assert_eq!(actual, expected);
423
1
    }
424

            
425
1
    #[test]
426
1
    fn test_selectors() {
427
1
        let actual = css_parser::selectors("a");
428
1
        let expected = Ok(vec![
429
1
            Selector { tag: Some("a".to_owned()), id: None, class: vec![], attr: vec![] },
430
1
            // Selector { tag: Some("b".to_owned()), id: None, class: vec![], attr: vec![] },
431
1
        ]);
432
1
        assert_eq!(actual, expected);
433
1
    }
434

            
435
1
    #[test]
436
1
    fn test_identifier() {
437
1
        let actual = css_parser::identifier("a");
438
1
        let expected = Ok("a".to_owned());
439
1
        assert_eq!(actual, expected);
440
1
    }
441

            
442
1
    #[test]
443
1
    fn test_declaration_block() {
444
1
        let actual = css_parser::declaration_block(
445
1
            "
446
1
            {
447
1
                foo: bar;
448
1
                baz: 42px;
449
1
            }
450
1
            "
451
1
        );
452
1
        let expected = Ok(vec![
453
1
            Declaration { name: "foo".to_owned(), value: Value::Keyword("bar".to_owned()) },
454
1
            Declaration { name: "baz".to_owned(), value: Value::Length(42.0, Unit::Px) },
455
1
        ]);
456
1
        assert_eq!(actual, expected);
457
1
    }
458

            
459
1
    #[test]
460
1
    fn test_declaration() {
461
1
        let actual = css_parser::declaration("foo: bar");
462
1
        let expected = Ok(Declaration {
463
1
            name: "foo".to_owned(),
464
1
            value: Value::Keyword("bar".to_owned())
465
1
        });
466
1
        assert_eq!(actual, expected);
467
1
    }
468

            
469
1
    #[test]
470
1
    fn test_color_rgb_value() {
471
1
        let actual = css_parser::color_value("rgb(1,2,3)");
472
1
        let expected = Ok(Value::ColorValue(Color { r: 1, g: 2, b: 3, a: 255 }));
473
1
        assert_eq!(actual, expected);
474
1
    }
475

            
476
1
    #[test]
477
1
    fn test_color_rgba_value() {
478
1
        let actual = css_parser::color_value("rgba(1,2,3,4)");
479
1
        let expected = Ok(Value::ColorValue(Color { r: 1, g: 2, b: 3, a: 4 }));
480
1
        assert_eq!(actual, expected);
481
1
    }
482

            
483
1
    #[test]
484
1
    fn test_hex_value_one() {
485
1
        let actual = css_parser::hex_value_one("f");
486
1
        let expected = Ok(15);
487
1
        assert_eq!(actual, expected);
488
1
    }
489

            
490
1
    #[test]
491
1
    fn test_hex_value_two() {
492
1
        let actual = css_parser::hex_value_two("ff");
493
1
        let expected = Ok(255);
494
1
        assert_eq!(actual, expected);
495
1
    }
496

            
497
1
    #[test]
498
1
    fn test_color_hex_value_three() {
499
1
        let actual = css_parser::color_value("#abc");
500
1
        let expected = Ok(Value::ColorValue(Color { r: 170, g: 187, b: 204, a: 255 }));
501
1
        assert_eq!(actual, expected);
502
1
    }
503

            
504
1
    #[test]
505
1
    fn test_color_hex_value_six() {
506
1
        let actual = css_parser::color_value("#abcdef");
507
1
        let expected = Ok(Value::ColorValue(Color { r: 171, g: 205, b: 239, a: 255 }));
508
1
        assert_eq!(actual, expected);
509
1
    }
510

            
511
1
    #[test]
512
1
    fn test_to_string() {
513
1
        let actual = sheet().add_rule(
514
1
            rule()
515
1
                .add_selector(
516
1
                    selector()
517
1
                        .add_tag("body")
518
1
                        .add_attr("class", AttrOp::Eq, "foo"),
519
1
                )
520
1
                .add_selector(selector().add_tag("p"))
521
1
                .add_declaration("margin", Value::Keyword("auto".to_owned()))
522
1
                .add_declaration("width", Value::Length(24.0, Unit::Px)),
523
1
        );
524
1
        let expected = r#"body[class="foo"],p{margin:auto;width:24px}"#;
525
1
        assert_eq!(String::from(&actual), expected);
526
1
    }
527

            
528
1
    #[test]
529
1
    fn test_from_str() {
530
1
        let css = Sheet::from(
531
1
            "
532
1
            a, b {
533
1
                display: block;
534
1
                background-color: #ff0000;
535
1
                margin: 24px;
536
1
                width: 100px;
537
1
            }
538
1

            
539
1
            c {
540
1
                display: inline;
541
1
                background-color: blue;
542
1
                margin: 24px;
543
1
                width: 32px;
544
1
                height: 24px;
545
1
            }
546
1
        ",
547
1
        );
548
1

            
549
1
        assert_eq!(css.0[0].selectors[0].tag, Some("a".to_owned()));
550
1
        assert_eq!(css.0[0].selectors[1].tag, Some("b".to_owned()));
551
1
        assert_eq!(css.0[0].declarations[0].name, "display".to_owned());
552

            
553
1
        assert_eq!(css.0[1].selectors[0].tag, Some("c".to_owned()));
554
1
    }
555
}