From d010a1c7ad683ca40b2eb978ef0535a40c7dc17a Mon Sep 17 00:00:00 2001
From: Thomas Voss <mail@thomasvoss.com>
Date: Thu, 5 Oct 2023 22:10:51 +0200
Subject: Add a new post on GSP

---
 src/srp/gsp/abbr.m4.gsp        |   1 +
 src/srp/gsp/example.gsp.gsp    |  11 ++
 src/srp/gsp/folds.scm.gsp      |   4 +
 src/srp/gsp/grammar.js.gsp     |  12 ++
 src/srp/gsp/highlights.scm.gsp |   9 ++
 src/srp/gsp/index.gsp          | 310 +++++++++++++++++++++++++++++++++++++++++
 src/srp/gsp/markdown.md.gsp    |   3 +
 src/srp/gsp/pug.pug.gsp        |   8 ++
 src/srp/index.gsp              |   1 +
 9 files changed, 359 insertions(+)
 create mode 100644 src/srp/gsp/abbr.m4.gsp
 create mode 100644 src/srp/gsp/example.gsp.gsp
 create mode 100644 src/srp/gsp/folds.scm.gsp
 create mode 100644 src/srp/gsp/grammar.js.gsp
 create mode 100644 src/srp/gsp/highlights.scm.gsp
 create mode 100644 src/srp/gsp/index.gsp
 create mode 100644 src/srp/gsp/markdown.md.gsp
 create mode 100644 src/srp/gsp/pug.pug.gsp

(limited to 'src/srp')

diff --git a/src/srp/gsp/abbr.m4.gsp b/src/srp/gsp/abbr.m4.gsp
new file mode 100644
index 0000000..48626e0
--- /dev/null
+++ b/src/srp/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/srp/gsp/example.gsp.gsp b/src/srp/gsp/example.gsp.gsp
new file mode 100644
index 0000000..7f30bf0
--- /dev/null
+++ b/src/srp/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/srp/gsp/folds.scm.gsp b/src/srp/gsp/folds.scm.gsp
new file mode 100644
index 0000000..8c7cb61
--- /dev/null
+++ b/src/srp/gsp/folds.scm.gsp
@@ -0,0 +1,4 @@
+[
+ (@span .fn{-node})
+ (@span .fn{-attribute_list})
+] @span .var{-\@fold}
diff --git a/src/srp/gsp/grammar.js.gsp b/src/srp/gsp/grammar.js.gsp
new file mode 100644
index 0000000..278fff0
--- /dev/null
+++ b/src/srp/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/srp/gsp/highlights.scm.gsp b/src/srp/gsp/highlights.scm.gsp
new file mode 100644
index 0000000..37f445e
--- /dev/null
+++ b/src/srp/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/srp/gsp/index.gsp b/src/srp/gsp/index.gsp
new file mode 100644
index 0000000..1ff3686
--- /dev/null
+++ b/src/srp/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-poluting 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 targetting just makes
+				everyones 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 sematic 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 classses 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.  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 annotions
+				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 anyones 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/srp/gsp/markdown.md.gsp b/src/srp/gsp/markdown.md.gsp
new file mode 100644
index 0000000..3d5f51a
--- /dev/null
+++ b/src/srp/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/srp/gsp/pug.pug.gsp b/src/srp/gsp/pug.pug.gsp
new file mode 100644
index 0000000..ac3e026
--- /dev/null
+++ b/src/srp/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
diff --git a/src/srp/index.gsp b/src/srp/index.gsp
index da62301..f829644 100644
--- a/src/srp/index.gsp
+++ b/src/srp/index.gsp
@@ -29,6 +29,7 @@ html lang="en" {
 			p {-Posts:}
 
 			ul {
+				li {a href="gsp" {-Writing an HTML Preprocessor (feat. Tree-Sitter)}}
 				li {a href="fw-ec" {-Patching My Laptop’s Embedded Controller}}
 			}
 		}
-- 
cgit v1.2.3