added markdown parser for @@ types used in typegen

This commit is contained in:
outfoxxed 2024-10-16 04:22:33 -07:00
parent 77e2d05d6f
commit 00feaca3d5
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
5 changed files with 226 additions and 206 deletions

View file

@ -104,12 +104,12 @@ export function getQMLTypeLinkObject(unparsed: string) {
: linkSplit[0]; : linkSplit[0];
const linkObj: QMLTypeLinkObject = { const linkObj: QMLTypeLinkObject = {
type: "qt", type: "qt",
module: linkModule, module: linkModule.replace("_", "-"),
name: linkSplit[1].slice(1), name: linkSplit[1].slice(1),
}; };
if (linkSplit.length > 2) { if (linkSplit.length > 2) {
linkObj.mname = linkSplit[3]; linkObj.mname = linkSplit[2].slice(1);
linkObj.mtype = linkSplit[4]; linkObj.mtype = linkSplit[3].slice(1);
} }
return linkObj; return linkObj;
}, },

View file

@ -1,10 +1,12 @@
import type { Parent, Node } from "unist";
import { visit, CONTINUE, SKIP } from "unist-util-visit"; import { visit, CONTINUE, SKIP } from "unist-util-visit";
import { fromHtml } from "hast-util-from-html"; import { fromHtml } from "hast-util-from-html";
import type { Root } from "hast"; import type * as Unist from "unist";
import type * as Html from "hast";
import type * as Md from "mdast";
import type { import type {
AstroMarkdownOptions, AstroMarkdownOptions,
MarkdownProcessor, MarkdownProcessor,
RemarkPlugin,
RehypePlugin, RehypePlugin,
} from "@astrojs/markdown-remark"; } from "@astrojs/markdown-remark";
import { createMarkdownProcessor } from "@astrojs/markdown-remark"; import { createMarkdownProcessor } from "@astrojs/markdown-remark";
@ -18,19 +20,52 @@ import {
getIconForLink, getIconForLink,
} from "./helpers.ts"; } from "./helpers.ts";
// couldn't find the actual type to use const remarkParseAtTypes: RemarkPlugin<[]> = () => {
interface HtmlNode extends Node { return (root: Md.Root): Md.Root => {
value: string; visit(
type: string; root as Unist.Parent,
tagName: string; (rawNode: Unist.Node) => {
if (rawNode.type === "text" || (rawNode.type === "code" && (rawNode as Md.Code).lang === "qml")) {
const node = rawNode as Md.Literal;
node.value = node.value.replace(
/@@((?<module>([A-Z]\w*\.)*)(?<type>([A-Z]\w*))\.?)?((?<member>[a-z]\w*)((?<function>\(\))|(?<signal>\(s\)))?)?(?=[$.,;:\s]|$)/g,
(_full, ...args) => {
type Capture = {
module: string | undefined;
type: string | undefined;
member: string | undefined;
function: string | undefined;
signal: string | undefined;
} }
const groups = args.pop() as Capture;
if (groups.module) {
groups.module = groups.module.substring(0, groups.module.length - 1);
const isQs = groups.module.startsWith("Quickshell");
groups.module = `99M${isQs ? "QS" : "QT_qml"}_${groups.module.replace(".", "_")}`;
} else groups.module = ""; // WARNING: rehype parser can't currently handle intra-module links
groups.type = groups.type ? `99N${groups.type}` : "";
groups.member = groups.member ? `99V${groups.member}` : "";
const type = groups.member ? `99T${groups.function ? "func" : groups.signal ? "signal" : "prop"}` : "";
return `TYPE${groups.module}${groups.type}${groups.member}${type}99TYPE`;
}
);
}
}
);
return root;
};
};
const rehypeRewriteTypelinks: RehypePlugin<[]> = () => { const rehypeRewriteTypelinks: RehypePlugin<[]> = () => {
return (root: Node): Root => { return (root: Html.Root): Html.Root => {
visit( visit(
root, root as Unist.Parent,
"text", "text",
(node: HtmlNode, index: number, parent: Parent) => { (node: Html.Text, index: number, parent: Html.Parent) => {
let changed = false; let changed = false;
node.value = node.value.replace( node.value = node.value.replace(
@ -65,7 +100,7 @@ const rehypeRewriteTypelinks: RehypePlugin<[]> = () => {
} }
); );
return root as Root; return root;
}; };
}; };
@ -93,7 +128,7 @@ export const markdownConfig: AstroMarkdownOptions = {
wrap: true, wrap: true,
transformers: [shikiRewriteTypelinks], transformers: [shikiRewriteTypelinks],
}, },
remarkPlugins: [[remarkAlert, { legacyTitle: true }]], remarkPlugins: [remarkParseAtTypes, [remarkAlert, { legacyTitle: true }]],
rehypePlugins: [ rehypePlugins: [
// FIXME: incompatible types between unified/Plugin and Astro/RehypePlugin // FIXME: incompatible types between unified/Plugin and Astro/RehypePlugin
[sectionize as RehypePlugin, { idPropertyName: "id" }], [sectionize as RehypePlugin, { idPropertyName: "id" }],

View file

@ -26,7 +26,7 @@ Each shell file starts with the shell root object. Only one may exist per config
```qml {filename="~/.config/quickshell/shell.qml"} ```qml {filename="~/.config/quickshell/shell.qml"}
import Quickshell import Quickshell
QS_Quickshell_ShellRoot { @@Quickshell.ShellRoot {
// ... // ...
} }
``` ```
@ -82,8 +82,8 @@ We'll start with an example:
import Quickshell // for ShellRoot and PanelWindow import Quickshell // for ShellRoot and PanelWindow
import QtQuick // for Text import QtQuick // for Text
QS_Quickshell_ShellRoot { @@Quickshell.ShellRoot {
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
anchors { anchors {
top: true top: true
left: true left: true
@ -92,7 +92,7 @@ QS_Quickshell_ShellRoot {
height: 30 height: 30
QT__Text { @@QtQuick.Text {
// center the bar in its parent component (the window) // center the bar in its parent component (the window)
anchors.centerIn: parent anchors.centerIn: parent
@ -115,9 +115,8 @@ To start with lets make a clock. To get the time we'll use the `date` command.
We can use a [Process](/docs/types/quickshell.io/process) object to run commands We can use a [Process](/docs/types/quickshell.io/process) object to run commands
and return their results. and return their results.
We'll listen to the [DataStreamParser.read](/docs/types/quickshell.io/datastreamparser/#signal.read) We'll listen to the @@Quickshell.Io.DataStreamParser.read(s) emitted by
[signal](/docs/configuration/qml-overview/#signals) emitted by @@Quickshell.Io.SplitParser using a
[SplitParser](/docs/types/quickshell.io/splitparser/) using a
[signal handler](/docs/configuration/qml-overview/#signal-handlers) [signal handler](/docs/configuration/qml-overview/#signal-handlers)
to update the text on the clock. to update the text on the clock.
@ -130,8 +129,8 @@ import Quickshell
import Quickshell.Io // for Process import Quickshell.Io // for Process
import QtQuick import QtQuick
QS_Quickshell_ShellRoot { @@Quickshell.ShellRoot {
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
anchors { anchors {
top: true top: true
left: true left: true
@ -140,14 +139,14 @@ QS_Quickshell_ShellRoot {
height: 30 height: 30
QT__Text { @@QtQuick.Text {
// give the text an ID we can refer to elsewhere in the file // give the text an ID we can refer to elsewhere in the file
id: clock id: clock
anchors.centerIn: parent anchors.centerIn: parent
// create a process management object // create a process management object
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
// the command it will run, every argument is its own string // the command it will run, every argument is its own string
command: ["date"] command: ["date"]
@ -156,7 +155,7 @@ QS_Quickshell_ShellRoot {
// process the stdout stream using a SplitParser // process the stdout stream using a SplitParser
// which returns chunks of output after a delimiter // which returns chunks of output after a delimiter
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
// listen for the read signal, which returns the data that was read // listen for the read signal, which returns the data that was read
// from stdout, then write that data to the clock's text property // from stdout, then write that data to the clock's text property
onRead: data => clock.text = data onRead: data => clock.text = data
@ -170,15 +169,15 @@ QS_Quickshell_ShellRoot {
## <MD_Title titleVar={2}> Running code at an interval </MD_Title> ## <MD_Title titleVar={2}> Running code at an interval </MD_Title>
With the above example, your bar should now display the time, but it isn't updating! With the above example, your bar should now display the time, but it isn't updating!
Let's use a [Timer](https://doc.qt.io/qt-6/qml-qtqml-timer.html) fix that. Let's use a @@QtQml.Timer to fix that.
```qml ```qml
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
QS_Quickshell_ShellRoot { @@Quickshell.ShellRoot {
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
anchors { anchors {
top: true top: true
left: true left: true
@ -187,11 +186,11 @@ QS_Quickshell_ShellRoot {
height: 30 height: 30
QT__Text { @@QtQuick.Text {
id: clock id: clock
anchors.centerIn: parent anchors.centerIn: parent
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
// give the process object an id so we can talk // give the process object an id so we can talk
// about it from the timer // about it from the timer
id: dateProc id: dateProc
@ -199,13 +198,13 @@ QS_Quickshell_ShellRoot {
command: ["date"] command: ["date"]
running: true running: true
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
onRead: data => clock.text = data onRead: data => clock.text = data
} }
} }
// use a timer to rerun the process at an interval // use a timer to rerun the process at an interval
QT_qtqml_Timer { @@QtQml.Timer {
// 1000 milliseconds is 1 second // 1000 milliseconds is 1 second
interval: 1000 interval: 1000
@ -230,34 +229,31 @@ If you have multiple monitors you might have noticed that your bar
is only on one of them. If not, you'll still want to **follow this section is only on one of them. If not, you'll still want to **follow this section
to make sure your bar doesn't disappear if your monitor disconnects**. to make sure your bar doesn't disappear if your monitor disconnects**.
We can use a [Variants](/docs/types/quickshell/variants) We can use a @@Quickshell.Variants object to create instances of _non widget items_.
object to create instances of _non widget items_. (See @@QtQuick.Repeater for doing
(See [Repeater](https://doc.qt.io/qt-6/qml-qtquick-repeater.html) for doing
something similar with visual items.) something similar with visual items.)
The `Variants` type creates instances of a The @@Quickshell.Variants type creates instances of a @@QtQml.Component based on
[Component](https://doc.qt.io/qt-6/qml-qtqml-component.html) based on a data model a data model you supply. (A component is a re-usable tree of objects.)
you supply. (A component is a re-usable tree of objects.)
The most common use of `Variants` in a shell is to create instances of The most common use of @@Quickshell.Variants in a shell is to create instances of
a window (your bar) based on your monitor list (the data model). a window (your bar) based on your monitor list (the data model).
Variants will inject the values in the data model into each new @@Quickshell.Variants will inject the values in the data model into each new
component's `modelData` property, which means we can easily pass each screen component's `modelData` property, which means we can easily pass each screen
to its own component. to its own component. (See @@Quickshell.QsWindow.screen.)
(See [Window.screen](/docs/types/quickshell/qswindow/#prop.screen).)
```qml ```qml
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
QS_Quickshell_ShellRoot { @@Quickshell.ShellRoot {
QS_Quickshell_Variants { @@Quickshell.Variants {
model: Quickshell.screens; model: Quickshell.screens;
delegate: QT_qtqml_Component { delegate: @@QtQml.Component {
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
// the screen from the screens list will be injected into this // the screen from the screens list will be injected into this
// property // property
property var modelData property var modelData
@ -273,21 +269,21 @@ QS_Quickshell_ShellRoot {
height: 30 height: 30
QT__Text { @@QtQuick.Text {
id: clock id: clock
anchors.centerIn: parent anchors.centerIn: parent
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
id: dateProc id: dateProc
command: ["date"] command: ["date"]
running: true running: true
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
onRead: data => clock.text = data onRead: data => clock.text = data
} }
} }
QT_qtqml_Timer { @@QtQml.Timer {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true
@ -301,16 +297,13 @@ QS_Quickshell_ShellRoot {
``` ```
<span class="small"> <span class="small">
See also: [Property See also: [Property Bindings](/docs/configuration/qml-overview/#property-bindings),
Bindings](/docs/configuration/qml-overview/#property-bindings),
[Variants.component](/docs/types/quickshell/variants/#prop.component),
[Quickshell.screens](/docs/types/quickshell/quickshell/#prop.screens),
[Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) [Array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
</span> </span>
With this example, bars will be created and destroyed as you plug and unplug them, With this example, bars will be created and destroyed as you plug and unplug them,
due to the reactive nature of the due to the reactive nature of the
[Quickshell.screens](/docs/types/quickshell/quickshell/#prop.screens) property. @@Quickshell.Quickshell.screens property.
(See: [Reactive Bindings](/docs/configuration/qml-overview/#reactive-bindings).) (See: [Reactive Bindings](/docs/configuration/qml-overview/#reactive-bindings).)
Now there's an important problem you might have noticed: when the window Now there's an important problem you might have noticed: when the window
@ -325,12 +318,12 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
QS_Quickshell_ShellRoot { @@Quickshell.ShellRoot {
QS_Quickshell_Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
delegate: QT_qtqml_Component { delegate: @@QtQml.Component {
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
property var modelData property var modelData
screen: modelData screen: modelData
@ -342,7 +335,7 @@ QS_Quickshell_ShellRoot {
height: 30 height: 30
QT__Text { @@QtQuick.Text {
id: clock id: clock
anchors.centerIn: parent anchors.centerIn: parent
} }
@ -350,17 +343,17 @@ QS_Quickshell_ShellRoot {
} }
} }
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
id: dateProc id: dateProc
command: ["date"] command: ["date"]
running: true running: true
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
onRead: data => clock.text = data onRead: data => clock.text = data
} }
} }
QT_qtqml_Timer { @@QtQml.Timer {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true
@ -400,17 +393,17 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
QS_Quickshell_ShellRoot { @@Quickshell.ShellRoot {
id: root id: root
// add a property in the root // add a property in the root
property string time; property string time;
QS_Quickshell_Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
delegate: QT_qtqml_Component { delegate: @@QtQml.Component {
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
property var modelData property var modelData
screen: modelData screen: modelData
@ -422,7 +415,7 @@ QS_Quickshell_ShellRoot {
height: 30 height: 30
QT__Text { @@QtQuick.Text {
// remove the id as we don't need it anymore // remove the id as we don't need it anymore
anchors.centerIn: parent anchors.centerIn: parent
@ -434,18 +427,18 @@ QS_Quickshell_ShellRoot {
} }
} }
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
id: dateProc id: dateProc
command: ["date"] command: ["date"]
running: true running: true
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
// update the property instead of the clock directly // update the property instead of the clock directly
onRead: data => root.time = data onRead: data => root.time = data
} }
} }
QT_qtqml_Timer { @@QtQml.Timer {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true
@ -460,12 +453,11 @@ above code, but we can make it more concise:
1. `Component`s can be defined implicitly, meaning we can remove the 1. `Component`s can be defined implicitly, meaning we can remove the
component wrapping the window and place the window directly into the component wrapping the window and place the window directly into the
`delegate` property. `delegate` property.
2. The [Variants.delegate](/docs/types/quickshell/variants/#prop.delegate) 2. The @@Quickshell.Variants.delegate property is a
property is a [Default Property](/docs/configuration/qml-overview/#the-default-property), [Default Property](/docs/configuration/qml-overview/#the-default-property),
which means we can skip the `delegate:` part of the assignment. which means we can skip the `delegate:` part of the assignment.
We're already using [ShellRoot](/docs/types/quickshell/shellroot/)'s We're already using the default property of @@Quickshell.ShellRoot to store our
default property to store our Variants, Process, and Timer components Variants, Process, and Timer components among other things.
among other things.
3. The ShellRoot doesn't actually need an `id` property to talk about 3. The ShellRoot doesn't actually need an `id` property to talk about
the time property, as it is the outermost object in the file which the time property, as it is the outermost object in the file which
has [special scoping rules](/docs/configuration/qml-overview/#property-access-scopes). has [special scoping rules](/docs/configuration/qml-overview/#property-access-scopes).
@ -477,13 +469,13 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
QS_Quickshell_ShellRoot { @@Quickshell.ShellRoot {
property string time; property string time;
QS_Quickshell_Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
property var modelData property var modelData
screen: modelData screen: modelData
@ -495,7 +487,7 @@ QS_Quickshell_ShellRoot {
height: 30 height: 30
QT__Text { @@QtQuick.Text {
anchors.centerIn: parent anchors.centerIn: parent
// now just time instead of root.time // now just time instead of root.time
@ -504,18 +496,18 @@ QS_Quickshell_ShellRoot {
} }
} }
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
id: dateProc id: dateProc
command: ["date"] command: ["date"]
running: true running: true
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
// now just time instead of root.time // now just time instead of root.time
onRead: data => time = data onRead: data => time = data
} }
} }
QT_qtqml_Timer { @@QtQml.Timer {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true
@ -534,7 +526,7 @@ To start with, let's move the entire bar into a new file.
```qml {filename="shell.qml"} ```qml {filename="shell.qml"}
import Quickshell import Quickshell
QS_Quickshell_ShellRoot { @@Quickshell.ShellRoot {
Bar {} Bar {}
} }
``` ```
@ -544,13 +536,13 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
QS_Quickshell_Scope { @@Quickshell.Scope {
property string time; property string time;
QS_Quickshell_Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
property var modelData property var modelData
screen: modelData screen: modelData
@ -562,7 +554,7 @@ QS_Quickshell_Scope {
height: 30 height: 30
QT__Text { @@QtQuick.Text {
anchors.centerIn: parent anchors.centerIn: parent
// now just time instead of root.time // now just time instead of root.time
@ -571,18 +563,18 @@ QS_Quickshell_Scope {
} }
} }
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
id: dateProc id: dateProc
command: ["date"] command: ["date"]
running: true running: true
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
// now just time instead of root.time // now just time instead of root.time
onRead: data => time = data onRead: data => time = data
} }
} }
QT_qtqml_Timer { @@QtQml.Timer {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true
@ -602,12 +594,12 @@ the clock component in the bar, as well as the process and timer that
make up the actual clock, need to be dealt with. make up the actual clock, need to be dealt with.
To start with, we can move the clock widget to a new file. For now it's just a To start with, we can move the clock widget to a new file. For now it's just a
single `Text` object but the same concepts apply regardless of complexity. single @@QtQuick.Text object but the same concepts apply regardless of complexity.
```qml {filename="ClockWidget.qml"} ```qml {filename="ClockWidget.qml"}
import QtQuick import QtQuick
QT__Text { @@QtQuick.Text {
// A property the creator of this type is required to set. // A property the creator of this type is required to set.
// Note that we could just set `text` instead, but don't because your // Note that we could just set `text` instead, but don't because your
// clock probably will not be this simple. // clock probably will not be this simple.
@ -622,14 +614,14 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
QS_Quickshell_Scope { @@Quickshell.Scope {
id: root id: root
property string time; property string time;
QS_Quickshell_Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
property var modelData property var modelData
screen: modelData screen: modelData
@ -650,17 +642,17 @@ QS_Quickshell_Scope {
} }
} }
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
id: dateProc id: dateProc
command: ["date"] command: ["date"]
running: true running: true
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
onRead: data => time = data onRead: data => time = data
} }
} }
QT_qtqml_Timer { @@QtQml.Timer {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true
@ -679,20 +671,20 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
QS_Quickshell_Scope { @@Quickshell.Scope {
property string time; property string time;
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
id: dateProc id: dateProc
command: ["date"] command: ["date"]
running: true running: true
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
onRead: data => time = data onRead: data => time = data
} }
} }
QT_qtqml_Timer { @@QtQml.Timer {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true
@ -704,14 +696,14 @@ QS_Quickshell_Scope {
```qml {filename="Bar.qml"} ```qml {filename="Bar.qml"}
import Quickshell import Quickshell
QS_Quickshell_Scope { @@Quickshell.Scope {
// the Time type we just created // the Time type we just created
Time { id: timeSource } Time { id: timeSource }
QS_Quickshell_Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
property var modelData property var modelData
screen: modelData screen: modelData
@ -751,20 +743,20 @@ import Quickshell.Io
import QtQuick import QtQuick
// your singletons should always have Singleton as the type // your singletons should always have Singleton as the type
QS_Quickshell_Singleton { @@Quickshell.Singleton {
property string time property string time
QS_Quickshell00Io_Process { @@Quickshell.Io.Process {
id: dateProc id: dateProc
command: ["date"] command: ["date"]
running: true running: true
stdout: QS_Quickshell00Io_SplitParser { stdout: @@Quickshell.Io.SplitParser {
onRead: data => time = data onRead: data => time = data
} }
} }
QT_qtqml_Timer { @@QtQml.Timer {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true
@ -776,7 +768,7 @@ QS_Quickshell_Singleton {
```qml {filename="ClockWidget.qml"} ```qml {filename="ClockWidget.qml"}
import QtQuick import QtQuick
QT__Text { @@QtQuick.Text {
// we no longer need time as an input // we no longer need time as an input
// directly access the time property from the Time singleton // directly access the time property from the Time singleton
@ -787,13 +779,13 @@ QT__Text {
```qml {filename="Bar.qml"} ```qml {filename="Bar.qml"}
import Quickshell import Quickshell
QS_Quickshell_Scope { @@Quickshell.Scope {
// no more time object // no more time object
QS_Quickshell_Variants { @@Quickshell.Variants {
model: Quickshell.screens model: Quickshell.screens
QS_Quickshell_PanelWindow { @@Quickshell.PanelWindow {
property var modelData property var modelData
screen: modelData screen: modelData
@ -830,11 +822,11 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import QtQuick import QtQuick
QS_Quickshell_Singleton { @@Quickshell.Singleton {
property var date: new Date() property var date: new Date()
property string time: date.toLocaleString(Qt.locale()) property string time: date.toLocaleString(Qt.locale())
QT_qtqml_Timer { @@QtQml.Timer {
interval: 1000 interval: 1000
running: true running: true
repeat: true repeat: true

View file

@ -32,19 +32,19 @@ page has good documentation of the basic layout types and how to use them.
## <MD_Title titleVar={2}> Manual Positioning </MD_Title> ## <MD_Title titleVar={2}> Manual Positioning </MD_Title>
If layouts and anchors can't easily fulfill your usecase, you can also manually position and size If layouts and anchors can't easily fulfill your usecase, you can also manually position and size
components by setting their `x`, `y`, `width` and `height` properties, which are relative to components by setting their @@QtQuick.Item.x, @@QtQuick.Item.y, @@QtQuick.Item.width and @@QtQuick.Item.height
the parent component. properties, which are relative to the parent component.
This example puts a 100x100px blue rectangle at x=20,y=40 in the parent item. Ensure the size This example puts a 100x100px blue rectangle at x=20,y=40 in the parent item. Ensure the size
of the parent is large enough for its content or positioning based on them will break. of the parent is large enough for its content or positioning based on them will break.
```qml ```qml
QT__Item { @@QtQuick.Item {
// make sure the component is large enough to fit its children // make sure the component is large enough to fit its children
implicitWidth: childrenRect.width implicitWidth: childrenRect.width
implicitHeight: childrenRect.height implicitHeight: childrenRect.height
QT__Rectangle { @@QtQuick.Rectangle {
color: "blue" color: "blue"
x: 20 x: 20
y: 40 y: 40
@ -58,27 +58,22 @@ QT__Item {
### <MD_Title titleVar={3}> Component Size </MD_Title> ### <MD_Title titleVar={3}> Component Size </MD_Title>
The [Item.implicitHeight] and [Item.implicitWidth] properties control the _base size_ of a The @@QtQuick.Item.implicitHeight and @@QtQuick.Item.implicitWidth properties control the
component, before layouts are applied. These properties are _not_ the same as _base size_ of a component, before layouts are applied. These properties are _not_ the same as
[Item.height] and [Item.width] which are the final size of the component. @@QtQuick.Item.height and @@QtQuick.Item.width which are the final size of the component.
You should nearly always use the implicit size properties when creating a component, You should nearly always use the implicit size properties when creating a component,
however using the normal width and height properties is fine if you know an however using the normal width and height properties is fine if you know an
item will never go in a layout. item will never go in a layout.
[Item.height]: https://doc.qt.io/qt-6/qml-qtquick-item.html#height-prop
[Item.width]: https://doc.qt.io/qt-6/qml-qtquick-item.html#width-prop
[Item.implicitHeight]: https://doc.qt.io/qt-6/qml-qtquick-item.html#implicitHeight-prop
[Item.implicitWidth]: https://doc.qt.io/qt-6/qml-qtquick-item.html#implicitWidth-prop
This example component puts a colored rectangle behind some text, and will act the same This example component puts a colored rectangle behind some text, and will act the same
way in a layout as the text by itself. way in a layout as the text by itself.
```qml {filename="TextWithBkgColor.qml"} ```qml {filename="TextWithBkgColor.qml"}
QT__Rectangle { @@QtQuick.Rectangle {
implicitWidth: text.implicitWidth implicitWidth: text.implicitWidth
implicitHeight: text.implicitHeight implicitHeight: text.implicitHeight
QT__Text { @@QtQuick.Text {
id: text id: text
text: "hello!" text: "hello!"
} }
@ -88,18 +83,18 @@ QT__Rectangle {
If you want to size your component based on multiple others or use any other math you can. If you want to size your component based on multiple others or use any other math you can.
```qml {filename="PaddedTexts.qml"} ```qml {filename="PaddedTexts.qml"}
QT__Item { @@QtQuick.Item {
// width of both texts plus 5 // width of both texts plus 5
implicitWidth: text1.implicitWidth + text2.implicitWidth + 5 implicitWidth: text1.implicitWidth + text2.implicitWidth + 5
// max height of both texts plus 5 // max height of both texts plus 5
implicitHeight: Math.min(text1.implicitHeight, text2.implicitHeight) + 5 implicitHeight: Math.min(text1.implicitHeight, text2.implicitHeight) + 5
QT__Text { @@QtQuick.Text {
id: text1 id: text1
text: "text1" text: "text1"
} }
QT__Text { @@QtQuick.Text {
id: text2 id: text2
anchors.left: text1.left anchors.left: text1.left
text: "text2" text: "text2"
@ -110,7 +105,7 @@ QT__Item {
### <MD_Title titleVar={3}> Coordinate space </MD_Title> ### <MD_Title titleVar={3}> Coordinate space </MD_Title>
You should always position or size components relative to the closest possible You should always position or size components relative to the closest possible
parent. Often this is just the `parent` property. parent. Often this is just the @@QtQuick.Item.parent property.
Refrain from using things like the size of your screen to size a component, Refrain from using things like the size of your screen to size a component,
as this will break as soon as anything up the component hierarchy changes, such as this will break as soon as anything up the component hierarchy changes, such

View file

@ -35,7 +35,7 @@ import QtQuick 6.0
import "myjs.js" as MyJs import "myjs.js" as MyJs
// Root Object // Root Object
QT__Item { @@QtQuick.Item {
// Id assignment // Id assignment
id: root id: root
@ -202,7 +202,7 @@ Expressions are snippets of javascript code assigned to a property. The last (or
can be the return value, or an explicit return statement (multiline expressions only) can be used. can be the return value, or an explicit return statement (multiline expressions only) can be used.
```qml ```qml
QT__Item { @@QtQuick.Item {
// simple expression // simple expression
property: 5 property: 5
@ -252,7 +252,7 @@ Properties can be defined inside of objects with the following syntax:
- `binding` is the property binding. See [Property bindings](#property-bindings) for details. - `binding` is the property binding. See [Property bindings](#property-bindings) for details.
```qml ```qml
QT__Item { @@QtQuick.Item {
// normal property // normal property
property int foo: 3 property int foo: 3
@ -274,12 +274,12 @@ Types can have a _default property_ which must accept either an object or a list
The default property will allow you to assign a value to it without using the name of the property: The default property will allow you to assign a value to it without using the name of the property:
```qml ```qml
QT__Item { @@QtQuick.Item {
// normal property // normal property
foo: 3 foo: 3
// this item is assigned to the outer object's default property // this item is assigned to the outer object's default property
QT__Item { @@QtQuick.Item {
} }
} }
``` ```
@ -288,16 +288,16 @@ If the default property is a list, you can put multiple objects into it the same
would put a single object in: would put a single object in:
```qml ```qml
QT__Item { @@QtQuick.Item {
// normal property // normal property
foo: 3 foo: 3
// this item is assigned to the outer object's default property // this item is assigned to the outer object's default property
QT__Item { @@QtQuick.Item {
} }
// this one is too // this one is too
QT__Item { @@QtQuick.Item {
} }
} }
``` ```
@ -308,13 +308,13 @@ Every object has a special property called `id` that can be assigned to give
the object a name it can be referred to throughout the current file. The id must be lowercase. the object a name it can be referred to throughout the current file. The id must be lowercase.
```qml ```qml
QT_qtquick11layouts_ColumnLayout { @@QtQuick.Layouts.ColumnLayout {
QT__Text { @@QtQuick.Text {
id: text id: text
text: "Hello World!" text: "Hello World!"
} }
QT_qtquick11controls_Button { @@QtQuick.Controls.Button {
text: "Make the text red"; text: "Make the text red";
onClicked: text.color = "red"; onClicked: text.color = "red";
} }
@ -344,14 +344,14 @@ The `parent` property is also defined for all objects, but may not always point
looks like it should. Use the `id` property if `parent` does not do what you want. looks like it should. Use the `id` property if `parent` does not do what you want.
```qml ```qml
QT__Item { @@QtQuick.Item {
property string rootDefinition property string rootDefinition
QT__Item { @@QtQuick.Item {
id: mid id: mid
property string midDefinition property string midDefinition
QT__Text { @@QtQuick.Text {
property string innerDefinition property string innerDefinition
// legal - innerDefinition is defined on the current object // legal - innerDefinition is defined on the current object
@ -402,19 +402,19 @@ functions, meaning if one of the properties a function depends on is re-evaluate
every expression depending on the function is also re-evaluated. every expression depending on the function is also re-evaluated.
```qml ```qml
QT_qtquick11layouts_ColumnLayout { @@QtQuick.Layouts.ColumnLayout {
property int clicks: 0 property int clicks: 0
function makeClicksLabel(): string { function makeClicksLabel(): string {
return "the button has been clicked " + clicks + " times!"; return "the button has been clicked " + clicks + " times!";
} }
QT_qtquick11controls_Button { @@QtQuick.Controls.Button {
text: "click me" text: "click me"
onClicked: clicks += 1 onClicked: clicks += 1
} }
QT__Text { @@QtQuick.Text {
text: makeClicksLabel() text: makeClicksLabel()
} }
} }
@ -450,7 +450,7 @@ Lambda syntax:
Assigning functions to properties: Assigning functions to properties:
```qml ```qml
QT__Item { @@QtQuick.Item {
// using functions // using functions
function dub(number: int): int { return number * 2; } function dub(number: int): int { return number * 2; }
property var operation: dub property var operation: dub
@ -463,7 +463,7 @@ QT__Item {
An overcomplicated click counter using a lambda callback: An overcomplicated click counter using a lambda callback:
```qml ```qml
QT_qtquick11layouts_ColumnLayout { @@QtQuick.Layouts.ColumnLayout {
property int clicks: 0 property int clicks: 0
function incrementAndCall(callback) { function incrementAndCall(callback) {
@ -471,14 +471,14 @@ QT_qtquick11layouts_ColumnLayout {
callback(clicks); callback(clicks);
} }
QT_qtquick11controls_Button { @@QtQuick.Controls.Button {
text: "click me" text: "click me"
onClicked: incrementAndCall(clicks => { onClicked: incrementAndCall(clicks => {
label.text = `the button was clicked ${clicks} time(s)!`; label.text = `the button was clicked ${clicks} time(s)!`;
}) })
} }
QT__Text { @@QtQuick.Text {
id: label id: label
text: "the button has not been clicked" text: "the button has not been clicked"
} }
@ -510,7 +510,7 @@ Signals all have a `connect(<function>)` method which invokes the given function
or signal when the signal is emitted. or signal when the signal is emitted.
```qml ```qml
QT_qtquick11layouts_ColumnLayout { @@QtQuick.Layouts.ColumnLayout {
property int clicks: 0 property int clicks: 0
function updateText() { function updateText() {
@ -518,12 +518,12 @@ QT_qtquick11layouts_ColumnLayout {
label.text = `the button has been clicked ${clicks} times!`; label.text = `the button has been clicked ${clicks} times!`;
} }
QT_qtquick11controls_Button { @@QtQuick.Controls.Button {
id: button id: button
text: "click me" text: "click me"
} }
QT__Text { @@QtQuick.Text {
id: label id: label
text: "the button has not been clicked" text: "the button has not been clicked"
} }
@ -540,9 +540,9 @@ QT_qtquick11layouts_ColumnLayout {
immediately once the object is fully initialized. immediately once the object is fully initialized.
</span> </span>
When the button is clicked, the button emits the `clicked` signal which we connected to When the button is clicked, the button emits the @@QtQuick.Controls.Button.clicked(s)
`updateText`. The signal then invokes `updateText` which updates the counter and the signal which we connected to `updateText`. The signal then invokes `updateText`
text on the label. which updates the counter and the text on the label.
##### <MD_Title titleVar={5}> Signal handlers </MD_Title> ##### <MD_Title titleVar={5}> Signal handlers </MD_Title>
@ -553,10 +553,10 @@ property implicitly defined which can be set to a function. (Note that the first
signal's name it capitalized.) signal's name it capitalized.)
Below is the same example as in [Making Connections](#making-connections), Below is the same example as in [Making Connections](#making-connections),
this time using the implicit signal handler property to handle `button.clicked`. this time using the implicit signal handler property to handle @@QtQuick.Controls.Button.clicked(s).
```qml ```qml
QT_qtquick11layouts_ColumnLayout { @@QtQuick.Layouts.ColumnLayout {
property int clicks: 0 property int clicks: 0
function updateText() { function updateText() {
@ -564,12 +564,12 @@ QT_qtquick11layouts_ColumnLayout {
label.text = `the button has been clicked ${clicks} times!`; label.text = `the button has been clicked ${clicks} times!`;
} }
QT_qtquick11controls_Button { @@QtQuick.Controls.Button {
text: "click me" text: "click me"
onClicked: updateText() onClicked: updateText()
} }
QT__Text { @@QtQuick.Text {
id: label id: label
text: "the button has not been clicked" text: "the button has not been clicked"
} }
@ -579,18 +579,18 @@ QT_qtquick11layouts_ColumnLayout {
##### <MD_Title titleVar={5}> Indirect signal handlers </MD_Title> ##### <MD_Title titleVar={5}> Indirect signal handlers </MD_Title>
When it is not possible or not convenient to directly define a signal handler, before resorting When it is not possible or not convenient to directly define a signal handler, before resorting
to `.connect`ing the properties, a [Connections] object can be used to access them. to `.connect`ing the properties, a @@QtQml.Connections object can be used to access them.
This is especially useful to connect to signals of singletons. This is especially useful to connect to signals of singletons.
```qml ```qml
QT__Item { @@QtQuick.Item {
QT_qtquick11controls_Button { @@QtQuick.Controls.Button {
id: myButton id: myButton
text "click me" text "click me"
} }
QT_qtqml_Connections { @@QtQml.Connections {
target: myButton target: myButton
function onClicked() { function onClicked() {
@ -609,8 +609,8 @@ Whenever the property is re-evaluated, its change signal is emitted. This is use
to update dependent properties, but can be directly used, usually with a signal handler. to update dependent properties, but can be directly used, usually with a signal handler.
```qml ```qml
QT_qtquick11layouts_ColumnLayout { @@QtQuick.Layouts.ColumnLayout {
CheckBox { @@QtQuick.Controls.CheckBox {
text: "check me" text: "check me"
onCheckStateChanged: { onCheckStateChanged: {
@ -618,7 +618,7 @@ QT_qtquick11layouts_ColumnLayout {
} }
} }
QT__Text { @@QtQuick.Text {
id: label id: label
text: labelText(false) text: labelText(false)
} }
@ -629,19 +629,19 @@ QT_qtquick11layouts_ColumnLayout {
} }
``` ```
In this example we listen for the `checkState` property of the CheckBox changing In this example we listen for changes to the @@QtQuick.Controls.CheckBox.checkState property of the CheckBox
using its change signal, `checkStateChanged` with the signal handler `onCheckStateChanged`. using its change signal, `checkStateChanged` with the signal handler `onCheckStateChanged`.
Since text is also a property we can do the same thing more concisely: Since text is also a property we can do the same thing more concisely:
```qml ```qml
QT_qtquick11layouts_ColumnLayout { @@QtQuick.Layouts.ColumnLayout {
CheckBox { @@QtQuick.Controls.CheckBox {
id: checkbox id: checkbox
text: "check me" text: "check me"
} }
QT__Text { @@QtQuick.Text {
id: label id: label
text: labelText(checkbox.checkState == Qt.Checked) text: labelText(checkbox.checkState == Qt.Checked)
} }
@ -655,13 +655,13 @@ QT_qtquick11layouts_ColumnLayout {
And the function can also be inlined to an expression: And the function can also be inlined to an expression:
```qml ```qml
QT_qtquick11layouts_ColumnLayout { @@QtQuick.Layouts.ColumnLayout {
CheckBox { @@QtQuick.Controls.CheckBox {
id: checkbox id: checkbox
text: "check me" text: "check me"
} }
QT__Text { @@QtQuick.Text {
id: label id: label
text: { text: {
const checked = checkbox.checkState == Qt.Checked; const checked = checkbox.checkState == Qt.Checked;
@ -682,11 +682,11 @@ tell you if it can be used as an attached object and how.
Attached objects are accessed in the form `<Typename>.<member>` and can have Attached objects are accessed in the form `<Typename>.<member>` and can have
properties, functions and signals. properties, functions and signals.
A good example is the [Component](https://doc.qt.io/qt-6/qml-qtqml-component.html) type, A good example is the @@QtQml.Component type,
which is attached to every object and often used to run code when an object initializes. which is attached to every object and often used to run code when an object initializes.
```qml ```qml
QT__Text { @@QtQuick.Text {
Component.onCompleted: { Component.onCompleted: {
text = "hello!" text = "hello!"
} }
@ -706,14 +706,14 @@ are not visible outside the file.
```qml ```qml
// MyText.qml // MyText.qml
QT__Rectangle { @@QtQuick.Rectangle {
required property string text required property string text
color: "red" color: "red"
implicitWidth: textObj.implicitWidth implicitWidth: textObj.implicitWidth
implicitHeight: textObj.implicitHeight implicitHeight: textObj.implicitHeight
QT__Text { @@QtQuick.Text {
id: textObj id: textObj
anchors.fill: parent anchors.fill: parent
text: parent.text text: parent.text
@ -721,7 +721,7 @@ QT__Rectangle {
} }
// AnotherComponent.qml // AnotherComponent.qml
QT__Item { @@QtQuick.Item {
MyText { MyText {
// The `text` property of `MyText` is required, so we must set it. // The `text` property of `MyText` is required, so we must set it.
text: "Hello World!" text: "Hello World!"
@ -748,13 +748,13 @@ of the type.
To make a type a singleton, put `pragma Singleton` at the top of the file. To make a type a singleton, put `pragma Singleton` at the top of the file.
To ensure it behaves correctly with quickshell you should also make To ensure it behaves correctly with quickshell you should also make
[Singleton](/docs/types/quickshell/singleton) the root item of your type. @@Quickshell.Singleton the root item of your type.
```qml ```qml
pragma Singleton pragma Singleton
import ... import ...
QS_Quickshell_Singleton { @@Quickshell.Singleton {
... ...
} }
``` ```
@ -785,18 +785,18 @@ A reactive binding occurs automatically when you use one or more properties in t
of another property. . of another property. .
```qml ```qml
QT__Item { @@QtQuick.Item {
property int clicks: 0 property int clicks: 0
QT_qtquick11controls_Button { @@QtQuick.Controls.Button {
text: `clicks: ${clicks}` text: `clicks: ${clicks}`
onClicked: clicks += 1 onClicked: clicks += 1
} }
} }
``` ```
In this example, the button's `text` property is re-evaluated every time the button is clicked, because In this example, the button's @@QtQuick.Controls.Button.text property is re-evaluated
the `clicks` property has changed. every time the button is clicked, because the `clicks` property has changed.
###### <MD_Title titleVar={6}> Avoiding creation </MD_Title> ###### <MD_Title titleVar={6}> Avoiding creation </MD_Title>
@ -806,10 +806,10 @@ You can use the `Component.onCompleted` signal to set a value using a property w
as assignments to properties do not create binding. as assignments to properties do not create binding.
```qml ```qml
QT__Item { @@QtQuick.Item {
property string theProperty: "initial value" property string theProperty: "initial value"
QT__Text { @@QtQuick.Text {
// text: "Right now, theProperty is: " + theProperty // text: "Right now, theProperty is: " + theProperty
Component.onCompleted: text = "At creation time, theProperty is: " + theProperty Component.onCompleted: text = "At creation time, theProperty is: " + theProperty
} }
@ -826,13 +826,13 @@ The `Qt.binding` function takes another function as an argument, and when assign
the property will use that function as its binding expression. the property will use that function as its binding expression.
```qml ```qml
QT__Item { @@QtQuick.Item {
QT__Text { @@QtQuick.Text {
id: boundText id: boundText
text: "not bound to anything" text: "not bound to anything"
} }
QT_qtquick11controls_Button { @@QtQuick.Controls.Button {
text: "bind the above text" text: "bind the above text"
onClicked: { onClicked: {
if (boundText.text == "not bound to anything") { if (boundText.text == "not bound to anything") {
@ -853,13 +853,13 @@ be updated.
To remove a binding, just assign a new value to the property without using `Qt.binding`. To remove a binding, just assign a new value to the property without using `Qt.binding`.
```qml ```qml
QT__Item { @@QtQuick.Item {
QT__Text { @@QtQuick.Text {
id: boundText id: boundText
text: `button is pressed: ${theButton.pressed}` text: `button is pressed: ${theButton.pressed}`
} }
QT_qtquick11controls_Button { @@QtQuick.Controls.Button {
id: theButton id: theButton
text: "break the binding" text: "break the binding"
onClicked: boundText.text = `button was pressed at the time the binding was broken: ${pressed}` onClicked: boundText.text = `button was pressed at the time the binding was broken: ${pressed}`
@ -876,13 +876,11 @@ it will not be updated further by the binding.
Often not all of your interface needs to load immediately. By default the QML Often not all of your interface needs to load immediately. By default the QML
engine initializes every object in the scene before showing anything onscreen. engine initializes every object in the scene before showing anything onscreen.
For parts of the interface you don't need to be immediately visible, load them For parts of the interface you don't need to be immediately visible, load them
asynchronously using a [LazyLoader](/docs/types/quickshell/lazyloader). asynchronously using a @@Quickshell.LazyLoader.
See its documentation for more information. See its documentation for more information.
#### <MD_Title titleVar={4}> Components </MD_Title> #### <MD_Title titleVar={4}> Components </MD_Title>
Another delayed loading mechanism is the [Component](https://doc.qt.io/qt-6/qml-qtqml-component.html) type. Another delayed loading mechanism is the @@QtQml.Component type.
This type can be used to create multiple instances of objects or lazily load them. It's used by types such This type can be used to create multiple instances of objects or lazily load them. It's used by types such
as [Repeater](https://doc.qt.io/qt-6/qml-qtquick-repeater.html) as @@QtQuick.Repeater and @@Quickshell.Variants to create instances of a component at runtime.
and [Quickshell.Variants](/docs/types/quickshell/variants)
to create instances of a component at runtime.