aboutsummaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
authorMatthieu Coudron <mattator@gmail.com>2020-01-22 00:52:01 +0100
committerRobert Helgesson <robert@rycee.net>2020-01-26 20:46:44 +0100
commitfba87f899870c7c8fa412efeb2bcb6c31ac21e32 (patch)
tree29b2c48f4f0943625f7e20a96f71da26dafb5663 /modules
parentd8d5f85ab7ca29d106429f6b7041f222e326978c (diff)
neomutt: add module
PR #1002
Diffstat (limited to 'modules')
-rw-r--r--modules/accounts/email.nix1
-rw-r--r--modules/misc/news.nix7
-rw-r--r--modules/modules.nix1
-rw-r--r--modules/programs/neomutt-accounts.nix35
-rw-r--r--modules/programs/neomutt.nix319
5 files changed, 363 insertions, 0 deletions
diff --git a/modules/accounts/email.nix b/modules/accounts/email.nix
index cc9d0dc2813..b3a9db947a9 100644
--- a/modules/accounts/email.nix
+++ b/modules/accounts/email.nix
@@ -391,6 +391,7 @@ in
(import ../programs/getmail-accounts.nix)
(import ../programs/mbsync-accounts.nix)
(import ../programs/msmtp-accounts.nix)
+ (import ../programs/neomutt-accounts.nix)
(import ../programs/notmuch-accounts.nix)
(import ../programs/offlineimap-accounts.nix)
]);
diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index 63c865b637d..6b01617fc55 100644
--- a/modules/misc/news.nix
+++ b/modules/misc/news.nix
@@ -1311,6 +1311,13 @@ in
A new module is available: 'services.grobi'.
'';
}
+
+ {
+ time = "2020-01-26T19:37:57+00:00";
+ message = ''
+ A new module is available: 'programs.neomutt'.
+ '';
+ }
];
};
}
diff --git a/modules/modules.nix b/modules/modules.nix
index dbb3f1dfee3..64418dbae11 100644
--- a/modules/modules.nix
+++ b/modules/modules.nix
@@ -78,6 +78,7 @@ let
(loadModule ./programs/mercurial.nix { })
(loadModule ./programs/mpv.nix { })
(loadModule ./programs/msmtp.nix { })
+ (loadModule ./programs/neomutt.nix { })
(loadModule ./programs/neovim.nix { })
(loadModule ./programs/newsboat.nix { })
(loadModule ./programs/noti.nix { })
diff --git a/modules/programs/neomutt-accounts.nix b/modules/programs/neomutt-accounts.nix
new file mode 100644
index 00000000000..a374f1167bd
--- /dev/null
+++ b/modules/programs/neomutt-accounts.nix
@@ -0,0 +1,35 @@
+{ config, lib, ... }:
+
+with lib;
+
+{
+ options.neomutt = {
+ enable = mkEnableOption "NeoMutt";
+
+ sendMailCommand = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "msmtpq --read-envelope-from --read-recipients";
+ description = ''
+ Command to send a mail. If not set, neomutt will be in charge of sending mails.
+ '';
+ };
+
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ example = "color status cyan default";
+ description = ''
+ Extra lines to add to the folder hook for this account.
+ '';
+ };
+ };
+
+ config = mkIf config.neomutt.enable {
+ neomutt.sendMailCommand = mkOptionDefault (
+ if config.msmtp.enable
+ then "msmtpq --read-envelope-from --read-recipients"
+ else null
+ );
+ };
+}
diff --git a/modules/programs/neomutt.nix b/modules/programs/neomutt.nix
new file mode 100644
index 00000000000..1f7022e0aca
--- /dev/null
+++ b/modules/programs/neomutt.nix
@@ -0,0 +1,319 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ cfg = config.programs.neomutt;
+
+ neomuttAccounts = filter (a: a.neomutt.enable)
+ (attrValues config.accounts.email.accounts);
+
+ sidebarModule = types.submodule {
+ options = {
+ enable = mkEnableOption "sidebar support";
+
+ width = mkOption {
+ type = types.int;
+ default = 22;
+ description = "Width of the sidebar";
+ };
+
+ shortPath = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ By default sidebar shows the full path of the mailbox, but
+ with this enabled only the relative name is shown.
+ '';
+ };
+
+ format = mkOption {
+ type = types.str;
+ default = "%B%?F? [%F]?%* %?N?%N/?%S";
+ description = ''
+ Sidebar format. Check neomutt documentation for details.
+ '';
+ };
+ };
+ };
+
+ bindModule = types.submodule {
+ options = {
+ map = mkOption {
+ type = types.enum [
+ "alias"
+ "attach"
+ "browser"
+ "compose"
+ "editor"
+ "generic"
+ "index"
+ "mix"
+ "pager"
+ "pgp"
+ "postpone"
+ "query"
+ "smime"
+ ];
+ default = "index";
+ description = "Select the menu to bind the command to.";
+ };
+
+ key = mkOption {
+ type = types.str;
+ example = "<left>";
+ description = "The key to bind.";
+ };
+
+ action = mkOption {
+ type = types.str;
+ example = "<enter-command>toggle sidebar_visible<enter><refresh>";
+ description = "Specify the action to take.";
+ };
+ };
+ };
+
+ yesno = x: if x then "yes" else "no";
+ setOption = n: v: if v == null then "unset ${n}" else "set ${n}=${v}";
+ escape = replaceStrings ["%"] ["%25"];
+
+ accountFilename = account:
+ config.xdg.configHome + "/neomutt/" + account.name;
+
+ genCommonFolderHooks = account: with account;
+ {
+ from = "'${address}'";
+ realname = "'${realName}'";
+ spoolfile = "'+${folders.inbox}'";
+ record = if folders.sent == null then null else "'+${folders.sent}'";
+ postponed = "'+${folders.drafts}'";
+ trash = "'+${folders.trash}'";
+ };
+
+ mtaSection = account: with account;
+ let
+ passCmd = concatStringsSep " " passwordCommand;
+ in
+ if neomutt.sendMailCommand != null then {
+ sendmail = "'${neomutt.sendMailCommand}'";
+ } else let
+ smtpProto = if smtp.tls.enable then "smtps" else "smtp";
+ smtpBaseUrl = "${smtpProto}://${escape userName}@${smtp.host}";
+ in {
+ smtp_url = "'${smtpBaseUrl}'";
+ smtp_pass = "'`${passCmd}`'";
+ };
+
+ genMaildirAccountConfig = account: with account;
+ let
+ folderHook =
+ mapAttrsToList setOption (
+ genCommonFolderHooks account
+ // { folder = "'${account.maildir.absPath}'"; }
+ )
+ ++ optional (neomutt.extraConfig != "") neomutt.extraConfig;
+ in
+ ''
+ ${concatStringsSep "\n" folderHook}
+ '';
+
+ registerAccount = account: with account;
+ ''
+ # register account ${name}
+ mailboxes "${account.maildir.absPath}/${folders.inbox}"
+ folder-hook ${account.maildir.absPath}/ " \
+ source ${accountFilename account} "
+ '';
+
+ mraSection = account: with account;
+ if account.maildir != null
+ then genMaildirAccountConfig account
+ else throw "Only maildir is supported at the moment";
+
+ optionsStr = attrs:
+ concatStringsSep "\n" (mapAttrsToList setOption attrs);
+
+
+ sidebarSection = ''
+ # Sidebar
+ set sidebar_visible = yes
+ set sidebar_short_path = ${yesno cfg.sidebar.shortPath}
+ set sidebar_width = ${toString cfg.sidebar.width}
+ set sidebar_format = '${cfg.sidebar.format}'
+ '';
+
+ bindSection =
+ concatMapStringsSep
+ "\n"
+ (bind: "bind ${bind.map} ${bind.key} \"${bind.action}\"")
+ cfg.binds;
+
+ macroSection =
+ concatMapStringsSep
+ "\n"
+ (bind: "macro ${bind.map} ${bind.key} \"${bind.action}\"")
+ cfg.macros;
+
+ mailCheckSection = ''
+ set mail_check_stats
+ set mail_check_stats_interval = ${toString cfg.checkStatsInterval}
+ '';
+
+ notmuchSection = account: with account; ''
+ # notmuch section
+ set nm_default_uri = "notmuch://${config.accounts.email.maildirBasePath}"
+ virtual-mailboxes "My INBOX" "notmuch://?query=tag:inbox"
+ '';
+
+ accountStr = account: with account; ''
+ # Generated by Home Manager.
+ set ssl_force_tls = yes
+ set certificate_file=${config.accounts.email.certificatesFile}
+
+ # GPG section
+ set crypt_use_gpgme = yes
+ set crypt_autosign = ${yesno (gpg.signByDefault or false)}
+ set pgp_use_gpg_agent = yes
+ set mbox_type = ${if maildir != null then "Maildir" else "mbox"}
+ set sort = "${cfg.sort}"
+
+ # MTA section
+ ${optionsStr (mtaSection account)}
+
+ ${optionalString (cfg.checkStatsInterval != null) mailCheckSection}
+
+ ${optionalString cfg.sidebar.enable sidebarSection}
+
+ # MRA section
+ ${mraSection account}
+
+ # Extra configuration
+ ${account.neomutt.extraConfig}
+ ''
+ + optionalString (account.signature.showSignature != "none") ''
+ set signature = ${pkgs.writeText "signature.txt" account.signature.text}
+ ''
+ + optionalString account.notmuch.enable (notmuchSection account);
+
+in
+
+{
+ options = {
+ programs.neomutt = {
+ enable = mkEnableOption "the NeoMutt mail client";
+
+ sidebar = mkOption {
+ type = sidebarModule;
+ default = {};
+ description = "Options related to the sidebar.";
+ };
+
+ binds = mkOption {
+ type = types.listOf bindModule;
+ default = [];
+ description = "List of keybindings.";
+ };
+
+ macros = mkOption {
+ type = types.listOf bindModule;
+ default = [];
+ description = "List of macros.";
+ };
+
+ sort = mkOption {
+ type = types.enum [
+ "date"
+ "date-received"
+ "from"
+ "mailbox-order"
+ "score"
+ "size"
+ "spam"
+ "subject"
+ "threads"
+ "to"
+ ];
+ default = "threads";
+ description = "Sorting method on messages.";
+ };
+
+ vimKeys = mkOption {
+ type = types.bool;
+ default = false;
+ description = "Enable vim-like bindings.";
+ };
+
+ checkStatsInterval = mkOption {
+ type = types.nullOr types.int;
+ default = null;
+ example = 60;
+ description = "Enable and set the interval of automatic mail check.";
+ };
+
+ editor = mkOption {
+ type = types.str;
+ default = "$EDITOR";
+ description = "Select the editor used for writing mail.";
+ };
+
+ settings = mkOption {
+ type = types.attrsOf types.str;
+ default = {};
+ description = "Extra configuration appended to the end.";
+ };
+
+ extraConfig = mkOption {
+ type = types.lines;
+ default = "";
+ description = "Extra configuration appended to the end.";
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ home.packages = [ pkgs.neomutt ];
+ home.file = let
+ rcFile = account: {
+ "${accountFilename account}".text = accountStr account;
+ };
+ in
+ foldl' (a: b: a // b) {} (map rcFile neomuttAccounts);
+
+ xdg.configFile."neomutt/neomuttrc" = mkIf (neomuttAccounts != []) {
+ text =
+ let
+ primary = filter (a: a.primary) neomuttAccounts;
+ in
+ ''
+ # Generated by Home Manager.
+ set header_cache = "${config.xdg.cacheHome}/neomutt/headers/"
+ set message_cachedir = "${config.xdg.cacheHome}/neomutt/messages/"
+ set editor = "${cfg.editor}"
+ set implicit_autoview = yes
+
+ alternative_order text/enriched text/plain text
+
+ set delete = yes
+
+ # Binds
+ ${bindSection}
+
+ # Macros
+ ${macroSection}
+
+ ${optionalString cfg.vimKeys "source ${pkgs.neomutt}/share/doc/neomutt/vim-keys/vim-keys.rc"}
+
+ # Extra configuration
+ ${optionsStr cfg.settings}
+
+ ${cfg.extraConfig}
+ ''
+ +
+ concatMapStringsSep "\n" registerAccount neomuttAccounts
+ +
+ # source primary account
+ "source ${accountFilename (builtins.head primary)}";
+ };
+ };
+}