parent
d8d5f85ab7
commit
fba87f8998
|
@ -391,6 +391,7 @@ in
|
||||||
(import ../programs/getmail-accounts.nix)
|
(import ../programs/getmail-accounts.nix)
|
||||||
(import ../programs/mbsync-accounts.nix)
|
(import ../programs/mbsync-accounts.nix)
|
||||||
(import ../programs/msmtp-accounts.nix)
|
(import ../programs/msmtp-accounts.nix)
|
||||||
|
(import ../programs/neomutt-accounts.nix)
|
||||||
(import ../programs/notmuch-accounts.nix)
|
(import ../programs/notmuch-accounts.nix)
|
||||||
(import ../programs/offlineimap-accounts.nix)
|
(import ../programs/offlineimap-accounts.nix)
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -1311,6 +1311,13 @@ in
|
||||||
A new module is available: 'services.grobi'.
|
A new module is available: 'services.grobi'.
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
time = "2020-01-26T19:37:57+00:00";
|
||||||
|
message = ''
|
||||||
|
A new module is available: 'programs.neomutt'.
|
||||||
|
'';
|
||||||
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,6 +78,7 @@ let
|
||||||
(loadModule ./programs/mercurial.nix { })
|
(loadModule ./programs/mercurial.nix { })
|
||||||
(loadModule ./programs/mpv.nix { })
|
(loadModule ./programs/mpv.nix { })
|
||||||
(loadModule ./programs/msmtp.nix { })
|
(loadModule ./programs/msmtp.nix { })
|
||||||
|
(loadModule ./programs/neomutt.nix { })
|
||||||
(loadModule ./programs/neovim.nix { })
|
(loadModule ./programs/neovim.nix { })
|
||||||
(loadModule ./programs/newsboat.nix { })
|
(loadModule ./programs/newsboat.nix { })
|
||||||
(loadModule ./programs/noti.nix { })
|
(loadModule ./programs/noti.nix { })
|
||||||
|
|
35
modules/programs/neomutt-accounts.nix
Normal file
35
modules/programs/neomutt-accounts.nix
Normal file
|
@ -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
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
319
modules/programs/neomutt.nix
Normal file
319
modules/programs/neomutt.nix
Normal file
|
@ -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)}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ import nmt {
|
||||||
// import ./modules/misc/xdg
|
// import ./modules/misc/xdg
|
||||||
// import ./modules/misc/xsession
|
// import ./modules/misc/xsession
|
||||||
// import ./modules/programs/firefox
|
// import ./modules/programs/firefox
|
||||||
|
// import ./modules/programs/neomutt
|
||||||
// import ./modules/programs/rofi
|
// import ./modules/programs/rofi
|
||||||
// import ./modules/services/sxhkd
|
// import ./modules/services/sxhkd
|
||||||
// import ./modules/systemd
|
// import ./modules/systemd
|
||||||
|
|
3
tests/modules/programs/neomutt/default.nix
Normal file
3
tests/modules/programs/neomutt/default.nix
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
neomutt-simple = ./neomutt.nix;
|
||||||
|
}
|
37
tests/modules/programs/neomutt/hm-example.com-expected
Normal file
37
tests/modules/programs/neomutt/hm-example.com-expected
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# Generated by Home Manager.
|
||||||
|
set ssl_force_tls = yes
|
||||||
|
set certificate_file=/etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
|
# GPG section
|
||||||
|
set crypt_use_gpgme = yes
|
||||||
|
set crypt_autosign = no
|
||||||
|
set pgp_use_gpg_agent = yes
|
||||||
|
set mbox_type = Maildir
|
||||||
|
set sort = "threads"
|
||||||
|
|
||||||
|
# MTA section
|
||||||
|
set smtp_pass='`password-command`'
|
||||||
|
set smtp_url='smtps://home.manager@smtp.example.com'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# MRA section
|
||||||
|
set folder='/home/hm-user/Mail/hm@example.com'
|
||||||
|
set from='hm@example.com'
|
||||||
|
set postponed='+Drafts'
|
||||||
|
set realname='H. M. Test'
|
||||||
|
set record='+Sent'
|
||||||
|
set spoolfile='+Inbox'
|
||||||
|
set trash='+Trash'
|
||||||
|
color status cyan default
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Extra configuration
|
||||||
|
color status cyan default
|
||||||
|
|
||||||
|
# notmuch section
|
||||||
|
set nm_default_uri = "notmuch:///home/hm-user/Mail"
|
||||||
|
virtual-mailboxes "My INBOX" "notmuch://?query=tag:inbox"
|
27
tests/modules/programs/neomutt/neomutt-expected.conf
Normal file
27
tests/modules/programs/neomutt/neomutt-expected.conf
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# Generated by Home Manager.
|
||||||
|
set header_cache = "/home/hm-user/.cache/neomutt/headers/"
|
||||||
|
set message_cachedir = "/home/hm-user/.cache/neomutt/messages/"
|
||||||
|
set editor = "$EDITOR"
|
||||||
|
set implicit_autoview = yes
|
||||||
|
|
||||||
|
alternative_order text/enriched text/plain text
|
||||||
|
|
||||||
|
set delete = yes
|
||||||
|
|
||||||
|
# Binds
|
||||||
|
|
||||||
|
|
||||||
|
# Macros
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Extra configuration
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# register account hm@example.com
|
||||||
|
mailboxes "/home/hm-user/Mail/hm@example.com/Inbox"
|
||||||
|
folder-hook /home/hm-user/Mail/hm@example.com/ " \
|
||||||
|
source /home/hm-user/.config/neomutt/hm@example.com "
|
||||||
|
source /home/hm-user/.config/neomutt/hm@example.com
|
46
tests/modules/programs/neomutt/neomutt.nix
Normal file
46
tests/modules/programs/neomutt/neomutt.nix
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
imports = [ ../../accounts/email-test-accounts.nix ];
|
||||||
|
|
||||||
|
config = {
|
||||||
|
home.username = "hm-user";
|
||||||
|
home.homeDirectory = "/home/hm-user";
|
||||||
|
xdg.configHome = mkForce "/home/hm-user/.config";
|
||||||
|
xdg.cacheHome = mkForce "/home/hm-user/.cache";
|
||||||
|
|
||||||
|
accounts.email.accounts = {
|
||||||
|
"hm@example.com" = {
|
||||||
|
primary = true;
|
||||||
|
notmuch.enable = true;
|
||||||
|
neomutt = {
|
||||||
|
enable = true;
|
||||||
|
extraConfig = ''
|
||||||
|
color status cyan default
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
imap.port = 993;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.neomutt = {
|
||||||
|
enable = true;
|
||||||
|
vimKeys = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
nixpkgs.overlays = [
|
||||||
|
(self: super: {
|
||||||
|
neomutt = pkgs.writeScriptBin "dummy-neomutt" "";
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.config/neomutt/neomuttrc
|
||||||
|
assertFileExists home-files/.config/neomutt/hm@example.com
|
||||||
|
assertFileContent home-files/.config/neomutt/neomuttrc ${./neomutt-expected.conf}
|
||||||
|
assertFileContent home-files/.config/neomutt/hm@example.com ${./hm-example.com-expected}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue