diff options
Diffstat (limited to 'src/blog')
-rw-r--r-- | src/blog/fw-ec/1172.png | bin | 0 -> 17531 bytes | |||
-rw-r--r-- | src/blog/fw-ec/fn-lock-1.diff.gsp | 12 | ||||
-rw-r--r-- | src/blog/fw-ec/fn-lock-2.diff.gsp | 36 | ||||
-rw-r--r-- | src/blog/fw-ec/hybrid.diff.gsp | 88 | ||||
-rw-r--r-- | src/blog/fw-ec/index.gsp | 229 | ||||
-rw-r--r-- | src/blog/fw-ec/kbd-sc-cb.c.gsp | 6 | ||||
-rw-r--r-- | src/blog/fw-ec/led.diff.gsp | 32 | ||||
-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 | ||||
-rw-r--r-- | src/blog/index.gsp | 40 |
16 files changed, 801 insertions, 0 deletions
diff --git a/src/blog/fw-ec/1172.png b/src/blog/fw-ec/1172.png Binary files differnew file mode 100644 index 0000000..14b3be1 --- /dev/null +++ b/src/blog/fw-ec/1172.png 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 } + } +} |