Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .github/workflows/pr-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@ jobs:

- name: ShellCheck
run: |
shellcheck -x install-scripts/*.sh install-scripts/lib/*.sh config/sets/*/apply.sh config/sets/basic/tmux/scripts/*.sh scripts/*
shellcheck -x install-scripts/*.sh install-scripts/lib/*.sh config/desktop-common.sh config/sets/*/apply.sh config/sets/basic/tmux/scripts/*.sh scripts/* tests/*.sh

# The gnome/kde/xfce sets apply the same decisions through three
# unrelated backends, so nothing else would notice one falling behind.
- name: Desktop intent coverage
run: bash tests/check-desktop-intents.sh

- name: Fish syntax check
run: |
Expand Down
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,13 @@ config/
os # "Linux" — hidden from `make picky` elsewhere
apply.sh
# further sets live alongside these, following the same layout
desktop-common.sh # What gnome/kde/xfce all agree to apply (see below)
install-scripts/ # Numbered setup scripts run by the Makefile
lib/sets.sh # Shared helpers for discovering/enabling sets
pick-sets.sh # the dialog checklist; takes set names to skip it
scripts/ # Misc helper scripts (e.g. Gentoo kernel upgrade)
tests/ # Dockerfiles used by CI to test installs per distro
check-desktop-intents.sh # Fails CI if a desktop set falls behind the others
```

## Config Sets & `make picky`
Expand Down Expand Up @@ -179,6 +181,45 @@ full-install` runs too, so you only need to pick once per machine. If you've
never picked, everything defaults to just `basic`, matching this repo's
historical behavior.

### Desktop intents

`gnome`, `kde` and `xfce` apply the same handful of decisions — key repeat
rate, Caps Lock as Escape, no screen lock, no idle display blanking, no
automount, an editable path bar, a dark theme — through three completely
unrelated backends (`gsettings`, `kwriteconfig`, `xfconf-query`). There's no
code worth sharing between them, so what gets shared instead is the decision.

`config/desktop-common.sh` holds both halves of that:

- the **values** all three should end up applying (`KEY_REPEAT_RATE`,
`KEY_REPEAT_DELAY_MS`), so changing the repeat rate is one edit rather than
three in three different unit systems — GNOME wants the gap between
repeats in milliseconds, the other two want a rate
- the **list** of settings all three are expected to cover, as
`DESKTOP_INTENTS`

Each `apply.sh` marks where it handles an intent with a `# intent: <id>`
comment above the relevant section, and `tests/check-desktop-intents.sh`
cross-references the two:

```
$ bash tests/check-desktop-intents.sh
intent gnome kde xfce
keyboard-repeat yes yes yes
caps-as-escape yes yes yes
...
```

It runs in CI and fails if a desktop is missing an intent, or marks one that
isn't declared (which catches typos in the markers). So adding a setting to
one desktop and forgetting the other two now breaks the build instead of
going unnoticed. Settings that genuinely only exist on one desktop — Dolphin's
menu bar, XFCE's panel layout — aren't intents and need no marker.

The `macos` set is deliberately outside this: it isn't a desktop environment
in the same sense, most of its settings have no Linux equivalent, and the few
that overlap use units that don't convert cleanly.

### Adding a new set

1. Create `config/sets/<name>/`.
Expand Down Expand Up @@ -403,6 +444,8 @@ When you submit a pull request, the following automated checks run:

- **Build Verification**: The GitHub Action (`pr-test.yml`) verifies that the dotfiles can be successfully built on each supported platform, and that the install actually landed (symlinks in place, fish functions loaded) — not just that the install command exited 0

- **Lint & Consistency**: `shellcheck` over every shell script in the repo, a `fish --no-execute` parse of every fish script, and `tests/check-desktop-intents.sh` to catch the `gnome`/`kde`/`xfce` sets drifting apart (see [Desktop intents](#desktop-intents))

### Workflow Details

The PR testing workflow:
Expand Down
43 changes: 43 additions & 0 deletions config/desktop-common.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# shellcheck shell=bash
# Shared ground truth for the desktop sets — gnome, kde and xfce.
#
# Those three sets say the same things to three completely different
# backends (gsettings, kwriteconfig, xfconf-query), so there's no code worth
# sharing between them. What *is* worth sharing is the decision behind the
# code: which settings this repo has an opinion about, and what that opinion
# is. Without that written down once, adding a setting to one desktop and
# forgetting the other two is invisible.
#
# So: every setting all three desktops are expected to cover gets an entry in
# DESKTOP_INTENTS below, and each apply.sh marks where it handles it with a
#
# # intent: <id>
#
# comment. tests/check-desktop-intents.sh cross-references the two and fails
# if a desktop is missing one, or claims an id that doesn't exist here.
# Settings that only make sense on one desktop (Dolphin's menu bar, XFCE's
# panel layout) aren't intents and need no annotation.
#
# The macos set is deliberately out of scope: it isn't a desktop environment
# in this sense, its settings mostly have no Linux equivalent, and the few
# that overlap use units that don't convert cleanly.
#
# Sourced by config/sets/{gnome,kde,xfce}/apply.sh.

# Values every desktop should end up applying, in their canonical units.
# Each backend converts as needed — GNOME, for one, wants the repeat
# *interval* in milliseconds rather than a rate.
KEY_REPEAT_RATE=50 # repeats per second, once repeating starts
KEY_REPEAT_DELAY_MS=250 # milliseconds held before repeating starts

# "<id>:<what it means>", one per setting all three desktops should cover.
# shellcheck disable=SC2034 # read by tests/check-desktop-intents.sh, which sources this
DESKTOP_INTENTS=(
"keyboard-repeat:Key repeat at ${KEY_REPEAT_RATE}/s after a ${KEY_REPEAT_DELAY_MS}ms delay"
"caps-as-escape:Caps Lock acts as Escape"
"no-screen-lock:Screen locking disabled entirely"
"no-idle-display:Display never dims or blanks when idle, on AC or battery"
"no-automount:Removable devices are not automounted"
"editable-path-bar:File dialogs offer an editable path entry, not breadcrumbs"
"dark-theme:A dark colour scheme"
)
39 changes: 26 additions & 13 deletions config/sets/gnome/apply.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ set -euo pipefail
# GNOME settings that diverge from stock defaults on this machine, mirroring
# config/sets/kde/apply.sh's choices for the GNOME desktop.
# Each section below is independent and safe to re-run.
#
# The "# intent:" markers below tie each section to an entry in
# config/desktop-common.sh, which is the one place the kde/gnome/xfce sets
# agree on what they're all supposed to cover.

REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
# shellcheck source=config/desktop-common.sh
source "$REPO/config/desktop-common.sh"

if ! command -v gsettings >/dev/null 2>&1; then
echo "Warning: gsettings not found (not a GNOME system?); skipping GNOME settings." >&2
Expand All @@ -21,36 +29,41 @@ gset() {
fi
}

# Keyboard repeat rate: 50 repeats/sec (20ms interval) with a 250ms initial
# delay (Settings > Keyboard).
gset org.gnome.desktop.peripherals.keyboard delay 250
gset org.gnome.desktop.peripherals.keyboard repeat-interval 20
# intent: keyboard-repeat
# GNOME takes the gap *between* repeats in milliseconds rather than a rate,
# so the shared rate is inverted here (Settings > Keyboard).
gset org.gnome.desktop.peripherals.keyboard delay "$KEY_REPEAT_DELAY_MS"
gset org.gnome.desktop.peripherals.keyboard repeat-interval "$(( 1000 / KEY_REPEAT_RATE ))"

# Remap Caps Lock to Escape (gnome-tweaks > Keyboard & Mouse > Additional
# Layout Options > Caps Lock Behavior).
# intent: caps-as-escape
# gnome-tweaks > Keyboard & Mouse > Additional Layout Options > Caps Lock
# Behavior.
gset org.gnome.desktop.input-sources xkb-options "['caps:escape']"

# Disable screen locking entirely (Settings > Privacy & Security > Screen
# Lock).
# intent: no-screen-lock
# Settings > Privacy & Security > Screen Lock.
gset org.gnome.desktop.screensaver lock-enabled false
gset org.gnome.desktop.screensaver idle-activation-enabled false

# intent: no-idle-display
# Never dim or blank the display when idle, on AC or battery (Settings >
# Power).
gset org.gnome.desktop.session idle-delay 0
gset org.gnome.settings-daemon.plugins.power idle-dim false
gset org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type nothing
gset org.gnome.settings-daemon.plugins.power sleep-inactive-battery-type nothing

# Disable automounting of removable devices (Settings > Removable Media).
# intent: no-automount
# Settings > Removable Media.
gset org.gnome.desktop.media-handling automount false
gset org.gnome.desktop.media-handling automount-open false

# GTK file open/save dialogs: use an editable path bar instead of
# breadcrumbs, matching Dolphin's setting.
# intent: editable-path-bar
# GTK file open/save dialogs: an editable path bar instead of breadcrumbs,
# matching Dolphin's setting.
gset org.gtk.Settings.FileChooser location-mode filename-entry
gset org.gtk.gtk4.Settings.FileChooser location-mode filename-entry

# Prefer a dark color scheme, GNOME's equivalent of Breeze Dark (Settings >
# Appearance).
# intent: dark-theme
# GNOME's equivalent of Breeze Dark (Settings > Appearance).
gset org.gnome.desktop.interface color-scheme prefer-dark
40 changes: 26 additions & 14 deletions config/sets/kde/apply.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ set -euo pipefail

# KDE Plasma settings that diverge from stock defaults on this machine.
# Each section below is independent and safe to re-run.
#
# The "# intent:" markers below tie each section to an entry in
# config/desktop-common.sh, which is the one place the kde/gnome/xfce sets
# agree on what they're all supposed to cover.

REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
# shellcheck source=config/desktop-common.sh
source "$REPO/config/desktop-common.sh"

kwriteconfig=""
for candidate in kwriteconfig6 kwriteconfig5; do
Expand All @@ -17,43 +25,47 @@ if [ -z "$kwriteconfig" ]; then
exit 0
fi

# Keyboard repeat rate: 50 repeats/sec with a 250ms initial delay
# (System Settings > Keyboard > Advanced), via kcminputrc.
"$kwriteconfig" --file kcminputrc --group Keyboard --key RepeatDelay 250
"$kwriteconfig" --file kcminputrc --group Keyboard --key RepeatRate 50
# intent: keyboard-repeat
# System Settings > Keyboard > Advanced, via kcminputrc.
"$kwriteconfig" --file kcminputrc --group Keyboard --key RepeatDelay "$KEY_REPEAT_DELAY_MS"
"$kwriteconfig" --file kcminputrc --group Keyboard --key RepeatRate "$KEY_REPEAT_RATE"

# Apply immediately in the current X11 session; a fresh Plasma login also
# re-applies it from kcminputrc either way.
if [ -n "${DISPLAY:-}" ] && command -v xset >/dev/null 2>&1; then
xset r rate 250 50 || true
xset r rate "$KEY_REPEAT_DELAY_MS" "$KEY_REPEAT_RATE" || true
fi

# Remap Caps Lock to Escape (System Settings > Keyboard > Advanced > Caps
# Lock behavior).
# intent: caps-as-escape
# System Settings > Keyboard > Advanced > Caps Lock behavior.
"$kwriteconfig" --file kxkbrc --group Layout --key Options "caps:escape"

# Disable screen locking entirely (System Settings > Screen Locking).
# intent: no-screen-lock
# System Settings > Screen Locking.
"$kwriteconfig" --file kscreenlockerrc --group Daemon --key Autolock false
"$kwriteconfig" --file kscreenlockerrc --group Daemon --key Timeout 0

# intent: no-idle-display
# Never dim or turn off the display when idle, on AC or battery
# (System Settings > Power Management > Energy Saving).
for profile in AC Battery; do
"$kwriteconfig" --file powerdevilrc --group "$profile" --group Display --key DimDisplayWhenIdle false
"$kwriteconfig" --file powerdevilrc --group "$profile" --group Display --key TurnOffDisplayWhenIdle false
done

# Disable automounting of removable devices (System Settings > Removable
# Storage).
# intent: no-automount
# System Settings > Removable Storage.
"$kwriteconfig" --file kded5rc --group Module-device_automounter --key autoload false

# Dolphin: hide the menu bar, and use an editable path bar instead of
# breadcrumbs in file open/save dialogs.
# Dolphin: hide the menu bar. KDE-only, so not a shared intent.
"$kwriteconfig" --file dolphinrc --group MainWindow --key MenuBar Disabled

# intent: editable-path-bar
# An editable path bar instead of breadcrumbs in file open/save dialogs.
"$kwriteconfig" --file kdeglobals --group "KFileDialog Settings" --key "Breadcrumb Navigation" false

# Use the Breeze Dark global theme (System Settings > Appearance > Global
# Theme).
# intent: dark-theme
# The Breeze Dark global theme (System Settings > Appearance > Global Theme).
if command -v plasma-apply-lookandfeel >/dev/null 2>&1; then
plasma-apply-lookandfeel -a org.kde.breezedark.desktop || true
else
Expand Down
33 changes: 23 additions & 10 deletions config/sets/xfce/apply.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ set -euo pipefail
# config/sets/kde/apply.sh and config/sets/gnome/apply.sh's choices for the
# XFCE desktop.
# Each section below is independent and safe to re-run.
#
# The "# intent:" markers below tie each section to an entry in
# config/desktop-common.sh, which is the one place the kde/gnome/xfce sets
# agree on what they're all supposed to cover.

REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
# shellcheck source=config/desktop-common.sh
source "$REPO/config/desktop-common.sh"

if ! command -v xfconf-query >/dev/null 2>&1; then
echo "Warning: xfconf-query not found (not an XFCE system?); skipping XFCE settings." >&2
Expand All @@ -23,19 +31,20 @@ xset_prop() {

# --- Keyboard ---------------------------------------------------------

# Keyboard repeat rate: 50 repeats/sec with a 250ms initial delay
# (Settings > Keyboard > Behaviour).
# intent: keyboard-repeat
# Settings > Keyboard > Behaviour.
xset_prop keyboards /Default/KeyRepeat bool true
xset_prop keyboards /Default/KeyRepeat/Rate int 50
xset_prop keyboards /Default/KeyRepeat/Delay int 250
xset_prop keyboards /Default/KeyRepeat/Rate int "$KEY_REPEAT_RATE"
xset_prop keyboards /Default/KeyRepeat/Delay int "$KEY_REPEAT_DELAY_MS"

# Apply immediately in the current X11 session; a fresh login also
# re-applies it from the "keyboards" channel either way.
if [ -n "${DISPLAY:-}" ] && command -v xset >/dev/null 2>&1; then
xset r rate 250 50 || true
xset r rate "$KEY_REPEAT_DELAY_MS" "$KEY_REPEAT_RATE" || true
fi

# Remap Caps Lock to Escape. Unlike the layout/group/compose-key options,
# intent: caps-as-escape
# Unlike the layout/group/compose-key options,
# xfsettingsd has no xfconf-backed setting for this XKB option group, so it
# can't be stored declaratively the way the kde/gnome sets do it — it's
# applied directly via setxkbmap instead, both now and on every future
Expand All @@ -57,7 +66,8 @@ fi

# --- Screen locking & power --------------------------------------------

# Disable screen locking entirely (Settings > Screensaver). xfce4-screensaver
# intent: no-screen-lock
# Settings > Screensaver. xfce4-screensaver
# is a separate, optional package (older XFCE releases use light-locker
# instead, which has no xfconf-backed settings of its own).
if command -v xfce4-screensaver >/dev/null 2>&1; then
Expand All @@ -67,6 +77,7 @@ else
echo "Warning: xfce4-screensaver not found; skipping screen lock settings." >&2
fi

# intent: no-idle-display
# Never dim or turn off the display when idle, on AC or battery, and don't
# lock on suspend/hibernate (Settings > Power Manager).
if command -v xfce4-power-manager >/dev/null 2>&1; then
Expand All @@ -80,9 +91,9 @@ fi

# --- Device automount ----------------------------------------------------

# Disable automounting of removable devices (Settings > Removable Drives
# and Media). thunar-volman is a separate, optional package from Thunar
# itself.
# intent: no-automount
# Settings > Removable Drives and Media. thunar-volman is a separate,
# optional package from Thunar itself.
if command -v thunar-volman >/dev/null 2>&1; then
xset_prop thunar-volman /autobrowse/enabled bool false
xset_prop thunar-volman /automount-drives/enabled bool false
Expand All @@ -94,6 +105,7 @@ fi

# --- File manager / dialogs ----------------------------------------------

# intent: editable-path-bar
# Thunar: use an editable path bar instead of breadcrumbs.
if command -v thunar >/dev/null 2>&1; then
xset_prop thunar /last-location-bar string ThunarLocationEntry
Expand All @@ -118,6 +130,7 @@ fi

# --- Appearance ------------------------------------------------------------

# intent: dark-theme
# Prefer a dark GTK + window manager theme, whichever of these common dark
# themes is actually installed (Settings > Appearance / Window Manager).
pick_dark_theme() {
Expand Down
Loading
Loading