diff options
Diffstat (limited to 'src/blog/gsp')
-rw-r--r-- | src/blog/gsp/abbr.m4.gsp | 1 | ||||
-rw-r--r-- | src/blog/gsp/example.gsp.gsp | 11 | ||||
-rw-r--r-- | src/blog/gsp/folds.scm.gsp | 4 | ||||
-rw-r--r-- | src/blog/gsp/grammar.js.gsp | 12 | ||||
-rw-r--r-- | src/blog/gsp/highlights.scm.gsp | 9 | ||||
-rw-r--r-- | src/blog/gsp/index.gsp | 310 | ||||
-rw-r--r-- | src/blog/gsp/markdown.md.gsp | 3 | ||||
-rw-r--r-- | src/blog/gsp/pug.pug.gsp | 8 |
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 |