1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
|
html lang="en" {
head { m4_include(head.gsp) }
body {
header {
div {
h1 {-Never Settle For Trash}
m4_include(nav.gsp)
}
figure .quote {
blockquote {
p {=
🚨🚨 BREAKING: TYPESCRIPT SNATCHES DEFEAT FROM THE JAWS OF VICTORY
🚨🚨
}
}
figcaption {-Lane Wagner}
}
}
main {
h2 {-Table of Contents}
ul {
li {a href="#simple" {-Simplicity and Abstraction}}
li {a href="#sucks" {-Most Software Sucks}}
li {a href="#solution" {-My Solution}}
li {a href="#syntax" {-Syntax Highlighting}}
li {a href="#takeaway" {-The Takeaway}}
}
h2 #simple {-Simplicity and Abstraction}
p {-
I like my software simple and devoid of useless abstraction. I often
find myself in positions where I’m searching for scissors to cut a sheet
of paper, and am instead greeted with a chainsaw. The urge to
over-complicate and -abstract your software can be strong; I often see
people who preach simple software writing programs to solve basic
problems that have 30 different command-line flags, and require a 50
page m4_abbr(PDF) explaining its operation.
}
p {-
Why do I mention all of this? Well as anyone who’s ever tried their
hand at web-development knows, websites are written in m4_abbr(HTML). I
wish I could say that’s a good thing, but as anyone who’s ever looked at
m4_abbr(HTML) before would know, that language is — to put it lightly —
really not great. It’s extremely verbose, and awkward to write- and
edit (angle brackets are not the easiest-to-reach keys on the keyboard).
}
p {-
So what’s the solution? The most obvious to me is to create a nicer to
read- and write language which I can easily transpile down to
m4_abbr(HTML). Ideally the m4_abbr(CLI) is very simple and works on the
standard input and -output like all good UNIX utilities. I should be
able to transpile my site by simply running ‘@code{-cmd in.xyz
out.html}’, where my input reflects the structure of my output will
nicer, less-polluting syntax such as in ‘@code{-div .cls { … \}}’.
}
p {-
The kind of tool I am describing here is what I imagine the ideal
solution to be. A @em{-simple} tool with a @em{-simple} function. It
takes an input language and produces an output language. There is also
minimal abstraction. The input language should reflect the structure of
m4_abbr(HTML), because that’s exactly what we’re trying to output. It
makes little sense to create a fundamentally different language when
m4_abbr(HTML) not only does a good job at defining a websites structure,
but sticking close to the language we are targeting just makes
everyone’s life easier in every way.
}
h2 #sucks {-Most Software Sucks}
p {-
So with my ideal solution being a simple language with a simple
m4_abbr(CLI) that sticks close to the structure of m4_abbr(HTML), let’s
take a look at what other people have come up with:
}
figure {
pre { m4_fmt_code(markdown.md.gsp) }
}
p {- Oh no.}
p {-
Now most readers probably had the initial reaction of “@em{-What’s wrong
with Markdown?}”. To answer your question: everything. The issue I
have with these highly-prevalent Markdown-based replacements for
m4_abbr(HTML) is that they ignore the fundamental fact that
m4_abbr(HTML) and Markdown are @em{-not} compatible languages with each
other. m4_abbr(HTML) is designed around making websites (with the added
autism of m4_abbr(XML)). It gives us things like semantic tags for
describing input forms, navigation bars, figures, and more. With the
addition of classes and IDs, we can even style two paragraphs on the
same page in different ways. This is fundamentally not possible in
Markdown. If we ignore the fact that Markdown is just poorly designed,
it offers us basically none of what we need to make an even
slightly-complex static page as it’s not meant for website-design but
simply to be a readable plain-text format you can use for documentation
or your email or something.
}
p {-
How do you make your navigation bar in Markdown? Or style two
paragraphs differently? You can’t. Some try to get around this by
adding extensions to the Markdown language, but they never manage to
cover all bases. Another problem I @em{-always} come across when trying
to use Markdown-to-m4_abbr(HTML) tools is code blocks. I always make
sure to use tabs for indentation in my code blocks instead of spaces, so
that I can vary the tab-width based on the screen size of the reader.
You obviously can’t do this with spaces since the fundamental (and
retarded) purpose of space-indentation is to force everyone to view code
with the same indentation, which sucks for users on mobile when you have
nice large indents. To this day I have yet to find a
Markdown-to-m4_abbr(HTML) converter that will let me have tab indents
without error-prone post-processing of the generated m4_abbr(HTML).
}
p {-
Ok well… there are other ways of generating m4_abbr(HTML); one rather
popular option is Pug:
}
figure {
pre .pug { m4_fmt_code(pug.pug.gsp) }
}
p {-
While Pug certainly hits the ‘maintain the same structure’ point right
on the head, it fails in one very crucial area — it’s a JavaScript
library @em{-only}, and so requires a whole m4_abbr(JS) setup simply to
transpile your site to m4_abbr(HTML). What a bummer. There is also a
second issue which is that it uses an indentation-sensitive syntax.
Normally I am actually a fan of languages like this — such as Python —
but in the case of a markup language like Pug, this is terrible as it
makes macros and templating with tools such as @code{-m4} exceptionally
difficult. Pug @em{-does} offer templating faculties via JavaScript,
but I really try to minimize the amount of JavaScript I need to write
whenever possible.
}
h2 #solution {-My Solution}
p {-
So with no existing tools fitting my entry criteria, I did the only
reasonable next thing and made my own tool. It tries to stick to the
format of m4_abbr(HTML) as closely as possible while offering an
@em{-extremely} easy-to-use transpiler. It also has no added bullshit
like filters, templates, etc. If you want macros, use a macro-processor
like @code{-m4}. I called it m4_abbr(GSP) because everyone knows that
German Shorthaired Pointers are better than pugs. Here is a quick
syntax example:
}
figure {
pre .gsp { m4_fmt_code(example.gsp.gsp) }
}
p {-
Here you can see almost all of m4_abbr(GSP). The document follows the
same structure as m4_abbr(HTML), but thanks to the use of braces instead
of opening- and closing tags, the syntax is far less verbose and easier
to read. The language also provides shorthands for classes and IDs
through m4_abbr(CSS)-selector syntax.
}
p {-
Templating and macros are also very easy via macro processors thanks to
the use of braces instead of whitespace-based scoping. You may have
noticed that I like to make use of abbreviations on this website that
expand when hovered over (unless you’re on mobile, in which case you
might not see them). I do this via the m4_abbr(HTML) @code{-<abbr>}
tag, providing the appropriate class. For example, many times on this
very page I’ve made use of @code{-\@abbr .html {-HTML\}}. Obviously
repeating that everywhere in my document can be quite annoying, so I’ve
gotten around this by making use of the following @code{-m4} macro:
}
figure {
pre { m4_fmt_code(abbr.m4.gsp) }
}
p {-
I can then insert abbreviations by simply writing something along the
lines of ‘@code{-m4_abbr(HTML)}’ in my document.
}
aside {
p {-
The first thing I did after finishing the transpiler was to rewrite
this entire site in m4_abbr(GSP). There is something that just feels
so great about writing a tool that you actually use in your day-to-day
life.
}
}
p {-
The transpiler itself is also incredibly easy to use, something
JavaScript developers would never be able to comprehend. In order to
transpile a m4_abbr(GSP) document into an m4_abbr(HTML) document, I
simply run ‘@code{-gsp index.gsp >index.html}’. Yep, that’s it.
}
h2 #syntax {-Syntax Highlighting}
p {-
One problem that I came across writing m4_abbr(GSP) was the lack of
syntax highlighting. It can seem not so important, but syntax
highlighting is crucial for helping you quickly identify different
syntax elements. The awesome solution I found for this ended being
Tree-Sitter. Tree-Sitter is a parser-generator that various text
editors such as Vim and Emacs can integrate with to offer efficient- and
high quality syntax highlighting, amongst other features such as
syntax-aware code folding and movement.
}
p {-
After a bit of research and reading the documentation, I found that
creating your own parsers is actually really easy. You effectively just
define a JavaScript object that describes the language grammar, and a C
parser is generated from that. If you’re interested, you can find the
m4_abbr(GSP) parser @a href="https://git.sr.ht/~mango/tree-sitter-gsp"
{-here}. To give you a bit of an idea of just how simple a Tree-Sitter
parser is, here’s a simplified example of how you describe the
definition of a node, and a node name @x-ref{-1}:
}
figure {
pre .js { m4_fmt_code(grammar.js.gsp) }
}
aside {
p data-ref="1" {-
The definition for what constitutes a node name is simplified in the
example. In actuality node names can contain all sorts of unicode
characters too (because m4_abbr(XML) said so), but I would like the
regex to actually fit on the screen.
}
}
p {-
As you can see, the grammar syntax is extremely simple. You simply
define your core syntax elements via regular expressions, and then
compose them together via helper functions such as @code{-optional} and
@code{-repeat} to define the full structure of your language.
}
p {-
This isn’t enough though. We now have a parser for our language that
can create a syntax tree that our editor can take advantage of, but our
editor still doesn’t know what each node actually @em{-is} so that it
can be syntax highlighted properly. Tree Sitter solves this through a
query file written in Scheme where we can describe how to syntax
highlight our m4_abbr(AST). This is what the configuration for
m4_abbr(GSP) looks like:
}
figure {
figcaption {
code {-queries/highlights.scm}
}
pre { m4_fmt_code(highlights.scm.gsp) }
}
p {-
As you can see, this is all really simple stuff, which is what I love so
much about Tree Sitter — it’s just so easy! With these basic
annotations your editor knows that attribute values should be
highlighted like strings, braces like tag delimiters, etc. In a similar
vein, writing a query to describe code-folding is really easy:
}
figure {
figcaption {
code {-queries/folds.scm}
}
pre { m4_fmt_code(folds.scm.gsp) }
}
h2 #takeaway {-The Takeaway}
p {-
So what’s the takeaway? I think it’s that when you have a problem,
often times the best solution is not to fundamentally redesign something
from the ground up, or to completely change the way a system works, but
to instead identify the specific thing that annoys you and find a fix
for it. I thought that the syntax of m4_abbr(HTML) was annoying and
bad, so I found a solution for the syntax, while keeping the core
structure the same. In the same line of thinking, try not to
over-abstract — I’m looking at you, Java developers. Abstraction often
leads to exponentially increased complications the moment we want to do
anything different or out of the ordinary, so unless you can find a
really nice abstraction that doesn’t really make anyone’s life harder,
try to avoid them when you can.
}
p {-
If you’re interested in m4_abbr(GSP), you can find the git repository
over at @a href="https://git.sr.ht/~mango/gsp" {-Sourcehut}.
}
}
hr{}
footer { m4_footer }
}
}
|