diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dccdc8f8ec81..3aa838abd1ea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -77,6 +77,9 @@ /modules/programs/mpv.nix @tadeokondrak +/modules/programs/ncmpcpp.nix @olmokramer +/tests/modules/programs/ncmpcpp @olmokramer + /modules/programs/ne.nix @cwyc /tests/modules/programs/ne @cwyc diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix index ff046360071c..8cb8781228b3 100644 --- a/modules/lib/maintainers.nix +++ b/modules/lib/maintainers.nix @@ -35,4 +35,10 @@ fingerprint = "D446 E58D 87A0 31C7 EC15 88D7 B461 2924 45C6 E696"; }]; }; + olmokramer = { + name = "Olmo Kramer"; + email = "olmokramer@users.noreply.github.com"; + github = "olmokramer"; + githubId = 3612514; + }; } diff --git a/modules/misc/news.nix b/modules/misc/news.nix index bdbd589a501b..2539aea7db1a 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -1642,6 +1642,13 @@ in A new module is available: 'programs.mcfly' ''; } + + { + time = "2020-08-26T18:47:12+00:00"; + message = '' + A new module is available: 'programs.ncmpcpp' + ''; + } ]; }; } diff --git a/modules/modules.nix b/modules/modules.nix index bae51d69297f..b4eb4d4027ca 100644 --- a/modules/modules.nix +++ b/modules/modules.nix @@ -90,6 +90,7 @@ let (loadModule ./programs/mercurial.nix { }) (loadModule ./programs/mpv.nix { }) (loadModule ./programs/msmtp.nix { }) + (loadModule ./programs/ncmpcpp.nix { }) (loadModule ./programs/ne.nix { }) (loadModule ./programs/neomutt.nix { }) (loadModule ./programs/neovim.nix { }) diff --git a/modules/programs/ncmpcpp.nix b/modules/programs/ncmpcpp.nix new file mode 100644 index 000000000000..f9644d3c689c --- /dev/null +++ b/modules/programs/ncmpcpp.nix @@ -0,0 +1,140 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.programs.ncmpcpp; + + mpdCfg = config.services.mpd; + + renderSettings = settings: + concatStringsSep "\n" (mapAttrsToList renderSetting settings); + + renderSetting = name: value: "${name}=${renderValue value}"; + + renderValue = option: + { + int = toString option; + bool = if option then "yes" else "no"; + string = option; + }.${builtins.typeOf option}; + + renderBindings = bindings: concatStringsSep "\n" (map renderBinding bindings); + + renderBinding = { key, command }: + concatStringsSep "\n " ([ ''def_key "${key}"'' ] ++ maybeWrapList command); + + maybeWrapList = xs: if isList xs then xs else [ xs ]; + + valueType = with types; oneOf [ bool int str ]; + + bindingType = types.submodule ({ name, config, ... }: { + options = { + key = mkOption { + type = types.str; + description = "Key to bind."; + example = "j"; + }; + + command = mkOption { + type = with types; either str (listOf str); + description = "Command or sequence of commands to be executed."; + example = "scroll_down"; + }; + }; + }); + +in { + meta.maintainers = with maintainers; [ olmokramer ]; + + options.programs.ncmpcpp = { + enable = + mkEnableOption "ncmpcpp - an ncurses Music Player Daemon (MPD) client"; + + package = mkOption { + type = types.package; + default = pkgs.ncmpcpp; + defaultText = literalExample "pkgs.ncmpcpp"; + description = '' + Package providing the ncmpcpp command. + ''; + example = + literalExample "pkgs.ncmpcpp.override { visualizerSupport = true; }"; + }; + + mpdMusicDir = mkOption { + type = types.nullOr types.path; + default = if pkgs.stdenv.hostPlatform.isLinux && mpdCfg.enable then + mpdCfg.musicDirectory + else + null; + defaultText = literalExample '' + if pkgs.stdenv.hostPlatform.isLinux && config.services.mpd.enable then + config.services.mpd.musicDirectory + else + null + ''; + description = '' + Value of the mpd_music_dir setting. On Linux platforms + the value of services.mpd.musicDirectory is used as the default if + services.mpd.enable is true. + ''; + example = "~/music"; + }; + + settings = mkOption { + type = types.attrsOf valueType; + default = { }; + description = '' + Attrset from name of a setting to its value. For available options + See + + ncmpcpp + 1 + + ''; + example = literalExample '' + { + ncmpcpp_directory = "~/.local/share/ncmpcpp"; + } + ''; + }; + + bindings = mkOption { + type = types.listOf bindingType; + default = [ ]; + description = "List of keybindings."; + example = literalExample '' + [ + { key = "j"; command = "scroll_down"; } + { key = "k"; command = "scroll_up"; } + { key = "J"; command = [ "select_item" "scroll_down" ]; } + { key = "K"; command = [ "select_item" "scroll_up" ]; } + ] + ''; + }; + }; + + config = mkIf cfg.enable { + warnings = mkIf (cfg.settings ? mpd_music_dir && cfg.mpdMusicDir != null) [ + ("programs.ncmpcpp.settings.mpd_music_dir will be overridden by" + + " programs.ncmpcpp.mpdMusicDir.") + ]; + + home.packages = [ cfg.package ]; + + xdg.configFile = { + "ncmpcpp/config" = let + settings = cfg.settings // optionalAttrs (cfg.mpdMusicDir != null) { + mpd_music_dir = toString cfg.mpdMusicDir; + }; + in mkIf (length (attrValues settings) > 0) { + text = renderSettings settings + "\n"; + }; + + "ncmpcpp/bindings" = mkIf (length cfg.bindings > 0) { + text = renderBindings cfg.bindings + "\n"; + }; + }; + }; +} diff --git a/tests/default.nix b/tests/default.nix index 3aa0c54431f1..45b0d83e6b82 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -53,6 +53,7 @@ import nmt { ./modules/programs/lf ./modules/programs/lieer ./modules/programs/mbsync + ./modules/programs/ncmpcpp ./modules/programs/ne ./modules/programs/neomutt ./modules/programs/newsboat @@ -81,6 +82,7 @@ import nmt { ./modules/programs/firefox ./modules/programs/getmail ./modules/services/lieer + ./modules/programs/ncmpcpp-linux ./modules/programs/rofi ./modules/programs/waybar ./modules/services/kanshi diff --git a/tests/modules/programs/ncmpcpp-linux/default.nix b/tests/modules/programs/ncmpcpp-linux/default.nix new file mode 100644 index 000000000000..b1185c852491 --- /dev/null +++ b/tests/modules/programs/ncmpcpp-linux/default.nix @@ -0,0 +1 @@ +{ ncmpcpp-use-mpd-config = ./ncmpcpp-use-mpd-config.nix; } diff --git a/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config-expected-config b/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config-expected-config new file mode 100644 index 000000000000..8aa57d08f16d --- /dev/null +++ b/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config-expected-config @@ -0,0 +1 @@ +mpd_music_dir=/home/user/music diff --git a/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config.nix b/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config.nix new file mode 100644 index 000000000000..5262f0314724 --- /dev/null +++ b/tests/modules/programs/ncmpcpp-linux/ncmpcpp-use-mpd-config.nix @@ -0,0 +1,25 @@ +{ pkgs, ... }: + +{ + config = { + programs.ncmpcpp.enable = true; + + services.mpd.enable = true; + services.mpd.musicDirectory = "/home/user/music"; + + nixpkgs.overlays = [ + (self: super: { + ncmpcpp = pkgs.writeScriptBin "dummy-ncmpcpp" ""; + mpd = pkgs.writeScriptBin "dummy-mpd" ""; + }) + ]; + + nmt.script = '' + assertFileContent \ + home-files/.config/ncmpcpp/config \ + ${./ncmpcpp-use-mpd-config-expected-config} + + assertPathNotExists home-files/.config/ncmpcpp/bindings + ''; + }; +} diff --git a/tests/modules/programs/ncmpcpp/default.nix b/tests/modules/programs/ncmpcpp/default.nix new file mode 100644 index 000000000000..c150b0d82486 --- /dev/null +++ b/tests/modules/programs/ncmpcpp/default.nix @@ -0,0 +1,4 @@ +{ + ncmpcpp-empty-settings = ./ncmpcpp-empty-settings.nix; + ncmpcpp-example-settings = ./ncmpcpp-example-settings.nix; +} diff --git a/tests/modules/programs/ncmpcpp/ncmpcpp-empty-settings.nix b/tests/modules/programs/ncmpcpp/ncmpcpp-empty-settings.nix new file mode 100644 index 000000000000..e5134002d3e8 --- /dev/null +++ b/tests/modules/programs/ncmpcpp/ncmpcpp-empty-settings.nix @@ -0,0 +1,16 @@ +{ pkgs, ... }: + +{ + config = { + programs.ncmpcpp.enable = true; + + nixpkgs.overlays = + [ (self: super: { ncmpcpp = pkgs.writeScriptBin "dummy-ncmpcpp" ""; }) ]; + + nmt.script = '' + assertPathNotExists home-files/.config/ncmpcpp/config + + assertPathNotExists home-files/.config/ncmpcpp/bindings + ''; + }; +} diff --git a/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-bindings b/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-bindings new file mode 100644 index 000000000000..a73bd129ffd6 --- /dev/null +++ b/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-bindings @@ -0,0 +1,16 @@ +def_key "j" + scroll_down +def_key "k" + scroll_up +def_key "J" + select_item + scroll_down +def_key "K" + select_item + scroll_up +def_key "x" + delete_playlist_items +def_key "x" + delete_browser_items +def_key "x" + delete_stored_playlist diff --git a/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-config b/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-config new file mode 100644 index 000000000000..6aedb6110e4e --- /dev/null +++ b/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings-expected-config @@ -0,0 +1,4 @@ +display_volume_level=no +mpd_music_dir=/home/user/music +playlist_disable_highlight_delay=0 +user_interface=alternative diff --git a/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings.nix b/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings.nix new file mode 100644 index 000000000000..02a1f09c9027 --- /dev/null +++ b/tests/modules/programs/ncmpcpp/ncmpcpp-example-settings.nix @@ -0,0 +1,60 @@ +{ pkgs, ... }: + +{ + config = { + programs.ncmpcpp = { + enable = true; + mpdMusicDir = "/home/user/music"; + + settings = { + user_interface = "alternative"; + display_volume_level = false; + playlist_disable_highlight_delay = 0; + }; + + bindings = [ + { + key = "j"; + command = "scroll_down"; + } + { + key = "k"; + command = "scroll_up"; + } + { + key = "J"; + command = [ "select_item" "scroll_down" ]; + } + { + key = "K"; + command = [ "select_item" "scroll_up" ]; + } + { + key = "x"; + command = "delete_playlist_items"; + } + { + key = "x"; + command = "delete_browser_items"; + } + { + key = "x"; + command = "delete_stored_playlist"; + } + ]; + }; + + nixpkgs.overlays = + [ (self: super: { ncmpcpp = pkgs.writeScriptBin "dummy-ncmpcpp" ""; }) ]; + + nmt.script = '' + assertFileContent \ + home-files/.config/ncmpcpp/config \ + ${./ncmpcpp-example-settings-expected-config} + + assertFileContent \ + home-files/.config/ncmpcpp/bindings \ + ${./ncmpcpp-example-settings-expected-bindings} + ''; + }; +}