Improve syntax highlighting in the language reference

Highlight all Slint code and don't do the preview on snippets where it
doesn't make sense.

Some snippets, such as the bare statement or expression snippets, are
now highlighted, but they are continued to be excluded from the doctest.
This commit is contained in:
Simon Hausmann 2022-03-23 11:27:08 +01:00 committed by Simon Hausmann
parent 1891e4489a
commit ed5b76e7fc
5 changed files with 46 additions and 28 deletions

View file

@ -59,7 +59,7 @@ Slint comes with a markup language that is specifically designed for user interf
powerful way to describe graphical elements, their placement, and the flow of data through the different states. It is a familiar syntax to describe the hierarchy
of elements and property bindings. Here's the obligatory "Hello World":
.. code-block:: slint-no-preview
.. code-block:: slint,ignore
HelloWorld := Window {
width: 400px;

View file

@ -148,7 +148,7 @@ You can also declare your own properties. The properties declared at the top lev
component are public and can be accessed by the component using it as an element, or using the
language bindings:
```slint
```slint,no_run
Example := Rectangle {
// declare a property of type int with the name `my-property`
property<int> my-property;
@ -186,7 +186,7 @@ together.
The right hand side of the `<=>` must be a reference to a property of the same type.
The type can be omitted in a property declaration to have the type automatically inferred.
```slint
```slint,no_run
Example := Window {
property<brush> rect-color <=> r.background;
// it is allowed to omit the type to have it automatically inferred
@ -227,7 +227,7 @@ Anonymous structs type can be declared with curly braces: `{ identifier1: type2,
The trailing semicolon is optional.
They can be initialized with a struct literal: `{ identifier1: expression1, identifier2: expression2 }`
```slint
```slint,no_run
Example := Window {
property<{name: string, score: int}> player: { name: "Foo", score: 100 };
property<{a: int, }> foo: { a: 3 };
@ -238,7 +238,7 @@ Example := Window {
It is possible to define a named struct using the `struct` keyword,
```slint
```slint,no_run
export struct Player := {
name: string,
score: int,
@ -254,7 +254,7 @@ Example := Window {
The type array is using square brackets for example `[int]` is an array of `int`. In the runtime, they are
basically used as models for the `for` expression.
```slint
```slint,no_run
Example := Window {
property<[int]> list-of-int: [1,2,3];
property<[{a: int, b: string}]> list-of-structs: [{ a: 1, b: "hello" }, {a: 2, b: "world"}];
@ -280,7 +280,7 @@ Example := Window {
* String can be converted to float by using the `to-float` function. That function returns 0 if the string is not
a valid number. you can check with `is-float` if the string contains a valid number
```slint
```slint,no_run
Example := Window {
// ok: int converts to string
property<{a: string, b: int}> prop1: {a: 12, b: 12 };
@ -341,7 +341,7 @@ element comes with a `clicked` callback, that's emitted when the user touches th
it with the mouse. In the example below, the emission of that callback is forwarded to another custom callback (`hello`) by declaring a
handler and emitting our custom callback:
```slint
```slint,no_run
Example := Rectangle {
// declare a callback
callback hello;
@ -358,7 +358,7 @@ Example := Rectangle {
It is also possible to add parameters to the callback.
```slint
```slint,no_run
Example := Rectangle {
// declares a callback
callback hello(int, string);
@ -368,7 +368,7 @@ Example := Rectangle {
And return value.
```slint
```slint,no_run
Example := Rectangle {
// declares a callback with a return value
callback hello(int, int) -> int;
@ -380,7 +380,7 @@ Example := Rectangle {
It is possible to declare callback aliases in a similar way to two-way bindings:
```slint
```slint,no_run
Example := Rectangle {
callback clicked <=> area.clicked;
area := TouchArea {}
@ -394,7 +394,7 @@ are typically used to combine basic arithmetic with access to properties of othe
these properties change, the expression is automatically re-evaluated and a new value is assigned
to the property the expression is associated with:
```slint
```slint,no_run
Example := Rectangle {
// declare a property of type int
property<int> my-property;
@ -409,7 +409,7 @@ If something changes `my-property`, the width will be updated automatically.
Arithmetic in expression with numbers works like in most programming language with the operators `*`, `+`, `-`, `/`:
```slint
```slint,no_run
Example := Rectangle {
property <int> p: 1 * 2 + 3 * 4; // same as (1 * 2) + (3 * 4)
}
@ -422,7 +422,7 @@ There are also the operators `&&` and `||` for logical *and* and *or* between bo
You can access properties by addressing the associated element, followed by a `.` and the property name:
```slint
```slint,no_run
Example := Rectangle {
foo := Rectangle {
x: 42px;
@ -559,25 +559,25 @@ Inside callback handlers, more complicated statements are allowed:
Assignment:
```ignore
```slint,ignore
clicked => { some-property = 42; }
```
Self-assignment with `+=` `-=` `*=` `/=`
```ignore
```slint,ignore
clicked => { some-property += 42; }
```
Calling a callback
```ignore
```slint,ignore
clicked => { root.some-callback(); }
```
Conditional statements
```ignore
```slint,ignore
clicked => {
if (condition) {
foo = 42;
@ -591,7 +591,7 @@ clicked => {
Empty expression
```ignore
```slint,ignore
clicked => { }
// or
clicked => { ; }
@ -684,11 +684,13 @@ Animation can be configured with the following parameter:
It is also possible to animate several properties with the same animation:
```ignore
```slint,ignore
animate x, y { duration: 100ms; }
```
is the same as
```ignore
```slint,ignore
animate x { duration: 100ms; }
animate y { duration: 100ms; }
```
@ -1017,7 +1019,7 @@ instructions the Slint compiler to include the font and makes the font families
For example:
```slint,notest
```slint,ignore
import "./NotoSans-Regular.ttf";
Example := Window {

View file

@ -6,7 +6,7 @@
<link rel="stylesheet" href="https://slint-ui.com/resources/highlightjs/11.0.1/default.min.css">
<script src="https://slint-ui.com/resources/highlightjs/11.0.1/highlight.min.js"></script>
<script>
hljs.registerLanguage("slint", function (hljs) {
function highlight_slint(hljs) {
const KEYWORDS = {
keyword:
'struct export import signal property animate for in if states transitions parent root self',
@ -49,13 +49,19 @@
],
illegal: /@/
};
});
};
// Tags used in fenced code blocks
for (let tag of ["slint", "slint,no_run", "slint,ignore"]) {
hljs.registerLanguage(tag, highlight_slint);
}
window.addEventListener("DOMContentLoaded", () => {
const rustDoc = document.querySelector('meta[name="generator"]')?.content == "rustdoc";
if (rustDoc) {
// Only highlight .slint blocks, leave the others to rustdoc
for (slintBlock of document.querySelectorAll(".language-slint")) {
for (slintBlock of document.querySelectorAll("[class*=language-slint]")) {
hljs.highlightElement(slintBlock)
}
@ -89,7 +95,7 @@
// The Sphinx/my_st generated HTML for code blocks does not use <code> tags, so highlight.js'
// default selector "pre code" does not match. Let's do it by hand:
for (block of document.querySelectorAll("div.highlight-slint div.highlight pre, div.highlight-slint-no-preview div.highlight pre")) {
for (block of document.querySelectorAll("div[class*=highlight-slint] div.highlight pre")) {
hljs.highlightElement(block)
}
}

View file

@ -31,7 +31,9 @@
async function run() {
await slint.default();
var elements = document.querySelectorAll("code.language-slint, .rustdoc pre.language-slint, div.highlight-slint");
let selector = ["code.language-slint", ".rustdoc pre.language-slint", "div.highlight-slint"]
.map((sel) => `${sel}:not([class*=slint\\,ignore]):not([class*=slint\\,no_run])`).join(",");
var elements = document.querySelectorAll(selector);
for (var i = 0; i < elements.length; ++i) {
let source = elements[i].innerText;
let div = document.createElement("div");

View file

@ -27,9 +27,17 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let file = file.replace('\r', ""); // Remove \r, because Windows.
let mut rest = file.as_str();
let mut count = 0;
const BEGIN_MARKER: &str = "\n```slint\n";
const BEGIN_MARKER: &str = "\n```slint";
while let Some(begin) = rest.find(BEGIN_MARKER) {
rest = rest[begin..].strip_prefix(BEGIN_MARKER).unwrap();
// Permit `slint,no_run` but skip `slint,ignore` and others.
rest = match rest.split_once('\n') {
Some((",no_run", rest)) => rest,
Some(("", _)) => rest,
_ => continue,
};
let end = rest.find("\n```\n").ok_or_else(|| {
format!("Could not find the end of a code snippet in {}", path.display())
})?;