Commit 0553499
Move config to ~/.config/roost/config.conf with externalized keybindings (#7)
* Move config to ~/.config/roost/config.conf with externalized keybindings
The hand-edited config file now lives at ~/.config/roost/config.conf
(or $XDG_CONFIG_HOME/roost/config.conf) on both macOS and Linux. The
SQLite database and IPC socket stay in their platform-native locations
(~/Library/Application Support/Roost on macOS, $XDG_DATA_HOME on
Linux).
Keybindings move out of cmd/roost and into the config file using
Ghostty's syntax:
keybind = super+j = new_tab # add a second trigger
keybind = super+t = unbind # disable a default
keybind = super+t = close_tab # reassign
Each keybind line is applied on top of the platform defaults; later
lines override earlier ones for the same trigger (last-wins). Unknown
actions and unparseable triggers are logged and skipped.
Implementation notes
- internal/config/paths.go: ConfigDir is now XDG-aware on darwin too;
ConfigFile() is config.conf instead of config.toml. New
LegacyMacConfigFile() points at the pre-cutover path so main.go can
log a one-shot migration warning when only the legacy file exists.
- internal/config/config.go: adds Keybinds []Keybind to Config and a
keybind arm to the parser. parseKeybind splits on the inner =;
errors include file:line.
- cmd/roost/shortcuts.go (new): triggerToAccel converts Ghostty
trigger syntax to a GTK accelerator string; resolveBindings is a
pure function that layers user keybinds on top of defaults
(unit-tested without a live widget tree).
- cmd/roost/app.go: installShortcuts is rewritten as an action-table
driven loop. The propagate-false path for clipboard actions is
preserved (returning false in the gated callback so an editable
widget keeps its native paste).
- cmd/roost/main.go: drops the package-global font vars; cfg threads
through NewApp -> NewSession.
Breaking change: a pre-existing config.toml is not auto-migrated.
Roost logs a warning at startup with the move command. The hard
cutover is fine because Roost is early-stage.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* gofmt: realign cases-map values in shortcuts_test.go
Caught by macOS lint job. The longer "super+bracketleft" entry was
already padded to its column; the shorter entries needed to extend
to match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Address PR #7 review feedback: deterministic shortcut order + minor fixes
- cmd/roost/app.go: sort the resolved triggers before installing
shortcuts. When two distinct triggers in the user's config normalize
to the same GTK accel (e.g. `ctrl+t` and `control+t`), Go's random
map iteration would otherwise pick the winner non-deterministically.
Sorting gives lexicographic last-wins.
- cmd/roost/main.go: quote both paths in the legacy-config migration
hint with %q so the macOS path (which contains spaces in
"Library/Application Support/Roost") is copy-paste safe.
- internal/config/paths_test.go: don't hard-code the default
~/.config layout in the macOS branch of TestResolve — a developer
with XDG_CONFIG_HOME set would spuriously fail. Compare on basename
instead. TestResolveConfigDirRespectsXDG already covers the env-var
path explicitly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Validate user keybinds before they replace defaults
Closes a UX issue CodeRabbit flagged on #7: with the previous flow,
a typo in a user keybind action (e.g. `keybind = ctrl+t = typo`)
would write the typo into the resolved trigger map, then get dropped
in the install loop's handler-lookup, leaving `ctrl+t` unbound. The
default `new_tab` binding was silently lost.
Now installShortcuts seeds the resolved set with platform defaults
only and merges each user keybind entry-by-entry, validating
trigger and action before overwrite. Invalid entries log a warning
and the default binding is preserved. `unbind` continues to work as
before.
resolveBindings stays purely structural — its existing test suite is
unchanged and a clarified comment on the unknown-action test pins
that contract for future callers.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Canonicalize trigger aliases at the install layer
Closes the third (and last) of CodeRabbit's PR #7 review threads:
the install pipeline keyed its resolved map by literal trigger text,
so `keybind = cmd+t = unbind` did NOT remove the macOS default
seeded as `super+t` even though both normalize to `<Meta>t`. Same
asymmetry for `cmd+t = close_tab` — it ended up alongside `super+t`
instead of replacing it.
Fix: extract canonicalizeBindings as a pure function that keys the
resolved map by the GTK accel form (the output of triggerToAccel).
Aliases collapse on insertion, unbind matches by accel, and the
production install loop iterates already-canonical accels.
The function bundles three jobs that were previously split across
shortcuts.go and the install loop in app.go: (1) alias collapse,
(2) action validation, (3) trigger validation. The warn callback
keeps it pure (no slog import in tests).
resolveBindings stays as a structural-merge primitive for the
existing test suite, with its docstring updated to point at
canonicalizeBindings as the production path.
Tests added for the four canonicalization invariants:
- super+t default + cmd+t = unbind → {} (alias collapse)
- super+t default + cmd+t = close_tab → {<Meta>t: close_tab}
- ctrl+t default + ctrl+t = typo → default preserved + warn
- ctrl+t default + hyper+t = close → default preserved + warn
- ctrl+t default + control+t = unbind → {} (alias unbind)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent a0274e3 commit 0553499
13 files changed
Lines changed: 963 additions & 123 deletions
File tree
- cmd/roost
- docs
- development
- getting-started
- reference
- internal/config
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| 21 | + | |
20 | 22 | | |
21 | 23 | | |
22 | 24 | | |
| |||
34 | 36 | | |
35 | 37 | | |
36 | 38 | | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
37 | 44 | | |
38 | 45 | | |
39 | 46 | | |
| |||
69 | 76 | | |
70 | 77 | | |
71 | 78 | | |
72 | | - | |
| 79 | + | |
73 | 80 | | |
74 | 81 | | |
75 | 82 | | |
| 83 | + | |
76 | 84 | | |
77 | 85 | | |
78 | 86 | | |
| |||
478 | 486 | | |
479 | 487 | | |
480 | 488 | | |
481 | | - | |
| 489 | + | |
482 | 490 | | |
483 | 491 | | |
484 | 492 | | |
| |||
894 | 902 | | |
895 | 903 | | |
896 | 904 | | |
897 | | - | |
898 | | - | |
899 | | - | |
900 | | - | |
901 | | - | |
902 | | - | |
903 | | - | |
904 | | - | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
905 | 911 | | |
906 | 912 | | |
907 | 913 | | |
908 | 914 | | |
909 | | - | |
| 915 | + | |
910 | 916 | | |
911 | 917 | | |
912 | 918 | | |
913 | 919 | | |
914 | 920 | | |
915 | | - | |
| 921 | + | |
916 | 922 | | |
917 | 923 | | |
918 | | - | |
| 924 | + | |
919 | 925 | | |
920 | 926 | | |
921 | 927 | | |
| |||
924 | 930 | | |
925 | 931 | | |
926 | 932 | | |
927 | | - | |
928 | | - | |
929 | | - | |
930 | | - | |
931 | | - | |
932 | | - | |
933 | | - | |
934 | | - | |
| 933 | + | |
| 934 | + | |
| 935 | + | |
| 936 | + | |
| 937 | + | |
| 938 | + | |
935 | 939 | | |
936 | 940 | | |
937 | | - | |
| 941 | + | |
938 | 942 | | |
939 | 943 | | |
940 | 944 | | |
941 | | - | |
| 945 | + | |
| 946 | + | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
942 | 950 | | |
943 | 951 | | |
944 | 952 | | |
945 | 953 | | |
946 | | - | |
947 | | - | |
948 | | - | |
949 | | - | |
950 | | - | |
| 954 | + | |
| 955 | + | |
| 956 | + | |
951 | 957 | | |
952 | | - | |
953 | | - | |
954 | | - | |
955 | | - | |
956 | | - | |
957 | | - | |
958 | | - | |
959 | | - | |
960 | | - | |
961 | | - | |
962 | | - | |
963 | | - | |
964 | | - | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
965 | 968 | | |
966 | | - | |
967 | | - | |
968 | | - | |
969 | | - | |
970 | | - | |
971 | | - | |
972 | | - | |
973 | | - | |
974 | | - | |
975 | | - | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
976 | 976 | | |
977 | 977 | | |
978 | | - | |
979 | | - | |
980 | | - | |
981 | | - | |
982 | 978 | | |
983 | | - | |
984 | | - | |
985 | | - | |
986 | | - | |
987 | | - | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
988 | 982 | | |
989 | | - | |
990 | | - | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
991 | 1006 | | |
992 | 1007 | | |
993 | | - | |
994 | | - | |
995 | | - | |
996 | | - | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
| 1015 | + | |
997 | 1016 | | |
998 | | - | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
| 1047 | + | |
| 1048 | + | |
| 1049 | + | |
| 1050 | + | |
| 1051 | + | |
999 | 1052 | | |
1000 | | - | |
1001 | | - | |
1002 | | - | |
1003 | | - | |
| 1053 | + | |
| 1054 | + | |
1004 | 1055 | | |
1005 | | - | |
1006 | | - | |
| 1056 | + | |
1007 | 1057 | | |
1008 | 1058 | | |
1009 | 1059 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
8 | 11 | | |
| 12 | + | |
9 | 13 | | |
10 | 14 | | |
11 | 15 | | |
| |||
21 | 25 | | |
22 | 26 | | |
23 | 27 | | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | | - | |
34 | 28 | | |
35 | 29 | | |
36 | 30 | | |
| |||
45 | 39 | | |
46 | 40 | | |
47 | 41 | | |
48 | | - | |
49 | | - | |
| 42 | + | |
50 | 43 | | |
51 | 44 | | |
52 | 45 | | |
| |||
64 | 57 | | |
65 | 58 | | |
66 | 59 | | |
67 | | - | |
| 60 | + | |
68 | 61 | | |
69 | 62 | | |
70 | 63 | | |
71 | 64 | | |
72 | 65 | | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
128 | 128 | | |
129 | 129 | | |
130 | 130 | | |
131 | | - | |
| 131 | + | |
132 | 132 | | |
133 | 133 | | |
134 | 134 | | |
| |||
0 commit comments