1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
use std::collections::BTreeMap;
use std::io::Read;

use tree_sitter::{Parser, Language, Tree, Node};
use regex::Regex;

mod error;
mod parser;
mod resolver;
mod style;

use crate::error::{BoxedError, Error};
pub use crate::style::{Style, Colour, StyleBuilder, Setting};
pub use resolver::Context;

extern "C" { 
    fn tree_sitter_syncat_stylesheet() -> Language;
}

#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
enum SelectorSegment {
    Any,
    Kind(String),
    Token(String),
    TokenPattern(String),
    DirectChild(Box<SelectorSegment>),
    BranchCheck(Vec<SelectorSegment>),
    NoChildren(Box<SelectorSegment>),
}

impl SelectorSegment {
    pub fn score(&self) -> (usize, usize) {
        use SelectorSegment::*;
        match self {
            Any => (0, 0),
            Kind(..) => (0, 1),
            Token(..) => (1, 0),
            TokenPattern(..) => (1, 0),
            DirectChild(child) => child.score(),
            BranchCheck(child) => child.iter().map(SelectorSegment::score).fold((0, 0), |(a, b), (c, d)| (a + c, b + d)),
            NoChildren(..) => (1, 0),
        }
    }
}

/// A Stylesheet
#[derive(Default, Debug)]
pub struct Stylesheet {
    style: StyleBuilder,
    scopes: BTreeMap<SelectorSegment, Stylesheet>,
}

impl Stylesheet {
    /// Creates a new Stylesheet by parsing the provided stream.
    pub fn from_reader<R: Read>(input: &mut R) -> Result<Stylesheet, BoxedError> {
        let mut parser = Parser::new();
        unsafe {
            parser.set_language(tree_sitter_syncat_stylesheet()).unwrap();
        }
        let mut source = String::new();
        input.read_to_string(&mut source).map_err(Box::new)?;
        let tree = parser.parse(&source, None).unwrap();
        Stylesheet::parse(&source, tree)
    }
}

impl std::str::FromStr for Stylesheet {
    type Err = BoxedError;

    fn from_str(input: &str) -> Result<Stylesheet, BoxedError> {
        let mut parser = Parser::new();
        unsafe {
            parser.set_language(tree_sitter_syncat_stylesheet()).unwrap();
        }
        let tree = parser.parse(input, None).unwrap();
        Stylesheet::parse(input, tree)
    }
}