1{ config, pkgs, lib, ... }:
2
3with lib;
4
5let
6 im = config.i18n.inputMethod;
7 cfg = im.fcitx5;
8 fcitx5Package = pkgs.fcitx5-with-addons.override { inherit (cfg) addons; };
9 settingsFormat = pkgs.formats.ini { };
10in
11{
12 options = {
13 i18n.inputMethod.fcitx5 = {
14 addons = mkOption {
15 type = with types; listOf package;
16 default = [ ];
17 example = literalExpression "with pkgs; [ fcitx5-rime ]";
18 description = lib.mdDoc ''
19 Enabled Fcitx5 addons.
20 '';
21 };
22 quickPhrase = mkOption {
23 type = with types; attrsOf str;
24 default = { };
25 example = literalExpression ''
26 {
27 smile = "(・∀・)";
28 angry = "( ̄ー ̄)";
29 }
30 '';
31 description = lib.mdDoc "Quick phrases.";
32 };
33 quickPhraseFiles = mkOption {
34 type = with types; attrsOf path;
35 default = { };
36 example = literalExpression ''
37 {
38 words = ./words.mb;
39 numbers = ./numbers.mb;
40 }
41 '';
42 description = lib.mdDoc "Quick phrase files.";
43 };
44 settings = {
45 globalOptions = lib.mkOption {
46 type = lib.types.submodule {
47 freeformType = settingsFormat.type;
48 };
49 default = { };
50 description = lib.mdDoc ''
51 The global options in `config` file in ini format.
52 '';
53 };
54 inputMethod = lib.mkOption {
55 type = lib.types.submodule {
56 freeformType = settingsFormat.type;
57 };
58 default = { };
59 description = lib.mdDoc ''
60 The input method configure in `profile` file in ini format.
61 '';
62 };
63 addons = lib.mkOption {
64 type = with lib.types; (attrsOf anything);
65 default = { };
66 description = lib.mdDoc ''
67 The addon configures in `conf` folder in ini format with global sections.
68 Each item is written to the corresponding file.
69 '';
70 example = literalExpression "{ pinyin.globalSection.EmojiEnabled = \"True\"; }";
71 };
72 };
73 ignoreUserConfig = lib.mkOption {
74 type = lib.types.bool;
75 default = false;
76 description = lib.mdDoc ''
77 Ignore the user configures. **Warning**: When this is enabled, the
78 user config files are totally ignored and the user dict can't be saved
79 and loaded.
80 '';
81 };
82 };
83 };
84
85 imports = [
86 (mkRemovedOptionModule [ "i18n" "inputMethod" "fcitx5" "enableRimeData" ] ''
87 RIME data is now included in `fcitx5-rime` by default, and can be customized using `fcitx5-rime.override { rimeDataPkgs = ...; }`
88 '')
89 ];
90
91 config = mkIf (im.enabled == "fcitx5") {
92 i18n.inputMethod.package = fcitx5Package;
93
94 i18n.inputMethod.fcitx5.addons = lib.optionals (cfg.quickPhrase != { }) [
95 (pkgs.writeTextDir "share/fcitx5/data/QuickPhrase.mb"
96 (lib.concatStringsSep "\n"
97 (lib.mapAttrsToList (name: value: "${name} ${value}") cfg.quickPhrase)))
98 ] ++ lib.optionals (cfg.quickPhraseFiles != { }) [
99 (pkgs.linkFarm "quickPhraseFiles" (lib.mapAttrs'
100 (name: value: lib.nameValuePair ("share/fcitx5/data/quickphrase.d/${name}.mb") value)
101 cfg.quickPhraseFiles))
102 ];
103 environment.etc =
104 let
105 optionalFile = p: f: v: lib.optionalAttrs (v != { }) {
106 "xdg/fcitx5/${p}".text = f v;
107 };
108 in
109 lib.attrsets.mergeAttrsList [
110 (optionalFile "config" (lib.generators.toINI { }) cfg.settings.globalOptions)
111 (optionalFile "profile" (lib.generators.toINI { }) cfg.settings.inputMethod)
112 (lib.concatMapAttrs
113 (name: value: optionalFile
114 "conf/${name}.conf"
115 (lib.generators.toINIWithGlobalSection { })
116 value)
117 cfg.settings.addons)
118 ];
119
120 environment.variables = {
121 GTK_IM_MODULE = "fcitx";
122 QT_IM_MODULE = "fcitx";
123 XMODIFIERS = "@im=fcitx";
124 QT_PLUGIN_PATH = [ "${fcitx5Package}/${pkgs.qt6.qtbase.qtPluginPrefix}" ];
125 } // lib.optionalAttrs cfg.ignoreUserConfig {
126 SKIP_FCITX_USER_PATH = "1";
127 };
128 };
129}