diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index dccdc8f8e..50e396c73 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -77,6 +77,10 @@
/modules/programs/mpv.nix @tadeokondrak
+/modules/programs/ncmpcpp.nix @olmokramer
+/tests/modules/programs/ncmpcpp @olmokramer
+/tests/modules/programs/ncmpcpp-linux @olmokramer
+
/modules/programs/ne.nix @cwyc
/tests/modules/programs/ne @cwyc
diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix
index ff0463600..8cb878122 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 bdbd589a5..ea551aa3d 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-09-01T18:38:18+00:00";
+ message = ''
+ A new module is available: 'programs.ncmpcpp'
+ '';
+ }
];
};
}
diff --git a/modules/modules.nix b/modules/modules.nix
index bae51d692..b4eb4d402 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 000000000..a39baab6c
--- /dev/null
+++ b/modules/programs/ncmpcpp.nix
@@ -0,0 +1,135 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ cfg = config.programs.ncmpcpp;
+
+ 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 = let mpdCfg = config.services.mpd;
+ in 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 = ''
+ Attribute set from name of a setting to its value. For available options
+ see
+
+ ncmpcpp
+ 1
+ .
+ '';
+ example = { 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 (settings != { }) { text = renderSettings settings + "\n"; };
+
+ "ncmpcpp/bindings" = mkIf (cfg.bindings != [ ]) {
+ text = renderBindings cfg.bindings + "\n";
+ };
+ };
+ };
+}
diff --git a/tests/default.nix b/tests/default.nix
index 3aa0c5443..45b0d83e6 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 000000000..b1185c852
--- /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 000000000..8aa57d08f
--- /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 000000000..5262f0314
--- /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 000000000..c150b0d82
--- /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 000000000..e5134002d
--- /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 000000000..a73bd129f
--- /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 000000000..6aedb6110
--- /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 000000000..02a1f09c9
--- /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}
+ '';
+ };
+}