summaryrefslogtreecommitdiffhomepage
path: root/src/blog
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2023-11-14 10:03:19 +0100
committerThomas Voss <mail@thomasvoss.com> 2023-11-14 10:08:19 +0100
commit234a47f69f0957bf3e3d268749b01e112d53bb6c (patch)
treeb6da59bc4d1bc9e93c0b0631042949bfd7ac02bc /src/blog
parent09e860d5a1e30901327aadb6bdfa0ee6afb00277 (diff)
Move /srp to /blog
Diffstat (limited to 'src/blog')
-rw-r--r--src/blog/fw-ec/1172.pngbin0 -> 17531 bytes
-rw-r--r--src/blog/fw-ec/fn-lock-1.diff.gsp12
-rw-r--r--src/blog/fw-ec/fn-lock-2.diff.gsp36
-rw-r--r--src/blog/fw-ec/hybrid.diff.gsp88
-rw-r--r--src/blog/fw-ec/index.gsp229
-rw-r--r--src/blog/fw-ec/kbd-sc-cb.c.gsp6
-rw-r--r--src/blog/fw-ec/led.diff.gsp32
-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
-rw-r--r--src/blog/index.gsp40
16 files changed, 801 insertions, 0 deletions
diff --git a/src/blog/fw-ec/1172.png b/src/blog/fw-ec/1172.png
new file mode 100644
index 0000000..14b3be1
--- /dev/null
+++ b/src/blog/fw-ec/1172.png
Binary files differ
diff --git a/src/blog/fw-ec/fn-lock-1.diff.gsp b/src/blog/fw-ec/fn-lock-1.diff.gsp
new file mode 100644
index 0000000..f847e41
--- /dev/null
+++ b/src/blog/fw-ec/fn-lock-1.diff.gsp
@@ -0,0 +1,12 @@
+@span .diff-meta {-diff --git a/board/hx20/board.h b/board/hx20/board.h}
+@span .diff-meta {-index 7b4ea288a..cfc6a61a2 100644}
+@span .diff-meta {---- a/board/hx20/board.h}
+@span .diff-meta {-+++ b/board/hx20/board.h}
+@span .diff-loc {-\@\@ -218,7 +218,6 \@\@}
+ #define CONFIG_CMD_LEDTEST
+ #define CONFIG_LED_PWM_COUNT 3
+ #define CONFIG_LED_PWM_TASK_DISABLED
+@span .diff-del {--#define CONFIG_CAPSLED_SUPPORT}
+
+ #ifdef CONFIG_ACCEL_KX022
+ #define CONFIG_LID_ANGLE
diff --git a/src/blog/fw-ec/fn-lock-2.diff.gsp b/src/blog/fw-ec/fn-lock-2.diff.gsp
new file mode 100644
index 0000000..7f9e702
--- /dev/null
+++ b/src/blog/fw-ec/fn-lock-2.diff.gsp
@@ -0,0 +1,36 @@
+@span .diff-meta {-diff --git a/board/hx20/keyboard_customization.c b/board/hx20/keyboard_customization.c}
+@span .diff-meta {-index 2b91f2e0c..9a5050a0f 100644}
+@span .diff-meta {---- a/board/hx20/keyboard_customization.c}
+@span .diff-meta {-+++ b/board/hx20/keyboard_customization.c}
+@span .diff-loc {-\@\@ -249,6 +249,23 \@\@ int fn_table_set(int8_t pressed, uint32_t fn_bit)}
+ return false;
+ \}
+
+@span .diff-ins {-+static void hx20_update_fnkey_led(void) {}
+@span .diff-ins {-+ /* Turn the capslock light into a fn-lock light */}
+@span .diff-ins {-+ gpio_set_level(GPIO_CAP_LED_L, (Fn_key & FN_LOCKED) ? 1 : 0);}
+@span .diff-ins {-+\}}
+@span .diff-ins {-+}
+@span .diff-ins {-+/* Set the fn-lock light to the correct setting when the system resumes */}
+@span .diff-ins {-+void hx20_fnkey_resume(void) {}
+@span .diff-ins {-+ hx20_update_fnkey_led();}
+@span .diff-ins {-+\}}
+@span .diff-ins {-+DECLARE_HOOK(HOOK_CHIPSET_RESUME, hx20_fnkey_resume, HOOK_PRIO_DEFAULT);}
+@span .diff-ins {-+}
+@span .diff-ins {-+/* Disable the fn-lock light on suspend */}
+@span .diff-ins {-+void hx20_fnkey_suspend(void) {}
+@span .diff-ins {-+ gpio_set_level(GPIO_CAP_LED_L, 0);}
+@span .diff-ins {-+\}}
+@span .diff-ins {-+DECLARE_HOOK(HOOK_CHIPSET_SUSPEND, hx20_fnkey_suspend, HOOK_PRIO_DEFAULT);}
+@span .diff-ins {-+}
+ void fnkey_shutdown(void) {
+ uint8_t current_kb = 0;
+
+@span .diff-loc {-\@\@ -420,6 +437,7 \@\@ int functional_hotkey(uint16_t *key_code, int8_t pressed)}
+ Fn_key &= ~FN_LOCKED;
+ else
+ Fn_key |= FN_LOCKED;
+@span .diff-ins {-+ hx20_update_fnkey_led();}
+ \}
+ return EC_ERROR_UNIMPLEMENTED;
+ \}
diff --git a/src/blog/fw-ec/hybrid.diff.gsp b/src/blog/fw-ec/hybrid.diff.gsp
new file mode 100644
index 0000000..dfd4518
--- /dev/null
+++ b/src/blog/fw-ec/hybrid.diff.gsp
@@ -0,0 +1,88 @@
+@span .diff-meta {-diff --git a/board/hx20/keyboard_customization.c b/board/hx20/keyboard_customization.c}
+@span .diff-meta {-index 9a5050a0f..2756f17ce 100644}
+@span .diff-meta {---- a/board/hx20/keyboard_customization.c}
+@span .diff-meta {-+++ b/board/hx20/keyboard_customization.c}
+@span .diff-loc {-\@\@ -22,12 +22,15 \@\@}
+ #define CPRINTS(format, args...) cprints(CC_KEYBOARD, format, ## args)
+ #define CPRINTF(format, args...) cprintf(CC_KEYBOARD, format, ## args)
+
+@span .diff-ins {-+/* The scancode for the caps-lock key, which is now a hybrid key */}
+@span .diff-ins {-+#define SCANCODE_CTRL_ESC 0x0101}
+@span .diff-ins {-+}
+ uint16_t scancode_set2[KEYBOARD_COLS_MAX][KEYBOARD_ROWS] = {
+ {0x0021, 0x007B, 0x0079, 0x0072, 0x007A, 0x0071, 0x0069, 0xe04A\},
+ {0xe071, 0xe070, 0x007D, 0xe01f, 0x006c, 0xe06c, 0xe07d, 0x0077\},
+ {0x0015, 0x0070, 0x00ff, 0x000D, 0x000E, 0x0016, 0x0067, 0x001c\},
+ {0xe011, 0x0011, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000\},
+@span .diff-del {-- {0xe05a, 0x0029, 0x0024, 0x000c, 0x0058, 0x0026, 0x0004, 0xe07a\},}
+@span .diff-ins {-+ {0xe05a, 0x0029, 0x0024, 0x000c, 0x0101, 0x0026, 0x0004, 0xe07a\},}
+ {0x0022, 0x001a, 0x0006, 0x0005, 0x001b, 0x001e, 0x001d, 0x0076\},
+ {0x002A, 0x0032, 0x0034, 0x002c, 0x002e, 0x0025, 0x002d, 0x002b\},
+ {0x003a, 0x0031, 0x0033, 0x0035, 0x0036, 0x003d, 0x003c, 0x003b\},
+@span .diff-loc {-\@\@ -497,6 +500,55 \@\@ int functional_hotkey(uint16_t *key_code, int8_t pressed)}
+ return EC_SUCCESS;
+ \}
+
+@span .diff-ins {-+int try_ctrl_esc(uint16_t *key_code, int8_t pressed) {}
+@span .diff-ins {-+ static enum {}
+@span .diff-ins {-+ NONE,}
+@span .diff-ins {-+ HELD,}
+@span .diff-ins {-+ CTRL}
+@span .diff-ins {-+ \} ctrl_esc_state;}
+@span .diff-ins {-+}
+@span .diff-ins {-+ if (*key_code == SCANCODE_CTRL_ESC) {}
+@span .diff-ins {-+ /* If we pressed the caps key, enter the HELD state. Otherwise,}
+@span .diff-ins {-+ * we are either releasing from the HELD state or the CTRL}
+@span .diff-ins {-+ * state. In both cases we should reset the state to NONE, but}
+@span .diff-ins {-+ * when releasing from the HELD state we want to send an ESC and}
+@span .diff-ins {-+ * when releasing from the CTRL state we want to end the CTRL.}
+@span .diff-ins {-+ *}
+@span .diff-ins {-+ * Also important to note is that even before we know if we’re}
+@span .diff-ins {-+ * going to be acting as ESC or CTRL, we need to send a press-}
+@span .diff-ins {-+ * event of the CTRL key because you can chord CTRL with mouse-}
+@span .diff-ins {-+ * clicks too, not just other keys.}
+@span .diff-ins {-+ */}
+@span .diff-ins {-+ if (pressed) {}
+@span .diff-ins {-+ ctrl_esc_state = HELD;}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_LEFT_CTRL, 1);}
+@span .diff-ins {-+ \} else if (ctrl_esc_state == HELD) {}
+@span .diff-ins {-+ ctrl_esc_state = NONE;}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_LEFT_CTRL, 0);}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_ESC, 1);}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_ESC, 0);}
+@span .diff-ins {-+ \} else if (ctrl_esc_state == CTRL) {}
+@span .diff-ins {-+ ctrl_esc_state = NONE;}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_LEFT_CTRL, 0);}
+@span .diff-ins {-+ \}}
+@span .diff-ins {-+}
+@span .diff-ins {-+ return EC_ERROR_UNIMPLEMENTED;}
+@span .diff-ins {-+ \}}
+@span .diff-ins {-+}
+@span .diff-ins {-+ /* If we get here then we are dealing with a key that isn’t the caps}
+@span .diff-ins {-+ * key. In that case we need to handle all 3 states. If the state is}
+@span .diff-ins {-+ * NONE then we can just exit from this function. If it’s HELD and we}
+@span .diff-ins {-+ * are pressing a key, then that’s a key-chord and we need to start a}
+@span .diff-ins {-+ * CTRL. Finally, if we are in the CTRL state, there is nothing to do.}
+@span .diff-ins {-+ */}
+@span .diff-ins {-+ if (ctrl_esc_state == HELD && pressed) {}
+@span .diff-ins {-+ ctrl_esc_state = CTRL;}
+@span .diff-ins {-+ simulate_keyboard(SCANCODE_LEFT_CTRL, 1);}
+@span .diff-ins {-+ \}}
+@span .diff-ins {-+}
+@span .diff-ins {-+ return EC_SUCCESS;}
+@span .diff-ins {-+\}}
+@span .diff-ins {-+}
+ enum ec_error_list keyboard_scancode_callback(uint16_t *make_code,
+ int8_t pressed)
+ {
+@span .diff-loc {-\@\@ -521,6 +573,10 \@\@ enum ec_error_list keyboard_scancode_callback(uint16_t *make_code,}
+ if (!pos_get_state())
+ return EC_SUCCESS;
+
+@span .diff-ins {-+ r = try_ctrl_esc(make_code, pressed);}
+@span .diff-ins {-+ if (r != EC_SUCCESS)}
+@span .diff-ins {-+ return r;}
+@span .diff-ins {-+}
+ r = hotkey_F1_F12(make_code, Fn_key, pressed);
+ if (r != EC_SUCCESS)
+ return r;
diff --git a/src/blog/fw-ec/index.gsp b/src/blog/fw-ec/index.gsp
new file mode 100644
index 0000000..acd39b9
--- /dev/null
+++ b/src/blog/fw-ec/index.gsp
@@ -0,0 +1,229 @@
+html lang="en" {
+ head { m4_include(head.gsp) }
+ body {
+ header {
+ div {
+ h1 {-Framework is Awesome}
+ m4_include(nav.gsp)
+ }
+
+ figure .quote {
+ blockquote {
+ p {=
+ UNIX was not designed to stop its users from doing stupid things, as
+ that would also stop them from doing clever things.
+ }
+ }
+ figcaption {-Doug Gywn}
+ }
+ }
+
+ main {
+ h2 {-Table of Contents}
+
+ ul {
+ li {a href="#framework" {-Framework and the EC}}
+ li {a href="#led" {-LED Fun!}}
+ li {a href="#more" {-There’s More Than One LED‽}}
+ li {a href="#hybrid" {-The Hybrid Key}}
+ li {a href="#next" {-What’s Next?}}
+ }
+
+ h2 #framework {-Framework and the m4_abbr(EC)}
+ p {-
+ @a href="https://frame.work" target="_blank" {-Framework}
+ — for those unaware — is the coolest laptop manufacturer ever. Their
+ whole @em{-shtick} is producing laptops that give the user the ability
+ to easily and effortlessly disassemble, repair, and modify their
+ hardware. I highly suggest checking them out if you’re interested in
+ computer hardware at all. The laptops even have hotswappable I/O!
+ }
+
+ p {-
+ Anyways getting back on topic, Framework has also been giving power to
+ the user on the software-side of things too! A good while ago they
+ open-sourced the
+ @a
+ href="https://github.com/FrameworkComputer/EmbeddedController"
+ target="_blank"
+ {-code for the embedded controller}
+ of their laptops, which offers all sorts of possibilities for
+ customization of the keyboard, m4_abbr(LED) lights, and more.
+ }
+
+ h2 #led {-m4_abbr(LED) Fun!}
+ p {-
+ This is an area of the m4_abbr(EC) which I have not really looked at or
+ touched much. I do want to play around with this a lot more in the
+ coming future though! So far just for shits-and-giggles, I’ve patched
+ the m4_abbr(EC) to make the power-button m4_abbr(LED) green instead of
+ the normal boring white:
+ }
+
+ aside {
+ p {-
+ Just a tip: if you want to try any of these patches out,
+ simply copy the diffs and paste them
+ into @code {-git apply}.
+ }
+ }
+
+ figure {
+ figcaption {
+ code {-~/board/hx20/led.c}
+ }
+ pre {= m4_fmt_code(led.diff.gsp) }
+ }
+
+ p {-
+ As you can see, it’s all fairly simple. I just had to change our
+ @code{-EC_LED_COLOR_WHITE} for @code{-EC_LED_COLOR_GREEN}. The codebase
+ defines a few colors, but they’re defined as m4_abbr(RGB) tuples which
+ is awesome, because it opens the door to custom m4_abbr(RGB) effects in
+ the future!
+ }
+
+ h2 #more {-There’s More Than One m4_abbr(LED)‽}
+ p {-
+ That’s right! The Framework laptop I own (13″; the 16″ releases soon
+ though!) has 3 more m4_abbr(LED) lights. One on the left of the
+ chassis, one on right of the chassis, and one on the capslock key. The
+ capslock m4_abbr(LED) acts as an indicator of whether or not you’ve got
+ capslock enabled. This is useless to me though, because my custom
+ keyboard layout doesn’t even support capslock (see the next section) —
+ so I patched it to be a function-lock indicator instead!
+ }
+
+ p {-
+ Here’s the diff — but do take care if you want to apply similar patches
+ to your laptop! The files I’m editing are under @code{-board/hx20}
+ since I’m on an 11th Gen Intel m4_abbr(CPU). If you have a different
+ m4_abbr(CPU), you will probably need to fuck with different code:
+ }
+
+ figure {
+ figcaption {
+ code {-~/board/hx20/board.h}
+ }
+ pre {= m4_fmt_code(fn-lock-1.diff.gsp) }
+ }
+
+ figure {
+ figcaption {
+ code {-~/board/hx20/keyboard-customization.c}
+ }
+ pre {= m4_fmt_code(fn-lock-2.diff.gsp) }
+ }
+
+ p {-
+ As you can see, toggling the capslock m4_abbr(LED) is as simple as
+ invoking @code{-gpio_set_level()}. Not only that, but disabling its
+ functionality with the capslock key is as easy as undefining the
+ @code{-CONFIG_CAPSLOCK_SUPPORT} macro. Figuring out if the function key
+ is locked is also really easy. The @code{-Fn_key} global variable is a
+ bit-field containing information pertaining to the function key, and we
+ also conveniently already have the @code{-FN_LOCKED} constant defined
+ that we can bitwise-AND with @code{-Fn_key} to check the locked state!
+ }
+
+ p {-
+ We also setup some hooks with the @code{-DECLARE_HOOK()} macro. These
+ just ensure that we are behaving properly on system resume and -suspend.
+ }
+
+ h2 #hybrid {-The Hybrid Key}
+ p {-
+ Wouldn’t it be cool if a physical key could represent two keys at the
+ same time? I thought so too. Like all Emacs users, I suffer from a
+ distinct lack of easily-accessible modifier keys. I need escape because
+ I use Vim bindings; I need left-control because all the Emacs bindings
+ use it; I need super for my window-managers’ bindings; I need left-alt
+ so I can type characters that don’t come on a standard American keyboard
+ (such as @em{-ß}, @em{-€}, and @em{-é}), and now I have a problem. All
+ my modifiers are taken, but Emacs still needs a meta key to work!
+ }
+
+ figure {
+ figcaption {-
+ @cite{-Workflow} by Randall Munroe
+ }
+ img alt="XKCD Comic 1172" src="1172.png" {}
+ }
+
+ p {-
+ What will I ever do‽ Well thanks to Framework making the m4_abbr(EC)
+ open-source, and conveniently giving me a file called
+ @code{-keyboard_customization.c}, I’m going to take two keys and stick
+ them in one! The basic premise is this: the capslock key is arguably
+ the easiest modifier key to hit, and it’s currently bound to the escape
+ key on my system. This is inefficient though, because nobody makes
+ key-bindings that chord the escape-key with another key;
+ chords @x-ref{-1} are always done with a modifier like control, and
+ Emacs is no different. So my plan was to make it so that the capslock
+ key when used on its own mimics an escape-key, while instead mimicking
+ the left-control-key when used in a chord with another key.
+ }
+
+ p {-
+ It took me a little longer this time to figure out how to implement what
+ I wanted since the code isn’t as clear, but it was still a surprisingly
+ easy feature to patch into the m4_abbr(EC)! I basically just updated
+ the scancode table, swapping out the capslock scancode for my own random
+ one that I called @code{-SCANCODE_CTRL_ESC}. I then created a new
+ function called @code{-try_ctrl_esc()} which is called in the on-keyup
+ and -down callback function. The @code{-try_ctrl_esc()} function
+ handles all of the logic as you can see in the following diff; it’s
+ basically just a state machine:
+ }
+
+ aside {
+ p data-ref="1" {-
+ If you’re confused by what I mean by a ‘key-chord’, I am simply
+ referring to pressing multiple keys in conjunction, such as when you
+ press ‘@kbd{-Ctrl + C}’ to copy text.
+ }
+ }
+
+ figure {
+ figcaption {
+ code {-~/board/hx20/keyboard_customization.c}
+ }
+ pre {= m4_fmt_code(hybrid.diff.gsp) }
+ }
+
+ p {-
+ One thing that’s good to take note of is what I return from
+ @code{-try_ctrl_esc()}. The general pattern for handling a keyup or
+ -down event is to stick the following code into
+ @code{-keyboard_scancode_callback()}:
+ }
+
+ figure {
+ figcaption {-
+ @code{-keyboard_scancode_callback()} in
+ @code{-~/board/hx20/keyboard_customization.c}
+ }
+ pre {= m4_fmt_code(kbd-sc-cb.c.gsp) }
+ }
+
+ p {-
+ In @code{-my_handler_function()} (or whatever you decide to name it),
+ you attempt to handle the event. If you don’t want to handle a
+ particular event and instead want to pass it on to the next handler, you
+ need to return @code{-EC_SUCCESS}. If you managed to successfully
+ handle the event though, then you need to return an error such as
+ @code{-EC_ERROR_UNIMPLEMENTED}. It’s pretty stupid and makes very
+ little sense from a naming perspective, but oh well…
+ }
+
+ h2 #next {-What’s Next?}
+ p {-
+ m4_abbr(RGB) m4_abbr(LED)s maybe.
+ }
+ }
+
+ hr{}
+
+ footer { m4_footer }
+ }
+}
diff --git a/src/blog/fw-ec/kbd-sc-cb.c.gsp b/src/blog/fw-ec/kbd-sc-cb.c.gsp
new file mode 100644
index 0000000..31524de
--- /dev/null
+++ b/src/blog/fw-ec/kbd-sc-cb.c.gsp
@@ -0,0 +1,6 @@
+@span .c-cmt {-/* ‘make_code’ is the scancode. ‘pressed’ is a boolean that is true if this is a}
+ @span .c-cmt {-keydown event, and false if it’s a keyup. */}
+
+r = @span .c-fn {-my_handler_function}(make_code, pressed);
+@span .c-kw {-if} (r != @span .c-pp {-EC_SUCCESS})
+ @span .c-kw {-return} r;
diff --git a/src/blog/fw-ec/led.diff.gsp b/src/blog/fw-ec/led.diff.gsp
new file mode 100644
index 0000000..ac7642f
--- /dev/null
+++ b/src/blog/fw-ec/led.diff.gsp
@@ -0,0 +1,32 @@
+@span .diff-meta {-diff --git a/board/hx20/led.c b/board/hx20/led.c}
+@span .diff-meta {-index a4dc4564e..dacf73fda 100644}
+@span .diff-meta {---- a/board/hx20/led.c}
+@span .diff-meta {-+++ b/board/hx20/led.c}
+@span .diff-loc {-\@\@ -283,22 +283,22 \@\@ static void led_set_power(void)}
+ /* don’t light up when at lid close */
+ if (!lid_is_open()) {
+ set_pwr_led_color(PWM_LED2, -1);
+@span .diff-del {-- enable_pwr_breath(PWM_LED2, EC_LED_COLOR_WHITE, breath_led_length, 0);}
+@span .diff-ins {-+ enable_pwr_breath(PWM_LED2, EC_LED_COLOR_GREEN, breath_led_length, 0);}
+ return;
+ \}
+
+ if (chipset_in_state(CHIPSET_STATE_ANY_SUSPEND))
+@span .diff-del {-- enable_pwr_breath(PWM_LED2, EC_LED_COLOR_WHITE, breath_led_length, 1);}
+@span .diff-ins {-+ enable_pwr_breath(PWM_LED2, EC_LED_COLOR_GREEN, breath_led_length, 1);}
+ else
+@span .diff-del {-- enable_pwr_breath(PWM_LED2, EC_LED_COLOR_WHITE, breath_led_length, 0);}
+@span .diff-ins {-+ enable_pwr_breath(PWM_LED2, EC_LED_COLOR_GREEN, breath_led_length, 0);}
+
+ if (chipset_in_state(CHIPSET_STATE_ON) | power_button_enable) {
+ if (charge_prevent_power_on(0))
+ set_pwr_led_color(PWM_LED2, (power_tick %
+ LED_TICKS_PER_CYCLE < LED_ON_TICKS) ?
+@span .diff-del {-- EC_LED_COLOR_WHITE : -1);}
+@span .diff-ins {-+ EC_LED_COLOR_GREEN : -1);}
+ else
+@span .diff-del {-- set_pwr_led_color(PWM_LED2, EC_LED_COLOR_WHITE);}
+@span .diff-ins {-+ set_pwr_led_color(PWM_LED2, EC_LED_COLOR_GREEN);}
+ \} else
+ set_pwr_led_color(PWM_LED2, -1);
+ \}
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
diff --git a/src/blog/index.gsp b/src/blog/index.gsp
new file mode 100644
index 0000000..68b53f8
--- /dev/null
+++ b/src/blog/index.gsp
@@ -0,0 +1,40 @@
+html lang="en" {
+ head { m4_include(head.gsp) }
+ body {
+ header {
+ div {
+ h1 {-Blog Posts}
+ m4_include(nav.gsp)
+ }
+
+ figure .quote {
+ blockquote {
+ p {=
+ Object-oriented programming is an exceptionally bad idea which could
+ only have originated in California.
+ }
+ }
+ figcaption {-Edsgar W. Dijkstra}
+ }
+ }
+
+ main {
+ p {-
+ On this section of the site you will find my blog. Most of what I post
+ here is related to software-development and -design, although maybe
+ you’ll find something unrelated on here too.
+ }
+
+ p {-Posts:}
+
+ ul {
+ m4_article(gsp, {-Writing an HTML Preprocessor (feat. Tree-Sitter)})
+ m4_article(fw-ec, {-Patching My Laptop’s Embedded Controller})
+ }
+ }
+
+ hr{}
+
+ footer { m4_footer }
+ }
+}