14 releases (stable)

2.3.0 Jan 17, 2023
2.2.1 Jul 15, 2021
2.2.0 Mar 14, 2020
2.1.5 Feb 25, 2020
0.1.0 Apr 8, 2019

#276 in Parser implementations

Download history 42/week @ 2023-05-30 8/week @ 2023-06-06 21/week @ 2023-06-13 40/week @ 2023-06-20 38/week @ 2023-06-27 43/week @ 2023-07-04 18/week @ 2023-07-11 18/week @ 2023-07-18 48/week @ 2023-07-25 8/week @ 2023-08-01 15/week @ 2023-08-08 31/week @ 2023-08-15 23/week @ 2023-08-22 8/week @ 2023-08-29 35/week @ 2023-09-05 15/week @ 2023-09-12

81 downloads per month
Used in 2 crates

MIT license

3.5K SLoC

C 2K SLoC Rust 1K SLoC // 0.0% comments

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 are loaded from files. All imports will be resolved relative to the file during the loading process.

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

// syncat.syncat
import "./colours.syncat";
declaration variable { color: $variable; }
declaration value { color: $value; }
let stylesheet = Stylesheet::from_file("syncat.syncat");


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:

$hello: world;

You could construct this Query:

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.

let style = stylesheet.style(&query).unwrap_or_default();
// 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


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.

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));


~88K SLoC