nvim plugin to check email

This commit is contained in:
Ray Andrew 2025-12-03 23:45:15 -06:00
parent eb10e2f9fc
commit 333824e8f9
Signed by: rayandrew
SSH key fingerprint: SHA256:XYrYrxF0Z3A72n8P/p6mqPRNQZT22F88XcLsG+kX4xw
9 changed files with 158 additions and 30 deletions

View file

@ -10,13 +10,13 @@ persistent-workspaces = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
enable-normalization-flatten-containers = false enable-normalization-flatten-containers = false
enable-normalization-opposite-orientation-for-nested-containers = false enable-normalization-opposite-orientation-for-nested-containers = false
on-focused-monitor-changed = ['move-mouse monitor-lazy-center'] on-focused-monitor-changed = ['move-mouse monitor-lazy-center']
exec-on-workspace-change = ['/Users/rayandrew/dotfiles/bin/path-shim', exec-on-workspace-change = ['~/dotfiles/bin/path-shim',
'sketchybar --trigger aerospace_workspace_changed FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE PREV_WORKSPACE=$AEROSPACE_PREV_WORKSPACE && aerospace-scratchpad hook pull-window $AEROSPACE_PREV_WORKSPACE $AEROSPACE_FOCUSED_WORKSPACE' 'sketchybar --trigger aerospace_workspace_changed FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE PREV_WORKSPACE=$AEROSPACE_PREV_WORKSPACE && aerospace-scratchpad hook pull-window $AEROSPACE_PREV_WORKSPACE $AEROSPACE_FOCUSED_WORKSPACE'
] ]
on-focus-changed = [ on-focus-changed = [
# 'move-mouse window-lazy-center', # 'move-mouse window-lazy-center',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --trigger front_app_switched', 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --trigger front_app_switched',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --trigger update_windows' 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --trigger update_windows'
] ]
[gaps] [gaps]
@ -77,14 +77,14 @@ on-focus-changed = [
alt-shift-semicolon = [ alt-shift-semicolon = [
'mode service', 'mode service',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --trigger send_message MESSAGE=SERVICE_MODE HOLD=true' 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --trigger send_message MESSAGE=SERVICE_MODE HOLD=true'
] ]
alt-r = [ alt-r = [
'mode resize', 'mode resize',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --trigger send_message MESSAGE=RESIZE_MODE HOLD=true' 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --trigger send_message MESSAGE=RESIZE_MODE HOLD=true'
] ]
cmd-ctrl-1 = "exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim aerospace-scratchpad show Finder" cmd-ctrl-1 = "exec-and-forget ~/dotfiles/bin/path-shim aerospace-scratchpad show Finder"
[mode.resize.binding] [mode.resize.binding]
h = 'resize width -50' h = 'resize width -50'
@ -93,18 +93,18 @@ on-focus-changed = [
l = 'resize width +50' l = 'resize width +50'
esc = [ esc = [
'mode main', 'mode main',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --trigger hide_message' 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --trigger hide_message'
] ]
enter = [ enter = [
'mode main', 'mode main',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --trigger hide_message' 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --trigger hide_message'
] ]
[mode.service.binding] [mode.service.binding]
esc = [ esc = [
'reload-config', 'reload-config',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --trigger hide_message', 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --trigger hide_message',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --reload', 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --reload',
'mode main', 'mode main',
] ]
r = ['flatten-workspace-tree', 'mode main'] r = ['flatten-workspace-tree', 'mode main']
@ -119,14 +119,14 @@ on-focus-changed = [
p = [ p = [
'exec-and-forget ~/dotfiles/bin/presentation-mode on', 'exec-and-forget ~/dotfiles/bin/presentation-mode on',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --bar height=0', 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --bar height=0',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --trigger hide_message', 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --trigger hide_message',
'mode main' 'mode main'
] ]
shift-p = [ shift-p = [
'exec-and-forget ~/dotfiles/bin/presentation-mode off', 'exec-and-forget ~/dotfiles/bin/presentation-mode off',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --bar height=30', 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --bar height=30',
'exec-and-forget /Users/rayandrew/dotfiles/bin/path-shim sketchybar --trigger hide_message', 'exec-and-forget ~/dotfiles/bin/path-shim sketchybar --trigger hide_message',
'mode main' 'mode main'
] ]
@ -140,11 +140,11 @@ on-focus-changed = [
[[on-window-detected]] [[on-window-detected]]
if.app-id = 'com.openai.chat' if.app-id = 'com.openai.chat'
run = ['move-node-to-workspace 3'] run = ['move-node-to-workspace 3', 'layout h_accordion']
[[on-window-detected]] [[on-window-detected]]
if.app-id = 'com.anthropic.claudefordesktop' if.app-id = 'com.anthropic.claudefordesktop'
run = ['move-node-to-workspace 3'] run = ['move-node-to-workspace 3', 'layout h_accordion']
[[on-window-detected]] [[on-window-detected]]
if.app-id = 'com.1password.1password' if.app-id = 'com.1password.1password'
@ -178,11 +178,11 @@ on-focus-changed = [
[[on-window-detected]] [[on-window-detected]]
if.app-id = 'org.mozilla.firefox' if.app-id = 'org.mozilla.firefox'
run = ['move-node-to-workspace 10'] run = ['move-node-to-workspace 10', 'layout h_accordion']
[[on-window-detected]] [[on-window-detected]]
if.app-id = 'com.apple.Safari' if.app-id = 'com.apple.Safari'
run = ['move-node-to-workspace 10'] run = ['move-node-to-workspace 10', 'layout h_accordion']
[[on-window-detected]] [[on-window-detected]]
if.app-id = 'org.zotero.zotero' if.app-id = 'org.zotero.zotero'

View file

@ -35,8 +35,9 @@ named-mailboxes "p/trash" =Trash
named-mailboxes "p/archive" =Archive named-mailboxes "p/archive" =Archive
# Virtual mailboxes (notmuch) # Virtual mailboxes (notmuch)
virtual-mailboxes "All Mail" "notmuch://?query=folder:personal/** AND date:30d.." virtual-mailboxes "Last 30d" "notmuch://?query=path:personal/** AND date:30d.."
virtual-mailboxes "Unread" "notmuch://?query=folder:personal/** AND tag:unread" virtual-mailboxes "All Mail" "notmuch://?query=path:personal/**"
virtual-mailboxes "Unread" "notmuch://?query=path:personal/** AND tag:unread"
# Signature # Signature
set signature = "~/.config/neomutt/signatures/personal" set signature = "~/.config/neomutt/signatures/personal"

View file

@ -36,8 +36,9 @@ named-mailboxes "u/archive" =Archive
named-mailboxes "u/teaching" =Teaching named-mailboxes "u/teaching" =Teaching
# Virtual mailboxes (notmuch) # Virtual mailboxes (notmuch)
virtual-mailboxes "All Mail" "notmuch://?query=folder:uchicago/** AND date:30d.." virtual-mailboxes "Last 30d" "notmuch://?query=path:uchicago/** AND date:30d.."
virtual-mailboxes "Unread" "notmuch://?query=folder:uchicago/** AND tag:unread" virtual-mailboxes "All Mail" "notmuch://?query=path:uchicago/**"
virtual-mailboxes "Unread" "notmuch://?query=path:uchicago/** AND tag:unread"
# Signature # Signature
set signature = "~/.config/neomutt/signatures/uchicago" set signature = "~/.config/neomutt/signatures/uchicago"

View file

@ -30,10 +30,15 @@ set mail_check_stats
set status_chars = " *%A" set status_chars = " *%A"
set status_format = "[ Folder: %D ] [%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]%>─%?p?( %p postponed )?" set status_format = "[ Folder: %D ] [%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]%>─%?p?( %p postponed )?"
set date_format = "%d.%m.%Y %H:%M" set date_format = "%d.%m.%Y %H:%M"
set sort = date
set sort_aux = date # set sort = date
# set sort_aux = date
set use_threads = reverse
set sort = last-date-received
set sort_browser = reverse-date
set uncollapse_jump set uncollapse_jump
set sort_re set sort_re
set index_format = "%4C %Z %{%b %d} %-15.15L %?E?(%E)&? %s" set index_format = "%4C %Z %{%b %d} %-15.15L %?E?(%E)&? %s"
set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*" set reply_regexp = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*"
set quote_regexp = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+" set quote_regexp = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+"
@ -80,5 +85,8 @@ set nm_default_url = `echo "notmuch://$HOME/mail"`
set nm_query_type = messages set nm_query_type = messages
set nm_record_tags = "-inbox,sent" set nm_record_tags = "-inbox,sent"
# Source primary account (personal) # Source primary account (uchicago)
source ~/.config/neomutt/accounts/personal source ~/.config/neomutt/accounts/uchicago
# # Source primary account (personal)
# source ~/.config/neomutt/accounts/personal

View file

@ -61,8 +61,41 @@ add 'wakatime/vim-wakatime'
add 'EdenEast/nightfox.nvim' add 'EdenEast/nightfox.nvim'
now(function() now(function()
require('mail-count').setup {
accounts = {
{ name = 'U', query = 'tag:unread AND path:uchicago/**' },
{ name = 'P', query = 'tag:unread AND path:personal/**' },
},
interval = 60000, -- 60 seconds
}
require('mini.statusline').setup { require('mini.statusline').setup {
use_icons = true, use_icons = true,
content = {
active = function()
local mode, mode_hl = MiniStatusline.section_mode { trunc_width = 120 }
local git = MiniStatusline.section_git { trunc_width = 40 }
local diff = MiniStatusline.section_diff { trunc_width = 75 }
local diagnostics = MiniStatusline.section_diagnostics { trunc_width = 75 }
local lsp = MiniStatusline.section_lsp { trunc_width = 75 }
local filename = MiniStatusline.section_filename { trunc_width = 140 }
local fileinfo = MiniStatusline.section_fileinfo { trunc_width = 120 }
local location = MiniStatusline.section_location { trunc_width = 75 }
local search = MiniStatusline.section_searchcount { trunc_width = 75 }
local mail = require('mail-count').get()
return MiniStatusline.combine_groups {
{ hl = mode_hl, strings = { mode } },
{ hl = 'MiniStatuslineDevinfo', strings = { git, diff, diagnostics, lsp } },
'%<',
{ hl = 'MiniStatuslineFilename', strings = { filename } },
'%=',
{ hl = 'MiniStatuslineMail', strings = { mail } },
{ hl = 'MiniStatuslineFileinfo', strings = { fileinfo } },
{ hl = mode_hl, strings = { search, location } },
}
end,
},
} }
require('mini.icons').setup { require('mini.icons').setup {

View file

@ -0,0 +1,84 @@
-- mail-count.lua - Async mail count for statusline
local M = {}
---@class MailCountAccount
---@field name string Display name (e.g., "U" for uchicago)
---@field query string Notmuch query for this account
---@class MailCountConfig
---@field accounts MailCountAccount[] List of accounts to check
---@field interval? number Check interval in milliseconds (default: 60000)
---@field icon? string Icon to display (default: "󰇮")
---@field hide_zero? boolean Hide when all counts are zero (default: false)
---@type MailCountConfig
local config = {
accounts = {},
interval = 60000,
icon = '󰇮',
hide_zero = false,
}
local counts = {}
local last_check = 0
local timer = nil
local function update_count(account)
vim.fn.jobstart({ 'notmuch', 'count', account.query }, {
stdout_buffered = true,
on_stdout = function(_, data)
if data and data[1] then counts[account.name] = tonumber(data[1]) or 0 end
end,
})
end
function M.refresh()
for _, account in ipairs(config.accounts) do
update_count(account)
end
last_check = vim.uv.now()
end
function M.get()
if #config.accounts == 0 then return '' end
local now = vim.uv.now()
if now - last_check > config.interval then M.refresh() end
local total = 0
local parts = {}
for _, account in ipairs(config.accounts) do
local count = counts[account.name] or 0
total = total + count
table.insert(parts, string.format('%s:%d', account.name, count))
end
if config.hide_zero and total == 0 then return '' end
return string.format('%s %s', config.icon, table.concat(parts, ' | '))
end
---@param opts? MailCountConfig
function M.setup(opts)
config = vim.tbl_deep_extend('force', config, opts or {})
-- Initialize counts
for _, account in ipairs(config.accounts) do
counts[account.name] = 0
end
-- Initial fetch on load
vim.schedule(function() M.refresh() end)
-- Stop existing timer if any
if timer then
timer:stop()
timer:close()
end
-- Refresh on timer
timer = vim.uv.new_timer()
timer:start(config.interval, config.interval, vim.schedule_wrap(function() M.refresh() end))
end
return M

View file

@ -349,6 +349,7 @@ local function apply_highlights(c, opts)
hi('MiniStatuslineFilename', { fg = c.fg, bg = c.bg_float }) hi('MiniStatuslineFilename', { fg = c.fg, bg = c.bg_float })
hi('MiniStatuslineFileinfo', { fg = c.fg, bg = c.bg_highlight }) hi('MiniStatuslineFileinfo', { fg = c.fg, bg = c.bg_highlight })
hi('MiniStatuslineInactive', { fg = c.fg_dark, bg = c.bg_float }) hi('MiniStatuslineInactive', { fg = c.fg_dark, bg = c.bg_float })
hi('MiniStatuslineMail', { fg = c.bg, bg = c.info, bold = true })
-- Mini.icons -- Mini.icons
hi('MiniIconsAzure', { fg = c.info }) hi('MiniIconsAzure', { fg = c.info })

View file

@ -6,11 +6,11 @@
"utils": "utils" "utils": "utils"
}, },
"locked": { "locked": {
"lastModified": 1764407814, "lastModified": 1764744276,
"narHash": "sha256-IiOWUqodFqzy4PhU6LcziwoJbbFR0AfaOBJDO83/mHM=", "narHash": "sha256-4Qrmb5+LLu2XWjW6XEbRHlRRCoKdUW4eWJ8N8pketn8=",
"owner": "cristianoliveira", "owner": "cristianoliveira",
"repo": "aerospace-scratchpad", "repo": "aerospace-scratchpad",
"rev": "d039cd49e2a15144c9a766509abe1b7f59eb6b04", "rev": "643bf206319f6f56437aff72b13a43bc06adc9ed",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -28,7 +28,7 @@
services.mbsync = { services.mbsync = {
enable = config.custom.email.mbsync; enable = config.custom.email.mbsync;
configFile = "${dots}/config/mbsync/mbsyncrc"; configFile = "${dots}/config/mbsync/mbsyncrc";
frequency = "*:0/1"; frequency = "*:0/5";
extraPackages = with pkgs; [ sops ] ++ lib.optionals config.custom.email.notmuch [ notmuch ]; extraPackages = with pkgs; [ sops ] ++ lib.optionals config.custom.email.notmuch [ notmuch ];
postExec = lib.mkIf config.custom.email.notmuch "${pkgs.notmuch}/bin/notmuch new"; postExec = lib.mkIf config.custom.email.notmuch "${pkgs.notmuch}/bin/notmuch new";
environment = { environment = {