-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmappings.sh
More file actions
executable file
·572 lines (505 loc) · 24 KB
/
mappings.sh
File metadata and controls
executable file
·572 lines (505 loc) · 24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
#!/bin/bash
# FoxML Theme Hub — source → destination mappings
# Format: "relative-path|system-destination"
# ~ is expanded at runtime
# ─────────────────────────────────────────
# Template files (rendered with palette colors)
# Source: templates/ directory
# ─────────────────────────────────────────
TEMPLATE_MAPPINGS=(
# Hyprland
"hyprland/theme.conf|~/.config/hypr/modules/theme.conf"
"hyprlock/hyprlock.conf|~/.config/hypr/hyprlock.conf"
# Neovim
"nvim/init.lua|~/.config/nvim/init.lua"
# Kitty
"kitty/kitty.conf|~/.config/kitty/kitty.conf"
# Waybar
"waybar/style.css|~/.config/waybar/style.css"
# Tmux
"tmux/.tmux.conf|~/.tmux.conf"
# Zsh
"zsh/.zshrc|~/.zshrc"
"zsh/colors.zsh|~/.config/zsh/colors.zsh"
"zsh/welcome.zsh|~/.config/zsh/welcome.zsh"
"zsh/caramel.zsh-theme|~/.oh-my-zsh/themes/caramel.zsh-theme"
# ReGreet (login screen — needs sudo to install to /etc/greetd/)
# "regreet/regreet.css|/etc/greetd/regreet.css"
# Mako
"mako/config|~/.config/mako/config"
# Dunst
"dunst/dunstrc|~/.config/dunst/dunstrc"
# Fastfetch
"fastfetch/config.jsonc|~/.config/fastfetch/config.jsonc"
# Rofi
"rofi/glass.rasi|~/.config/rofi/glass.rasi"
# GTK
"gtk-3.0/gtk.css|~/.config/gtk-3.0/gtk.css"
"gtk-4.0/gtk.css|~/.config/gtk-4.0/gtk.css"
# btop
"btop/foxml.theme|~/.config/btop/themes/foxml.theme"
# Yazi
"yazi/theme.toml|~/.config/yazi/theme.toml"
# Lazygit
"lazygit/config.yml|~/.config/lazygit/config.yml"
# Zathura
"zathura/zathurarc|~/.config/zathura/zathurarc"
# Vencord
"vencord/foxml.css|~/.config/Vencord/themes/foxml.css"
# Spicetify
"spicetify/color.ini|~/.config/spicetify/Themes/FoxML/color.ini"
"spicetify/user.css|~/.config/spicetify/Themes/FoxML/user.css"
# Bat
"bat/foxml.tmTheme|~/.config/bat/themes/Fox ML.tmTheme"
# Git (delta pager — included from ~/.gitconfig, doesn't touch user identity)
"git/delta.gitconfig|~/.config/git/delta-foxml.gitconfig"
# Cursor/VS Code
"cursor/foxml-color-theme.json|~/.cursor/extensions/foxml-theme/themes/foxml-color-theme.json"
# Firefox
"firefox/userChrome.css|FIREFOX_PROFILE/chrome/userChrome.css"
"firefox/userContent.css|FIREFOX_PROFILE/chrome/userContent.css"
)
# ─────────────────────────────────────────
# Shared files (copied as-is, no rendering)
# Source: shared/ directory, with _ replacing /
# ─────────────────────────────────────────
SHARED_MAPPINGS=(
# Hyprland
"hyprland.conf|~/.config/hypr/hyprland.conf"
"hyprland_hypridle_ac.conf|~/.config/hypr/hypridle-ac.conf"
"hyprland_hypridle_battery.conf|~/.config/hypr/hypridle-battery.conf"
# Launcher toggle scripts (referenced by keybinds.conf)
"launchers/toggle/toggle_btop.sh|~/.config/launchers/toggle/toggle_btop.sh"
"launchers/toggle/toggle_yazi.sh|~/.config/launchers/toggle/toggle_yazi.sh"
"launchers/toggle/toggle_ncspot.sh|~/.config/launchers/toggle/toggle_ncspot.sh"
"launchers/toggle/toggle_spotify.sh|~/.config/launchers/toggle/toggle_spotify.sh"
# Neovim
"nvim_lazy-lock.json|~/.config/nvim/lazy-lock.json"
"nvim_ftplugin/cpp.lua|~/.config/nvim/ftplugin/cpp.lua"
# Rofi config
"rofi_config.rasi|~/.config/rofi/config.rasi"
# GTK settings
"gtk-3.0_settings.ini|~/.config/gtk-3.0/settings.ini"
"gtk-4.0_settings.ini|~/.config/gtk-4.0/settings.ini"
# Zsh non-color
"zsh_aliases.zsh|~/.config/zsh/aliases.zsh"
"zsh_git.zsh|~/.config/zsh/git.zsh"
"zsh_paths.zsh|~/.config/zsh/paths.zsh"
"zsh_conda.zsh|~/.config/zsh/conda.zsh"
# Waybar config
"waybar_config|~/.config/waybar/config"
"waybar_scripts/cpu.sh|~/.config/waybar/scripts/cpu.sh"
"waybar_scripts/gpu.sh|~/.config/waybar/scripts/gpu.sh"
"waybar_scripts/disk.sh|~/.config/waybar/scripts/disk.sh"
"waybar_scripts/updates.sh|~/.config/waybar/scripts/updates.sh"
"waybar_scripts/ppd_cycle.sh|~/.config/waybar/scripts/ppd_cycle.sh"
# ReGreet (login screen — needs sudo to install to /etc/greetd/)
# "regreet.toml|/etc/greetd/regreet.toml"
)
# ─────────────────────────────────────────
# Special install handlers
# ─────────────────────────────────────────
get_firefox_profile() {
# Firefox 150+ on Arch defaults to XDG paths (~/.config/mozilla/firefox);
# older versions and other distros still use the legacy ~/.mozilla path.
# Check both, preferring whichever has a *.default-release profile.
for base in "$HOME/.config/mozilla/firefox" "$HOME/.mozilla/firefox"; do
local hit
hit=$(find "$base" -maxdepth 1 -name "*.default-release*" -type d 2>/dev/null | head -1)
[[ -n "$hit" ]] && { echo "$hit"; return; }
done
}
install_specials() {
local rendered_dir="$1"
# Firefox — resolve FIREFOX_PROFILE placeholder
local ff_profile
ff_profile="$(get_firefox_profile)"
if [[ -n "$ff_profile" ]]; then
for css in userChrome.css userContent.css; do
if [[ -f "$rendered_dir/firefox/$css" ]]; then
mkdir -p "$ff_profile/chrome"
cp "$rendered_dir/firefox/$css" "$ff_profile/chrome/$css"
echo " ✓ Firefox $css"
fi
done
# Set the legacy stylesheet pref via user.js so userChrome/userContent
# actually load — user.js is read on every launch and overrides
# prefs.js, so this stays correct even if Firefox rewrites prefs.
local ff_userjs="$ff_profile/user.js"
local ff_pref='user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true);'
if ! grep -qF 'toolkit.legacyUserProfileCustomizations.stylesheets' "$ff_userjs" 2>/dev/null; then
printf '// FoxML theming\n%s\n' "$ff_pref" >> "$ff_userjs"
echo " ✓ Firefox user.js (legacy stylesheet pref)"
fi
else
echo " ⚠ No Firefox profile found, skipping"
fi
# Cursor/VS Code — package.json setup
for ext_dir in ~/.cursor/extensions ~/.vscode/extensions; do
if [[ -d "$ext_dir" && -f "$rendered_dir/cursor/foxml-color-theme.json" ]]; then
mkdir -p "$ext_dir/foxml-theme/themes"
cp "$rendered_dir/cursor/foxml-color-theme.json" "$ext_dir/foxml-theme/themes/"
cat > "$ext_dir/foxml-theme/package.json" << 'PKGJSON'
{
"name": "foxml-theme",
"displayName": "Fox ML Theme",
"version": "1.0.0",
"publisher": "foxml",
"engines": { "vscode": "^1.60.0" },
"categories": ["Themes"],
"contributes": {
"themes": [{ "label": "Fox ML", "uiTheme": "vs-dark", "path": "./themes/foxml-color-theme.json" }]
}
}
PKGJSON
echo " ✓ $(basename "$ext_dir" | sed 's/^\.//') theme"
fi
done
# Spicetify config
if command -v spicetify &>/dev/null; then
spicetify config current_theme FoxML 2>/dev/null || true
spicetify config color_scheme Base 2>/dev/null || true
echo " Run 'spicetify apply' to activate"
fi
# Bat cache rebuild
if command -v bat &>/dev/null; then
bat cache --build &>/dev/null
echo " ✓ Bat cache rebuilt"
fi
# ~/.local/bin helpers (tmux pane-label, etc.) — referenced by configs but
# too small for their own subdir; kept executable on copy.
if [[ -d "$SCRIPT_DIR/shared/bin" ]]; then
mkdir -p "$HOME/.local/bin"
for bin in "$SCRIPT_DIR/shared/bin/"*; do
[[ -f "$bin" ]] || continue
cp "$bin" "$HOME/.local/bin/$(basename "$bin")"
chmod +x "$HOME/.local/bin/$(basename "$bin")"
echo " ✓ bin/$(basename "$bin")"
done
fi
# Hyprland scripts
if [[ -d "$SCRIPT_DIR/shared/hyprland_scripts" ]]; then
mkdir -p ~/.config/hypr/scripts
for script in "$SCRIPT_DIR/shared/hyprland_scripts/"*.sh; do
[[ -f "$script" ]] || continue
cp "$script" "$HOME/.config/hypr/scripts/$(basename "$script")"
chmod +x "$HOME/.config/hypr/scripts/$(basename "$script")"
echo " ✓ scripts/$(basename "$script")"
done
fi
# Hyprland modules
if [[ -d "$SCRIPT_DIR/shared/hyprland_modules" ]]; then
mkdir -p ~/.config/hypr/modules
for mod in "$SCRIPT_DIR/shared/hyprland_modules/"*.conf; do
[[ -f "$mod" ]] || continue
local basename="$(basename "$mod")"
[[ "$basename" == "theme.conf" ]] && continue # theme.conf comes from templates
[[ "$basename" == "nvidia.conf" ]] && continue # opt-in, handled by install_nvidia()
cp "$mod" "$HOME/.config/hypr/modules/$basename"
echo " ✓ modules/$basename"
done
fi
# ReGreet (login screen — requires sudo)
if [[ -f "$rendered_dir/regreet/regreet.css" ]]; then
# Stage files where user can review them
mkdir -p ~/.config/regreet
cp "$rendered_dir/regreet/regreet.css" ~/.config/regreet/regreet.css
cp "$SCRIPT_DIR/shared/regreet.toml" ~/.config/regreet/regreet.toml
cp "$SCRIPT_DIR/shared/greetd_hyprland.conf" ~/.config/regreet/hyprland.conf
echo " ✓ ReGreet staged to ~/.config/regreet/"
echo " To activate:"
echo " sudo cp ~/.config/regreet/regreet.{css,toml} /etc/greetd/"
echo " sudo cp ~/.config/regreet/hyprland.conf /etc/greetd/hyprland.conf"
echo " sudo cp ~/.wallpapers/foxml_earthy.jpg /usr/share/wallpapers/"
echo " Then set greetd config.toml to:"
echo " command = \"Hyprland -c /etc/greetd/hyprland.conf\""
fi
# Wallpapers (image files only — skip README etc.)
if [[ -d "$SCRIPT_DIR/shared/wallpapers" ]]; then
mkdir -p ~/.wallpapers
shopt -s nullglob nocaseglob
for wp in "$SCRIPT_DIR/shared/wallpapers/"*.{jpg,jpeg,png,webp}; do
cp "$wp" ~/.wallpapers/
echo " ✓ $(basename "$wp")"
done
shopt -u nullglob nocaseglob
fi
# Cursor theme — Catppuccin Mocha Peach matches the FoxML earthy palette.
# The Hyprland env + GTK ini both reference it; this fetches the theme
# files from the upstream GitHub release if they're not already present.
local cursor_name="catppuccin-mocha-peach-cursors"
local cursor_dir="$HOME/.local/share/icons/$cursor_name"
if [[ ! -d "$cursor_dir" ]]; then
local cursor_url="https://github.com/catppuccin/cursors/releases/download/v2.0.0/${cursor_name}.zip"
local tmp_zip; tmp_zip="$(mktemp --suffix=.zip)"
if curl -fsSL -o "$tmp_zip" "$cursor_url"; then
mkdir -p "$HOME/.local/share/icons"
unzip -o -q "$tmp_zip" -d "$HOME/.local/share/icons/"
rm -f "$tmp_zip"
echo " ✓ cursor theme: $cursor_name"
else
echo " ⚠ cursor download failed; install from AUR or skip"
fi
else
echo " ✓ cursor theme already present"
fi
if command -v gsettings &>/dev/null; then
gsettings set org.gnome.desktop.interface cursor-theme "$cursor_name" 2>/dev/null || true
gsettings set org.gnome.desktop.interface cursor-size 30 2>/dev/null || true
fi
# Icon theme — Papirus-Dark with Catppuccin Mocha Peach folders. The
# GTK ini already references Papirus-Dark; this fetches the theme
# user-locally (no sudo) and recolors folders to match the cursor.
local icons_dir="$HOME/.local/share/icons"
if [[ ! -d "$icons_dir/Papirus" ]]; then
if curl -fsSL "https://raw.githubusercontent.com/PapirusDevelopmentTeam/papirus-icon-theme/master/install.sh" \
| DESTDIR="$icons_dir" sh &>/dev/null; then
echo " ✓ Papirus icon theme"
else
echo " ⚠ Papirus install failed; skipping folder recolor"
fi
else
echo " ✓ Papirus already present"
fi
if [[ -d "$icons_dir/Papirus" ]]; then
# Inject Catppuccin folder SVGs (Papirus-Dark/Light symlink to Papirus)
local cat_tmp; cat_tmp="$(mktemp -d)"
if git clone --depth 1 --quiet \
https://github.com/catppuccin/papirus-folders.git "$cat_tmp/repo" 2>/dev/null; then
cp -r "$cat_tmp/repo/src/"* "$icons_dir/Papirus/" 2>/dev/null || true
echo " ✓ Catppuccin folder palette injected"
fi
rm -rf "$cat_tmp"
# Fetch the papirus-folders helper if not on PATH and apply peach color
local pf_script
if command -v papirus-folders &>/dev/null; then
pf_script="papirus-folders"
else
pf_script="$(mktemp)"
curl -fsSL -o "$pf_script" \
"https://raw.githubusercontent.com/PapirusDevelopmentTeam/papirus-folders/master/papirus-folders" \
&& chmod +x "$pf_script"
fi
if [[ -x "$pf_script" ]]; then
"$pf_script" -C cat-mocha-peach -t Papirus-Dark &>/dev/null || true
echo " ✓ folders → cat-mocha-peach"
[[ "$pf_script" != "papirus-folders" ]] && rm -f "$pf_script"
fi
if command -v gsettings &>/dev/null; then
gsettings set org.gnome.desktop.interface icon-theme "Papirus-Dark" 2>/dev/null || true
fi
fi
# bat — write a tiny config that selects the FoxML tmTheme by name
local bat_dir="$HOME/.config/bat"
if [[ -d "$bat_dir/themes" ]]; then
if [[ -f "$bat_dir/config" ]] && grep -q '^--theme=' "$bat_dir/config"; then
sed -i -E 's|^--theme=.*|--theme="Fox ML"|' "$bat_dir/config"
else
mkdir -p "$bat_dir"
printf -- '--theme="Fox ML"\n' >> "$bat_dir/config"
fi
echo " ✓ bat --theme=\"Fox ML\""
fi
# delta — wire the rendered FoxML gitconfig in via [include] so the user's
# ~/.gitconfig (identity, etc.) stays untouched. git-config -e replaces the
# same key on re-runs, and we only add the include if delta is installed.
if command -v delta &>/dev/null && [[ -f "$rendered_dir/git/delta.gitconfig" ]]; then
local delta_inc="$HOME/.config/git/delta-foxml.gitconfig"
if ! git config --global --get-all include.path 2>/dev/null | grep -qxF "$delta_inc"; then
git config --global --add include.path "$delta_inc"
fi
echo " ✓ git delta include → $delta_inc"
fi
# btop — flip user's btop.conf to the FoxML theme (file is owned by btop)
local btop_conf="$HOME/.config/btop/btop.conf"
if [[ -f "$btop_conf" ]]; then
if grep -qE '^color_theme\s*=\s*"foxml"' "$btop_conf"; then
echo " ✓ btop already on FoxML theme"
else
sed -i -E 's|^(color_theme\s*=\s*).*|\1"foxml"|' "$btop_conf"
echo " ✓ btop color_theme → foxml"
fi
fi
# Systemd user units (wallpaper rotation timer, etc.)
if [[ -d "$SCRIPT_DIR/shared/systemd_user" ]]; then
mkdir -p ~/.config/systemd/user
local installed_any=0
for unit in "$SCRIPT_DIR/shared/systemd_user/"*.{service,timer}; do
[[ -f "$unit" ]] || continue
cp "$unit" "$HOME/.config/systemd/user/$(basename "$unit")"
echo " ✓ systemd/$(basename "$unit")"
installed_any=1
done
if (( installed_any )); then
systemctl --user daemon-reload &>/dev/null || true
for timer in "$SCRIPT_DIR/shared/systemd_user/"*.timer; do
[[ -f "$timer" ]] || continue
systemctl --user enable --now "$(basename "$timer")" &>/dev/null || true
done
echo " ✓ systemd user timers enabled"
fi
fi
}
# ─────────────────────────────────────────
# Nvidia (full Wayland session on dGPU) — opt-in via install.sh --nvidia
# Wires Hyprland env vars + mkinitcpio MODULES + kernel cmdline so the
# nvidia driver loads at boot and Aquamarine targets the discrete card.
# Idempotent: rerunning detects existing config and skips edits.
# ─────────────────────────────────────────
install_nvidia() {
# Detect dGPU and iGPU PCI addresses. Aquamarine needs BOTH because the
# eDP display is hardwired to the iGPU on Optimus laptops — nvidia
# renders, intel scans out via DMA-BUF.
local nvidia_addr="" intel_addr=""
for dev in /sys/bus/pci/devices/*/; do
local vendor class
vendor="$(cat "$dev/vendor" 2>/dev/null)"
class="$(cat "$dev/class" 2>/dev/null)"
[[ "$class" == 0x03* ]] || continue # display controllers only
case "$vendor" in
0x10de) [[ -z "$nvidia_addr" ]] && nvidia_addr="$(basename "$dev")" ;;
0x8086) [[ -z "$intel_addr" ]] && intel_addr="$(basename "$dev")" ;;
0x1002) [[ -z "$intel_addr" ]] && intel_addr="$(basename "$dev")" ;; # AMD iGPU also fits the scanout role
esac
done
if [[ -z "$nvidia_addr" ]]; then
echo " ⚠ No NVIDIA GPU found, skipping nvidia setup"
return
fi
# Resolve by-path symlinks to /dev/dri/cardN — aquamarine splits
# AQ_DRM_DEVICES on ':', and the by-path names contain ':' themselves
# (pci-0000:01:00.0-card), which shreds the list. cardN is colon-free.
local nvidia_drm intel_drm
nvidia_drm="$(readlink -f "/dev/dri/by-path/pci-${nvidia_addr}-card" 2>/dev/null)"
if [[ -z "$nvidia_drm" || ! -e "$nvidia_drm" ]]; then
echo " ⚠ Could not resolve /dev/dri/by-path/pci-${nvidia_addr}-card — is the nvidia driver loaded?"
return
fi
local aq_drm_devices="$nvidia_drm"
if [[ -n "$intel_addr" ]]; then
intel_drm="$(readlink -f "/dev/dri/by-path/pci-${intel_addr}-card" 2>/dev/null)"
if [[ -n "$intel_drm" && -e "$intel_drm" ]]; then
aq_drm_devices+=":${intel_drm}"
echo " Detected NVIDIA at ${nvidia_addr} (${nvidia_drm}), iGPU at ${intel_addr} (${intel_drm})"
else
echo " Detected NVIDIA at ${nvidia_addr} (${nvidia_drm}); iGPU at ${intel_addr} but no DRM node yet — listing nvidia only"
fi
else
echo " Detected NVIDIA at ${nvidia_addr} (${nvidia_drm}) (no iGPU — single-GPU box)"
fi
# Hyprland env-var module
if [[ -f "$SCRIPT_DIR/shared/hyprland_modules/nvidia.conf" ]]; then
mkdir -p ~/.config/hypr/modules
sed "s|AQ_DRM_DEVICES,.*|AQ_DRM_DEVICES, ${aq_drm_devices}|" \
"$SCRIPT_DIR/shared/hyprland_modules/nvidia.conf" \
> ~/.config/hypr/modules/nvidia.conf
echo " ✓ modules/nvidia.conf (AQ_DRM_DEVICES → ${aq_drm_devices})"
local hypr_main="$HOME/.config/hypr/hyprland.conf"
if [[ -f "$hypr_main" ]] && ! grep -qF 'modules/nvidia.conf' "$hypr_main"; then
printf '\n# Nvidia (added by install.sh --nvidia)\nsource = ~/.config/hypr/modules/nvidia.conf\n' \
>> "$hypr_main"
echo " ✓ hyprland.conf sources nvidia.conf"
fi
fi
# /etc/mkinitcpio.conf — early-load nvidia modules so they claim the device
# before kms / nouveau can. Idempotent: skip if nvidia_drm already listed.
#
# Guard against tiny EFI System Partitions: nvidia-bearing initramfs grows
# to ~135 MB on this driver line, and a half-written .img on a full /boot
# leaves the system unbootable. Refuse to edit if /boot has under 80 MB free.
local mkinit="/etc/mkinitcpio.conf"
if [[ -f "$mkinit" ]] && ! grep -qE '^MODULES=.*nvidia_drm' "$mkinit"; then
local boot_free_mb
boot_free_mb=$(df --output=avail -BM /boot 2>/dev/null | tail -1 | tr -dc '0-9')
if [[ -n "$boot_free_mb" && "$boot_free_mb" -lt 80 ]]; then
echo " ⚠ /boot has only ${boot_free_mb} MB free — skipping mkinitcpio edit"
echo " nvidia-bearing initramfs needs ~135 MB. Free space in /boot"
echo " (older kernels, fallback initramfs) and re-run, or skip this"
echo " step — the dGPU will still render via udev module loading."
else
sudo sed -i.foxml-bak \
's/^MODULES=([^)]*)/MODULES=(nvidia nvidia_modeset nvidia_uvm nvidia_drm)/' \
"$mkinit"
echo " ✓ mkinitcpio MODULES updated (backup: ${mkinit}.foxml-bak)"
sudo mkinitcpio -P 2>&1 | tail -3
fi
else
echo " • mkinitcpio already has nvidia modules"
fi
# systemd-boot loader entry — add kernel cmdline for DRM modeset.
# Other bootloaders (GRUB, refind) need manual editing; we warn here.
local boot_entry="/boot/loader/entries/arch.conf"
if [[ -f "$boot_entry" ]]; then
if ! grep -qF 'nvidia_drm.modeset=1' "$boot_entry"; then
sudo sed -i.foxml-bak \
-E 's/^(options .*)$/\1 nvidia_drm.modeset=1 nvidia_drm.fbdev=1/' \
"$boot_entry"
echo " ✓ kernel cmdline updated (backup: ${boot_entry}.foxml-bak)"
else
echo " • kernel cmdline already has nvidia_drm.modeset=1"
fi
elif [[ -f /etc/default/grub ]]; then
echo " ⚠ GRUB detected — add 'nvidia_drm.modeset=1 nvidia_drm.fbdev=1'"
echo " to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub, then"
echo " run: sudo grub-mkconfig -o /boot/grub/grub.cfg"
else
echo " ⚠ Unknown bootloader — add 'nvidia_drm.modeset=1 nvidia_drm.fbdev=1'"
echo " to your kernel cmdline manually."
fi
echo ""
echo " Reboot to load the nvidia driver."
echo " Recovery: if Hyprland fails to start, switch to a TTY"
echo " (Ctrl+Alt+F2), restore ${mkinit}.foxml-bak and"
echo " ${boot_entry}.foxml-bak, run 'sudo mkinitcpio -P', reboot."
}
# ─────────────────────────────────────────
# Special update handlers (pull system → templates)
# ─────────────────────────────────────────
update_specials() {
local template_dir="$1"
local sed_expr="$2"
# Firefox
local ff_profile
ff_profile="$(get_firefox_profile)"
if [[ -n "$ff_profile" ]]; then
for css in userChrome.css userContent.css; do
if [[ -f "$ff_profile/chrome/$css" ]]; then
sed "$sed_expr" "$ff_profile/chrome/$css" > "$template_dir/firefox/$css"
echo " ✓ Firefox $css"
fi
done
fi
# Cursor/VS Code
for ext_dir in ~/.cursor/extensions ~/.vscode/extensions; do
local src="$ext_dir/foxml-theme/themes/foxml-color-theme.json"
if [[ -f "$src" ]]; then
sed "$sed_expr" "$src" > "$template_dir/cursor/foxml-color-theme.json"
echo " ✓ foxml-color-theme.json"
break
fi
done
# Bat
local bat_dir
bat_dir="$(bat --config-dir 2>/dev/null || echo "$HOME/.config/bat")"
if [[ -f "$bat_dir/themes/Fox ML.tmTheme" ]]; then
sed "$sed_expr" "$bat_dir/themes/Fox ML.tmTheme" > "$template_dir/bat/foxml.tmTheme"
echo " ✓ Bat theme"
fi
# Spicetify
local spice_dir="$HOME/.config/spicetify/Themes/FoxML"
if [[ -d "$spice_dir" ]]; then
for f in color.ini user.css; do
[[ -f "$spice_dir/$f" ]] && sed "$sed_expr" "$spice_dir/$f" > "$template_dir/spicetify/$f"
done
echo " ✓ Spicetify"
fi
# Hyprland scripts
if [[ -d ~/.config/hypr/scripts ]]; then
mkdir -p "$SCRIPT_DIR/shared/hyprland_scripts"
for script in ~/.config/hypr/scripts/*.sh; do
[[ -f "$script" ]] || continue
cp "$script" "$SCRIPT_DIR/shared/hyprland_scripts/$(basename "$script")"
echo " ✓ scripts/$(basename "$script")"
done
fi
}