Go, Wayland, and spending too much writing time writing a tool that makes XML into HTML so you can read it without your eyes bleeding
Yes, that title is too long and I know it.
If my previous blog post didn't make it clear, I don't like dealing with XML. Obtuse to write, obtuse to read. Given that I wrote a program so that I wouldn't need to write XML for an application menu protocol, it only makes sense that I would do the same for reading Wayland protocols. And thus, ReadWay and its non-web cousin ilo Welenko were born.
Parsing the XML
If you're familiar with Wayland, you're probably familiar with the XML files you can find in /usr/share/wayland
and /usr/share/wayland-protocols
. What you may not have noticed is the /usr/share/wayland/wayland.dtd
file lurking alongside the core Wayland protocol. This is a document type definition file, which defines what a valid XML document looks like. Thankfully, this is a fairly simple DTD to write Go structures for. This DTD definition:
<!ELEMENT description (#PCDATA)>
<!ATTLIST description summary CDATA #REQUIRED>
becomes this Go code:
type Description struct {
Summary string `xml:"summary,attr"`
Body string `xml:",chardata"`
}
And this:
<!ELEMENT protocol (copyright?, description?, interface+)>
<!ATTLIST protocol name CDATA #REQUIRED>
becomes
type Protocol struct {
Name string `xml:"name,attr"`
Copyright string `xml:"copyright"`
Description Description `xml:"description"`
Interfaces []Interface `xml:"interface"`
}
Fairly simple, eh?
To unmarshal a protocol XML into a Go structure, you just xml.Unmarshal
like this:
data, err := ioutil.ReadFile(path)
// handle error
proto := Protocol{}
err = xml.Unmarshal(data, &proto)
// handle error
// do something with proto
Templates
Of course, Go structs aren't particularly easy to read for documents even compared to XML. This is when Go's html/template
package comes into play. You can throw a Protocol
and a template at it like so:
<h1>{{ .Name }} <small class="text-muted">protocol</small></h1>
<p>
{{ .Description.Body }}
</p>
{{ range $iface := .Interfaces }}
<h2>{{ $iface.Name }} <small class="text-muted">interface version {{ $iface.Version }}</small></h2>
<!-- finish rendering interfaces -->
{{ end }}
Of course, you have the more generic text/template
package, which is what ilo Welenko uses. Same concept applies:
Kirigami.Page {
title: "{{ .Name }}"
ColumnLayout {
{{ range $iface := .Interfaces }}
Kirigami.Heading {
text: "{{ $iface.Name }} version {{ $iface.Version }}"
}
{{ end }}
}
}
(And yes, I am statically generating QML code in Go and loading it instead of marshalling it into Qt data types and using model/views/repeaters.)
See Also:
- ReadWay hosted: ReadWay hosted on the internet. The “special thing that might happen when you drag an XML file onto [the] paragraph” is a Wayland protocol being rendered in your browser using WASM. The future is now. And it don't need no cookies.
- ReadWay source: The static generator for ReadWay.
- ilo Welenko: The desktop counterpart to ReadWay that renders into QML rather than HTML. At the time of this post, it's very incomplete compared to the web version.
Contact Me
Have any thoughts/comments/concerns about this post, or want to tell me that I shouldn't statically render QML? Here's how you can contact me:
- Telegram:
@pontaoski
- Discord:
pontaoski blackquill 🏳🌈#8758
- Matrix:
pontaoski@tchnics.de
- IRC:
appadeia_
- Email:
uhhadd@gmail.com
Tags: #libre