Last active
April 26, 2025 20:05
-
-
Save VinceGuidry/e85fa37e3e60f2dcb63c051cee71060f to your computer and use it in GitHub Desktop.
Ruby DSL
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'tempfile' | |
# The DSL class. The render method simply takes a block, then executes the block in the scope of the DSL class. You can see | |
# a use of it in the next file. | |
module Keyd | |
class DSL | |
def self.render(&block) | |
d = new | |
d.instance_exec(&block) | |
d.render | |
end | |
def initialize = @output = '' | |
def render = @output | |
def build(s) = @build << s << "\n" | |
def push(string) = @output << string | |
def build_block(name, &block) | |
@build = "[#{name}]\n\n" | |
block.call | |
push @build << "\n" | |
end | |
def block(name, contents) = push("[#{name}]\n\n#{contents}\n\n") | |
def id_block(ids) = block('ids', ids.join("\n")) | |
def global = block('global', 'layer_indicator = 1') | |
def empty_block(name) = push("[#{name}]\n\n") | |
def bind(key, bindng) = build("#{key} = #{bindng}") | |
def overload(key, layer, tap) = build("#{key} = overload(#{layer}, #{tap})") | |
def overload_layer(key) = build("#{key} = overload(#{key}, #{key})") | |
def clear(key) = build("#{key} = clear()") | |
def clear_c(key) = build("#{key} = clearm(C-#{key})") | |
def clear_a(key) = build("#{key} = clearm(A-#{key})") | |
def layer(key, layer) = build("#{key} = layer(#{layer})") | |
def lm(k) = "lettermod(#{lm_hash[k]}, #{k}, 150, 200)" | |
def lettermod(key, layer) = build("#{key} = #{lm(key)}") | |
def comment_menu_macro(key, b, comment) = build("# #{comment}\n#{key} = macro(cyclewindows+#{b})") | |
def cm(key) = build("#{key} = C-M-#{key}") | |
def lettermods = lm_hash.each {|k, l| lettermod k, l } | |
def lm_hash | |
{ | |
'f' => 'focusright', | |
'd' => 'meta', | |
'a' => 'shift', | |
's' => 'alt', | |
'r' => 'workspace', | |
} | |
end | |
def layer_blocks | |
build_block('workspace') do | |
comment_menu_macro 'j', 'q', 'swap-etbws' | |
comment_menu_macro 'k', 'r', 'add-editor-row' | |
comment_menu_macro 'l', 't', 'restore' | |
comment_menu_macro 'semicolon', 'u', 'save' | |
end | |
build_block('focusright') do | |
comment_menu_macro 'j', 'w', 'focus-work' | |
comment_menu_macro 'k', 'b', 'focus-browser' | |
comment_menu_macro 'l', 'c', 'focus-comm' | |
comment_menu_macro 'u', 's', 'scratchpad-show' | |
comment_menu_macro 'i', 'y', 'rotate-editors-backward' | |
comment_menu_macro 'o', 'e', 'rotate-editors-forward' | |
end | |
end | |
def meta_cm_0_9(name) | |
build_block(name) do | |
cm '1' | |
cm '2' | |
cm '3' | |
cm '4' | |
cm '5' | |
cm '6' | |
cm '7' | |
cm '8' | |
cm '9' | |
cm '0' | |
end | |
end | |
def re_letter(key, b: 'noop', s: nil, ec: nil, esc: nil) | |
bind key, b | |
bind "edit.#{key}", key | |
bind "lineedit.#{key}", key | |
if s | |
bind "shift.#{key}", s | |
bind "edit+shift.#{key}", "S-#{key}" | |
bind "lineedit+shift.#{key}", "S-#{key}" | |
end | |
bind "meta.#{key}", "M-#{key}" | |
bind "meta+shift.#{key}", "S-M-#{key}" | |
bind "edit+compose.#{key}", ec if ec | |
bind "workspace+#{key}", key | |
if esc | |
bind "compose+edit+shift.#{key}", esc | |
bind "compose+lineedit+shift.#{key}", esc | |
end | |
build '' | |
end | |
def e_letter(key, b: 'noop', s: nil, a: nil, ec: nil) | |
bind key, b | |
bind "edit.#{key}", key | |
if s | |
bind "shift.#{key}", s | |
bind "edit+shift.#{key}", "S-#{key}" | |
end | |
bind "edit+compose.#{key}", ec if ec | |
yield if block_given? | |
a.call if a | |
build '' | |
end | |
def e_letters | |
@sub = ('a'..'z').to_a.zip(Array.new(26, nil)).to_h | |
lm_hash.each {|k, l| ltr(k, b: lm(k)) } | |
yield if block_given? | |
@sub.each do |k, h| | |
h.nil? ? e_letter(k.to_s) : e_letter(k.to_s, **h) | |
end | |
end | |
def re_letters | |
@sub = ('a'..'z').to_a.zip(Array.new(26, nil)).to_h | |
lm_hash.each {|k, l| ltr(k, b: lm(k)) } | |
yield if block_given? | |
@sub.each do |k, h| | |
h.nil? ? re_letter(k.to_s) : re_letter(k, **h) | |
end | |
end | |
def ltr(k, h = nil, &block) | |
@sub[k] = {} if @sub[k].nil? | |
@sub[k].merge! h if h | |
if block | |
@sub[k][:a] = block | |
end | |
end | |
def bare(k, b) | |
@sub[k] = {} if @sub[k].nil? | |
@sub[k][:b] = b | |
end | |
def shift(k, b) | |
@sub[k] = {} if @sub[k].nil? | |
@sub[k][:s] = b | |
end | |
def add(k, &block) | |
@sub[k] = {} if @sub[k].nil? | |
@sub[k][:a] = block | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# I think the only reason why the output of the render call was saved to a variable is so I can troubleshoot it just with a | |
# REPL call at the bottom of the file. Leaving this as Ruby and not, say, `IO.read`ing in a file allows full access to ruby. | |
ids = ["3297:c6cf"] | |
t = DSL.render do | |
id_block ids | |
global | |
build_block('main') do | |
clear 'z+x' | |
overload 'capslock', 'capslock', 'esc' | |
clear_c 'scrolllock' | |
overload 'compose', 'compose', 'C-compose' | |
overload 'tab', 'shift', 'tab' | |
overload 'grave', 'tilde', 'grave' | |
lettermods | |
end | |
layer_blocks | |
build_block('compose') do | |
bind 'j', 'left' | |
bind 'k', 'down' | |
bind 'l', 'up' | |
bind 'semicolon', 'right' | |
end | |
meta_cm_0_9 'meta:M' | |
empty_block 'capslock:C' | |
build_block('nav') do | |
clear 'z' | |
end | |
empty_block 'nav+control' | |
build_block 'nav+shift' do | |
bind 'm', 'M-left' | |
bind 'comma', 'M-down' | |
bind 'dot', 'M-up' | |
bind 'slash', 'M-right' | |
end | |
build_block 'edit' do | |
clear 'z+x' | |
end | |
empty_block 'edit+shift' | |
build_block 'lineedit' do | |
clear 'z+x' | |
end | |
empty_block 'lineedit+shift' | |
end | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# The output. If you're wondering why this seems like a lot of work just to manage this, it's because it's the simplest one. | |
# The one generating the main keyd config clocks in at 369 LOC, and manually editing it was causing intense psychic pain. | |
[ids] | |
3297:c6cf | |
[global] | |
layer_indicator = 1 | |
[main] | |
z+x = clear() | |
capslock = overload(capslock, esc) | |
scrolllock = clearm(C-scrolllock) | |
compose = overload(compose, C-compose) | |
tab = overload(shift, tab) | |
grave = overload(tilde, grave) | |
f = lettermod(focusright, f, 150, 200) | |
d = lettermod(meta, d, 150, 200) | |
a = lettermod(shift, a, 150, 200) | |
s = lettermod(alt, s, 150, 200) | |
r = lettermod(workspace, r, 150, 200) | |
# What it spits out. | |
[workspace] | |
# swap-etbws | |
j = macro(cyclewindows+q) | |
# add-editor-row | |
k = macro(cyclewindows+r) | |
# restore | |
l = macro(cyclewindows+t) | |
# save | |
semicolon = macro(cyclewindows+u) | |
[focusright] | |
# focus-work | |
j = macro(cyclewindows+w) | |
# focus-browser | |
k = macro(cyclewindows+b) | |
# focus-comm | |
l = macro(cyclewindows+c) | |
# scratchpad-show | |
u = macro(cyclewindows+s) | |
# rotate-editors-backward | |
i = macro(cyclewindows+y) | |
# rotate-editors-forward | |
o = macro(cyclewindows+e) | |
[compose] | |
j = left | |
k = down | |
l = up | |
semicolon = right | |
[meta:M] | |
1 = C-M-1 | |
2 = C-M-2 | |
3 = C-M-3 | |
4 = C-M-4 | |
5 = C-M-5 | |
6 = C-M-6 | |
7 = C-M-7 | |
8 = C-M-8 | |
9 = C-M-9 | |
0 = C-M-0 | |
[capslock:C] | |
[nav] | |
z = clear() | |
[nav+control] | |
[nav+shift] | |
m = M-left | |
comma = M-down | |
dot = M-up | |
slash = M-right | |
[edit] | |
z+x = clear() | |
[edit+shift] | |
[lineedit] | |
z+x = clear() | |
[lineedit+shift] | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment