yep, more dotfiles
1{ config
2, lib
3, pkgs
4, ...
5}:
6
7let
8 cfg = config.programs.xcompose;
9in
10{
11 options.programs.xcompose = with lib; {
12 enable = mkEnableOption "XCompose keyboard configuration";
13
14 loadConfigInEnv = mkOption {
15 description = ''
16 Load the XCompose file by passing the `XCOMPOSEFILE` environment variable instead of linking to ~/.XCompose.
17
18 That is nice to avoid cluttering the HOME directory, it's preferable to disable it when experimenting
19 with your compose config to reload faster than having to reload your VM.
20 '';
21 default = true;
22 type = types.bool;
23 };
24
25 includeLocaleCompose = mkOption {
26 description = "Whether to include the base libX11 locale compose file";
27 default = false;
28 type = types.bool;
29 };
30
31 sequences = mkOption {
32 description = ''
33 Shapeless tree of macros
34 - Keys name can be easily found with wev (or xev)
35 - https://www.compart.com/en/unicode — Lists all Unicode characters
36 '';
37 default = { };
38 example = {
39 Multi_key = {
40 "g" = {
41 a = "α";
42 b = "β";
43 };
44 };
45 };
46 type = types.anything;
47 };
48
49 extraConfig = mkOption {
50 description = ''
51 Unmanaged xcompose sequences and directives
52 '';
53 default = "";
54 example = ''
55 <Multi_key> <Multi_key> <a> <5> : "٥"
56 '';
57 type = types.lines;
58 };
59 };
60
61 config =
62 with lib;
63 let
64 comboListToString = foldl (acc: val: acc + "<${val}> ") "";
65 sanitizeComboResult = escape [ ''"'' ];
66
67 comboSetToList = ip: flatten (mapAttrsToList
68 (name: value:
69 if isAttrs value then
70 let vs = comboSetToList value;
71 in
72 map ({ combo, value }: { combo = [ name ] ++ combo; inherit value; }) vs
73 else if isString value then
74 { combo = [ name ]; inherit value; }
75 else throw "combo value must be a string"
76 )
77 ip);
78 complexListToSimple = map ({ combo, value }: { combo = comboListToString combo; value = sanitizeComboResult value; });
79 toComposeFile = foldl (acc: val: acc + "${val.combo}: \"${val.value}\"\n") "";
80
81 processComposeSet = set: toComposeFile (complexListToSimple (comboSetToList set));
82
83 # TODO: see if include changes if put after compose declarations
84 composeFile = pkgs.writeText "XCompose" ''
85 ${optionalString cfg.includeLocaleCompose "include \"%L\""}
86 ${processComposeSet cfg.sequences}
87 ${cfg.extraConfig}
88 '';
89 in
90 mkIf cfg.enable {
91 home.sessionVariables = mkIf cfg.loadConfigInEnv { XCOMPOSEFILE = composeFile; };
92 home.file = mkIf (!cfg.loadConfigInEnv) { ".XCompose".source = composeFile; };
93 };
94}