16 releases (stable)

3.5.0 Nov 1, 2023
2.5.0 Nov 1, 2023
2.4.0 Oct 17, 2023
2.3.0 Jan 17, 2023
0.2.1 Apr 29, 2019

#703 in Parser implementations


Used in 2 crates

MIT license

100KB
3.5K SLoC

C 2K SLoC Rust 1.5K 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

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

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

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.

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

Dependencies

~3–5MB
~93K SLoC