From 0ad41947dddf4042fb22df294f5b947dfe17cca0 Mon Sep 17 00:00:00 2001 From: Heitor Augusto Date: Thu, 12 Sep 2024 15:42:36 -0300 Subject: [PATCH 1/2] Add KXMLGUI support and add konsole options for toolbar customization --- lib/kxmlgui.nix | 226 +++++++++++++++++++++++++++++++++++++++ modules/apps/konsole.nix | 167 ++++++++++++++++++----------- 2 files changed, 329 insertions(+), 64 deletions(-) create mode 100644 lib/kxmlgui.nix diff --git a/lib/kxmlgui.nix b/lib/kxmlgui.nix new file mode 100644 index 00000000..934d750a --- /dev/null +++ b/lib/kxmlgui.nix @@ -0,0 +1,226 @@ +{ lib, ... }: +let + boolToString = bool: if bool then "1" else "0"; + + propertyType = lib.types.submodule { + options = { + name = lib.mkOption { + type = lib.types.str; + description = "The name of the property."; + }; + shortcut = lib.mkOption { + type = lib.types.str; + description = "The shortcut of the property."; + }; + }; + }; + + actionPropertiesType = lib.types.submodule { + options = { + scheme = lib.mkOption { + type = lib.types.str; + description = "The scheme of the action properties."; + }; + properties = lib.mkOption { + type = lib.types.listOf propertyType; + description = "The properties of the action properties."; + }; + }; + }; + + toolbarType = lib.types.submodule { + options = { + alreadyVisited = lib.mkOption { + type = with lib.types; nullOr bool; + default = null; + example = true; + description = "Whether the toolbar has already been visited."; + apply = value: if value != null then boolToString value else null; + }; + noMerge = lib.mkOption { + type = with lib.types; nullOr bool; + default = null; + example = true; + description = "Whether the toolbar should not be merged."; + apply = value: if value != null then boolToString value else null; + }; + items = lib.mkOption { + type = lib.types.listOf itemType; + description = "The items of the toolbar."; + }; + }; + }; + + itemType = lib.types.submodule { + options = { + type = lib.mkOption { + type = lib.types.enum [ + "action" + "group" + "text" + "separator" + ]; + description = "The type of the item."; + example = "action"; + }; + group = lib.mkOption { + type = with lib.types; nullOr str; + default = null; + description = "The group of the item."; + }; + value = lib.mkOption { + type = lib.types.str; + description = "The value of the item."; + }; + }; + }; + + menuType = lib.types.submodule { + options = { + name = lib.mkOption { + type = lib.types.str; + description = "The name of the menu."; + }; + items = lib.mkOption { + type = lib.types.listOf itemType; + description = "The items of the menu."; + }; + }; + }; + + menuBarType = lib.types.submodule { + options = { + alreadyVisited = lib.mkOption { + type = with lib.types; nullOr bool; + default = null; + example = true; + description = "Whether the menu bar has already been visited."; + apply = value: if value != null then boolToString value else null; + }; + noMerge = lib.mkOption { + type = with lib.types; nullOr bool; + default = null; + example = true; + description = "Whether the menu bar should not be merged."; + apply = value: if value != null then boolToString value else null; + }; + menus = lib.mkOption { + type = lib.types.listOf menuType; + description = "The menus of the menu bar."; + }; + }; + }; + + kxmlguiType = lib.types.submodule { + options = { + name = lib.mkOption { + type = lib.types.str; + description = "The name of the configuration."; + }; + version = lib.mkOption { + type = lib.types.ints.unsigned; + description = "The version of the configuration."; + }; + translationDomain = lib.mkOption { + type = with lib.types; nullOr str; + default = null; + example = "kxmlgui6"; + description = "The translation domain of the configuration"; + }; + menubar = lib.mkOption { + type = lib.types.nullOr menuBarType; + default = null; + description = "The menu bar of the configuration."; + }; + toolbar = lib.mkOption { + type = lib.types.nullOr toolbarType; + default = null; + description = "The toolbar of the configuration."; + }; + actionProperties = lib.mkOption { + type = lib.types.nullOr actionPropertiesType; + default = null; + description = "The action properties of the configuration."; + }; + }; + }; + + generateKXMLGUI = + name: version: translationDomain: menubar: toolbar: actionProperties: + let + generateItem = + item: + if item.type == "action" then + '''' + else if item.type == "group" then + '''' + else if item.type == "text" then + "${item.value}" + else + ""; + generateActionProperty = + property: ''''; + in + '' + + + + ${ + lib.optionalString (menubar != null) '' + + ${ + lib.concatMapStringsSep "\n" (menu: '' + + ${ + lib.concatMapStringsSep "\n" (item: '' + ${generateItem item} + '') menu.items + } + + '') menubar.menus + } + + '' + } + ${ + lib.optionalString (toolbar != null) '' + + ${lib.concatMapStringsSep "\n" (item: ''${generateItem item}'') toolbar.items} + + '' + } + ${ + lib.optionalString (actionProperties != null) '' + ${lib.concatMapStringsSep "\n" (actionProps: '' + + ${ + lib.concatMapStringsSep "\n" (property: '' + ${generateActionProperty property} + '') actionProps.properties + } + + '') actionProperties} + '' + } + + ''; +in +{ + inherit generateKXMLGUI kxmlguiType; +} diff --git a/modules/apps/konsole.nix b/modules/apps/konsole.nix index c6d1ad2b..6078a3d5 100644 --- a/modules/apps/konsole.nix +++ b/modules/apps/konsole.nix @@ -1,12 +1,27 @@ -{ config, lib, pkgs, ... }: +{ + config, + lib, + pkgs, + ... +}: let - inherit (import ../../lib/types.nix { inherit lib; inherit config; }) basicSettingsType; + inherit + (import ../../lib/types.nix { + inherit lib; + inherit config; + }) + basicSettingsType + ; + inherit (import ../../lib/kxmlgui.nix { inherit lib; }) generateKXMLGUI kxmlguiType; # used as shown in the example in the library docs: # https://ryantm.github.io/nixpkgs/functions/library/attrsets/#function-library-lib.attrsets.mapAttrs-prime - createColorSchemes = lib.attrsets.mapAttrs' (name: value: lib.attrsets.nameValuePair - ("konsole/${name}.colorscheme") - ({ enable = true; source = value; }) + createColorSchemes = lib.attrsets.mapAttrs' ( + name: value: + lib.attrsets.nameValuePair ("konsole/${name}.colorscheme") { + enable = true; + source = value; + } ); cfg = config.programs.konsole; @@ -42,11 +57,11 @@ let name = lib.mkOption { type = lib.types.str; /* - TODO: Set default to null after adding an assertion - Konsole needs to have a font set to be able to change font size - Since I couldn't get that to work I'll just set a default font - Not ideal since IMO we should only write things that are set explicitly - by the user but ehh it is what it is + TODO: Set default to null after adding an assertion + Konsole needs to have a font set to be able to change font size + Since I couldn't get that to work I'll just set a default font + Not ideal since IMO we should only write things that are set explicitly + by the user but ehh it is what it is */ default = "Hack"; example = "Hack"; @@ -121,27 +136,41 @@ in }; extraConfig = lib.mkOption { - type = with lib.types; nullOr (attrsOf (attrsOf (basicSettingsType))); + type = with lib.types; nullOr (attrsOf (attrsOf basicSettingsType)); default = null; description = '' Extra config to add to konsolerc. ''; }; + + toolbar = { + konsole = lib.mkOption { + type = lib.types.nullOr kxmlguiType; + default = null; + description = '' + The toolbar of Konsole. + ''; + }; + session = lib.mkOption { + type = lib.types.nullOr kxmlguiType; + default = null; + description = '' + The toolbar of Konsole sessions. + ''; + }; + }; }; config = lib.mkIf (cfg.enable) { programs.plasma.configFile."konsolerc" = lib.mkMerge [ - ( - lib.mkIf (cfg.defaultProfile != null) { - "Desktop Entry"."DefaultProfile" = "${cfg.defaultProfile}.profile"; - } - ) - ( - lib.mkIf (cfg.extraConfig != null) (lib.mapAttrs - (groupName: groupAttrs: - (lib.mapAttrs (keyName: keyAttrs: { value = keyAttrs; }) groupAttrs)) - cfg.extraConfig) - ) + (lib.mkIf (cfg.defaultProfile != null) { + "Desktop Entry"."DefaultProfile" = "${cfg.defaultProfile}.profile"; + }) + (lib.mkIf (cfg.extraConfig != null) ( + lib.mapAttrs ( + groupName: groupAttrs: (lib.mapAttrs (keyName: keyAttrs: { value = keyAttrs; }) groupAttrs) + ) cfg.extraConfig + )) { "UiSettings"."ColorScheme" = lib.mkIf (cfg.ui.colorScheme != null) { value = cfg.ui.colorScheme; @@ -153,51 +182,61 @@ in ]; xdg.dataFile = lib.mkMerge [ - (lib.mkIf (cfg.profiles != { }) - ( - lib.mkMerge ([ - ( - lib.mkMerge ( - lib.mapAttrsToList - ( - attrName: profile: - let - # Use the name from the name option if it's set - profileName = if builtins.isString profile.name then profile.name else attrName; - fontString = lib.mkIf (profile.font.name != null) "${profile.font.name},${builtins.toString profile.font.size}"; - in + (lib.mkIf (cfg.profiles != { }) ( + lib.mkMerge [ + (lib.mkMerge ( + lib.mapAttrsToList ( + attrName: profile: + let + # Use the name from the name option if it's set + profileName = if builtins.isString profile.name then profile.name else attrName; + fontString = lib.mkIf ( + profile.font.name != null + ) "${profile.font.name},${builtins.toString profile.font.size}"; + in + { + "konsole/${profileName}.profile".text = lib.generators.toINI { } ( + lib.recursiveUpdate { + "General" = ( + { + "Name" = profileName; + # Konsole generated profiles seem to always have this + "Parent" = "FALLBACK/"; + } + // (lib.optionalAttrs (profile.command != null) { "Command" = profile.command; }) + ); + "Appearance" = ( { - "konsole/${profileName}.profile".text = lib.generators.toINI { } - (lib.recursiveUpdate - { - "General" = ( - { - "Name" = profileName; - # Konsole generated profiles seem to always have this - "Parent" = "FALLBACK/"; - } // - (lib.optionalAttrs (profile.command != null) { "Command" = profile.command; }) - ); - "Appearance" = ( - { - # If the font size is not set we leave a comma at the end after the name - # We should fix this probs but konsole doesn't seem to care ¯\_(ツ)_/¯ - "Font" = fontString.content; - } // - (lib.optionalAttrs (profile.colorScheme != null) { "ColorScheme" = profile.colorScheme; }) - ); - } - profile.extraConfig - ); + # If the font size is not set we leave a comma at the end after the name + # We should fix this probs but konsole doesn't seem to care ¯\_(ツ)_/¯ + "Font" = fontString.content; } - ) - cfg.profiles - ) - ) - ]) - ) - ) + // (lib.optionalAttrs (profile.colorScheme != null) { "ColorScheme" = profile.colorScheme; }) + ); + } profile.extraConfig + ); + } + ) cfg.profiles + )) + ] + )) (createColorSchemes cfg.customColorSchemes) + (lib.mkIf (cfg.toolbar.konsole != null) { + "kxmlgui5/konsole/konsoleui.rc".text = ( + generateKXMLGUI cfg.toolbar.konsole.name cfg.toolbar.konsole.version + cfg.toolbar.konsole.translationDomain + cfg.toolbar.konsole.menubar + cfg.toolbar.konsole.toolbar + cfg.toolbar.konsole.actionProperties + ); + "kxmlgui5/konsole/sessionui.rc".text = ( + generateKXMLGUI cfg.toolbar.session.name cfg.toolbar.session.version + cfg.toolbar.session.translationDomain + cfg.toolbar.session.menubar + cfg.toolbar.session.toolbar + cfg.toolbar.session.actionProperties + ); + }) ]; }; } From efbb79e084503cd7f3e30530b2905adf52aa0fa9 Mon Sep 17 00:00:00 2001 From: Heitor Augusto Date: Thu, 12 Sep 2024 15:45:20 -0300 Subject: [PATCH 2/2] Add a separate conditional for session toolbar --- modules/apps/konsole.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/apps/konsole.nix b/modules/apps/konsole.nix index 6078a3d5..15710aed 100644 --- a/modules/apps/konsole.nix +++ b/modules/apps/konsole.nix @@ -229,6 +229,8 @@ in cfg.toolbar.konsole.toolbar cfg.toolbar.konsole.actionProperties ); + }) + (lib.mkIf (cfg.toolbar.session != null) { "kxmlgui5/konsole/sessionui.rc".text = ( generateKXMLGUI cfg.toolbar.session.name cfg.toolbar.session.version cfg.toolbar.session.translationDomain