flake-update-20260505
  1#! /usr/bin/env nix-shell
  2#! nix-shell -i bash -p qmk -p keymap-drawer -p librsvg
  3# shellcheck shell=bash
  4
  5# Generate keymap SVGs for keyboards using keymap-drawer
  6# Usage: ./generate-keymaps.sh [eyelash|moonlander|all]
  7
  8set -euo pipefail
  9
 10SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 11KEYMAP_DRAWER_DIR="$SCRIPT_DIR/keymap-drawer"
 12OUTPUT_DIR="${OUTPUT_DIR:-$SCRIPT_DIR}"
 13DEPS_DIR="$SCRIPT_DIR/.deps"
 14
 15# Colors for output
 16GREEN='\033[0;32m'
 17BLUE='\033[0;34m'
 18YELLOW='\033[1;33m'
 19NC='\033[0m' # No Color
 20
 21log_info() {
 22	echo -e "${BLUE}==>${NC} $1"
 23}
 24
 25log_success() {
 26	echo -e "${GREEN}==>${NC} $1"
 27}
 28
 29log_warn() {
 30	echo -e "${YELLOW}==>${NC} $1"
 31}
 32
 33# Create output directory
 34mkdir -p "$OUTPUT_DIR"
 35
 36# Ensure zmk-helpers is cloned at the correct revision from west.yml
 37ensure_zmk_helpers() {
 38	local west_yml="$SCRIPT_DIR/eyelash_corne/config/west.yml"
 39	local target_dir="$DEPS_DIR/zmk-helpers"
 40
 41	if [[ ! -f "$west_yml" ]]; then
 42		log_warn "west.yml not found at $west_yml, skipping zmk-helpers setup"
 43		return 1
 44	fi
 45
 46	# Parse revision from west.yml (the revision line after "name: zmk-helpers")
 47	local revision
 48	revision=$(awk '/name: zmk-helpers/{found=1} found && /revision:/{print $2; exit}' "$west_yml")
 49	if [[ -z "$revision" ]]; then
 50		log_warn "Could not parse zmk-helpers revision from west.yml"
 51		return 1
 52	fi
 53
 54	# Parse remote URL from west.yml
 55	local remote_name
 56	remote_name=$(awk '/name: zmk-helpers/{found=1} found && /remote:/{print $2; exit}' "$west_yml")
 57	local url_base
 58	url_base=$(awk -v name="$remote_name" '$0 ~ "name: " name {found=1} found && /url-base:/{print $2; exit}' "$west_yml")
 59	local repo_url="${url_base}/zmk-helpers.git"
 60
 61	if [[ ! -d "$target_dir" ]]; then
 62		log_info "Cloning zmk-helpers ($revision) to $target_dir..."
 63		mkdir -p "$DEPS_DIR"
 64		git clone --depth 1 --branch "$revision" "$repo_url" "$target_dir" 2>/dev/null
 65		log_success "zmk-helpers cloned at $revision"
 66	fi
 67}
 68
 69# Generate resolved config with absolute deps path
 70resolve_config() {
 71	local config_template="$KEYMAP_DRAWER_DIR/config.yaml"
 72	local resolved_config
 73	resolved_config=$(mktemp "${TMPDIR:-/tmp}/keymap-drawer-config.XXXXXX.yaml")
 74	sed "s|__DEPS_DIR__|$DEPS_DIR|g" "$config_template" >"$resolved_config"
 75	echo "$resolved_config"
 76}
 77
 78# Convert SVG to PNG
 79svg_to_png() {
 80	local svg="$1"
 81	local png="${svg%.svg}.png"
 82	rsvg-convert -o "$png" "$svg"
 83	log_success "Generated: $png"
 84}
 85
 86# Setup deps and config
 87ensure_zmk_helpers
 88RESOLVED_CONFIG=$(resolve_config)
 89trap 'rm -f "$RESOLVED_CONFIG"' EXIT
 90
 91generate_eyelash_corne() {
 92	log_info "Generating keymap for eyelash_corne (ZMK)..."
 93
 94	local zmk_config="$SCRIPT_DIR/eyelash_corne/config/eyelash_corne.keymap"
 95	local output_svg="$OUTPUT_DIR/eyelash_corne.svg"
 96
 97	if [[ ! -f "$zmk_config" ]]; then
 98		log_warn "ZMK config not found at $zmk_config"
 99		return 1
100	fi
101
102	# Parse ZMK keymap and draw SVG
103	keymap -c "$RESOLVED_CONFIG" parse -z "$zmk_config" |
104		keymap -c "$RESOLVED_CONFIG" draw - >"$output_svg"
105
106	log_success "Generated: $output_svg"
107	svg_to_png "$output_svg"
108}
109
110generate_moonlander() {
111	log_info "Generating keymap for moonlander (QMK)..."
112
113	local qmk_firmware_dir="$SCRIPT_DIR/moonlander/build/qmk_firmware"
114	local keyboard="zsa/moonlander"
115	local keymap_name="vincent"
116	local qmk_json="/tmp/moonlander_keymap.json"
117	local keymap_yaml="/tmp/moonlander_keymap.yaml"
118	local output_svg="$OUTPUT_DIR/moonlander.svg"
119
120	# Check if QMK firmware is checked out
121	if [[ ! -d "$qmk_firmware_dir" ]]; then
122		log_warn "QMK firmware not found. Running checkout..."
123		(cd "$SCRIPT_DIR/moonlander" && ./go.sh checkout)
124	fi
125
126	# Ensure symlink exists
127	if [[ ! -L "$qmk_firmware_dir/keyboards/$keyboard/keymaps/$keymap_name" ]]; then
128		log_info "Creating symlink for keymap..."
129		mkdir -p "$qmk_firmware_dir/keyboards/$keyboard/keymaps"
130		ln -rvsf "$SCRIPT_DIR/moonlander/config" "$qmk_firmware_dir/keyboards/$keyboard/keymaps/$keymap_name"
131	fi
132
133	# Convert keymap to JSON using QMK CLI from the firmware directory
134	log_info "Converting QMK keymap to JSON..."
135	if ! (cd "$qmk_firmware_dir" && qmk c2json --no-cpp -kb "$keyboard" -km "$keymap_name" >"$qmk_json" 2>/dev/null); then
136		log_warn "QMK conversion failed."
137		log_warn "Alternative: Use QMK Configurator to export JSON or manually create YAML."
138		return 1
139	fi
140
141	# Parse QMK JSON to YAML
142	log_info "Parsing keymap to YAML..."
143	keymap -c "$RESOLVED_CONFIG" parse -c 14 -q "$qmk_json" >"$keymap_yaml"
144
145	# Add manual combo definitions to the YAML
146	log_info "Adding manual combo definitions..."
147	cat >>"$keymap_yaml" <<'EOF'
148combos:
149  # Layer switching combos (L0=Bépo, L1=ErgoL, L2=QWERTY)
150  - { p: [67, 70], k: "→ Bépo", l: [L1, L2], draw_separate: true }
151  - { p: [66, 71], k: "→ ErgoL", l: [L0, L2], draw_separate: true }
152  - { p: [58, 61], k: "→ QWERTY", l: [L0, L1], draw_separate: true }
153  - { p: [17, 18], k: "⇄ Mouse", draw_separate: true }
154
155  # Escape combos (layer-specific)
156  - { p: [39, 40], k: ESC, l: [L0] }
157  - { p: [39, 40], k: ESC, l: [L2] }
158
159  # Special character combos (available on all layers)
160  - { p: [15, 16], k: "|" }
161  - { p: [16, 17], k: "@" }
162  - { p: [17, 18], k: "#" }
163  - { p: [18, 19], k: "&" }
164  - { p: [18, 32], k: "$" }
165  - { p: [17, 31], k: "/" }
166  - { p: [31, 45], k: "\\" }
167  - { p: [16, 30], k: "-" }
168  - { p: [32, 46], k: "_" }
169  - { p: [30, 44], k: "=" }
170
171  # Bracket combos (available on all layers)
172  - { p: [23, 38], k: "(" }
173  - { p: [38, 50], k: ")" }
174  - { p: [22, 37], k: "{" }
175  - { p: [37, 49], k: "}" }
176  - { p: [24, 39], k: "[" }
177  - { p: [39, 51], k: "]" }
178  - { p: [23, 24], k: "<" }
179  - { p: [24, 25], k: ">" }
180
181  # Additional character combos
182  - { p: [22, 36], k: '"' }
183  - { p: [19, 33], k: "~" }
184  - { p: [33, 47], k: "%" }
185  - { p: [36, 48], k: '`' }
186  - { p: [26, 40], k: "*" }
187  - { p: [40, 52], k: "+" }
188
189  # Leader key combo (available on all layers)
190  - { p: [31, 32], k: LEADER }
191EOF
192
193	# Draw SVG from YAML with combos
194	log_info "Drawing SVG with combos..."
195	if keymap -c "$RESOLVED_CONFIG" draw "$keymap_yaml" >"$output_svg" 2>&1; then
196		log_success "Generated: $output_svg"
197		svg_to_png "$output_svg"
198		# Clean up temp files
199		rm -f "$qmk_json" "$keymap_yaml"
200	else
201		log_warn "Failed to draw SVG. YAML file saved at: $keymap_yaml"
202		log_info "You can inspect it for debugging"
203		return 1
204	fi
205}
206
207generate_keyball44() {
208	log_info "Generating keymap for keyball44 (ZMK)..."
209
210	local zmk_config="$SCRIPT_DIR/keyball44/config/keyball44.keymap"
211	local layout_json="$SCRIPT_DIR/keyball44/config/keyball44.json"
212	local output_svg="$OUTPUT_DIR/keyball44.svg"
213	local keymap_yaml
214	keymap_yaml=$(mktemp "${TMPDIR:-/tmp}/keyball44-keymap.XXXXXX.yaml")
215
216	if [[ ! -f "$zmk_config" ]]; then
217		log_warn "ZMK config not found at $zmk_config"
218		return 1
219	fi
220
221	# Parse ZMK keymap to YAML, then replace layout with JSON reference
222	keymap -c "$RESOLVED_CONFIG" parse -z "$zmk_config" >"$keymap_yaml"
223
224	# Replace the layout line with the JSON physical layout
225	sed -i "s|^layout:.*|layout: {qmk_info_json: $layout_json}|" "$keymap_yaml"
226
227	# Draw SVG from YAML
228	keymap -c "$RESOLVED_CONFIG" draw "$keymap_yaml" >"$output_svg"
229	rm -f "$keymap_yaml"
230
231	log_success "Generated: $output_svg"
232	svg_to_png "$output_svg"
233}
234
235# Main logic
236case "${1:-all}" in
237eyelash | eyelash_corne)
238	generate_eyelash_corne
239	;;
240moonlander)
241	generate_moonlander
242	;;
243keyball | keyball44)
244	generate_keyball44
245	;;
246all)
247	generate_eyelash_corne || true
248	generate_moonlander || true
249	generate_keyball44 || true
250	;;
251*)
252	echo "Usage: $0 [eyelash|moonlander|keyball44|all]"
253	echo ""
254	echo "Options:"
255	echo "  eyelash     Generate only eyelash_corne keymap"
256	echo "  moonlander  Generate only moonlander keymap"
257	echo "  keyball44   Generate only keyball44 keymap"
258	echo "  all         Generate all keymaps (default)"
259	echo ""
260	echo "Output directory: $OUTPUT_DIR"
261	exit 1
262	;;
263esac
264
265log_success "Done! SVGs saved to: $OUTPUT_DIR"