summaryrefslogtreecommitdiffhomepage
path: root/src/blog/gsp
diff options
context:
space:
mode:
Diffstat (limited to 'src/blog/gsp')
-rw-r--r--src/blog/gsp/abbr.m4.gsp1
-rw-r--r--src/blog/gsp/example.gsp.gsp11
-rw-r--r--src/blog/gsp/folds.scm.gsp4
-rw-r--r--src/blog/gsp/grammar.js.gsp12
-rw-r--r--src/blog/gsp/highlights.scm.gsp9
-rw-r--r--src/blog/gsp/index.gsp310
-rw-r--r--src/blog/gsp/markdown.md.gsp3
-rw-r--r--src/blog/gsp/pug.pug.gsp8
8 files changed, 358 insertions, 0 deletions
diff --git a/src/blog/gsp/abbr.m4.gsp b/src/blog/gsp/abbr.m4.gsp
new file mode 100644
index 0000000..99ac1d7
--- /dev/null
+++ b/src/blog/gsp/abbr.m4.gsp
@@ -0,0 +1 @@
+@span .fn {-⁨m4_define⁩}(⁨m4_abbr⁩, `\@abbr .@span .fn {-⁨m4_translit⁩}(@span .var {-$1}, A-Z, a-z) {-@span .var {-$1}\}')
diff --git a/src/blog/gsp/example.gsp.gsp b/src/blog/gsp/example.gsp.gsp
new file mode 100644
index 0000000..7f30bf0
--- /dev/null
+++ b/src/blog/gsp/example.gsp.gsp
@@ -0,0 +1,11 @@
+@span .gsp-node {-html} @span .gsp-attr {-lang}@span .gsp-op {-=}@span .gsp-val {-"en"} @span .gsp-op {-{}
+ @span .gsp-node {-body} @span .gsp-op {-{}
+ @span .gsp-node {-p} @span .gsp-op {-{-} Hello, World!@span .gsp-op {-\}}
+
+ @span .gsp-node {-ul} @span .gsp-op {-{}
+ @span .gsp-node {-li} @span .gsp-op {-{}@span .gsp-node {-a} @span .gsp-attr {-href}@span .gsp-op {-=}@span .gsp-val {-"#"} @span .gsp-attr {-#home} @span .gsp-op {-{-}Home Page@span .gsp-op {-\}\}}
+ @span .gsp-node {-li} @span .gsp-op {-{}@span .gsp-node {-a} @span .gsp-attr {-href}@span .gsp-op {-=}@span .gsp-val {-"#"} @span .gsp-attr {-#about} @span .gsp-op {-{-}About Me@span .gsp-op {-\}\}}
+ @span .gsp-node {-li} @span .gsp-op {-{}@span .gsp-node {-a} @span .gsp-attr {-href}@span .gsp-op {-=}@span .gsp-val {-"#"} @span .gsp-attr {-#links} @span .gsp-op {-{-}Fun Links@span .gsp-op {-\}\}}
+ @span .gsp-op {-\}}
+ @span .gsp-op {-\}}
+@span .gsp-op {-\}}
diff --git a/src/blog/gsp/folds.scm.gsp b/src/blog/gsp/folds.scm.gsp
new file mode 100644
index 0000000..fb8ce45
--- /dev/null
+++ b/src/blog/gsp/folds.scm.gsp
@@ -0,0 +1,4 @@
+[
+ (@span .fn {-node})
+ (@span .fn {-attribute_list})
+] @span .var {-\@fold}
diff --git a/src/blog/gsp/grammar.js.gsp b/src/blog/gsp/grammar.js.gsp
new file mode 100644
index 0000000..7a06e7f
--- /dev/null
+++ b/src/blog/gsp/grammar.js.gsp
@@ -0,0 +1,12 @@
+{
+ @span .var {-node}: @span .var {-$} => @span .fn {-seq}(
+ @span .fn {-optional}('>'),
+ @span .var {-$.node_name},
+ @span .fn {-optional}(@span .var {-$.attribute_list}),
+ @span .str {-'{'},
+ @span .fn {-optional}(@span .var {-$.node_body}),
+ @span .str {-'\}'},
+ ),
+
+ @span .var {-node_name}: @span .var {-$} => @span .str {-/[a-zA-Z:_][a-zA-Z0-9:_\\-​.]*​/},
+\}
diff --git a/src/blog/gsp/highlights.scm.gsp b/src/blog/gsp/highlights.scm.gsp
new file mode 100644
index 0000000..6deeb8a
--- /dev/null
+++ b/src/blog/gsp/highlights.scm.gsp
@@ -0,0 +1,9 @@
+[@span .str {-">"} @span .str {-"-"} @span .str {-"="} @span .str {-"\@"}] @span .var {-\@operator}
+[@span .str {-"{"} @span .str {-"\}"}] @span .var {-\@tag.delimiter}
+(@span .fn {-node_name}) @span .var {-\@tag}
+[
+ (@span .fn {-attribute_name})
+ (@span .fn {-class_shorthand})
+ (@span .fn {-id_shorthand})
+] @span .var {-\@tag.attribute}
+(@span .fn {-attribute_value}) @span .var {-\@string}
diff --git a/src/blog/gsp/index.gsp b/src/blog/gsp/index.gsp
new file mode 100644
index 0000000..8c56883
--- /dev/null
+++ b/src/blog/gsp/index.gsp
@@ -0,0 +1,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 }
+ }
+}
diff --git a/src/blog/gsp/markdown.md.gsp b/src/blog/gsp/markdown.md.gsp
new file mode 100644
index 0000000..3d5f51a
--- /dev/null
+++ b/src/blog/gsp/markdown.md.gsp
@@ -0,0 +1,3 @@
+@span .md-delim {-#} @span .md-head {-Markdown 4 Lyfe}
+
+Welcome to my website written in Hugo!
diff --git a/src/blog/gsp/pug.pug.gsp b/src/blog/gsp/pug.pug.gsp
new file mode 100644
index 0000000..de816e3
--- /dev/null
+++ b/src/blog/gsp/pug.pug.gsp
@@ -0,0 +1,8 @@
+@span .pug-node {-div}
+ @span .pug-node {-p}
+ @span .pug-cont {-|} Hello world! This is a
+ @span .pug-cont {-|} multiline paragraph.
+ @span .pug-node {-ul}
+ @span .pug-node {-li} foo
+ @span .pug-node {-li} bar
+ @span .pug-node {-li} baz