syncat-stylesheet 2.2.0

Parser for Syncat Stylesheets.
Documentation
[Tree-sitter]: https://github.com/tree-sitter/tree-sitter
[syncat-themes]: https://github.com/foxfriends/syncat-themes

# Syncat Stylesheets

This documentation consists only of the usage of the `syncat_stylesheet` crate.
For documentation on the syntax and semantics of these stylesheets, see the 
[syncat-themes][] repository.

## Stylesheets

Stylesheets are loaded from files. All imports will be resolved relative to the file
during the loading process.

```syncat
// colours.syncat
$variable: red;
$value: bryellow;

// syncat.syncat
import "./colours.syncat";
declaration variable { color: $variable; }
declaration value { color: $value; }
```

```rust
let stylesheet = Stylesheet::from_file("syncat.syncat");
```

## Queries

Queries take the form of trees, as these stylesheets are typically used to apply 
properties (i.e. styles) to trees (as in parse trees).

Each node of a `Query` has a `kind` and a `token`, which must be provided. These 
nodes may also contain child nodes, which are also just `Query`, which can have 
more subqueries.

When matching against rules, the nodes of the rule are checked with the right-most 
branch of the tree.

For example, with the following source code:

```syncat
$hello: world;
```

You could construct this `Query`:

```rust
let mut query = Query::new("declaration", "$hello: world;");
query.add_child(Query::new("variable", "$hello"));
query.add_child(Query::new("value", "$world"));
```

Which corresponds to a tree like this:

```
(declaration (variable "$hello")
             (value "world"))
```

Which can then be matched against a `Stylesheet` by using the `Stylesheet::style` method.
This will return `Some(style)` if there were matches, or `None` if there were
none. Often this distinction does not matter, so you can unwrap to the default
`Style`.

```rust
let style = stylesheet.style(&query).unwrap_or_default();
```

```syncat
// successfully:
declaration value {} // because the value is on the right-most branch, and has the declaration as a parent
variable + value {} // because the value is on the right-most branch, and a direct sibling of the variable
declaration {} // because the declaration is a parent of the rightmost branch
value & "world" {} // because the value on the right-most branch has token "world"

// unsuccessfully
declaration > variable {} // because the variable is not on the right-most branch
value & "wor" {} // because the token "wor" does not match the token "world"
declaration variable value {} // because the value is not nested within the variable
declaration > {} // because the declaration is not the node directly at the end of the right-most branch
```

## Applications

Once you have a `Style` value, its properties can be extracted using the `Style::get` 
or `Style::try_get` methods. `Style::get` will retrieve the raw value, while `Style::try_get`
will attempt to convert that value to a contextual type.

With the `ansi_term` feature enabled (it is not by default), conversions to
`ansi_term::Style` are provided. Alternatively, you can simply extract whatever
properties you expect from the `Style` and interpret them however you choose.

```rust
let content: String = style.try_get("content")?.unwrap_or_else(|| String::from("hello world"));
let ansi_style: ansi_term::Style = style.try_into()?;
println!("{}", ansi_style.paint(content));
```