aboutsummaryrefslogtreecommitdiffstats
path: root/modules/communication/neomutt
diff options
context:
space:
mode:
Diffstat (limited to 'modules/communication/neomutt')
-rw-r--r--modules/communication/neomutt/account/default.nix2
-rw-r--r--modules/communication/neomutt/account/flavors/gmail.nix2
-rw-r--r--modules/communication/neomutt/account/options.nix2
-rw-r--r--modules/communication/neomutt/assertions.nix2
-rw-r--r--modules/communication/neomutt/default.nix2
-rw-r--r--modules/communication/neomutt/keybindings.nix816
-rw-r--r--modules/communication/neomutt/macros.nix30
-rw-r--r--modules/communication/neomutt/neomutt.nix4
-rw-r--r--modules/communication/neomutt/sync/default.nix2
-rw-r--r--modules/communication/neomutt/sync/mbsync.nix2
-rw-r--r--modules/communication/neomutt/sync/notmuch.nix2
11 files changed, 489 insertions, 377 deletions
diff --git a/modules/communication/neomutt/account/default.nix b/modules/communication/neomutt/account/default.nix
index e6e60d2..f0b1cb1 100644
--- a/modules/communication/neomutt/account/default.nix
+++ b/modules/communication/neomutt/account/default.nix
@@ -1,4 +1,4 @@
-# Account - Converts neomutt account options into home-manager email config
+# Converts neomutt account options into home-manager email config
{ config, lib, ... }:
{
options.communication.neomutt.accounts = lib.mkOption {
diff --git a/modules/communication/neomutt/account/flavors/gmail.nix b/modules/communication/neomutt/account/flavors/gmail.nix
index 28ec979..ba39c58 100644
--- a/modules/communication/neomutt/account/flavors/gmail.nix
+++ b/modules/communication/neomutt/account/flavors/gmail.nix
@@ -1,4 +1,4 @@
-# Gmail - Gmail-specific defaults for folder names, mbsync patterns, and mailboxes
+# Gmail-specific defaults for folder names, mbsync patterns, and mailboxes
{
config,
lib,
diff --git a/modules/communication/neomutt/account/options.nix b/modules/communication/neomutt/account/options.nix
index 3dd6c9f..45e6744 100644
--- a/modules/communication/neomutt/account/options.nix
+++ b/modules/communication/neomutt/account/options.nix
@@ -1,4 +1,4 @@
-# Options - Email account option definitions (realName, address, folders, gpg, etc.)
+# Email account option definitions
{ lib, ... }:
{
options = {
diff --git a/modules/communication/neomutt/assertions.nix b/modules/communication/neomutt/assertions.nix
index 5fad5c9..aa28502 100644
--- a/modules/communication/neomutt/assertions.nix
+++ b/modules/communication/neomutt/assertions.nix
@@ -1,4 +1,4 @@
-# Assertions - Validates neomutt dependencies (less, bat, kitty, chawan) are enabled
+# Validates neomutt dependencies are enabled
{ config, ... }:
{
assertions = [
diff --git a/modules/communication/neomutt/default.nix b/modules/communication/neomutt/default.nix
index 1512465..6d882e1 100644
--- a/modules/communication/neomutt/default.nix
+++ b/modules/communication/neomutt/default.nix
@@ -1,4 +1,4 @@
-# Neomutt - Email suite entry point (neomutt + mbsync + notmuch)
+# Email suite entry point
{
config,
lib,
diff --git a/modules/communication/neomutt/keybindings.nix b/modules/communication/neomutt/keybindings.nix
index 59712fa..e9a3490 100644
--- a/modules/communication/neomutt/keybindings.nix
+++ b/modules/communication/neomutt/keybindings.nix
@@ -1,359 +1,485 @@
-# Keybindings - Vim-style keyboard shortcuts for neomutt
-#
-# Covers the core menus: generic (fallback), index, pager, sidebar,
-# attach, browser, compose. Menus like pgp/smime/mix/postpone/alias/query
-# are intentionally left mostly on defaults - they're rarely touched and
-# not worth risking an incorrect binding for. Press `?` inside neomutt
-# in any menu to see the live, authoritative list of bound functions.
{ config, lib, ... }:
+
{
- config.programs.neomutt.binds = lib.mkIf config.communication.neomutt.enable [
- # --- sidebar navigation (vim: Ctrl-k=up, Ctrl-j=down) ---
- {
- map = [
- "index"
- "pager"
- ];
- key = "\\Ck";
- action = "sidebar-prev";
- }
- {
- map = [
- "index"
- "pager"
- ];
- key = "\\Cj";
- action = "sidebar-next";
- }
- {
- # jump into the highlighted mailbox
- map = [
- "index"
- "pager"
- ];
- key = "\\Co";
- action = "sidebar-open";
- }
- {
- map = [
- "index"
- "pager"
- ];
- key = "\\Cp";
- action = "sidebar-prev-new";
- }
- {
- map = [
- "index"
- "pager"
- ];
- key = "\\Cn";
- action = "sidebar-next-new";
- }
- {
- # show/hide the sidebar column entirely
- map = [
- "index"
- "pager"
- ];
- key = "B";
- action = "sidebar-toggle-visible";
- }
+ config.programs.neomutt.binds = lib.mkIf config.communication.neomutt.enable (
+ lib.mkMerge [
+ # Force noop bindings to the top of neomuttrc
+ (lib.mkBefore [
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ "browser"
+ "attach"
+ "compose"
+ ];
+ key = "z";
+ action = "noop";
+ }
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ "browser"
+ "attach"
+ "compose"
+ ];
+ key = "d";
+ action = "noop";
+ }
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ "browser"
+ "attach"
+ "compose"
+ ];
+ key = "g";
+ action = "noop";
+ }
+ ])
- # --- basic entry navigation (generic = fallback for every list-style menu) ---
- {
- map = [ "generic" ];
- key = "j";
- action = "next-entry";
- }
- {
- map = [ "generic" ];
- key = "k";
- action = "previous-entry";
- }
- {
- map = [ "generic" ];
- key = "gg";
- action = "first-entry";
- }
- {
- map = [
- "index"
- "generic"
- ];
- key = "G";
- action = "last-entry";
- }
+ # Other bindings
+ [
+ # Sidebar navigation
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "\\Ck";
+ action = "sidebar-prev";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "\\Cj";
+ action = "sidebar-next";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "\\Co";
+ action = "sidebar-open";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "\\Cn";
+ action = "sidebar-toggle-visible";
+ }
- # --- scroll-to-position, straight from vim (zt/zz/zb) ---
- {
- map = [ "generic" ];
- key = "zt";
- action = "current-top";
- }
- {
- map = [ "generic" ];
- key = "zz";
- action = "current-middle";
- }
- {
- map = [ "generic" ];
- key = "zb";
- action = "current-bottom";
- }
+ # Basic movement
+ {
+ map = [ "generic" ];
+ key = "j";
+ action = "next-entry";
+ }
+ {
+ map = [ "generic" ];
+ key = "k";
+ action = "previous-entry";
+ }
+ {
+ map = [ "generic" ];
+ key = "gg";
+ action = "first-entry";
+ }
+ {
+ map = [
+ "index"
+ "generic"
+ ];
+ key = "G";
+ action = "last-entry";
+ }
+ {
+ map = [ "pager" ];
+ key = "h";
+ action = "exit";
+ }
+ {
+ map = [ "pager" ];
+ key = "l";
+ action = "view-attachments";
+ }
+ {
+ map = [ "index" ];
+ key = "l";
+ action = "display-message";
+ }
- # --- pager scrolling ---
- {
- map = [ "pager" ];
- key = "j";
- action = "next-line";
- }
- {
- map = [ "pager" ];
- key = "k";
- action = "previous-line";
- }
- {
- map = [ "pager" ];
- key = "gg";
- action = "top";
- }
- {
- map = [ "pager" ];
- key = "G";
- action = "bottom";
- }
- {
- map = [
- "generic"
- "index"
- "pager"
- ];
- key = "\\Cd";
- action = "half-down";
- }
- {
- map = [
- "generic"
- "index"
- "pager"
- ];
- key = "\\Cu";
- action = "half-up";
- }
- {
- map = [
- "generic"
- "index"
- "pager"
- ];
- key = "\\Cf";
- action = "next-page";
- }
- {
- # NOTE: Ctrl-B is deliberately left unbound in the pager map here -
- # macros.nix claims it there for the chawan browser-view macro.
- map = [ "index" ];
- key = "\\Cb";
- action = "previous-page";
- }
+ # Scrolling
+ {
+ map = [ "generic" ];
+ key = "zt";
+ action = "current-top";
+ }
+ {
+ map = [ "generic" ];
+ key = "zz";
+ action = "current-middle";
+ }
+ {
+ map = [ "generic" ];
+ key = "zb";
+ action = "current-bottom";
+ }
+ {
+ map = [ "pager" ];
+ key = "j";
+ action = "next-line";
+ }
+ {
+ map = [ "pager" ];
+ key = "k";
+ action = "previous-line";
+ }
+ {
+ map = [ "pager" ];
+ key = "gg";
+ action = "top";
+ }
+ {
+ map = [ "pager" ];
+ key = "G";
+ action = "bottom";
+ }
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ ];
+ key = "\\Cd";
+ action = "half-down";
+ }
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ ];
+ key = "\\Cu";
+ action = "half-up";
+ }
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ ];
+ key = "\\Cf";
+ action = "next-page";
+ }
+ {
+ map = [ "index" ];
+ key = "\\Cb";
+ action = "previous-page";
+ }
- # --- h/l as "back / go into", vim left/right ---
- {
- map = [ "pager" ];
- key = "h";
- action = "exit";
- }
- {
- map = [ "pager" ];
- key = "l";
- action = "view-attachments";
- }
- {
- map = [ "index" ];
- key = "l";
- action = "display-message";
- }
+ # Searching and limiting
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ ];
+ key = "/";
+ action = "search";
+ }
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ ];
+ key = "?";
+ action = "search-reverse";
+ }
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ ];
+ key = "n";
+ action = "search-next";
+ }
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ ];
+ key = "N";
+ action = "search-opposite";
+ }
+ {
+ map = [ "index" ];
+ key = "gf";
+ action = "limit";
+ }
- # --- search (mostly default already, restated for a complete reference) ---
- {
- map = [
- "generic"
- "index"
- "pager"
- ];
- key = "/";
- action = "search";
- }
- {
- map = [
- "generic"
- "index"
- "pager"
- ];
- key = "?";
- action = "search-reverse";
- }
- {
- map = [
- "generic"
- "index"
- "pager"
- ];
- key = "n";
- action = "search-next";
- }
- {
- map = [
- "generic"
- "index"
- "pager"
- ];
- key = "N";
- action = "search-opposite";
- }
+ # Message states and threads
+ {
+ map = [ "index" ];
+ key = "]";
+ action = "next-unread";
+ }
+ {
+ map = [ "index" ];
+ key = "[";
+ action = "previous-unread";
+ }
+ {
+ map = [ "index" ];
+ key = "}";
+ action = "next-new";
+ }
+ {
+ map = [ "index" ];
+ key = "{";
+ action = "previous-new";
+ }
+ {
+ map = [ "index" ];
+ key = "za";
+ action = "collapse-thread";
+ }
+ {
+ map = [ "index" ];
+ key = "zA";
+ action = "collapse-all";
+ }
- # --- delete / undelete, vim dd ---
- {
- map = [
- "index"
- "pager"
- ];
- key = "dd";
- action = "delete-message";
- }
- {
- map = [ "index" ];
- key = "dT";
- action = "delete-thread";
- }
- {
- map = [ "index" ];
- key = "u";
- action = "undelete-message";
- }
- {
- map = [ "index" ];
- key = "U";
- action = "undelete-thread";
- }
- {
- map = [ "attach" ];
- key = "dd";
- action = "delete-entry";
- }
- {
- map = [ "attach" ];
- key = "u";
- action = "undelete-entry";
- }
+ # Core email actions
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "m";
+ action = "mail";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "r";
+ action = "reply";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "R";
+ action = "group-reply";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "f";
+ action = "forward-message";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "c";
+ action = "change-folder";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "s";
+ action = "save-message";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "y";
+ action = "copy-message";
+ }
+ {
+ map = [ "index" ];
+ key = "t";
+ action = "tag-entry";
+ }
+ {
+ map = [ "pager" ];
+ key = "t";
+ action = "tag-message";
+ }
+ {
+ map = [ "index" ];
+ key = "T";
+ action = "tag-thread";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "gh";
+ action = "display-toggle-weed";
+ }
- # --- limit / filter the index, gf = filter, gF = clear filter ---
- {
- # prompts for a limit pattern; macros.nix binds gF to clear it
- map = [ "index" ];
- key = "gf";
- action = "limit";
- }
+ # Deletion and undeletion
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "dd";
+ action = "delete-message";
+ }
+ {
+ map = [ "index" ];
+ key = "dT";
+ action = "delete-thread";
+ }
+ {
+ map = [
+ "index"
+ "pager"
+ ];
+ key = "u";
+ action = "undelete-message";
+ }
+ {
+ map = [ "index" ];
+ key = "U";
+ action = "undelete-thread";
+ }
+ {
+ map = [ "attach" ];
+ key = "dd";
+ action = "delete-entry";
+ }
+ {
+ map = [ "attach" ];
+ key = "u";
+ action = "undelete-entry";
+ }
- # --- unread / new / flagged navigation ---
- {
- map = [ "index" ];
- key = "]";
- action = "next-unread";
- }
- {
- map = [ "index" ];
- key = "[";
- action = "previous-unread";
- }
- {
- map = [ "index" ];
- key = "}";
- action = "next-new";
- }
- {
- map = [ "index" ];
- key = "{";
- action = "previous-new";
- }
- {
- map = [ "index" ];
- key = "gn";
- action = "next-flagged";
- }
- {
- map = [ "index" ];
- key = "gp";
- action = "previous-flagged";
- }
+ # Menu specific
+ {
+ map = [ "attach" ];
+ key = "l";
+ action = "view-attach";
+ }
+ {
+ map = [ "attach" ];
+ key = "s";
+ action = "save-entry";
+ }
+ {
+ map = [ "attach" ];
+ key = "p";
+ action = "print-entry";
+ }
- # --- attach menu ---
- {
- map = [ "attach" ];
- key = "l";
- action = "view-attach";
- }
- {
- map = [ "attach" ];
- key = "s";
- action = "save-entry";
- }
- {
- map = [ "attach" ];
- key = "p";
- action = "print-entry";
- }
+ {
+ map = [ "browser" ];
+ key = "j";
+ action = "next-entry";
+ }
+ {
+ map = [ "browser" ];
+ key = "k";
+ action = "previous-entry";
+ }
+ {
+ map = [ "browser" ];
+ key = "gg";
+ action = "first-entry";
+ }
+ {
+ map = [ "browser" ];
+ key = "G";
+ action = "last-entry";
+ }
+ {
+ map = [ "browser" ];
+ key = "l";
+ action = "select-entry";
+ }
+ {
+ map = [ "browser" ];
+ key = "\\Cd";
+ action = "half-down";
+ }
+ {
+ map = [ "browser" ];
+ key = "\\Cu";
+ action = "half-up";
+ }
- # --- browser (folder / file picker) ---
- {
- map = [ "browser" ];
- key = "j";
- action = "next-entry";
- }
- {
- map = [ "browser" ];
- key = "k";
- action = "previous-entry";
- }
- {
- map = [ "browser" ];
- key = "gg";
- action = "first-entry";
- }
- {
- map = [ "browser" ];
- key = "G";
- action = "last-entry";
- }
- {
- # neomutt has no dedicated "go up a directory" function - the ".."
- # row is a normal entry, so l/Enter on it goes up just fine
- map = [ "browser" ];
- key = "l";
- action = "select-entry";
- }
- {
- map = [ "browser" ];
- key = "\\Cd";
- action = "half-down";
- }
- {
- map = [ "browser" ];
- key = "\\Cu";
- action = "half-up";
- }
+ {
+ map = [ "compose" ];
+ key = "j";
+ action = "next-entry";
+ }
+ {
+ map = [ "compose" ];
+ key = "k";
+ action = "previous-entry";
+ }
+ {
+ map = [ "compose" ];
+ key = "y";
+ action = "send-message";
+ }
+ {
+ map = [ "compose" ];
+ key = "a";
+ action = "attach-file";
+ }
+ {
+ map = [ "compose" ];
+ key = "e";
+ action = "edit-message";
+ }
+ {
+ map = [ "compose" ];
+ key = "p";
+ action = "postpone-message";
+ }
- # --- compose menu ---
- {
- map = [ "compose" ];
- key = "j";
- action = "next-entry";
- }
- {
- map = [ "compose" ];
- key = "k";
- action = "previous-entry";
- }
- ];
+ # Global exit
+ {
+ map = [
+ "generic"
+ "index"
+ "pager"
+ "browser"
+ "attach"
+ "compose"
+ ];
+ key = "q";
+ action = "exit";
+ }
+ ]
+ ]
+ );
}
diff --git a/modules/communication/neomutt/macros.nix b/modules/communication/neomutt/macros.nix
index 4a1fd5d..9ad3593 100644
--- a/modules/communication/neomutt/macros.nix
+++ b/modules/communication/neomutt/macros.nix
@@ -1,10 +1,9 @@
-# Macros - neomutt macros for sync, URL extraction, flag legend, and quit
+# neomutt macros for sync, URL extraction, flag legend, and quit
{ config, lib, ... }:
{
config.programs.neomutt.macros = lib.mkIf config.communication.neomutt.enable [
{
- # sync the mailbox and run the external sync script, silencing the
- # "press any key" prompt around it. Vim mnemonic: g-prefixed, "go sync".
+ # Sync the mailbox and run the external sync script
map = [
"index"
"pager"
@@ -13,9 +12,7 @@
action = "<enter-command>set my_wait_key=$wait_key wait_key=no<enter><sync-mailbox><shell-escape>${lib.getExe config.scripts.neomutt-sync.package}<enter><sync-mailbox><enter-command>set wait_key=$my_wait_key<enter>";
}
{
- # extract every URL from the message via urlscan into a picker menu,
- # then follow the selected one. Vim mnemonic: gx, same as vim-plugins
- # that open the link/file under the cursor.
+ # Extract every URL from the message via urlscan into a picker menu
map = [
"index"
"pager"
@@ -24,42 +21,31 @@
action = "<pipe-message>urlscan<enter>";
}
{
- # open the message body in interactive chawan -- real vim-style
- # cursor navigation (hjkl, Tab/Shift-Tab between links, Enter to
- # follow, B back, q to return to neomutt). Replaces the old
- # urlscan-based link picker.
- # Kept on Ctrl-B since that's common muscle-memory for "open this in
- # a browser-like view" - previous-page is intentionally NOT bound to
- # Ctrl-B in the pager (see binds.nix) so this doesn't get shadowed.
+ # Open the message body in interactive chawan with vim-style navigation
map = [ "pager" ];
key = "\\Cb";
action = "<enter-command>set my_pipe_decode=$pipe_decode pipe_decode=yes<enter><pipe-message>${lib.getExe config.web.chawan.package} -o \"title='neomutt'\"<enter><enter-command>set pipe_decode=$my_pipe_decode<enter>";
}
{
- # on a specific attachment (not just the top-level
- # message): pipe-entry sends the selected attachment instead.
- # Same gx mnemonic as the index/pager macro above.
+ # Pipe the selected attachment instead of the whole message
map = [ "attach" ];
key = "gx";
action = "<pipe-entry>${lib.getExe config.web.chawan.package} -o \"title='neomutt'\" <enter>";
}
{
- # clear the current limit/filter and show every message again,
- # the counterpart to gf (interactive limit prompt) in binds.nix
+ # Clear the current limit and show every message again
map = [ "index" ];
key = "gF";
action = "<limit>all<enter>";
}
{
- # save and quit, vim-style (sync mailbox, then quit) - same ZZ
- # you'd type in vim to write and exit
+ # Save the mailbox and quit
map = [ "index" ];
key = "ZZ";
action = "<sync-mailbox><quit>";
}
{
- # quit without saving, vim-style counterpart to ZZ - same ZQ
- # you'd type in vim to discard and exit
+ # Quit without saving
map = [ "index" ];
key = "ZQ";
action = "<exit>";
diff --git a/modules/communication/neomutt/neomutt.nix b/modules/communication/neomutt/neomutt.nix
index 997c948..e25d0b3 100644
--- a/modules/communication/neomutt/neomutt.nix
+++ b/modules/communication/neomutt/neomutt.nix
@@ -1,4 +1,4 @@
-# neomutt - Terminal email client
+# Terminal email client
{
config,
lib,
@@ -44,7 +44,7 @@
};
sidebar.enable = true;
sort = "reverse-threads";
- vimKeys = true;
+ vimKeys = false;
unmailboxes = true;
checkStatsInterval = 20;
extraConfig = builtins.readFile ./.neomuttrc;
diff --git a/modules/communication/neomutt/sync/default.nix b/modules/communication/neomutt/sync/default.nix
index 2fcaa18..629a655 100644
--- a/modules/communication/neomutt/sync/default.nix
+++ b/modules/communication/neomutt/sync/default.nix
@@ -1,4 +1,4 @@
-# Sync - Mail synchronization modules (mbsync, notmuch)
+# Mail synchronization modules
{ ... }:
{
imports = [
diff --git a/modules/communication/neomutt/sync/mbsync.nix b/modules/communication/neomutt/sync/mbsync.nix
index 7642099..28b7b2c 100644
--- a/modules/communication/neomutt/sync/mbsync.nix
+++ b/modules/communication/neomutt/sync/mbsync.nix
@@ -1,4 +1,4 @@
-# Mbsync - Mailbox synchronization (isync/mbsync)
+# Mailbox synchronization
{ config, lib, ... }:
{
config = lib.mkIf config.communication.neomutt.enable {
diff --git a/modules/communication/neomutt/sync/notmuch.nix b/modules/communication/neomutt/sync/notmuch.nix
index 277b232..6f806fb 100644
--- a/modules/communication/neomutt/sync/notmuch.nix
+++ b/modules/communication/neomutt/sync/notmuch.nix
@@ -1,4 +1,4 @@
-# Notmuch - Mail indexer for fast email search
+# Mail indexer for fast email search
{ config, lib, ... }:
{
config = lib.mkIf config.communication.neomutt.enable {